Porta seriale virtuale per Linux


128

Devo testare un'applicazione per porta seriale su Linux, tuttavia, la mia macchina di prova ha solo una porta seriale.

C'è un modo per aggiungere una porta seriale virtuale a Linux e testare la mia applicazione emulando un dispositivo tramite una shell o uno script?

Nota: non posso rimappare la porta, è hardcoded su ttys2 e devo testare l'applicazione così come è scritta.

Risposte:


75

Puoi usare una pty ("pseudo-telescrivente", dove una porta seriale è una "vera telescrivente") per questo. Da un'estremità, apri /dev/ptyp5e quindi collega il tuo programma a /dev/ttyp5;ttyp5agirà proprio come una porta seriale, ma invierà / riceverà tutto ciò che fa tramite / dev / ptyp5.

Se ne hai davvero bisogno per parlare con un file chiamato /dev/ttys2, sposta semplicemente il tuo vecchio /dev/ttys2e crea un collegamento simbolico da ptyp5a ttys2.

Ovviamente puoi usare un numero diverso da ptyp5. Forse scegline uno con un numero alto per evitare duplicati, poiché anche tutti i tuoi terminali di accesso useranno ptys.

Wikipedia ha di più sui pty: http://en.wikipedia.org/wiki/Pseudo_terminal


8
Su Linux puoi usare le chiamate di sistema openpty / forkpty. Vedi la pagina man
Matthew Smith,

8
come creare una coppia di porte seriali virtuali utilizzando lo strumento della riga di comando?
linjunhalida

8
nota che molti parametri della porta seriale, es. baudrate, parità, controllo del flusso hw, dimensione dei caratteri (?) non sono implementati in pty, è quindi impossibile testare la tua applicazione in presenza di errori di trasmissione seriale.
Dima Tisnek

10
Questo è utile, ma descrive gli pseudo-terminali BSD "vecchio stile". Gli pseudo-terminali UNIX 98 di "nuovo stile" funzionano in modo leggermente diverso - vedere la ptspagina man per i dettagli.
Craig McQueen

3
@LaszloPapp Mi scuso, ho mentito tutto il tempo
Matthew Smith,

160

A complemento della risposta di @ slonik.

Puoi testare socat per creare la porta seriale virtuale seguendo la seguente procedura (testata su Ubuntu 12.04):

Apri un terminale (chiamiamolo Terminal 0) ed eseguilo:

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

Il codice sopra restituisce:

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]

Apri un altro terminale e scrivi (Terminal 1):

cat < /dev/pts/2

il nome della porta di questo comando può essere modificato in base al pc. dipende dall'output precedente.

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 

dovresti usare il numero disponibile nell'area evidenziata.

Apri un altro terminale e scrivi (Terminal 2):

echo "Test" > /dev/pts/3

Ora torna al Terminal 1 e vedrai la stringa "Test".


Questo ha funzionato meglio per me rispetto alla risposta di slonik, perché si assegna automaticamente ai file della porta COM virtuale e non viene visualizzato.
gbmhunter

7
Se vuoi che un nome file riproducibile usi link=/path/to/linkdopo ogni dichiarazione di dispositivo (dopo echo = 0). Può quindi essere utilizzato nei test automatizzati. (come fa Slonik nella risposta)
Patrick B.

Ha funzionato esattamente come accennato. Mi ha aiutato grazie.
nim118

1
Per creare un tipo di programma che si collega a una vera e propria porta seriale: socat -d -d pty,raw,echo=0 /dev/ttyUSB5,raw,echo=0.
Penghe Geng

posso creare una porta seriale con nomi come /dev/ttyS0invece di /dev/pts/1?
mrid

48

Usa socat per questo:

Per esempio:

socat PTY,link=/dev/ttyS10 PTY,link=/dev/ttyS11

Questo ha funzionato bene per me, testato con minicom! Sembra che l'ingresso a un terminale venga ripetuto a entrambi (quindi riapparirà anche sul terminale di ingresso).
gbmhunter

