Forum: PC-Programmierung Größe des RS232-Puffers bei Linux in C?


von chris (Gast)


Lesenswert?

Hallo Forengemeinde,
versuche eine angekommene SMS in C unter Linux von einem Surfstick 
"huawei E160" auszulesen. Gebe also den Befehl zum Auslesen 
"AT+CMGR=0\r\n" ein und erwarte die Antwort vom Surfstick, um diese dann 
mit strtok() zu zerlegen und auszuwerten. Problem ist nur, dass alle 
anderen Kommandos, wie z.B. Netzabfrage "AT+COPS?\n" oder 
Modemmodellabfrage "AT+CGMM\n" Strings zurückgeben. Nur die SMS-Abfrage 
scheitert.
1
int smsabfrag(){          /////////////// SMS ABFRAGEN
2
 
3
int bytes = 0;      
4
int h;        //Löschzähler für Puffer2
5
char puffer2[200];    //Puffer zum Auslesen von Schnittstelle
6
int fd_ser;      //Serielle Schnittstelle
7
int k=1;       //Zählervariable initialisieren
8
char *ptr;       //Temporärer String
9
10
11
fd_ser = open_port();    //Schnittstelle öffnen
12
13
set_fgcolor(3);
14
log_meld("Frage SMS ab...\n");
15
16
write(fd_ser,   "AT+CMGR=0\r\n",11);
17
18
//write(fd_ser, "AT+CPBR=1\r\n",12);
19
//write(fd_ser, "AT+COPS?\r\n",11);
20
21
smsinhalt = 0;         //  Global definierte Variable für den Inhalt der SMS
22
23
  
24
  for (h=0;h==201;h++)  
25
  {
26
  puffer2[h] = 0x00;
27
  }
28
29
30
bytes = read_port(&fd_ser,puffer2);   // Daten lesen
31
clear_screen();       // Bildschirm löschen
32
33
ptr = strtok(puffer2, "\n,");    // Zeilenumbruch maskieren
34
35
  while(ptr != NULL)
36
  {
37
  set_cursor(3,k);
38
  
39
  printf("Detektion: %d. string--> %s \n",k++,ptr); //Ausgabe von Stringnummer und  String
40
                     
41
  ptr = strtok(NULL, "\n,");      //  Zeilenumruch maskieren   
42
       }
43
                                                            
44
45
//////set_fgcolor(4);
46
//////set_cursor(0,15);
47
//////printf ("%s", smsinhalt);
48
//////set_fgcolor(2);
49
log_meld("SMS abgefragt.\n");
50
51
}

Programmoutput:

�� Detektion: 1. string--> AT+CMGR=0

Wenn ich
1
write(fd_ser,   "AT+CMGR=0\r\n",11);
durch
1
write(fd_ser, "AT+COPS?\r\n",11);

ersetze, ist der Output richtig:

   Detektion: 1. string--> AT+COPS?
   Detektion: 2. string--> +COPS: 0
   Detektion: 3. string--> 0
   Detektion: 4. string--> "o2 - de"
   Detektion: 5. string--> 0
   Detektion: 6. string-->
   Detektion: 7. string--> OK


Wenn ich allerdings parallel minicom öffne, um dem Datenstrom zu 
beobachten, funktioniert das auslesen mit:
1
write(fd_ser,   "AT+CMGR=0\r\n",11);

Output:

   Detektion: 1. string-->
   Detektion: 2. string--> +CMGR: "REC READ"
   Detektion: 3. string--> "+49176XXXXXXXX"
   Detektion: 4. string--> "09/11/21
   Detektion: 5. string--> 10:33:21+04"
   Detektion: 6. string--> Test0001
   Detektion: 7. string-->
   Detektion: 8. string--> OK
   Detektion: 9. string--> :

