Inkonsistenz bei einer seriellen Schnittstelle



  • Horrido!
    Folgendes Problem:
    Ich verwende eine serielle Schnittstelle um Daten an ein Gerät zu schicken. [1]
    Um die Richtigkeit des Protokolls zu prüfen schreibe ich mit der gleichen Funktion und dem gleichen Datenbuffer in eine Datei [2]

    bytesWritten = write(fd, pData, len);           //[1] Hier schreibe ich in 
    #ifdef VSNFD_DEBUG 				//die serielle Schnittstelle
    	 printf("\nBytes to write: %i", len);   
    	 printf("\nBytes written:  %i", bytesWritten);
    
    	 FILE *testfile = fopen("./testFile.bin","wb");
    	 int tf = fileno(testfile);
    	 write(tf,pData,len);           	//[2]Hier schreibe ich in
    	 fclose(testfile);			//die "Prüfdatei"
    #endif
    

    Zusätzlich habe ein "Lausch" - Programm geschrieben mit dem ich über ein 0-Modemkabel die Daten der seriellen Schnittstelle wieder einlesen kann.
    Durch den Vergleich des Inhalts der Prüfdatei und der Ausgabe des Lauschprogramms komme ich zu folgendem Ergebnis, das zu dem Verhalten des Gerätes paßt:
    1. Mitten in einem 24 Byte Paket ist ein Byte immer doppelt (immer das gleiche) -> Gerät funktioniert nicht
    2. Bei einer anderen 16 Bit Sendung ist alles wie es sein soll. -> Gerät funktioniert

    Woher kann es kommen, daß immer dieses eine Byte doppelt geschickt wird.
    Es gibt keinen Weg dieses Problem zu umgehen.
    Danke im voraus,
    Achill



  • Das was du also mit deinem Lauschprogramm empfängst stimmt nicht mit dem überein was in deiner Logdatei steht?

    Wenn ja, dann überprüfe nochmal, ob du alles richtig eingestellt hast bei der seriellen Schnittstelle: Baudrate, Parity, ...



  • Die Konfiguration der seriellen Schnittstelle sieht im Moment so aus:

    struct termios options;
    
    	tcgetattr(fd, &options);
    
    	cfsetispeed(&options, B57600);
    	cfsetospeed(&options, B57600);
    
    	options.c_cflag |= (CLOCAL | CREAD);
    
    	options.c_cflag &= ~PARENB;
    	options.c_cflag &= ~CSTOPB;
    	options.c_cflag &= ~CSIZE;
    	options.c_cflag |= CS8;
    
    	options.c_iflag &= ~(IXON | IXOFF | IXANY);
    	options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    
    	fcntl(fd, F_SETFL, FNDELAY);  // raw mode
    
    	options.c_cc[VMIN] = 1; 
            options.c_cc[VTIME] = 50; 
    
    	tcflush(fd, TCIFLUSH);
    	if(tcsetattr(fd, TCSANOW, &options) == -1) return SERIAL_CONFIG_ERROR;
    	return DEVICE_OK;
    

    Das ganze soll unter Linux laufen.
    Vielleicht hab ich ja was offensichtliches Übersehen?

    Edit by AJ: CPP-Tags waren vertauscht.



  • Wichtig ist eigentlich nur, dass die Einstellungen beider Programme gleich sind.
    Ich geh jetzt mal davon aus, dass meine Frage mit Ja beantwortet wurde. Dass also im Logfile etwas anderes steht als tatsächlich ankommt.

    Welche Einstellungen braucht eigentlich das Gerät?



  • Zum Logfile:
    Bei manchen Messages kommt das gleiche an der seriellen Schnittstelle an wie im Logfile. Bei manchen nicht. Hängt von der Nachricht ab. Die Nachrichten haben unterschiedliche Längen.

    Einstellung, die das Gerät braucht ist:
    57600 baud, 8 data bits, 1 stop bit, keine parity

    Das Bytes verdoppelt wird ist 0x0A, vielleicht hat das ne Sonderfunktion?

    Gruß
    Achill



  • @Achill,
    was macht dein Lausch-Programm wenn deine gesendeten Daten nicht in einem Block übertragen werden? Das wäre ein Grund für die unterschiedliche Länge. Dein Lausch-Programm hört nach einem Block eventuell auf oder liest weiter fleißig Nullen.

    EDIT:
    So wie ich dich verstanden habe, sind die Daten ja OK...lediglich zu viele/wenig. Daher würde ich die Schnittstelleneinstellungen ausschließen.



  • Achill schrieb:

    options.c_cflag |= (CLOCAL | CREAD);
    	
    	options.c_cflag &= ~PARENB;
    	options.c_cflag &= ~CSTOPB;
    	options.c_cflag &= ~CSIZE;
    	options.c_cflag |= CS8;
    	
    	
    	options.c_iflag &= ~(IXON | IXOFF | IXANY);
    	options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    

    Dieser Teil kommt mir komisch vor. Hier müsstest du eigentlich deine Einstellungen setzen, allerdings schaut der Code nicht danach aus. Hast du das von irgendwo kopiert? Welche Werte haben deine Konstanten (CLOCAL, CREAD, PARENB, ...) und gibt es noch andere?

    @herrmann
    Wenn sich die Daten der Logdatei von den gesendeten Daten unterscheiden, dann kann es eigentlich nur an den Einstellungen liegen oder die serielle Schnittstelle ist defekt; allerdings bezweifle ich das.

    Und auch wenn das Lauschprogramm nicht richtig laufen würde, müsste zumindest das Gerät funktionieren bzw. antworten.



  • 0x0A sieht aus wie ein Zeilenumbruch, der mal bei der Übertragung eingefügt wird oder nicht? Oder der vom Lauschprogramm entfernt wird?

    Was liest denn ein anderes Lauschprogramm (freeware, shareware)?
    Und was sendet ein Terminalprogramm, welches auch Binär-daten senden kann?

    Blackbird



  • @Herrmann: Die Daten werden in einem Block übertragen, das prüfe ich. Außerdem würde das Auftreten des Fehlers / nicht Auftreten des ehler genau zum Geräteverhalten passen.

    @AJ: Hab das von http://www.easysw.com/~mike/serial/serial.html

    @zufaul: Ja, ist ein Linefeed, werrd das gleich mal näher betrachten

    Gruß
    Achill



  • @AJ, die Einstellen sehen meiner Meinung nach OK aus. Jedenfalls sehen Initialisierungen bei mir nahezu gleich aus.

    @Achill, wie überprüfst du, dass die Daten in einem Block gesendet werden. Mit C hast du darüber keine Kontrolle da das Betriebssystem diese Sache übernimmt. Also bei mir auf Arbeit werden die Daten teilweise schon bei 32 Byte zerhackt und in kleineren Brocken gesendet.

    Hier mal etwas Code aus einem älteren Projekt
    (ist aber Linux/Unis-Quellcode)

    ...
      struct termios flags;
    
      if ( !pDv || !InitSerial( pDt ) )
        return 0;
    
      pDt->iFd = open( pDv, O_RDWR );
      if ( pDt->iFd < 0 )
        return 0;
    
      flags.c_cflag     = CLOCAL | CREAD;
      flags.c_cflag    |= B9600;
      flags.c_cflag    |= CS8;
      flags.c_oflag     = 0;
      flags.c_lflag     = 0;
      flags.c_cc[VTIME] = 0;
      flags.c_cc[VMIN]  = 0;
    
      if ( tcflush( pDt->iFd, TCIFLUSH ) )
        return 0;
      if ( tcsetattr( pDt->iFd, TCSANOW, &flags ) )
        return 0;
      ...
    


  • Horrido!
    Das Problem hat sich scheinbar erledigt (wenn ich nicht was vollkommen übersehen hab...).
    Ich hab noch ein

    options.c_oflag &= ~OPOST;
    

    hinzugefügt, dann lief es. Das war bei mir auch vorher drin, allerdings auskommentiert. Hatte das mal getestet und da lief es nicht.
    Da hatte ich noch die alte Gerätekonfig benutzt und da es nicht funktionierte, hab ich es wohl abgehakt. Nachdem ich durch das Neuschreiben der gesamten Gerätekonfig einen anderen Fehler der Verbindung beseitigt hab, hab ich es einfach nicht mit dem OPOST getestet... d'oh!
    Vielen Dank für die Hilfe!
    Gruß
    Achill


Anmelden zum Antworten