Re: [vz-dev] Siemens TD3511 mit Protokoll D0
Hallo zusammen, also es funktioniert nun sowohl mit dem ISKRAemeco MT174 als auch dem Siemens TD3511. Anbei findet ihr den Patch. Ich hab versucht sowenig Änderungen zu machen wie es geht. Hier nochmal die Zusammenfassungen: 1) Das Device wird im blocking mode geöffnet. Das führte bei mir dazu, dass die read() Funktion mit 0 zurückkehrt. Das heißt normalerweise ein eof oder derartiges. Sowas sollte bei einem seriellen Device niemals passieren. Ich weiß auch nicht warum das der Fall ist. - Ich hab den Code dahingehend geändert, dass das Device im non-blocking mode geöffnet wird. Damit funktioniert's nun. 2) Die Statemachine sollte niemals unendlich warten und irgendwo hängen bleiben. - Ich hab ein Timeout von 10s eingebaut. Also wenn innerhalb 10s keine Daten empfangen werden bzw. beim Start kein Sync-byte kommt, wird dieser Lesevorgang abgebrochen. 3) Die Statemaching wird immer beim Empfang eines '/' zurückgesetzt. Da mein Zähler ein '/' im Identification String sendet, hängt sich die Statemachine auf. - Das habe ich rausgenommen. 4) Mein Zähler sendet ca. 330 obis-codes. Da ist dann sowas dabei wie 2.8.1*16, 2.8.1*15 usw. Ich interessiere mich eigentlich nur für die Einträge von 2.8.0. Das ist insofern ein Problem, dass der D0-Meter nur maximal 32 Einträge zulässt. Das heißt bis die interessanten codes ankommen, sind die 32 Einträge schon längst belegt. - Ich filtere jetzt nur noch obis-codes heraus die ein value und eine Einheit besitzen. Damit kommen bei meinem Zähler genau 32 zusammen. 5) Der Zähler sendet ungültige Obis-Codes. Zumindest ist der string für die Klasse Obis.cpp nicht auswertbar. Das führt dazu, dass vzlogger abstürzt. Vermutlich sind es die obis-codes die unter anderem Buchstaben statt Zahlen haben. - Ich hab die Stellen mit einem try-except Block abgefangen und überspringe die betroffenen obis-codes. 6) Fehler beim Setzen der Parity - Das hab ich korrigiert. Weiterhin habe ich mal die Ausgaben der beiden Zähler angehangen, mit denen das getestet wurde. Gruß Sebastian ISKRAemeco_MT174.txt Description: Binary data Siemens_TD-3511.txt Description: Binary data diff --git a/src/Obis.cpp b/src/Obis.cpp index f918797..eebf5f8 100644 --- a/src/Obis.cpp +++ b/src/Obis.cpp @@ -192,7 +192,7 @@ int Obis::parse(const char *str) { } int Obis::lookup_alias(const char *alias) { - for (const obis_alias_t *it = aliases; it != NULL; it++) { + for (const obis_alias_t *it = aliases; !it-id.isNull(); it++) { if (strcmp(it-name, alias) == 0) { *this = it-id; return SUCCESS; diff --git a/src/protocols/MeterD0.cpp b/src/protocols/MeterD0.cpp index f48f864..cc74146 100644 --- a/src/protocols/MeterD0.cpp +++ b/src/protocols/MeterD0.cpp @@ -204,6 +204,13 @@ ssize_t MeterD0::read(std::vectorReadingrds, size_t max_readings) { char byte; /* we parse our input byte wise */ int byte_iterator; size_t number_of_tuples; +int bytes_read; + +time_t start_time; +time_t end_time; + +// get current time +time(start_time); if(_pull.size()) { int wlen=write(_fd,_pull.c_str(),_pull.size()); @@ -215,12 +222,41 @@ ssize_t MeterD0::read(std::vectorReadingrds, size_t max_readings) { context = START;/* start with context START */ - while (::read(_fd, byte, 1)) { - if (byte == '/') context = START; /* reset to START if / reoccurs */ - else if (byte == '!') context = END; /* ! is the identifier for the END */ + while (1) { + +// check if timed out +time(end_time); +if (difftime(end_time, start_time) 10) +{ + print(log_error, nothing received for more than 10 seconds, name().c_str()); + break; +} + +// now read a single byte +bytes_read = ::read(_fd, byte, 1); +if (bytes_read == 0 || bytes_read == -1 errno == EAGAIN) +{ +// wait and read again +usleep(5000); // 5 ms +continue; +} +else if (bytes_read == -1) +{ +// an error occured reading a byte +print(log_error, error reading a byte (%d), name().c_str(), errno); +break; +} + +// reset timeout +if (context != START) +{ +time(start_time); +} + + if (byte == '!') context = END; /* ! is the identifier for the END */ switch (context) { case START: /* strip the initial / */ -if (byte != '\r' byte != '\n') { /*allow extra new line at the start */ +if (byte == '/') { byte_iterator = number_of_tuples = 0;/* start */ context = VENDOR;/* set new context: START - VENDOR */ } @@
Re: [vz-dev] Siemens TD3511 mit Protokoll D0
Hallo Thomas, das Testprogramm kannst du dir selber kompilieren. Quellen sind hier: http://semiworks.de/~semi/test.c Gruß Sebastian Am 2013-12-13 10:39, schrieb Thomas Schenkel: Hallo Sebastian, ich mache alles was Du willst ;) Gibts Deinen Sourcecode schon irgendwo zum download oder nur über die diffs? Welche Quelle lag diesem denn zu Grunde? Vielleicht kann ich da auch noch ein wenig rumbasteln. Würde gerne ein bisschem mehr debugmeldungen haben wollen (sendet der MT174 überhaput was während vzlogger läuft etc.), aber meine cpp-Kenntnisse sind nur rudimentär (Wirtschaftsinformatikstudium 1996) und danach nur im Marketing gearbeitet ;-) Aber die Idee mit dem Testprogramm ist super. Vielleicht finden wir es so. Ist schon leicht deprimierend... VG Thomas Am 13.12.2013 10:31, schrieb Sebastian Michel: Hallo Thomas, sieht wohl so aus als ob es nicht geht :-) Dann helfen nur noch tracing Ausgaben. Oder ich schick dir heute abend mal mein kleines Testprogramm. Das macht genau wie der vzlogger die Schnittstelle auf und stellt sie ein, schickt die pull-sequenz und gibt dann einfach alle empfangenen Daten aus. Gruß Sebastian Am 2013-12-13 10:22, schrieb Thomas Schenkel: Hallo Sebastian, ich habe mal laufen lassen ... pi@raspberrypi /usr/local/bin $ sudo vzlogger.seb -c /etc/vzlogger.conf [Dec 13 09:29:49][mtr0] Creating new meter with protocol d0. [Dec 13 09:29:49][d0] pullseq len:5 found [Dec 13 09:29:49][mtr0] Meter configured. enabled [Dec 13 09:29:49] New meter initialized (protocol=d0) [Dec 13 09:29:49] Configure channel. [Dec 13 09:29:49][chn0] New channel initialized (uuid=...beebd6 protocol=volkszaehler id=1-0:1.8.0) [Dec 13 09:29:49] Have 1 meters. [Dec 13 09:29:49][main] foreground=1, daemon=1, local=1 [Dec 13 09:29:49] NOT Daemonize process... [Dec 13 09:29:49] Opened logfile /var/log/vzlogger.log [Dec 13 09:29:49][] === Start meters. [Dec 13 09:29:49][mtr0] Meter connection established [Dec 13 09:29:49][mtr0] Meter thread started [Dec 13 09:29:49][mtr0] meter is opened. Start channels. [Dec 13 09:29:49][chn0] Logging thread started [Dec 13 09:29:49][http] Starting local interface HTTPd on port 80 [Dec 13 09:29:49][] Startup done. [Dec 13 09:29:49][mtr0] Number of readers: 32 [Dec 13 09:29:49][mtr0] Config.daemon: 1 [Dec 13 09:29:49][mtr0] Config.local: 1 [Dec 13 09:29:49][chn0] Start logging thread for volkszaehler-api. Running as daemon: yes [Dec 13 09:29:49][chn0] Using default api: [Dec 13 09:29:49][d0] sending pullsequenz send (len:5 is:5). [Dec 13 09:30:00][d0] nothing received for more than 10 seconds [Dec 13 09:30:00][d0] Something unexpected happened: read:378! [Dec 13 09:30:00][mtr0] Got 0 new readings from meter: [Dec 13 09:30:00][chn0] == number of tuples: 0 [Dec 13 09:30:00][chn0] JSON request body is null. Nothing to send now. [Dec 13 09:30:00][chn0] Buffer dump (size=0 keep=0): {} [Dec 13 09:30:00][d0] sending pullsequenz send (len:5 is:5). [Dec 13 09:30:11][d0] nothing received for more than 10 seconds [Dec 13 09:30:11][d0] Something unexpected happened: read:378! [Dec 13 09:30:11][mtr0] Got 0 new readings from meter: [Dec 13 09:30:11][chn0] == number of tuples: 0 [Dec 13 09:30:11][chn0] JSON request body is null. Nothing to send now. [Dec 13 09:30:11][chn0] Buffer dump (size=0 keep=0): {} [Dec 13 09:30:11][d0] sending pullsequenz send (len:5 is:5). [Dec 13 09:30:22][d0] nothing received for more than 10 seconds [Dec 13 09:30:22][d0] Something unexpected happened: read:378! [Dec 13 09:30:22][mtr0] Got 0 new readings from meter: [Dec 13 09:30:22][chn0] == number of tuples: 0 [Dec 13 09:30:22][chn0] JSON request body is null. Nothing to send now. [Dec 13 09:30:22][chn0] Buffer dump (size=0 keep=0): {} [Dec 13 09:30:22][d0] sending pullsequenz send (len:5 is:5). [Dec 13 09:30:33][d0] nothing received for more than 10 seconds [Dec 13 09:30:33][d0] Something unexpected happened: read:378! [Dec 13 09:30:33][mtr0] Got 0 new readings from meter: [Dec 13 09:30:33][chn0] == number of tuples: 0 [Dec 13 09:30:33][chn0] JSON request body is null. Nothing to send now. [Dec 13 09:30:33][chn0] Buffer dump (size=0 keep=0): {} [Dec 13 09:30:33][d0] sending pullsequenz send (len:5 is:5). [Dec 13 09:30:44][d0] nothing received for more than 10 seconds [Dec 13 09:30:44][d0] Something unexpected happened: read:378! [Dec 13 09:30:44][mtr0] Got 0 new readings from meter: [Dec 13 09:30:44][chn0] == number of tuples: 0 [Dec 13 09:30:44][chn0] JSON request body is null. Nothing to send now. [Dec 13 09:30:44][chn0] Buffer dump (size=0 keep=0): {} [Dec 13 09:30:44][d0] sending pullsequenz send (len:5 is:5). [Dec 13 09:30:55][d0] nothing received for more than 10 seconds [Dec 13 09:30:55][d0] Something unexpected happened: read:378! [Dec 13 09:30:55][mtr0] Got 0 new readings from meter: [Dec 13 09:30:55][chn0] == number of tuples: 0 [Dec 13 09:30:55][chn0] JSON request body is null. Nothing to send
Re: [vz-dev] Siemens TD3511 mit Protokoll D0
Hallo in die Runde, also ich denke es gibt noch einen Fehler in vzlogger beim Konfigurieren der Schnittstelle. Beim Setzen der even Parity gibt es eine Zeile die sieht so aus: tio.c_cflag |= ~ PARENB; Es muss aber so ausschauen: tio.c_cflag |= PARENB; @Rainer: Mit der Änderung funktioniert nun das Testprogramm. Das kannst du ja mal testen. Außerdem hab ich in deine vzlogger.conf noch Einträge für Baudrate und Format ergänzt. Ich muss nun mal alles zusammen schreiben. Es sollte am Ende sowohl bei mir als auch bei Rainer funktionieren. Es gibt da leider Unterschiede bei dem Ausgabeformat der beiden Zähler. Da schaue ich nochmal nach. Aber für heute ist erstmal Schluss. Sebastian Am 2013-12-13 20:56, schrieb Thomas Schenkel: Hallo Rainer, da bringst du mich auf eine Idee. Vielleicht sollte man die Funktionalität in meinem Fall mal auskommentieren, damit er die Schnittstelle nicht verstellt und die gegebenen Werte (geladen vom rc.local) verwendet. Was denkt ihr, machbar oder geht nicht, weil ... ? Grüße Thomas Am 13.12.2013 17:55, schrieb Rainer Gauweiler: Ich denke es hängt am Handshake (RTC/CTS). Irgendwie initialisiert der vzloger die Schnittstelle nicht richtig und schaltet das Handshake ein. Der Lesekopf stellt fest dass er die empfangenen Daten nicht senden darf und wartet ab. stty hebt das dann wieder auf und schon flutschen die Daten. Ich weiss leider nicht wie man in C das Handshake setzt. Es gab hier kürzlich einen Patch auf der Liste, der scheint aber nicht zu tun... Gruss Rainer --- Diese E-Mail ist frei von Viren und Malware, denn der avast! Antivirus Schutz ist aktiv. http://www.avast.com
Re: [vz-dev] Siemens TD3511 mit Protokoll D0
Hallo, ich bin es nochmal. Ich hab ein sleep in der Schleife vergessen. Der vzlogger funktioniert im Prinzip, aber ohne das sleep hat er 100% CPU-Auslastung. Anbei mal eine berichtigte Version. Gruß Sebastian Am 2013-12-12 07:41, schrieb Michael Wulz: Guten Morgen, besten Dank für das Diff. Werde es gleich bei mir probieren - hatte auch immer die gleichen Probleme. Damit wird mein Logger auch stabiler rennen ;-) merci Am 12.12.13 07:35, schrieb Sebastian Michel: Hallo Zusammen, ich habe bei mir einen opt. USB-Lesekopf von Udo in Verbindung mit einem Siemens TD-3511 am Laufen. Das ganze hängt an einem raspberry pi mit image von volkszähler. Leider lief es nicht so problemlos wie erhofft. Der vzlogger hat zwar die pullseq geschickt, aber dann keine Daten empfangen. Ich hab mir dann die Quellen vom vzlogger angeschaut und folgende Änderungen in MeterD0.cpp gemacht, dass es läuft: 1) Das Device wird im blocking mode geöffnet. Das führte bei mir dazu, dass die read() Funktion mit 0 zurückkehrt. Das heißt normalerweise ein eof oder derartiges. Sowas sollte bei einem seriellen Device niemals passieren. Ich weiß auch nicht warum das der Fall ist. - Ich hab den Code dahingehend geändert, dass das Device im non-blocking mode geöffnet wird. Damit funktioniert's nun. 2) Die Statemachine sollte niemals unendlich warten und irgendwo hängen bleiben. - Ich hab ein Timeout von 10s eingebaut. Also wenn innerhalb 10s keine Daten empfangen werden bzw. beim Start kein Sync-byte kommt, wird dieser Lesevorgang abgebrochen. 3) Die Statemaching wird immer beim Empfang eines '/' zurückgesetzt. Da mein Zähler ein '/' im Identification String sendet, hängt sich die Statemachine auf. - Das habe ich rausgenommen. 4) Mein Zähler sendet ca. 330 obis-codes. Da ist dann sowas dabei wie 2.8.1*16, 2.8.1*15 usw. Ich interessiere mich eigentlich nur für die Einträge von 2.8.0. Das ist insofern ein Problem, dass der D0-Meter nur maximal 32 Einträge zulässt. Das heißt bis die interessanten codes ankommen, sind die 32 Einträge schon längst belegt. - Das ist vielleicht nicht ganz sauber, aber ich nehme nur obis-codes an die eine Länge von genau 5 bytes haben. Damit kommen bei meinem Zähler genau 32 zusammen. 5) Der Zähler sendet ungültige Obis-Codes. Zumindest ist der string für die Klasse Obis.cpp nicht auswertbar. Das führt dazu, dass vzlogger abstürzt. Vermutlich sind es die obis-codes die unter anderem Buchstaben statt Zahlen haben. - Ich hab die Stellen mit einem try-except Block abgefangen und überspringe die betroffenen obis-codes. Alles in allem freue ich mich, dass es nun funktioniert. Die Änderungen habe ich als Diff mal angehangen. Viele Grüße Sebastiandiff --git a/src/Obis.cpp b/src/Obis.cpp index f918797..eebf5f8 100644 --- a/src/Obis.cpp +++ b/src/Obis.cpp @@ -192,7 +192,7 @@ int Obis::parse(const char *str) { } int Obis::lookup_alias(const char *alias) { - for (const obis_alias_t *it = aliases; it != NULL; it++) { + for (const obis_alias_t *it = aliases; !it-id.isNull(); it++) { if (strcmp(it-name, alias) == 0) { *this = it-id; return SUCCESS; diff --git a/src/protocols/MeterD0.cpp b/src/protocols/MeterD0.cpp index f48f864..e3e34b3 100644 --- a/src/protocols/MeterD0.cpp +++ b/src/protocols/MeterD0.cpp @@ -204,6 +204,13 @@ ssize_t MeterD0::read(std::vectorReadingrds, size_t max_readings) { char byte; /* we parse our input byte wise */ int byte_iterator; size_t number_of_tuples; +int bytes_read; + +time_t start_time; +time_t end_time; + +// get current time +time(start_time); if(_pull.size()) { int wlen=write(_fd,_pull.c_str(),_pull.size()); @@ -215,12 +222,41 @@ ssize_t MeterD0::read(std::vectorReadingrds, size_t max_readings) { context = START;/* start with context START */ - while (::read(_fd, byte, 1)) { - if (byte == '/') context = START; /* reset to START if / reoccurs */ - else if (byte == '!') context = END; /* ! is the identifier for the END */ + while (1) { + +// check if timed out +time(end_time); +if (difftime(end_time, start_time) 10) +{ + print(log_error, nothing received for more than 10 seconds, name().c_str()); + break; +} + +// now read a single byte +bytes_read = ::read(_fd, byte, 1); +if (bytes_read == 0 || bytes_read == -1 errno == EAGAIN) +{ +// wait and read again +usleep(5000); // 5 ms +continue; +} +else if (bytes_read == -1) +{ +// an error occured reading a byte +print(log_error, error reading a byte (%d), name().c_str(), errno); +break; +} + +// reset timeout
[vz-dev] Siemens TD3511 mit Protokoll D0
Hallo Zusammen, ich habe bei mir einen opt. USB-Lesekopf von Udo in Verbindung mit einem Siemens TD-3511 am Laufen. Das ganze hängt an einem raspberry pi mit image von volkszähler. Leider lief es nicht so problemlos wie erhofft. Der vzlogger hat zwar die pullseq geschickt, aber dann keine Daten empfangen. Ich hab mir dann die Quellen vom vzlogger angeschaut und folgende Änderungen in MeterD0.cpp gemacht, dass es läuft: 1) Das Device wird im blocking mode geöffnet. Das führte bei mir dazu, dass die read() Funktion mit 0 zurückkehrt. Das heißt normalerweise ein eof oder derartiges. Sowas sollte bei einem seriellen Device niemals passieren. Ich weiß auch nicht warum das der Fall ist. - Ich hab den Code dahingehend geändert, dass das Device im non-blocking mode geöffnet wird. Damit funktioniert's nun. 2) Die Statemachine sollte niemals unendlich warten und irgendwo hängen bleiben. - Ich hab ein Timeout von 10s eingebaut. Also wenn innerhalb 10s keine Daten empfangen werden bzw. beim Start kein Sync-byte kommt, wird dieser Lesevorgang abgebrochen. 3) Die Statemaching wird immer beim Empfang eines '/' zurückgesetzt. Da mein Zähler ein '/' im Identification String sendet, hängt sich die Statemachine auf. - Das habe ich rausgenommen. 4) Mein Zähler sendet ca. 330 obis-codes. Da ist dann sowas dabei wie 2.8.1*16, 2.8.1*15 usw. Ich interessiere mich eigentlich nur für die Einträge von 2.8.0. Das ist insofern ein Problem, dass der D0-Meter nur maximal 32 Einträge zulässt. Das heißt bis die interessanten codes ankommen, sind die 32 Einträge schon längst belegt. - Das ist vielleicht nicht ganz sauber, aber ich nehme nur obis-codes an die eine Länge von genau 5 bytes haben. Damit kommen bei meinem Zähler genau 32 zusammen. 5) Der Zähler sendet ungültige Obis-Codes. Zumindest ist der string für die Klasse Obis.cpp nicht auswertbar. Das führt dazu, dass vzlogger abstürzt. Vermutlich sind es die obis-codes die unter anderem Buchstaben statt Zahlen haben. - Ich hab die Stellen mit einem try-except Block abgefangen und überspringe die betroffenen obis-codes. Alles in allem freue ich mich, dass es nun funktioniert. Die Änderungen habe ich als Diff mal angehangen. Viele Grüße Sebastiandiff --git a/src/Obis.cpp b/src/Obis.cpp index f918797..eebf5f8 100644 --- a/src/Obis.cpp +++ b/src/Obis.cpp @@ -192,7 +192,7 @@ int Obis::parse(const char *str) { } int Obis::lookup_alias(const char *alias) { - for (const obis_alias_t *it = aliases; it != NULL; it++) { + for (const obis_alias_t *it = aliases; !it-id.isNull(); it++) { if (strcmp(it-name, alias) == 0) { *this = it-id; return SUCCESS; diff --git a/src/protocols/MeterD0.cpp b/src/protocols/MeterD0.cpp index f48f864..3cdcdbf 100644 --- a/src/protocols/MeterD0.cpp +++ b/src/protocols/MeterD0.cpp @@ -204,6 +204,13 @@ ssize_t MeterD0::read(std::vectorReadingrds, size_t max_readings) { char byte; /* we parse our input byte wise */ int byte_iterator; size_t number_of_tuples; +int bytes_read; + +time_t start_time; +time_t end_time; + +// get current time +time(start_time); if(_pull.size()) { int wlen=write(_fd,_pull.c_str(),_pull.size()); @@ -215,12 +222,40 @@ ssize_t MeterD0::read(std::vectorReadingrds, size_t max_readings) { context = START;/* start with context START */ - while (::read(_fd, byte, 1)) { - if (byte == '/') context = START; /* reset to START if / reoccurs */ - else if (byte == '!') context = END; /* ! is the identifier for the END */ + while (1) { + +// check if timed out +time(end_time); +if (difftime(end_time, start_time) 10) +{ + print(log_error, nothing received for more than 10 seconds, name().c_str()); + break; +} + +// now read a single byte +bytes_read = ::read(_fd, byte, 1); +if (bytes_read == 0 || bytes_read == -1 errno == EAGAIN) +{ +// read again +continue; +} +else if (bytes_read == -1) +{ +// an error occured reading a byte +print(log_error, error reading a byte (%d), name().c_str(), errno); +break; +} + +// reset timeout +if (context != START) +{ +time(start_time); +} + + if (byte == '!') context = END; /* ! is the identifier for the END */ switch (context) { case START: /* strip the initial / */ -if (byte != '\r' byte != '\n') { /*allow extra new line at the start */ +if (byte == '/') { byte_iterator = number_of_tuples = 0;/* start */ context = VENDOR;/* set new context: START -