Hier noch die RS232-Einstellungen:
1
int open_port(void){
2
3
int fd_ser;
4
struct termios terminal;
5
set_fgcolor(3);
6
log_meld ("Port öffnen...");
7
int fefe = 0xFE;
8
9
  {
10
  /*
11
   * Oeffnet seriellen Port
12
   * Gibt das Filehandle zurueck oder -1 bei Fehler
13
   * der Parameter port muss 0, 1, 2 oder 3 sein
14
   *
15
   * RS232-Parameter
16
   * - 19200 baud
17
   * - 8 bits/byte
18
   * - no parity
19
   * - no handshake
20
   * - 1 stop bit
21
   */
22
   int fd;
23
   struct termios options;
24
   fd = open("/dev/ttyUSB1", O_RDWR | /*O_NOCTTY | */O_NDELAY); 
25
26
    
27
   if (fd >= 0)
28
   {
29
     /* get the current options */
30
     fcntl(fd, F_SETFL, 0);
31
     if (tcgetattr(fd, &options) != 0) return(-1);
32
     bzero(&options, sizeof(options)); 
33
34
     cfsetspeed(&options, BAUD);       
35
   
36
37
     /* setze Optionen */
38
     options.c_cflag &= ~CRTSCTS;   /* Kein Hardwarehandshake */
39
     options.c_cflag &=  PARENB;         /* kein Paritybit */
40
     options.c_cflag &=  CSTOPB;         /* 1 Stoppbit */
41
     options.c_cflag &=  CSIZE;          /* 8 Datenbits */
42
     options.c_cflag |= CS8;
43
     options.c_cflag |= (CLOCAL | CREAD);/* CD-Signal ignorieren */
44
     /* Kein Echo, keine Steuerzeichen, keine Interrupts */
45
     options.c_lflag &=  (ICANON|  ECHO | ECHOE | ECHOK | ECHONL | ISIG | IMAXBEL );
46
     options.c_oflag &=  OPOST;          /* setze "raw" Input */
47
     options.c_oflag &= OFILL;     
48
     options.c_cc[VMIN]  = 0;            /* warten auf min. 0 Zeichen */
49
     options.c_cc[VTIME] = 50;           /* Timeout 5 Sekunden */
50
     tcflush(fd,TCSAFLUSH);
51
 //  tcflush(fd,TCIOFLUSH);
52
     /*if (tcsetattr(fd, TCSANOW, &options) != 0) return(-1);
53
54
     fcntl(fd, F_SETFL, FNDELAY);
55
     fcntl(fd, F_SETFL, 0);
56
     */
57
     }
58
59
  return(fd);
60
61
 }

Kann mir das alles nicht mehr erklären. Habt Ihr vielleicht dafür ne 
Erklärung?

Vielen Dank,

MfG

chris

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Wenn ich
>
>    write(fd_ser,   "AT+CMGR=0\r\n",11);
>
> durch
>
>    write(fd_ser, "AT+COPS?\r\n",11);
>
> ersetze, ist der Output richtig:

Die Konstante 11 ist hier merkwürdig. Ich nehme an, daß das die Anzahl 
der zu sendenden Zeichen ist; das zweite Beispiel aber verwendet einen 
nur 10 Zeichen langen String, so daß als 11. Zeichen die terminierende 
\0 gesendet wird.

Das wird nicht des Problemes Ursache sein, aber es kann Nebeneffekte 
hervorrufen.

Du solltest überprüfen, ob für Deinen Stream nicht etwa eine 
automatische Zeilenumbrucherweiterung aktiv ist, die aus \n automatisch 
\r\n erzeugt. Oder beim Empfang das Gegenteil davon vornimmt.

Ansonsten: Sieh Dir halt die Sourcen von Minicom an, wie da die 
Schnittstelle initialisiert und behandelt wird.

von chris (Gast)


Lesenswert?

Wenn ich minicom mit VT102 - Emulation parallel laufen lasse, 
funktioniert das Auslesen. Wenn ich allerdings ANSI-Emulation aktiviere, 
habe ich den selben Effekt, wie ohne minicom (funktioniert nicht).

Wo finde ich die minicom source?

MfG

chris

von chris (Gast)


Lesenswert?

Ich habe eine Lösung gefunden, mit der ich nicht zufrieden bin:

2 mal hintereinander folgenden Teil ausgeben:
1
bytes = read_port(&fd_ser,puffer2);   // Daten lesen

Kann mir jedoch immernoch nicht erklären, warum das von Nöten ist. 
Vielleicht der Empfangspuffer der 232 zu gering?

MfG

von Klaus W. (mfgkw)


Lesenswert?

vielleicht ist ja read_port schuld?
Gibt es dazu auch einen Quelltext?

von Mark .. (mork)


Lesenswert?

@chris
1
 /* Kein Echo, keine Steuerzeichen, keine Interrupts */
2
     options.c_lflag &=  (ICANON|  ECHO | ECHOE | ECHOK | ECHONL | ISIG | IMAXBEL );
3
     options.c_oflag &=  OPOST;          /* setze "raw" Input */
4
     options.c_oflag &= OFILL;
Hier passt Kommentar und Code nicht zusammen. Duch
1
options.c_lflag &=  (ICANON|  ECHO | ECHOE | ECHOK | ECHONL | ISIG | IMAXBEL );
 löschst Du alle anderen Bits außer ICANON,  ECHO, ECHOE, ECHOK, 
ECHONL und ISIG.

Was Du vermutlich haben willst ist
1
options.c_lflag &=  ~(ICANON|  ECHO | ECHOE | ECHOK | ECHONL | ISIG | IMAXBEL );
Dadurch werden die o.g. Bits gelöscht und der Rest bleibt gleich. Um 
alle Flags wie Echo, line buffer usw auf einmal zu deaktivieren kann man 
auch cfmakeraw(options) aufrufen (Siehe 
http://linux.about.com/library/cmd/blcmdl3_termios.htm).

MfG Mark

von chris (Gast)


Lesenswert?

Die Änderung lt. Mark bringt auch keine Besserung. Hier die read_port:
1
 int read_port(int *fd_ser,unsigned char* buffer) {
2
     int a;
3
     fd_set rfds;
4
     struct timeval tv;
5
     int retval;
6
                  
7
            FD_ZERO(&rfds);
8
            FD_SET(*fd_ser,&rfds);
9
            tv.tv_sec = 1;
10
            tv.tv_usec = 0;
11
            retval = select(*fd_ser+1,&rfds,NULL,NULL,&tv);
12
            if (retval) {
13
                    a=read(*fd_ser,buffer,255);
14
                    return a;
15
                        } 
16
      else return 0;
17
 }

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Definitiv ist der Puffer zu klein! Du hast einen Puffer für 200 Zeichen 
und in read_port() werden über read maximal 255 Zeichen eingelesen!

Das ist aber nicht das Problem. Das Problem ist dein Verständnis wie die 
Kommunikation arbeitet.

Es ist quasi normal mehrere Leseversuche hintereinander zu machen, bis 
"kein weiteres Zeichen gelesen" (bytes = 0) zurückkommt. Bei TCP 
Anforderungen ist das ähnlich.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.