Paul van der Wielen
/
MT382_serial
Reading Utility metering data using MBED
Diff: mt382.h
- Revision:
- 0:bacf1c9b9afc
- Child:
- 1:633092f351c6
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mt382.h Mon Sep 24 12:33:58 2012 +0000 @@ -0,0 +1,225 @@ +#ifndef MBED_H +#include "mbed.h" +#endif +/* + * Copyright (c) 2012 Paul van der Wielen, Pro-Serv + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to use + * and implement the software for none commercial reason and usage only and + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Usage and assumptions: + * interfacing an MT382 smart meter using P1 port, schematic is fairly simple and + * provides for an isolated connection to the outside world, schematic to foloow in due time. + * + * Overview of used record codes & formats + * 0-0:96.1.1(5A424556303035303936303530313132) Serialno meter in hexadecimal ascii code + * 1-0:1.8.1(00185.000*kWh) * Total consumpion tarif 1 (night) + * 1-0:1.8.2(00084.000*kWh) * Total consumpion tarif 2 (day) + * 1-0:2.8.1(00013.000*kWh) * Total delivery tarif 1 (night) + * 1-0:2.8.2(00019.000*kWh) * Total delivery tarif 2 (day) + * 0-0:96.14.0(0001) 1 Actual tarif (1) + * 1-0:1.7.0(0000.98*kW) * Current usage + * 1-0:2.7.0(0000.00*kW) * Current delivery + * 0-0:17.0.0(999*A) Maximum current by phase + * 0-0:96.3.10(1) Position of switch + * 0-0:96.13.1() 1 Message (numeric) + * 0-0:96.13.0() 1 Message (text) + * 0-1:24.1.0(3) Other equipment on M-Bus + * 0-1:96.1.0(3238313031353431323030333330313132) Serialno of gasmeter + * 0-1:24.3.0(120517020000)(08)(60)(1)(0-1:24.2.1)(m3) Time of last gas measurement (120517020000 = 17 mei 2012 2uur + * (00124.477) * Total consumption gas + * 0-1:24.4.0(1) Position of gas valve? + * ^-Implemented, 1-planned for later date + */ + +namespace MT { + +class MT382 { + +protected: + DigitalOut *_out; + Timeout *_delay; + Serial *_dev; + float _defDelay; + int _defBaud; + int _defBits; + int _defParity; + int _defStop; + // array with items to find in data stream + char _l_mt[7][8]; + char _mt_temp[32]; + char _mt_line[64]; + char _mt_data[512]; + double _mt_res[7]; + // stream status (1 = start char , 2 = stop char) + int _mt_sts; + int _mt_pnt; + int _mt_flg; + + void init(PinName po, PinName tx, PinName rx) { + _out = new DigitalOut( po ); + _out->write(1); + _dev = new Serial(tx, rx); + _delay = new Timeout; + _defBaud = 9600; + _defBits = 7; + _defParity = 2; + _defStop = 1; + setComm(); + } + +public: + + friend class Timeout; + + /* PinDetect constructor(s) & overloading */ + MT382() { error("Provide valid PinName for out, tx & rx"); } + + MT382(PinName po, PinName tx, PinName rx) { + init( po, tx, rx); + } + + /* PinDetect destructor */ + ~MT382() { + if ( _delay ) delete( _delay ); + if ( _out ) delete( _out ); + if ( _dev ) delete( _dev ); + } + + // adjust communication parameters as needed + void setComm(int baud = 9600, int bits = 7, int parity = 2, int stop = 1) { + _defBaud = baud; + _dev->baud(_defBaud); + _defBits = bits; + _defParity = parity; + _defStop = stop; + + switch (_defParity) { + case 0: + _dev->format(_defBits, Serial::None, _defStop); + break; + case 1: + _dev->format(_defBits, Serial::Odd, _defStop); + break; + case 2: + _dev->format(_defBits, Serial::Even, _defStop); + break; + default: + _dev->format(_defBits, Serial::None, _defStop); + break; + } + } + + // adjust timeout value + void setTime(float maxtime = 5.0) { + _defDelay = maxtime; + } + + // adjust the value match strings + void setMatch(char * m0 = "", char * m1 = "", char * m2 = "", + char * m3 = "", char * m4 = "", char * m5 = "", char * m6 = "") { + strcpy (_l_mt[0],m0); + strcpy (_l_mt[1],m1); + strcpy (_l_mt[2],m2); + strcpy (_l_mt[3],m3); + strcpy (_l_mt[4],m4); + strcpy (_l_mt[5],m5); + strcpy (_l_mt[6],m6); + } + + // signal time out condition + void isr_delay() { + _mt_sts = 0x80; + _delay->detach(); + } + + char * getRaw(void) { + return _mt_data; + } + + // get data from 'smart meter' + int getReading () { + + _delay->attach(this, &MT382::isr_delay, _defDelay); + _out->write(0); + _mt_pnt = 0; + _mt_sts = 0; + + while((_mt_sts & 0x02) == 0 && (_mt_sts & 0x80) == 0) { + if(_dev->readable()) { + _mt_data[_mt_pnt++] = _dev->getc(); + if (_mt_data[_mt_pnt-1] == '/') { + _mt_sts = 1; + } + if (_mt_data[_mt_pnt-1] == '!') { + _mt_sts = _mt_sts | 0x02; + _delay->detach(); + _out->write(1); + } + } + } + + int mt_tmp = 0; + _mt_flg = 0; + int mt_elem = sizeof(_l_mt)/sizeof(_l_mt[0]); + if ((_mt_sts == 0x03) && ((_mt_sts & 0x80) == 0)){ + for (int buf_pnt = 0; buf_pnt <= _mt_pnt; buf_pnt++) { + _mt_line[mt_tmp++] = _mt_data[buf_pnt]; + if (_mt_data[buf_pnt] == 0x0a) { + _mt_line[mt_tmp] = 0x00; + if ((_mt_flg & 0x01) == 0x01) { + // special case handling -> param 5 + strncpy (_mt_temp, strchr(_mt_line,'(') + 1, strchr(_mt_line,')') - strchr(_mt_line,'(') - 1); + _mt_res[(_mt_flg >> 4) & 0x0f] = strtod(_mt_temp, NULL); + _mt_flg = 0; + } + for (int j = 0; j < mt_elem; j++) { + if (strstr (_mt_line, _l_mt[j])) { + for (int cnt = 0; cnt < sizeof(_mt_temp); cnt++) { + _mt_temp[cnt] = 0x00; + } + if (j < 6) { + strncpy (_mt_temp, strchr(_mt_line,'(') + 1, strchr(_mt_line,'*') - strchr(_mt_line,'(') - 1); + } else { + // flag special case due to inconsistent formating of raw data + _mt_flg = j << 4 | 0x01; + } + _mt_res[j] = strtod(_mt_temp, NULL); + } + } + mt_tmp = 0; + } + } + } else { + return -1; + } + return 0; + } + + // return selected value + double getValue(int param = 0) { + return _mt_res[param]; + } + + // return raw data character count + int getCount(void) { + return _mt_pnt; + } +}; + +}; // namespace MT ends. + +using namespace MT; \ No newline at end of file