empfangen per rs232 seltsames verhalten (nix geht)



  • Hi alle miteinander!
    Folgende Situation: In der Schule (also momentan nicht verfügbar) haben wir eine Wetterstation, die alle 10sek Daten über die RS232-Schnittstelle sendet, egal ob jemand empfängt oder nicht. Ich Habe das Protokoll und will nun ein Programm schreiben, dass zuhört und mitschreibt 🙂 !
    Leider gibt es dabei ein paar Probleme. Wenn ich testeshalber mit "dd if=test.dat of=/dev/ttyS1" Testdaten rübersende, erwarte ich folgende Ausgabe:

    Datenpaket A identifiziert!
    Humidity: now: 65%
    max: 80% 12:32 14.9
    min: 12% 02:01 01.2
    

    Bekommen tue ich aber garnix. Um sicherzustellen, dass der Sendebuffer auch geflusht wird, habe ich schon mal ein "echo > /dev/ttyS1" hinterher geschickt, passierte aber immer noch nix.
    Gemeinerweise funzt aber "(cat /dev/ttyS0 &) && (dd if=test.dat of=/dev/ttyS1) && (echo ^D > /dev/ttyS1)". OK, es werden keine 0 und so gesendet, also die Zeichen, die man nicht sehen kann.
    Meine Frage: Warum? Was ist an meinem Code falsch?

    weathermon.h

    #ifndef WEATHERMON
    #define WEATHERMON
    
    #define HI(x) ((int)((x>>4)&0xF))
    #define LO(x) ((int)(x&0xF))
    
    class Application {
    	public:
    		Application(int argc, char* argv[]);
    		~Application();
    
    		void Run(void);
    
    	private:
    		int commport;
    };
    
    #endif
    

    weathermon.cpp

    #include <signal.h>
    #include <setjmp.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <termios.h>
    
    #include <string>
    #include "weathermon.h"
    
    Application::Application(int argc, char* argv[]) {
        // verarbeite cmd-line
    	std::string cport = "/dev/ttyS0";
    
    	for(int i=1; i<argc; ++i) {
    		if(strcmp(argv[i], "-c") == 0)
    			cport = argv[++i];
    	}
    
        // configure rs232-connection
    	commport = open(cport.c_str(), O_RDONLY | O_NOCTTY | O_NDELAY);
    	fcntl(commport, F_SETFL, 0);
    	termios options;
    	tcgetattr(commport, &options);
    	cfsetispeed(&options, B9600);
    	options.c_cflag |= (CLOCAL|CREAD);
    	options.c_cflag &= ~PARENB;
    	options.c_cflag &= ~CSTOPB;
    	options.c_cflag &= ~CSIZE;
    	options.c_cflag |= CS8;
    	tcsetattr(commport, TCSANOW, &options);
    }
    
    Application::~Application() {
    	printf("Bye!\n");
    	close(commport);
    }
    
    void Application::Run(void) {
    	char id, data[36];
    	while(1) {
    		switch(read(commport, &id, 1)) {
    			case ((31<<3)|0)&0xFF:  // 1111 1000
    				printf("Datenpaket A identifiziert!\n");
    				read(commport,data+2, 34); // data[2] == 2. gesendetes byte
    				printf("Humidity: now: %i%i%%\n", LO(data[21]), HI(data[21]));
    				printf("max: %i%i%% %i%i:%i%i %i%i.%i\n", LO(data[22]), HI(data[22]),
    						LO(data[24]), HI(data[24]), LO(data[23]), HI(data[23]),
    						LO(data[25]), HI(data[25]), HI(data[26]));
    				printf("min: %i%i%% %i%i:%i%i %i%i.%i\n", HI(data[27]), LO(data[26]),
    						HI(data[29]), LO(data[28]), HI(data[28]), LO(data[27]),
    						HI(data[30]), LO(data[29]), LO(data[30]));
    				break;
    			case ((31<<3)|1)&0xFF:  // 1111 1001
    				break;
    			case ((31<<3)|2)&0xFF:  // 1111 1010
    				break;
    			case ((31<<3)|3)&0xFF:  // 1111 1011
    				break;
    			case ((31<<3)|4)&0xFF:  // 1111 1100
    				break;
    		}
    	}
    }
    
    Application* app = 0;
    jmp_buf jumper;
    
    void cleanup(int) {
    	longjmp(jumper, 1);
    }
    
    int main(int argc, char* argv[]) {
       	app = new Application(argc, argv);
    
    	if(setjmp(jumper) == 0) {
    		signal(SIGTERM, cleanup);
    		signal(SIGABRT, cleanup);
    		try {
    			app->Run();
    		}
    		catch(std::runtime_error err) {
    			fprintf(stderr, "weathermon: %s\n", err.what());
    		}
    		catch(...) {
    			fprintf(stderr, "weathermon: undefined error!\n");
    		}
    	}
    
        delete app;
    	return 1;
    }
    


  • Da is ein Fehler im Code, der da eigentlich net ist. Durch das rumprobieren mit streams und fread() ist da Mist entstanden. Verhalten ist aber das gleiche!
    Statt:

    switch(read(commport, &id, 1)) {
    

    Das:

    read(commport, &id, 1);
    switch(id) {
    

    Sorry.



  • OK .. nochmal sorry! Ich habe gerade festgestellt, dass es am Testdatensatz lag.
    Dennoch habe ich ein Problem: Wenn er zum "read(commport,data+2, 34);" Kommt, und eines von den 34 Bytes ein '\n' ist (was durchaus passieren kann, aber nicht als solches gemeint ist), bricht er mit dem lesen ab.
    Kann man ihm irgendwie klarmachen, dass '\n' auch nur eine Zahl ist?



  • Hallo

    Das ganze liegt daran das du im Canonical mode bist.
    Dieser Mode liest dir Zeilenweise dein Signal ein und da bei /n ein Zeilenende vorliegt hoert er auf.

    Das es funktioiert, musst den canonical mode ausschalten

    ungefaehr so:

    options.c_lflag &= ~(ECHO|ICANON);
    
    options.c_cc[VMIN]=1;    //min. 1 zeichen empfangen
    options.c_cc[VTIME=]= 0; //kein timer
    

    Das ganze wird auch recht gut im Serial Programing Howto erklaert
    http://en.tldp.org/HOWTO/Serial-Programming-HOWTO/index.html
    und im Serial Programming Guide for POSIX Operating Systems
    http://www.easysw.com/~mike/serial/serial.html

    Ich hoffe ich konnte dir damit helfen.

    Gruss
    C-Snoopy



  • Danke für die Info!
    Ich habe sogar schon auf diesen Seiten nachgesehen, doch, da ich lesefaul bin, habe ich einfach nach dem Wort "binary" und dem Teilwort "bin" gesucht. Da ich nicht fündig geworden bin, bin ich mit der Meinung "Wird hier wohl nicht erklärt" davon gegangen. (Memo an mich selbst: "Kreativer beim Suchwortentwickeln werden! (Bloß nicht die Lesefaulheit aufgeben, ist ja viel zu viel Arbeit)")


Anmelden zum Antworten