2013-04-02 14 views
5

Sto leggendo i dati tramite una connessione USB come porta seriale con il driver PL2303. Restituisce correttamente quando si esegue un open e quando si impostano le opzioni TTY e non bloccano. Quando provo a chiudere la connessione, si blocca. In questo stato legge " " invece dei caratteri.Il programma si blocca quando si chiude la connessione della porta seriale

Posso collegarmi perfettamente al dispositivo con cutecom. Ecco la parte strana:

  1. Se prima mi collego al dispositivo tramite cutecom (un monitor seriale), il mio programma si connetterà e chiuderà perfettamente bene ogni volta in seguito. Legge i personaggi come mi aspetto che vengano letti. (No ).
  2. Se disconnetto e ricollego l'hardware, il mio programma si interromperà fino a quando eseguirò cutecom.

Poiché funziona dopo l'utilizzo di cutecom, mi viene in mente che mi manca qualcosa nella mia connessione iniziale o nelle impostazioni di connessione. Ecco quello che io uso per la connessione:

baud_rate = 38400; 
fd = open (device_path, O_RDONLY | O_NOCTTY); 

Nel mio set_tty_options funzione:

struct termios tty_options; 

memset (&tty_options, 0, sizeof(tty_options)); 
tcgetattr (fd, &tty_options); 

cfsetispeed(&tty_options, baud_rate);       // set baud rate 
tty_options.c_cflag = (tty_options.c_cflag & ~CSIZE) | CS8; // 8 bit msgs 
tty_options.c_cflag |= (CLOCAL | CREAD);      // enable reading 

tty_options.c_cflag &= ~(PARENB | PARODD);     // shut off parity 
tty_options.c_cflag |= parity; 
tty_options.c_cflag &= ~CSTOPB; 
tty_options.c_cflag &= ~CRTSCTS; 

if (tcsetattr (fd, TCSANOW, &tty_options) != 0) 
{ 
    printf("error %d from tcsetattr\n", errno); 
    return TTY_ERROR; 
} 

In set_blocking funzione:

if (tcgetattr (fd, &tty) != 0) 
{ 
    printf("error %d from tggetattr", errno); 
    return FAILURE; 
} 

// 0 or 1 byte is enough to return from read 
tty.c_cc[VMIN] = should_block ? 1 : 0; 
tty.c_cc[VTIME] = 5;   // 0.5 seconds read timeout 

if (tcsetattr (fd, TCSANOW, &tty) != 0) 
{ 
    printf("error %d setting term attributes", errno); 
    return FAILURE; 
} 
+0

Vedo 2 problemi con il codice. Il primo è che la funzione 'set_tty_options' non sembra inizializzare completamente la struttura' tty_options'. Questo potrebbe spiegare "il mio programma funziona se eseguo X per primo, ma si blocca/fallisce se eseguito da solo". Questo è il classico sintomo di un programma che non inizializza correttamente o completamente il suo ambiente. Secondo, la funzione 'set_blocking' è fasulla per l'input canonico. 'c_cc [VMIN]' e 'c_cc [VTIME]' dovrebbero essere usati solo per l'input ** non-canonical ** (aka raw). Per un 'read()' non bloccante di input canonico, usa 'fcntl()' per impostarlo. – sawdust

risposta

0

Ecco cosa ho fatto. L'ho capito essenzialmente copiando e incollando parti dal codice sorgente cutecom's.

  1. Quando si apre ...

    int fd, n; 
    fd = open (device_path, O_RDONLY | O_NOCTTY | O_NDELAY); 
    
    ... error check fd ... 
    
    n = fcntl(ail_info->ail_serial_fd, F_GETFL, 0); 
    fcntl(fd, F_SETFL, n & ~O_NDELAY); 
    
  2. Non è possibile impostare la velocità di trasmissione, come stavo facendo. Devi usare lo B38400 definito;

    baud = B38400;

  3. Poi, ho aggiunto la risposta di wallyk.

    tty_settings.c_lflag = 0;

Edit: Come da commento segatura, ho trovato un modo migliore per impostare questo all'ingresso crudo.

tty_options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); 

E funziona.

+0

* "Poi ho aggiunto la risposta di wallyk. Tty_settings.c_lflag = 0;" * - La porta seriale non è ancora stata configurata correttamente. A cosa è impostato 'c_oflag'? Si noti che l'assegnazione difficile ai membri della struttura 'termios' non è raccomandata per POSIX. Dovresti chiamare 'tcgetattr()', e quindi abilitare o disabilitare ogni campo di attributo (come fai per 'c_cflag'). Vedere [Guida alla programmazione seriale per sistemi operativi POSIX] (http://www.easysw.com/~mike/serial/serial.html). Stai utilizzando le chiamate POSIX, quindi segui le loro regole. – sawdust

1

Penso che si desidera aggiungere | O_SYNC alle bandiere aperti ad insistere su I/O sincrono. Dubito che stia causando comunque un problema.

Tuttavia, penso che si vuole ignorare il segnale di break, che viene segnalato come un carattere NUL come si stanno ottenendo:

tty_settings.c_iflag &= ~IGNBRK;   // ignore break signal 

Inoltre, si vuole essere sicuri che il processo di ingresso è completamente spento, in modo che la ricezione di un backspace,^C,^\, ecc non attivano alcuna reazione:

tty_settings.c_lflag = 0;    // no signaling chars, no echo, 
             // no canonical processing 

sembra che si sta già utilizzando my set_blocking() function, in modo che dovrebbe essere a posto.

Problemi correlati