1
Non ho lo stesso comportamento dell'eco ... minicom ha una funzione "echo locale" ... ma quando è disabilitata, funziona esattamente come farebbe una vera porta seriale. grazie per il consiglio.
cptHammer

16

C'è anche tty0tty http://sourceforge.net/projects/tty0tty/ che è un vero emulatore di null modem per Linux.

È un semplice modulo del kernel: un piccolo file sorgente. Non so perché ha ottenuto solo il pollice verso il basso su sourceforge, ma funziona bene per me. La cosa migliore è che emula anche i pin hardware (RTC / CTS DSR / DTR). Implementa anche i comandi TIOCMGET / TIOCMSET e TIOCMIWAIT iotcl!

Su un kernel recente potresti ricevere errori di compilazione. Questo è facile da aggiustare. Basta inserire poche righe all'inizio del sorgente module / tty0tty.c (dopo gli include):

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

Quando il modulo viene caricato, crea 4 coppie di porte seriali. I dispositivi sono da / dev / tnt0 a / dev / tnt7 dove tnt0 è connesso a tnt1, tnt2 è connesso a tnt3, ecc. Potrebbe essere necessario correggere i permessi del file per poter usare i dispositivi.

modificare:

Immagino di essere stato un po 'veloce con il mio entusiasmo. Anche se il conducente sembra promettente, sembra instabile. Non lo so per certo, ma penso che si sia schiantato una macchina in ufficio su cui stavo lavorando da casa. Non posso controllare finché non torno in ufficio lunedì.

La seconda cosa è che TIOCMIWAIT non funziona. Il codice sembra essere copiato da un codice di esempio "tiny tty". La gestione di TIOCMIWAIT sembra a posto, ma non si sveglia mai perché manca la chiamata corrispondente a wake_up_interruptible ().

modificare:

L'incidente in ufficio è stato davvero colpa del guidatore. Mancava un'inizializzazione e il codice TIOCMIWAIT completamente non testato ha causato un arresto anomalo della macchina.

Ho passato ieri e oggi a riscrivere il driver. Ci sono stati molti problemi, ma ora funziona bene per me. Manca ancora del codice per il controllo del flusso hardware gestito dal driver, ma non ne ho bisogno perché gestirò i pin da solo usando TIOCMGET / TIOCMSET / TIOCMIWAIT dal codice in modalità utente.

Se qualcuno è interessato alla mia versione del codice, mandami un messaggio e te lo invierò.


2
Sarei interessato a vedere il tuo codice. Puoi contribuire di nuovo al progetto tty0tty? Tuttavia, preferirei che le persone migliorassero il codice pseudo-terminale nel kernel Linux. Ad esempio, aggiungi il supporto per l'handshaking hardware e TIOCMIWAIT.
Craig McQueen

3
"Se qualcuno è interessato alla mia versione del codice, mandami un messaggio e te lo invierò." Sì, mi interessa! Puoi indicarlo da qualche parte, ad esempio su GitHub?
Craig McQueen

7
Ho caricato il driver su: github.com/pitti98/nullmodem Spiacente, ci è voluto così tanto tempo per rispondere. Non sono molto attivo sullo stackoverflow e ho trascurato il tuo commento!
Peter Remmers

No, l'ho scritto perché ne avevo bisogno e ho smesso una volta che era abbastanza buono per fare quello che volevo. Ora che è pubblico, spero che sia utile per qualcun altro, e forse qualcuno riprende da dove l'ho lasciato.
Peter Remmers

8

Potresti voler guardare Tibbo VSPDL per creare una porta seriale virtuale Linux usando un driver del kernel: sembra piuttosto nuovo ed è disponibile per il download in questo momento (versione beta). Non sono sicuro della licenza a questo punto o se vogliono renderla disponibile in commercio solo in futuro.

Esistono altre alternative commerciali, come http://www.ttyredirector.com/ .

In Open Source, Remserial (GPL) può anche fare quello che vuoi, usando Unix PTY. Trasmette i dati seriali in "forma grezza" a una presa di rete; La configurazione simile a STTY dei parametri del terminale deve essere eseguita durante la creazione della porta, la modifica successiva come descritto in RFC 2217 non sembra essere supportata. Dovresti essere in grado di eseguire due istanze di remserial per creare un nullmodem virtuale come com0com, tranne per il fatto che dovrai impostare la velocità della porta ecc. In anticipo.

