Wirtualny port szeregowy dla systemu Linux

129

Muszę przetestować aplikację portu szeregowego w systemie Linux, jednak moja maszyna testowa ma tylko jeden port szeregowy.

Czy istnieje sposób na dodanie wirtualnego portu szeregowego do systemu Linux i przetestowanie mojej aplikacji poprzez emulację urządzenia za pomocą powłoki lub skryptu?

Uwaga: nie mogę zmienić mapowania portu, został zakodowany na ttys2 i muszę przetestować aplikację w takiej postaci, w jakiej została napisana.

JeffV
źródło

Odpowiedzi:

75

Możesz użyć do tego pty ("pseudo-teletype", gdzie port szeregowy jest "rzeczywistym teletype"). Z jednej strony otwórz /dev/ptyp5, a następnie dołącz swój program do /dev/ttyp5; ttyp5będzie zachowywał się jak port szeregowy, ale wysyła / odbiera wszystko, co robi, przez / dev / ptyp5.

Jeśli naprawdę potrzebujesz go do komunikowania się z plikiem o nazwie /dev/ttys2, po prostu usuń stary plik /dev/ttys2z drogi i utwórz łącze symboliczne z ptyp5do ttys2.

Oczywiście możesz użyć innego numeru niż ptyp5. Być może wybierz taki z wysoką liczbą, aby uniknąć duplikatów, ponieważ wszystkie twoje terminale logowania będą również używać ptys.

Wikipedia zawiera więcej informacji o ptys: http://en.wikipedia.org/wiki/Pseudo_terminal

apenwarr
źródło
8
W Linuksie możesz używać wywołań systemowych openpty / forkpty. Zobacz stronę
podręcznika
8
jak utworzyć wirtualną parę portów szeregowych za pomocą narzędzia wiersza poleceń?
linjunhalida
8
zwróć uwagę, że wiele parametrów portu szeregowego, np. szybkość transmisji, parzystość, sterowanie przepływem HW, rozmiar znaku (?) nie jest zaimplementowanych w pty, dlatego nie jest możliwe przetestowanie aplikacji w obecności błędów transmisji szeregowej.
Dima Tisnek
10
Jest to pomocne, ale opisuje pseudoterminale BSD w „starym stylu”. Pseudoterminale UNIX 98 w "nowym stylu" działają nieco inaczej - zobacz ptsstronę podręcznika po szczegóły.
Craig McQueen
3
@LaszloPapp Przepraszam, cały czas kłamałem
Matthew Smith,
161

Uzupełnienie odpowiedzi @ slonik.

Możesz przetestować socat, aby utworzyć wirtualny port szeregowy, wykonując następującą procedurę (testowane na Ubuntu 12.04):

Otwórz terminal (nazwijmy go Terminal 0) i uruchom go:

socat -d -d pty,raw,echo=0 pty,raw,echo=0

Powyższy kod zwraca:

2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/2
2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/3
2013/11/01 13:47:27 socat[2506] N starting data transfer loop with FDs [3,3] and [5,5]

Otwórz inny terminal i napisz (Terminal 1):

cat < /dev/pts/2

nazwę portu tego polecenia można zmienić w zależności od komputera. zależy to od poprzedniego wyjścia.

