[vz-dev] [vz-users] vzlogger MeterD0 mit L&G

Karlheinz karlheinz.es at gmx.de
Mon Apr 28 22:07:19 CEST 2014


Hallo Reinhard,

die print Anweisung hab ich aus vorherigen Code-Stellen kopiert - es 
sollte funktionieren. Probier doch bitte mal aus, ob die MeterD0.cpp 
(Anhang) bei dir geht.

Gruß

Karlheinz


------- Original Nachricht --------
Betreff: Re: [vz-dev] [vz-users] vzlogger MeterD0 mit L&G
Von: Reinhard Wilzeck <reinhard at wilzeck.de>
An: volkszaehler.org <volkszaehler-dev at demo.volkszaehler.org>
Datum: Freitag, 25. April 2014 19:16:34

> Noch eine blöde Frage( auf die Gefahr mich ohne meinen PC zu blamieren):
> Ist die printanweisung richtig?
> Vielleich noch ein %s ? 2 Argumente nach dem " aber nur ein Platzhalter.
>
>
> Mfg. Reinhard Wilzeck
>
>
>
> -------- Ursprüngliche Nachricht --------
> Von: Karlheinz <karlheinz.es at gmx.de>
> Datum: 25.04.2014 12:15 (GMT+01:00)
> An: volkszaehler-dev at demo.volkszaehler.org
> Betreff: Re: [vz-dev] [vz-users] vzlogger MeterD0 mit L&G
>
>
> Hallo Reinhard,
>
> Danke für den Hinweis.
> Bei mir bricht vzlogger schon früher ab. Ich habe eine print-Anweisung 
> nach "case OBIS_CODE:" drin, die nach dem CRLF nicht mehr durchlaufen 
> wird.
> case OBIS_CODE:
> print(log_debug, "DEBUG OBIS_CODE byte hex= %X ",name().c_str(), byte);
>
> =-O  ssl ratlos! Hast du einen Tipp für Anfänger wie ich das debuggen 
> kann?
>
> Dein Problem mit '*' war schon im MeterD0 drin.
>
> Gruß
> Karlheinz
>
> ------- Original Nachricht --------
> Betreff: Re: [vz-dev] [vz-users] vzlogger MeterD0 mit L&G
> Von: Reinhard Wilzeck <reinhard at wilzeck.de>
> An: volkszaehler.org <volkszaehler-dev at demo.volkszaehler.org>
> Datum: Donnerstag, 24. April 2014 22:28:45
>
>> Hallo,
>> ich hatte damals das gleiche Problem und habe es auf die brutale Art 
>> gelöst.
>> "Illegale" Zeichen werden unterdrückt, bevor der OBIS Parser dadurch 
>> abstürzen kann.
>> Wir müssen den STX (0x02) ausblenden. (ordentlicher wäre auf den STX 
>> zu warten, aber davon haben wir nix. Und wenn der STX richtig 
>> ausgewertet wird, dann müßten wir konsequenterweise das Telgramm bis 
>> zum Ende auswerten, damit wir Fehler erkennen)
>> Ich hatte auch ein Problem mit "*" vor der Einheit. Da die Einheit 
>> auch nicht wirklich verwendet wird kann man auch bei dem "*" schon 
>> Schluss machen)
>>
>> Nachstehende Modifikation sollte die Probleme auch für Deinen Fall lösen.
>>                 case OBIS_CODE:
>> *  if ((byte != '\n') && (byte != '\r')&& (byte != 0x02)***&& (byte 
>> != 0x1F)*)// STX und US ausklammern *
>>                     {
>>                         if (byte == '(') {
>>                             obis_code[byte_iterator] = '\0';
>>                             byte_iterator = 0;
>>
>>                             context = VALUE;
>>                         }
>>                         else obis_code[byte_iterator++] = byte;
>>                     }
>>                     break;
>>
>>                 case VALUE:
>> ***if (byte == '*' **|| byte == ')') {*
>>                         value[byte_iterator] = '\0';
>>                         byte_iterator = 0;
>>
>>                         if (byte == ')') {
>>                             unit[0] = '\0';
>>                             context =  END_LINE;
>>                         }
>>                         else {
>>                             context = UNIT;
>>                         }
>>                     }
>>                     else value[byte_iterator++] = byte;
>>                     break;
>>
>> Gruß
>>     Reinhard
>>
>> Am 23.04.2014 23:48, schrieb Karlheinz:
>>> Hallo Stefan,
>>>
>>> es gibt einige Beiträge mit diesem D0-Problem. Shell-Scripts gibts 
>>> es auch schon im Wiki. Besser wäre es wenn vzlogger das von Haus aus 
>>> unterstützt.
>>> Aber ohne Debug-Unterstützung komme ich leider nicht weiter.
>>> Wie erzeuge ich eine debug-fähige vzlogger version, die ich mit ddd 
>>> debuggen kann?
>>> Vielleicht verirrt sich mal ein Programmierer in den Chat 
>>> <http://webchat.freenode.net/?channels=volkszaehler.org>und leistet 
>>> etwas Entwicklungshilfe :-)
>>>
>>> Gruß
>>> Karlheinz
>>>
>>> ------- Original Nachricht --------
>>> Betreff: Re: [vz-users] vzlogger MeterD0 mit L&G
>>> Von: Stefan Klammer <klammerstefan85 at gmail.com>
>>> An: volkszaehler.org - users <volkszaehler-users at demo.volkszaehler.org>
>>> Datum: Mittwoch, 23. April 2014 08:26:47
>>>
>>>> Hallo Karlheinz,
>>>>
>>>> ich habe ein ähnliches Problem mit meinem (Landis & Gyr ZMD120AR), 
>>>> dieser sendet am Schluss der Übertragung ein Zeichen das dem 
>>>> vzlogger bzw. d0 Parser nicht passt und der logger somit aussteigt. 
>>>> Ich wollte denn D0 Parser auch schon anpassen das er wirklich nur 
>>>> die geforderten OBIS Codes ausliest (z.B.: 1.8.1) und alles andere 
>>>> was er nicht kennt einfach ignoriert. Leider bin ich bis jetzt 
>>>> nicht dazugekommen. Vielleicht kannst du das mal ausprobieren wäre 
>>>> super wenn da endlich mal was Zustande kommt.
>>>>
>>>> Vielleicht schaust du dir das hier mal an: 
>>>> http://www.mail-archive.com/volkszaehler-dev%40lists.volkszaehler.org/msg02150.html
>>>> Hört sich nach einem ähnlichen Problem an.
>>>>
>>>> Oder hier: 
>>>> http://www.mail-archive.com/volkszaehler-dev%40lists.volkszaehler.org/msg01732.html
>>>> Da kannst du meine Ausgaben vom Zähler sehen.
>>>>
>>>> Hoffe du kriegst noch was raus. Wäre schön zu hören wenns klappt.
>>>>
>>>> Gruß Stefan
>>>>
>>>> Am 18. April 2014 17:17 schrieb Karlheinz <karlheinz.es at gmx.de 
>>>> <mailto:karlheinz.es at gmx.de>>:
>>>>
>>>>     Hallo Leute,
>>>>
>>>>     seit Tagen versuche ich den vzlogger (MeterD0.cpp) auch für
>>>>     meinen Stromzähler (Landys & Gir ZMD120 ...) anzupassen. Über
>>>>     die ersten Stolpersteine bin ich mittlerweile drüber, aber nun
>>>>     steigt das Programm bei der while Schleife "while (::read(_fd,
>>>>     &byte, 1)) { "  beim Zeichen 0x1F immer aus. Wenn ich das
>>>>     richtig sehe wird das Zeichen 0x1F und dann 0x02 gesendet,
>>>>     bevor es bei F.F usw. weiter geht.
>>>>
>>>>     /LGZ52ZMD120APt.G03
>>>>     ..F.F(00000000)
>>>>     0.0.0( 26700)
>>>>     1.8.1(012334.7*kWh)
>>>>     ...
>>>>
>>>>     Hat jemand eine Idee?
>>>>
>>>>     Gruß
>>>>     Karlheinz
>>>>
>>>>
>>>
>>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://demo.volkszaehler.org/pipermail/volkszaehler-dev/attachments/20140428/9cb94345/attachment-0001.html>
-------------- next part --------------
/**
 * Plaintext protocol according to DIN EN 62056-21
 *
 * This protocol uses OBIS codes to identify the readout data
 *
 * This is our example protocol. Use this skeleton to add your own
 * protocols and meters.
 *
 * @package vzlogger
 * @copyright Copyright (c) 2011, The volkszaehler.org project
 * @license http://www.gnu.org/licenses/gpl.txt GNU Public License
 * @author Steffen Vogel <info at steffenvogel.de>
 * @author Mathias Dalheimer <md at gonium.net>
 */
/*
 * This file is part of volkzaehler.org
 *
 * volkzaehler.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * volkzaehler.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with volkszaehler.org. If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <sys/time.h>

/* socket */
#include <netdb.h>
#include <sys/socket.h>

#include "protocols/MeterD0.hpp"
#include <VZException.hpp>

#include "Obis.hpp"

MeterD0::MeterD0(std::list<Option> options) 
		: Protocol("d0")
		, _host("")
		, _device("")
{
	OptionList optlist;

	/* connection */
	try {
		_host = optlist.lookup_string(options, "host");
	} catch ( vz::OptionNotFoundException &e ) {
		try {
			_device = optlist.lookup_string(options, "device");
		} catch ( vz::VZException &e ){
			print(log_error, "Missing device or host", name().c_str());
			throw ;
		}
	} catch( vz::VZException &e ) {
		print(log_error, "Missing device or host", name().c_str());
		throw;
	}
	try {
		std::string hex;
		hex = optlist.lookup_string(options, "pullseq");
		int n=hex.size();
		int i;
		for(i=0;i<n;i=i+2) {
			char hs[3];
			strncpy(hs,hex.c_str()+i,2);
			char hx[2];
			hx[0]=strtol(hs,NULL,16);
			_pull.append(hx,1);
		}
		print(log_debug,"pullseq len:%d found",name().c_str(),_pull.size());
	} catch( vz::OptionNotFoundException &e ) {
		/* using default value if not specified */
		_pull = "";
	}

	/* baudrate */
	int baudrate = 9600; /* default to avoid compiler warning */
	try {
		baudrate = optlist.lookup_int(options, "baudrate");
		/* find constant for termios structure */
		switch (baudrate) {
				case 50: _baudrate = B50; break;
				case 75: _baudrate = B75; break;
				case 110: _baudrate = B110; break;
				case 134: _baudrate = B134; break;
				case 150: _baudrate = B150; break;
				case 200: _baudrate = B200; break;
				case 300: _baudrate = B300; break;
				case 600: _baudrate = B600; break;
				case 1200: _baudrate = B1200; break;
				case 1800: _baudrate = B1800; break;
				case 2400: _baudrate = B2400; break;
				case 4800: _baudrate = B4800; break;
				case 9600: _baudrate = B9600; break;
				case 19200: _baudrate = B19200; break;
				case 38400: _baudrate = B38400; break;
				case 57600: _baudrate = B57600; break;
				case 115200: _baudrate = B115200; break;
				case 230400: _baudrate = B230400; break;
				default:
					print(log_error, "Invalid baudrate: %i", name().c_str(), baudrate);
					throw vz::VZException("Invalid baudrate");
		}
	} catch( vz::OptionNotFoundException &e ) {
		/* using default value if not specified */
		_baudrate = B9600;
	} catch( vz::VZException &e ) {
		print(log_error, "Failed to parse the baudrate", name().c_str());
		throw;
	}

	_parity=parity_7e1;
	try {
		const char *parity = optlist.lookup_string(options, "parity");
		/* find constant for termios structure */
		if(strcasecmp(parity,"8n1")==0) {
			_parity=parity_8n1;
		} else if(strcasecmp(parity,"7n1")==0) {
			_parity=parity_7n1;
		} else if(strcasecmp(parity,"7e1")==0) {
			_parity=parity_7e1;
		} else if(strcasecmp(parity,"7o1")==0) {
			_parity=parity_7o1;
		} else {
			throw vz::VZException("Invalid parity");
		}
	} catch( vz::OptionNotFoundException &e ) {
		/* using default value if not specified */
		_parity = parity_7e1;
	} catch( vz::VZException &e ) {
		print(log_error, "Failed to parse the parity", name().c_str());
		throw;
	}

}

MeterD0::~MeterD0() {
}

int MeterD0::open() {
	if (_device != "") {
		_fd = _openDevice(&_oldtio, _baudrate);
	}
	else if (_host != "") {
		char *addr = strdup(host());
		const char *node = strsep(&addr, ":");
		const char *service = strsep(&addr, ":");

		_fd = _openSocket(node, service);
	}

	return (_fd < 0) ? ERR : SUCCESS;
}

int MeterD0::close() {
	return ::close(_fd);
}

ssize_t MeterD0::read(std::vector<Reading>&rds, size_t max_readings) {

	enum { START, VENDOR, BAUDRATE, IDENTIFICATION, START_LINE, OBIS_CODE, VALUE, UNIT, END_LINE, ERROR_MESSAGE, END } context;

	bool error_flag = false;
	char vendor[3+1];		/* 3 upper case vendor + '\0' termination */
	char identification[16+1];	/* 16 meter specific + '\0' termination */
	char obis_code[16+1];		/* A-B:C.D.E*F
														 fields A, B, E, F are optional
														 fields C & D are mandatory
														 A: energy type; 1: energy
														 B: channel number; 0: no channel specified
														 C: data items; 0-89 in COSEM context: IEC 62056-62, Clause D.1; 96: General service entries
														 1:  Totel Active power+
														 21: L1 Active power+
														 31: L1 Current
														 32: L1 Voltage
														 41: L2 Active power+
														 51: L2 Current
														 52: L2 Voltage
														 61: L3 Active power+
														 71: L3 Current
														 72: L3 Voltage
														 96.1.255: Metering point ID 256 (electricity related) 
														 96.5.5: Meter started status flag
														 D: types
														 E: further processing or classification of quantities
														 F: storage of data
														 see DIN-EN-62056-61 */
	char value[32+1];		/* value, i.e. the actual reading */
	char unit[16+1];		/* the unit of the value, e.g. kWh, V, ... */

	char baudrate;			/* 1 byte for */
	char byte;			/* we parse our input byte wise */
	int byte_iterator; 
	char endseq[2+1]; /* Endsequence ! not ?! */

	size_t number_of_tuples;

	if(_pull.size()) {
		int wlen=write(_fd,_pull.c_str(),_pull.size());
		print(log_debug,"sending pullsequenz send (len:%d is:%d).",name().c_str(),_pull.size(),wlen);
	}


	byte_iterator =  number_of_tuples = baudrate = 0;

	context = START;				/* start with context START */

	while (::read(_fd, &byte, 1)) {
		/* reset to START if "/" reoccurs */
/* 		if (byte == '/') context = START; 	 */
/*		else if (byte == '!') context = END;	 */
/* "!" is the identifier for the END */	
/*        print(log_debug, "DEBUG begin switch byte hex= %X ", name().c_str(), byte);*/
        if (byte == '/') context = VENDOR;
		else if (byte == '?' or byte == '!') context = END; /* "!" is the identifier for the END */

		switch (context) {
				case START:			/* strip the initial "/" */
				    print(log_error, "DEBUG START byte= %c %x ", name().c_str(), byte, byte);
    			            if  (byte != '\r' &&  byte != '\n') { /*allow extra new line at the start */
                    			 byte_iterator = number_of_tuples = 0;        /* start */
					 context = VENDOR;        /* set new context: START -> VENDOR */
                		    }
					break;

				case VENDOR:			/* VENDOR has 3 Bytes */
					/*print(log_debug, "DEBUG Vendor1 byte= %c hex= %x byteIterator= %i ",name().c_str(), byte, byte, byte_iterator);*/
					if  (byte == '\r' or  byte == '\n' or byte == '/' ) {
					    byte_iterator = number_of_tuples = 0;
					    break;
				        }
					print(log_debug, "DEBUG Vendor2 byte= %c hex= %x byteIterator= %i ",name().c_str(), byte, byte, byte_iterator);

					if (!isalpha(byte)) goto error; /* Vendor ID needs to be alpha */
					vendor[byte_iterator++] = byte;	/* read next byte */
					if (byte_iterator >= 3) {	/* stop after 3rd byte */
						vendor[byte_iterator] = '\0'; /* termination */
						byte_iterator = 0;	/* reset byte counter */

						context = BAUDRATE;	/* set new context: VENDOR -> BAUDRATE */
					} 
					break;

				case BAUDRATE:			/* BAUDRATE consists of 1 char only */
					print(log_debug, "DEBUG BAUDRATE byte= %c %x ",name().c_str(), byte, byte);
					baudrate = byte;	
					context = IDENTIFICATION;	/* set new context: BAUDRATE -> IDENTIFICATION */
					byte_iterator = 0;
					break;

				case IDENTIFICATION:		/* IDENTIFICATION has 16 bytes */
					print(log_debug, "DEBUG IDENTIFICATION byte= %c hex= %x ",name().c_str(), byte, byte);
					if (byte == '\r' || byte == '\n') { /* detect line end */
						identification[byte_iterator] = '\0'; /* termination */
						context = OBIS_CODE;	/* set new context: IDENTIFICATION -> OBIS_CODE */
						byte_iterator = 0;
					}
					else {
						if(!isprint(byte)) {
							print(log_error, "====> binary character '%x'", name().c_str(), byte);
							//error_flag=true;
						}
						else {
							identification[byte_iterator++] = byte;
						}
					}
					break;

				case START_LINE:
					break;
				case OBIS_CODE:
					/*print(log_debug, "DEBUG OBIS_CODE byte= %c hex= %x ",name().c_str(), byte, byte);*/
					print(log_debug, "DEBUG OBIS_CODE byte hex= %X ",name().c_str(), byte);
            	if ((byte != '\n') && (byte != '\r') && (byte != 0x1F) && (byte != 0x02) ) {
			print(log_debug, "DEBUG OBIS_CODE 2 byte hex= %X ",name().c_str(), byte);
                    if (byte == 'F') {
                            /* Fehlerausgabe mit F beginnend */
                            context = ERROR_MESSAGE;
                            break;
                        }

                        print(log_debug, "DEBUG OBIS_CODE start byte= %c hex= %x ",name().c_str(), byte, byte);
                        if (byte == '(') {
                            obis_code[byte_iterator] = '\0';
                            byte_iterator = 0;
                            context = VALUE;
                        }
                        else obis_code[byte_iterator++] = byte;
                }

                /*print(log_debug, "DEBUG OBIS_CODE end byte= %c hex= %x ",name().c_str(), byte, byte);*/
                print(log_debug, "DEBUG OBIS_CODE end byte hex= %x ",name().c_str(), byte);
                break;

				case VALUE:
					print(log_debug, "DEBUG VALUE byte= %c hex= %x ",name().c_str(), byte, byte);
					if (byte == '*' || byte == ')') {
						value[byte_iterator] = '\0';
						byte_iterator = 0;

						if (byte == ')') {
							unit[0] = '\0';
							context =  END_LINE;
						}
						else {
							context = UNIT;
						}
					}
					else value[byte_iterator++] = byte;
					break;

				case UNIT:
					if (byte == ')') {
						unit[byte_iterator] = '\0';
						byte_iterator = 0;

						context = END_LINE;
					}
					else unit[byte_iterator++] = byte;
					break;

				case END_LINE:
					if (byte == '\r' || byte == '\n') {
						/* free slots available and sain content? */
						if ((number_of_tuples < max_readings) && (strlen(obis_code) > 0) && 
								(strlen(value) > 0)) {
							print(log_debug, "Parsed reading (OBIS code=%s, value=%s, unit=%s)", name().c_str(), obis_code, value, unit);
							rds[number_of_tuples].value(strtof(value, NULL));
							Obis obis(obis_code);
							ReadingIdentifier *rid(new ObisIdentifier(obis));
							rds[number_of_tuples].identifier(rid);
							rds[number_of_tuples].time();

							byte_iterator = 0;
							number_of_tuples++;

							context = OBIS_CODE;
						}
					}
					break;
				case ERROR_MESSAGE:
				    print(log_debug, "DEBUG ERROR_MESSAGE byte= %c hex= %x ",name().c_str(), byte, byte);
				    /* waiting for CR or NL */
				    if ((byte == '\n') or (byte == '\r')) {
                        context = OBIS_CODE;
				    }
				    break;
				case END:
                    print(log_debug, "DEBUG END1 %c %i ", name().c_str(), byte, byte_iterator);
                    endseq[byte_iterator++] = byte;
                    print(log_debug, "DEBUG END2 byte: %c  iterator: %i ", name().c_str(), byte, byte_iterator);
                    if(endseq[0] == '?' ) {
                        /* endseq[byte_iterator++] = byte;*/
                        /* context = END; */
                        print(log_debug, "DEBUG END3 byte: %x endseq: %x ", name().c_str(), byte, endseq);
                        if(endseq[1] == '!') {
                            context = VENDOR;
                            endseq[byte_iterator] = '\0';
                            print(log_debug, "DEBUG END4 goto VENDOR", name().c_str());
                            byte_iterator = 0;
                            endseq[3] = { 0 };
                        }
                    break;
                    }

                    if(error_flag) {
						print(log_error, "reading binary values.", name().c_str());
						goto error;
                    }
					print(log_debug, "Read package with %i tuples (vendor=%s, baudrate=%c, identification=%s)",
								name().c_str(), number_of_tuples, vendor, baudrate, identification);
					return number_of_tuples;
		}
	}

	error:
	print(log_error, "Something unexpected happened: %s:%i!", name().c_str(), __FUNCTION__, __LINE__);
	print(log_debug, "Read (vendor=%s, baudrate=%c, identification=%s)",
		name().c_str(), number_of_tuples, vendor, baudrate, identification);
	return 0;
} 

int MeterD0::_openSocket(const char *node, const char *service) {
	struct sockaddr_in sin;
	struct addrinfo *ais;
	int fd; /* file descriptor */
	int res;

	fd = socket(PF_INET, SOCK_STREAM, 0);
	if (fd < 0) {
		print(log_error, "socket(): %s", name().c_str(), strerror(errno));
		return ERR;
	}

	getaddrinfo(node, service, NULL, &ais);
	memcpy(&sin, ais->ai_addr, ais->ai_addrlen);
	freeaddrinfo(ais);

	res = connect(fd, (struct sockaddr *) &sin, sizeof(sin));
	if (res < 0) {
		print(log_error, "connect(%s, %s): %s", name().c_str(), node, service, strerror(errno));
		return ERR;
	}

	return fd;
}

int MeterD0::_openDevice(struct termios *old_tio, speed_t baudrate) {
	struct termios tio;
	memset(&tio, 0, sizeof(struct termios));

	int fd = ::open(device(), O_RDWR);
	if (fd < 0) {
		print(log_error, "open(%s): %s", name().c_str(), device(), strerror(errno));
		return ERR;
	}

	/* get old configuration */
	tcgetattr(fd, &tio) ;

	/* backup old configuration to restore it when closing the meter connection */
	memcpy(old_tio, &tio, sizeof(struct termios));

	tio.c_iflag &= ~(BRKINT | INLCR | IMAXBEL);
	tio.c_oflag &= ~(OPOST | ONLCR);
	tio.c_lflag &= ~(ISIG | ICANON | IEXTEN | ECHO);

	switch(_parity) {
	case parity_8n1:
		tio.c_cflag &= ~ PARENB;
		tio.c_cflag &= ~ CSTOPB;
		tio.c_cflag &= ~ CSIZE;
		tio.c_cflag |= CS8;
		break;
	case parity_7n1:
		tio.c_cflag &= ~ PARENB;
		tio.c_cflag &= ~ CSTOPB;
		tio.c_cflag &= ~ CSIZE;
		tio.c_cflag |= CS7;
		break;
	case parity_7e1:
		tio.c_cflag |= ~ PARENB;
		tio.c_cflag &= ~ PARODD;
		tio.c_cflag &= ~ CSTOPB;
		tio.c_cflag &= ~ CSIZE;
		tio.c_cflag |= CS7;
		break;
	case parity_7o1:
		tio.c_cflag |= ~ PARENB;
		tio.c_cflag |= ~ PARODD;
		tio.c_cflag &= ~ CSTOPB;
		tio.c_cflag &= ~ CSIZE;
		tio.c_cflag |= CS7;
		break;
	}

	/* set baudrate */
	cfsetispeed(&tio, baudrate);
	cfsetospeed(&tio, baudrate);

	/* apply new configuration */
	tcsetattr(fd, TCSANOW, &tio);

	return fd;
}


More information about the volkszaehler-dev mailing list