Socat (anche GPL) è come una variante estesa di Remserial con molte molte più opzioni, incluso un metodo "PTY" per reindirizzare il PTY a qualcos'altro, che può essere un'altra istanza di Socat. Per Unit tets, socat è probabilmente più carino di remserial perché puoi direttamente cat file nel PTY. Vedere l' esempio PTY sulla manpage. Esiste una patch in "contrib" per fornire il supporto RFC2217 per la negoziazione delle impostazioni della linea seriale.


6

Utilizzando i collegamenti pubblicati nelle risposte precedenti, ho codificato un piccolo esempio in C ++ utilizzando una porta seriale virtuale. Ho inserito il codice in GitHub: https://github.com/cymait/virtual-serial-port-example .

Il codice è abbastanza autoesplicativo. Per prima cosa, crei il processo master eseguendo ./main master e stamperà sullo stderr che il dispositivo sta utilizzando. Dopodiché, invoca ./main slave device, dove device è il dispositivo stampato nel primo comando.

E questo è tutto. Hai un collegamento bidirezionale tra i due processi.

Usando questo esempio puoi testare l'applicazione inviando tutti i tipi di dati e vedere se funziona correttamente.

Inoltre, puoi sempre collegare il dispositivo in modo simbolico, quindi non è necessario ricompilare l'applicazione che stai testando.


1
while (read (fd, & inputbyte, 1) == 1) {...} read non è definito nel codice. la scrittura non è definita. close non è definito.
Mattis Asp

4

Saresti in grado di utilizzare un adattatore USB-> RS232? Ne ho alcuni e usano solo il driver FTDI. Quindi, dovresti essere in grado di rinominare / dev / ttyUSB0 (o ​​qualsiasi cosa venga creata) come / dev / ttyS2.


4

Posso pensare a tre opzioni:

Implementare RFC 2217

RFC 2217 copre una porta com per lo standard TCP / IP che consente a un client su un sistema di emulare una porta seriale ai programmi locali, mentre invia e riceve in modo trasparente dati e segnali di controllo a un server su un altro sistema che ha effettivamente la porta seriale. Ecco una panoramica di alto livello .

Quello che faresti è trovare o implementare un driver per la porta com client che implementa il lato client del sistema sul tuo PC: sembra essere una vera porta seriale ma in realtà trasporta tutto su un server. Potresti essere in grado di ottenere questo driver gratuitamente da Digi, Lantronix, ecc a supporto dei loro veri server di porte seriali indipendenti.

Dovresti quindi implementare il lato server della connessione localmente in un altro programma, consentendo al client di connettersi ed emettere i dati e controllare i comandi secondo necessità.

Probabilmente non è banale, ma l'RFC è disponibile e potresti essere in grado di trovare un progetto open source che implementa uno o entrambi i lati della connessione.

Modifica il driver della porta seriale di Linux

In alternativa, il sorgente del driver della porta seriale per Linux è immediatamente disponibile. Prendilo, distruggi i pezzi di controllo hardware e fai in modo che un driver esegua due porte / dev / ttySx, come un semplice loopback. Quindi collega il tuo programma reale a ttyS2 e il tuo simulatore all'altro ttySx.

Utilizza due cavi USB <--> seriali in loopback

Ma la cosa più semplice da fare adesso? Spendi $ 40 su due dispositivi USB con porta seriale, collegali insieme (null modem) e in realtà hai due porte seriali reali: una per il programma che stai testando, una per il tuo simulatore.

-Adamo


1
In realtà i cavi UART USB null modem mi sembrano una soluzione piuttosto elegante in quanto supportano sia i test locali (procurati un hub USB se sei a corto di porte) sia il debug remoto.
Maxthon Chan

Non ho esaminato la sua qualità, ma ttynvt implementa RFC 2217 tramite Linux FUSE
Daniel Santos
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.