Newsgroup: it.comp.os.linux.development
Titolo: seriale in linux

Devo realizzare un programma che comunica via seriale con un circuirino.
Premetto che il circuito funziona perchè la comunicazione con lo stesso
simulata con minicom funziona perfettamente.
Il problema deve quindi trovarsi nel programma che ho scritto. linux
vede tutto come dei file e pensavo perciò che fosse possibile comunicare
con la seriale semplicemente aprendo il relativo file. Naturalmente sono
necessarie delle preventive configurazioni ed è qui che penso di aver
sbagliato.
Vi allego parte del codice in modo che possiate dargli un'occhiata.
Il programma deve semplicemente (x ora) inviare un carattere '@' grezzo
(senza alcun tipo di controllo) sulla seriale e deve ricevere dal
dispositivo un altro '@' in ritorno.
Ditemi dove sbaglio. Grazie. Alessio
#include <stdio.h>
#include <termios.h>
#include <fcntl.h>
#include <errno.h>
#define BAUDRATE B9600
main()
{
  int com;
  unsigned int c;
  char car;
  struct termios options;
 
  cfsetispeed(&options,BAUDRATE);
  cfsetospeed(&options,BAUDRATE);
  options.c_cflag |= (CLOCAL | CREAD);
  options.c_cflag &= CBAUD;
  options.c_cflag |= B9600;
 
  options.c_cflag &= ~PARENB;
  options.c_cflag &= ~CSTOPB;
  options.c_cflag &= ~CSIZE;
  options.c_cflag |= CS8;
  options.c_cflag |= CREAD;
  options.c_cflag |= CLOCAL;
  cfsetispeed(&options,B9600);
  cfsetospeed(&options,B9600);
 
  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
  options.c_iflag &= ~(IXON | IXOFF | IXANY);
  options.c_oflag &= ~OPOST;
 
  tcsetattr(com,TCSANOW,&options);
  com=open("/dev/ttyS1",O_RDWR | O_NOCTTY | O_NDELAY );
  if(com<0)printf("\nErrore\n");
  else
    {
      printf("\nHo aperto una connessione su COM2\n");
      car='@';
      write(com,&car,1);
      read(com,&car,1);
      printf("\nho letto %d caratteri\n",nr);
      printf("\n%c\n",car);
    }
 
  close(com);
}
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

       printf("\nho letto %d caratteri\n",nr);
nr da dove salta fuori ? immagino sia nr=read...

 nr da dove salta fuori ? immagino sia nr=read...
Si, anche qui è perchè ho fatto sparire delle porzioni di codice per
evitare di spedire una mail troppo lunga e mi sono dimenticato di 
cancellare tutti i riferimenti alla variabile nr
Mo provo tutte le modifiche che mi hai suggerito e ti faccio sapere...
Nel frattempo grazie.
Alessio.


Niente da fare... il programma non funziona, ho aggiunto del codice
per controllare il tipo di errore che si verifica.
      switch(errno)
	{
	case EINTR:printf("\nerrore 1\n");break;
	case EAGAIN:printf("\nerrore 2\n");break;
	case EIO:printf("\nerrore 3\n");break;
	case EISDIR:printf("\nerrore 4\n");break;
	case EBADF:printf("\nerrore 5\n");break;
	case EINVAL:printf("\nerrore 6\n");break;
	case EFAULT:printf("\nerrore 7\n");break;
	default: printf("\nboh\n");
	}
L'errore è sempre il numero 2 che vuol dire??? Dovrebbe indicare che
ho selezionato una periferica del tipo non a blocchi e che non ci sono
dati in attesa da leggere... cosa devo fare?
Alessio.


 dati in attesa da leggere... cosa devo fare?
calma calma.
sei troppo conciso: non capisco dopo quale chiamata
hai ottenuto l'errore che citi.
E' sulla open ?
sulla write ?
sulla read?
sulla tcsetattr?
comunque la strada e' quella giusta:
occorre scoprire quale chiamata di sistema fallisce, e perche'.
intanto minicom ci dice che la com2 funziona,
e che il dispositivo funziona.

 dati in attesa da leggere... cosa devo fare?
cacchio... e' sulla read ?
allora EAGAIN (da man 2 read) ci dice
che non ci sono caratteri da leggere su un dispositivo NON BLOCCANTE!
ovvero hai scelto le chiamate asincrone, quelle che escono immediatamente.
La write asincrona affida i dati all'UART e ritorna immediatamente.
Nella riga che segue una write asincrona NON puoi essere
sicuro che tutti i caratteri sono usciti dalla seriale.
La read asincrona ritorna i caratteri presenti sul buffer della seriale,
ed esce immediatamente.
Il tuo programma e' concluso prima ancora che il carattere
sia uscito dalla seriale!
metodo 1)
    inserisci
        usleep(400000);
    dopo la open,dopo la write, dopo la read.
metodo 2)
    passa alle chiamate sincrone e togli O_NDELAY dalla open.
    pero' qualcosa non mi torna comunque:
    a quel che so io per fare le chiamate asincrone
    occorre usare anche fcntl(opzione...)
    non e' che la hai omessa dai tuoi post ?

     non e' che la hai omessa dai tuoi post ?
In effetti nell'ultimo sorgente che ho prodotto questa chiamata non
era presente ma era cmq una soluzione che avevo già sperimentato e cmq
il programma non dava segno di miglioramento.
Ora ho cmq rimosso O_NDELAY ed ho aggiunto la seguente linea prima 
della open:
fcntl(com,F_SETFL,0);
l'unico risultato che ottengo è che il programma apparentemente invia
il carattere (ho controllato il ritorno della write) ma si blocca al
momento della ricezione del carattere, sembra quasi rimanere in attesa
di un input.
Il mistero è sempre più fitto...


A rigor di logica (ed è ciò che avviene anche nella maggior parte dei
casi) il settaggio di qualcosa viene fatto prima che quest'ultimo venga
acceso/messo in moto.
Qui no! Ho spostato le linee di codice relative alla configurazione dopo
la "open" , quando la connessione quindi già esiste, e il programma
sembra funzionare. Questi sono gli errori + difficili da trovare (io
l'ho fatto spostando a caso linee di codice)
Ora ho un altro piccolo dubbio: al momento il programma funziona in
alternanza nel senso che la prima volta che lo avvio va, poi no, poi si
poi no, non è che devo svuotare qualche buffer ad ogni avvio del 
programma tipo fflush?


 l'ho fatto spostando a caso linee di codice)
quel  "a caso" mi fa dedurre che hai assoluto bisogno di leggere la 20ina di
pagine di cui sopra.
Tutte le impostazioni della seriale, da tcgetattr
a tcsetattr e famiglia, hanno come parametro
un file descriptor (la tua variabile "com" per intenderci).
Un file descriptor lo hai ottenuto solo se hai fatto
una open con successo.
Quindi le funzioni di impostazioni delal seriale vanno usate
dopo la open, eprima di cominciare a leggerci e scriverci.
Il mio consiglio e' di abbandonare la fretta,
di spegnere il pc, e di leggere il manualetto indicato.
P.S.
quando si sta imparando a manovrare la seriale e' utile
non iniziare con il dispositivo ma mettendo un jumper
(i' uno di quelli da mobo o da hard disk) tra i pin
2 e 3 della porta seriale del tuo pc.
Cosi' facendo, impostando la seriale senza controllo
hardware , puoi scrivere su di essa e leggerai in ingresso
quello che hai scritto.
In questo modo prima risolverai i problemi di programmazione,
poi quelli del dispositivo.