Reading Utility metering data using MBED

Dependencies:   mbed

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