Hallo,
ich habe hier neben mir einen Navi*** GPS-Empfänger mit TTL-Output.
4800baud
8N1
Im Hyperterminal unter Wind****f funktioniert das auslesen der NMEA
Datensätze prächtig.
Jetzt möchte ich die Datensätze aber über eine serielle Schnittstelle
(TTL) unter Linux empfangen.
Ich habe mir dazu das folgende Programm zusammengebastelt.
Allerdings habe ich folgendes Problem: In der Konsole erscheint
lediglich "0", aber periodisch, wahrscheinlich passend mit dem
Eintreffen eines neuen NMEA Datensatzes.
Was mach ich falsch?
1
# include <stdio.h>
2
# include <unistd.h>
3
# include <fcntl.h>
4
# include <termios.h>
5
# include <sys/select.h>
6
7
# define TERM_DEVICE "/dev/ttyUSB0" /* = COM1 */
8
# define TERM_SPEED B4800 /* Bit/Sek */
9
10
intmain()
11
{
12
intfd,old_flags;
13
ssize_tlength;
14
charbuffer[16];
15
structtermiosterm_attr;
16
fd_setinput_fdset;
17
18
if((fd=open(TERM_DEVICE,O_RDWR))==-1)
19
{
20
perror("terminal: Can't open device "TERM_DEVICE);
>>Jetzt möchte ich die Datensätze aber über eine serielle Schnittstelle>>(TTL) unter Linux empfangen.
Was Fertiges nehmen: http://de.wikipedia.org/wiki/Minicom
Schlank und schnell und einfach und zuverlässig.
Gute Nacht
Detlef
Hallo,
Du bist sicher, dass du Hardware-Handshake benutzt?
term_attr.c_cflag = TERM_SPEED | CS8 | CRTSCTS | CLOCAL | CREAD;
Das du mit select() arbeitest würde ich noch
term_attr..c_cc[VMIN]=1;
term_attr..c_cc[VTIME]=0;
setzen (s.struct termios)
Außerdem würde ich keinen Fehler werfen, wenn beim read()==-1 errno
EAGAIN oder EWOULDBLOCK ist:
int res = read(fd, buffer, 16);
if (res<0)
{
if (errno==EAGAIN || errno==EWOULDBLOCK)
{
usleep(1000);
continue;
}
else
perror(...);
}
Gruß,
Hardware-Handshake vor den kopfschlag
CRTSCTS ist jetzt rausgenommen.
Aber irgendwie ist das Ergebnis noch nicht befriedigend.
mehr als "{" bekomm ich nicht zu Gesicht
Werd noch mal in Ruhe Code lesen
Ich weiss nicht ob das dein Problem ist, aber ich wuerde davon absehen,
die Baudrate in c_cflag zu setzen.
Nimm eher cfsetispeed/cfsetospeed anstatt TERM_SPEED. Das ist portabler.
Zur Diagnose: nimm minicom zur Initialisierung der seriellen
Schnittstelle und lies diese dann mit stty -a aus (waehrend minicom
laeuft).
Thomas
EDIT: oder cutecom anstelle von minicom.
Das mit Minicom ist nicht so einfach.
Das ganze muss auf das Foxboard von ACME angepasst werden, habs bis
jetzt noch nicht geschafft das vernünftig zu kompilieren.
Hi nochmal,
vielleicht hilft es Dir ja weiter, wie ich meine Schnittstellen
initialisiere. Ich lese immer mit select() und Timeouts und dieser Code
hat eigentlich immer gut funktioniert (der Code kommt aus meiner
seriellen Klasse und kompiliert so natürlich nicht):
void Open()
{
mHandle = open( "/dev/ttyS0", O_RDWR | O_NOCTTY | O_NONBLOCK);
if (mHandle<0)
throw TOSErr("Could not open com port",errno);
int BaudRate=19200;
struct termios newtio;
newtio.c_cflag = CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR | IGNBRK ;
newtio.c_oflag = 0;
newtio.c_lflag &= ~ (ICANON | ECHO | ECHOE | ISIG);
newtio.c_cc[VMIN]=1;
newtio.c_cc[VTIME]=0;
if(cfsetospeed(&newtio, BaudRate))
throw TOSErr("cfsetospeed failed",errno);
if (cfsetispeed(&newtio, BaudRate))
throw TOSErr("cfsetispeed failed",errno);
tcflush(mHandle, TCIFLUSH);
if (tcsetattr(mHandle,TCSANOW,&newtio))
throw TOSErr("tcsetattr failed",errno);
}
und beim Lesen dann:
void Read(char * const inBuf, const int BytesToRead, int & BytesRead,
const bool aNoThrow)
{
if (mHandle<0)
throw TErr("com port not opened:");
if (BytesToRead<=0)
return;
BytesRead=0;
int BytesLeft=BytesToRead;
fd_set AcceptSet;
struct timeval timeout;
int rounds=0;
while (BytesLeft)
{
// Warten mit select()
// Achtung:Timeout-Struktur wird unter Linux in select() verändert
rounds++;
timeout.tv_sec=mSerInfo.Timeout_ms/1000;
timeout.tv_usec=(mSerInfo.Timeout_ms*1000)%1000000;
FD_ZERO(&AcceptSet);
FD_SET(mHandle,&AcceptSet);
int st=select(mHandle+1,&AcceptSet,NULL,NULL,&timeout);
if (st==0)
{
// Timeout
if (!aNoThrow)
throw TErr("Read command timeout. Read only
"+ToString(BytesRead)+" of "+ToString(BytesToRead)+" bytes.");
else
return;
}
else if (st<0)
{
throw TOSErr("TSerIO::Read select failed",errno);
}
int res = read(mHandle, inBuf+BytesRead, BytesLeft);
if (res<0)
{
if (errno==EAGAIN || errno==EWOULDBLOCK)
{
usleep(1000);
continue;
}
else
throw TOSErr("Read command failed. Read only
"+ToString(BytesRead)+" of "+ToString(BytesToRead)+" bytes.",errno);
}
BytesLeft-=res;
BytesRead+=res;
}
}
Gruß,