/* Copyright (C) 2017-2018 Fredrik Öhrström This program 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 (at your option) any later version. This program 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 this program. If not, see . */ #ifndef WMBUS_H #define WMBUS_H #include"manufacturers.h" #include"serial.h" #include"util.h" #include #define LIST_OF_LINK_MODES X(LinkModeC1)X(LinkModeT1)X(UNKNOWN_LINKMODE) enum LinkMode { #define X(name) name, LIST_OF_LINK_MODES #undef X }; #define CC_B_BIDIRECTIONAL_BIT 0x80 #define CC_RD_RESPONSE_DELAY_BIT 0x40 #define CC_S_SYNCH_FRAME_BIT 0x20 #define CC_R_RELAYED_BIT 0x10 #define CC_P_HIGH_PRIO_BIT 0x08 // Bits 31-29 in SN, ie 0xc0 of the final byte in the stream, // since the bytes arrive with the least significant first // aka little endian. #define SN_ENC_BITS 0xc0 using namespace std; struct Telegram { int len {}; // The length of the telegram, 1 byte. int c_field {}; // 1 byte (0x44=telegram, no response expected!) int m_field {}; // Manufacturer 2 bytes vector a_field; // A field 6 bytes // The 6 a field bytes are composed of: vector a_field_address; // Address in BCD = 8 decimal 00000000...99999999 digits. int a_field_version {}; // 1 byte int a_field_device_type {}; // 1 byte int ci_field {}; // 1 byte // When ci_field==0x7a then there are 4 extra header bytes, short data header int acc {}; // 1 byte int status {}; // 1 byte int configuration {}; // 2 bytes // When ci_field==0x8d then there are 8 extra header bytes (ELL header) int cc_field {}; // 1 byte // acc; // 1 byte uchar sn[4] {}; // 4 bytes // That is 6 bytes (not 8), the next two bytes, the payload crc // part of this ELL header, even though they are inside the encrypted payload. vector parsed; // Parsed fields vector payload; // To be parsed. vector content; // Decrypted content. bool handled {}; // Set to true, when a meter has accepted the telegram. // The id as written on the physical meter device. string id() { return bin2hex(a_field_address); } void parse(vector &payload); void print(); void verboseFields(); // A vector of indentations and explanations, to be printed // below the raw data bytes to explain the telegram content. vector> explanations; void addExplanation(vector::iterator &bytes, int len, const char* fmt, ...); void addMoreExplanation(int pos, const char* fmt, ...); void explainParse(string intro, int from); }; struct WMBus { virtual bool ping() = 0; virtual uint32_t getDeviceId() = 0; virtual LinkMode getLinkMode() = 0; virtual void setLinkMode(LinkMode lm) = 0; virtual void onTelegram(function cb) = 0; virtual SerialDevice *serial() = 0; virtual void simulate() = 0; }; #define LIST_OF_MBUS_DEVICES X(DEVICE_IM871A)X(DEVICE_AMB8465)X(DEVICE_SIMULATOR)X(DEVICE_UNKNOWN) enum MBusDeviceType { #define X(name) name, LIST_OF_MBUS_DEVICES #undef X }; // The detect function can be supplied the device "auto" and will try default locations for the device. // Returned is the type and the found device string. pair detectMBusDevice(string device, SerialCommunicationManager *manager); WMBus *openIM871A(string device, SerialCommunicationManager *manager); WMBus *openAMB8465(string device, SerialCommunicationManager *manager); struct WMBusSimulator; WMBus *openSimulator(string file, SerialCommunicationManager *manager); string manufacturer(int m_field); string manufacturerFlag(int m_field); string deviceType(int m_field, int a_field_device_type); string mediaType(int m_field, int a_field_device_type); string ciType(int ci_field); string cType(int c_field); string ccType(int cc_field); string difType(int dif); float vifScale(int vif); string vifType(int vif); string vifeType(int vif, int vife); enum DIFTYPE { DIF_INTEGER, DIF_REAL, DIF_BCD }; int difLenBytes(int dif); DIFTYPE difDataType(int dif); #endif