2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/**2**
2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/**3**
2013/11/01 13:47:27 socat[2506] N starting data transfer loop with FDs 

należy użyć numeru dostępnego w zaznaczonym obszarze.

Otwórz inny terminal i napisz (Terminal 2):

echo "Test" > /dev/pts/3

Wróćmy teraz do terminala 1, a zobaczysz ciąg „Test”.

cantoni
źródło
To zadziałało lepiej dla mnie niż odpowiedź slonika, ponieważ automatycznie przypisuje do plików wirtualnego portu COM i nie wyświetla echa.
gbmhunter
7
Jeśli chcesz, aby nazwa pliku była odtwarzalna, użyj link=/path/to/linkpo każdej deklaracji urządzenia (po echo = 0). Dzięki temu może być używany w testach automatycznych. (tak jak slonik w swojej odpowiedzi)
Patrick B.
To działało dokładnie tak, jak wspomniano. Pomogło mi dzięki.
nim118
1
Aby utworzyć pty, że linki do prawdziwego portu szeregowego: socat -d -d pty,raw,echo=0 /dev/ttyUSB5,raw,echo=0.
Penghe Geng
czy mogę stworzyć port szeregowy o nazwach takich jak /dev/ttyS0zamiast /dev/pts/1?
środa
48

Użyj do tego socat:

Na przykład:

socat PTY,link=/dev/ttyS10 PTY,link=/dev/ttyS11
slonik
źródło
To działało dobrze dla mnie, przetestowane z minicom! Wygląda na to, że sygnał wejściowy do jednego terminala jest echo do obu (więc pojawi się również ponownie na terminalu wejściowym).
gbmhunter
1
Nie mam takiego samego zachowania echa… minicom ma funkcję „lokalnego echa”… ale kiedy jest wyłączona, działa dokładnie tak samo, jak prawdziwy port szeregowy. dzięki za wskazówkę.
cptHammer
16

Jest też http://sourceforge.net/projects/tty0tty/ tty0tty, który jest prawdziwym emulatorem null-modem dla Linuksa.

Jest to prosty moduł jądra - mały plik źródłowy. Nie wiem, dlaczego na SourceForge jest tylko kciuk w dół, ale dla mnie działa dobrze. Najlepsze jest to, że emuluje również piny sprzętowe (RTC / CTS DSR / DTR). Implementuje nawet polecenia iotcl TIOCMGET / TIOCMSET i TIOCMIWAIT!

Na ostatnim jądrze mogą pojawić się błędy kompilacji. To jest łatwe do naprawienia. Wystarczy wstawić kilka wierszy na górze źródła module / tty0tty.c (po dołączeniach):

#ifndef init_MUTEX
#define init_MUTEX(x) sema_init((x),1)
#endif

Po załadowaniu moduł tworzy 4 pary portów szeregowych. Urządzenia to / dev / tnt0 do / dev / tnt7, gdzie tnt0 jest podłączony do tnt1, tnt2 jest podłączony do tnt3 itd. Aby móc korzystać z urządzeń, może być konieczne poprawienie uprawnień do pliku.

edytować:

Myślę, że byłem trochę szybki z moim entuzjazmem. Chociaż sterownik wygląda obiecująco, wydaje się niestabilny. Nie wiem na pewno, ale wydaje mi się, że zepsuło to maszynę w biurze, nad którym pracowałem w domu. Nie mogę tego sprawdzić, dopóki nie wrócę do biura w poniedziałek.

Po drugie, TIOCMIWAIT nie działa. Kod wydaje się być skopiowany z jakiegoś przykładowego kodu „tiny tty”. Wydaje się, że obsługa TIOCMIWAIT jest na miejscu, ale nigdy się nie budzi, ponieważ brakuje odpowiedniego wywołania wake_up_interruptible ().

edytować:

Wypadek w biurze naprawdę był winą kierowcy. Brakowało inicjalizacji, a całkowicie niesprawdzony kod TIOCMIWAIT spowodował awarię maszyny.

Wczoraj i dziś spędziłem na przepisywaniu sterownika. Było wiele problemów, ale teraz działa dobrze dla mnie. Wciąż brakuje kodu do kontroli przepływu sprzętu zarządzanego przez sterownik, ale nie potrzebuję go, ponieważ będę zarządzał pinami samodzielnie za pomocą TIOCMGET / TIOCMSET / TIOCMIWAIT z kodu trybu użytkownika.

Jeśli ktoś jest zainteresowany moją wersją kodu, wyślij mi wiadomość, a wyślę ją do Ciebie.

Peter Remmers
źródło
2
Chciałbym zobaczyć twój kod. Czy możesz wnieść go z powrotem do projektu tty0tty? Wolałbym jednak, aby ludzie poprawiali kod pseudoterminalu w jądrze Linuksa. Np. Dodaj obsługę sprzętowego uzgadniania i TIOCMIWAIT.
Craig McQueen
3
„Jeśli ktoś jest zainteresowany moją wersją kodu, wyślij mi wiadomość, a wyślę ją do Ciebie”. Tak, jestem zainteresowany! Czy możesz go gdzieś wskazać, np. Na GitHubie?
Craig McQueen
7
Wgrałem sterownik na: github.com/pitti98/nullmodem Przepraszamy, że tak długo trwało udzielanie odpowiedzi. Nie jestem zbyt aktywny w stackoverflow i przeoczyłem twój komentarz!
Peter Remmers
Nie, napisałem to, ponieważ tego potrzebowałem i przestałem, gdy było wystarczająco dobre, aby robić to, co chciałem. Teraz, gdy jest publiczna, mam nadzieję, że jest przydatna dla kogoś innego i może ktoś odbierze ją tam, gdzie ją zostawiłem.
Peter Remmers
8

Możesz spojrzeć na Tibbo VSPDL do tworzenia wirtualnego portu szeregowego linux za pomocą sterownika jądra - wydaje się całkiem nowy i jest już dostępny do pobrania (wersja beta). Nie jestem pewien co do licencji w tym momencie lub czy chcą ją udostępnić komercyjnie dopiero w przyszłości.

Istnieją inne komercyjne alternatywy, takie jak http://www.ttyredirector.com/ .

W Open Source, Remserial (GPL) może również robić, co chcesz, używając Unix PTY. Przesyła dane szeregowe w „surowej formie” do gniazda sieciowego; Podczas tworzenia portu należy wykonać konfigurację parametrów terminala podobną do STTY, zmiana ich później, jak opisano w RFC 2217, nie wydaje się być obsługiwana. Powinieneś być w stanie uruchomić dwie instancje remserial, aby stworzyć wirtualny nullmodem, taki jak com0com, z wyjątkiem tego, że będziesz musiał wcześniej ustawić prędkość portu itp.

Socat (również GPL) jest jak rozszerzona odmiana Remserial z wieloma innymi opcjami, w tym metodą „PTY” do przekierowania PTY do czegoś innego, co może być kolejną instancją Socat. W przypadku tetów jednostek socat jest prawdopodobnie lepszy niż remserial, ponieważ można bezpośrednio umieszczać pliki w formacie PTY. Zobacz przykład PTY na stronie podręcznika. W obszarze „contrib” istnieje łatka zapewniająca obsługę RFC2217 do negocjowania ustawień linii szeregowej.


źródło
6

Korzystając z linków zamieszczonych w poprzednich odpowiedziach, zakodowałem mały przykład w C ++ przy użyciu wirtualnego portu szeregowego. Wrzuciłem kod do GitHub: https://github.com/cymait/virtual-serial-port-example .

Kod jest dość zrozumiały. Najpierw utwórz proces główny, uruchamiając ./main master, który wydrukuje na stderr używane przez urządzenie. Następnie wywołujesz ./main urządzenie podrzędne, gdzie urządzenie jest urządzeniem wypisanym w pierwszym poleceniu.

I to wszystko. Masz dwukierunkowe połączenie między tymi dwoma procesami.

Korzystając z tego przykładu, możesz przetestować aplikację, wysyłając wszelkiego rodzaju dane i sprawdzić, czy działa poprawnie.

Ponadto zawsze możesz utworzyć dowiązanie symboliczne do urządzenia, więc nie musisz ponownie kompilować testowanej aplikacji.

Mauro Ciancio
źródło
1
while (read (fd, & inputbyte, 1) == 1) {...} read jest niezdefiniowane w twoim kodzie. write jest niezdefiniowane. close jest niezdefiniowane.
Mattis Asp,
4

Czy byłbyś w stanie użyć adaptera USB-> RS232? Mam kilka, a oni po prostu używają sterownika FTDI. Następnie powinieneś być w stanie zmienić nazwę / dev / ttyUSB0 (lub cokolwiek zostanie utworzone) na / dev / ttyS2.

Wyjec
źródło
4

Przychodzą mi do głowy trzy opcje:

Implementuj RFC 2217

RFC 2217 obejmuje port COM w standardzie TCP / IP, który pozwala klientowi w jednym systemie emulować port szeregowy do programów lokalnych, podczas gdy w niewidoczny sposób wysyła i odbiera dane oraz sygnały sterujące do serwera w innym systemie, który faktycznie ma port szeregowy. Oto ogólny przegląd .

To, co byś zrobił, to znalezienie lub zaimplementowanie sterownika portu com klienta, który zaimplementowałby stronę klienta systemu na twoim komputerze - wyglądający jak prawdziwy port szeregowy, ale w rzeczywistości przenoszący wszystko na serwer. Możesz uzyskać ten sterownik za darmo od Digi, Lantronix itp. W celu wsparcia ich prawdziwych samodzielnych serwerów portu szeregowego.

Następnie zaimplementowałbyś połączenie po stronie serwera lokalnie w innym programie - umożliwiając klientowi łączenie się i wydawanie danych i poleceń sterujących w razie potrzeby.

Prawdopodobnie nie jest to trywialne, ale RFC istnieje i możesz znaleźć projekt open source, który implementuje jedną lub obie strony połączenia.

Zmodyfikuj sterownik portu szeregowego Linuksa

Alternatywnie, łatwo dostępne jest źródło sterownika portu szeregowego dla systemu Linux. Weź to, wypatruj sprzętowe elementy sterujące i niech ten jeden sterownik uruchamia dwa porty / dev / ttySx, jako prostą pętlę zwrotną. Następnie podłącz swój prawdziwy program do ttyS2, a symulator do drugiego ttySx.

Użyj dwóch kabli szeregowych USB <--> w sprzężeniu zwrotnym

Ale najłatwiejsza rzecz do zrobienia teraz? Wydaj 40 USD na dwa urządzenia USB z portem szeregowym, połącz je ze sobą (modem zerowy) i faktycznie posiadaj dwa prawdziwe porty szeregowe - jeden dla testowanego programu, drugi dla symulatora.

-Adam

Adam Davis
źródło
1
Właściwie kable USB UART z zerowym modemem wydają mi się dość eleganckim rozwiązaniem, ponieważ obsługuje zarówno lokalne testowanie (zdobądź koncentrator USB, jeśli masz mało portów), jak i zdalne debugowanie.
Maxthon Chan
Nie sprawdzałem jego jakości, ale ttynvt implementuje RFC 2217 przez Linux FUSE
Daniel Santos