diff --git a/cmdline.h b/cmdline.h index 5e47b4a..5547777 100644 --- a/cmdline.h +++ b/cmdline.h @@ -57,6 +57,7 @@ struct CommandLine { char *usb_device {}; LinkMode link_mode {}; bool link_mode_set {}; + bool no_init {}; vector meters; }; diff --git a/dvparser.cc b/dvparser.cc index 4f85e25..524a51d 100644 --- a/dvparser.cc +++ b/dvparser.cc @@ -77,7 +77,7 @@ bool parseDV(Telegram *t, int datalen = difLenBytes(dif); DEBUG_PARSER("(dvparser debug) dif=%02x datalen=%d \"%s\"\n", dif, datalen, difType(dif).c_str()); if (datalen == -2) { - warning("(dvparser) cannot handle dif %02X ignoring rest of telegram.\n", dif); + debug("(dvparser) cannot handle dif %02X ignoring rest of telegram.\n", dif); return false; } if (dif == 0x2f) { @@ -96,7 +96,7 @@ bool parseDV(Telegram *t, (*format)++; } - if (*format == format_end) { warning("(dvparser) warning: unexpected end of data (vif expected)"); break; } + if (*format == format_end) { debug("(dvparser) warning: unexpected end of data (vif expected)"); break; } uchar vif = **format; DEBUG_PARSER("(dvparser debug) vif=%02x \"%s\"\n", vif, vifType(vif).c_str()); @@ -110,7 +110,7 @@ bool parseDV(Telegram *t, strprintf(dv, "%02X%02X", dif, vif); if ((vif&0x80) == 0x80) { // vif extension - if (*format == format_end) { warning("(dvparser) warning: unexpected end of data (vife expected)"); break; } + if (*format == format_end) { debug("(dvparser) warning: unexpected end of data (vife expected)"); break; } uchar vife = **format; DEBUG_PARSER("(dvparser debug) vife=%02x\n", vife); if (full_header) { @@ -140,7 +140,7 @@ bool parseDV(Telegram *t, int remaining = std::distance(data, data_end); if (variable_length) { - debug("(dvparser) varlen %02x\n", *(data+0)); + debug("(dvparser debug) varlen %02x\n", *(data+0)); if (remaining > 2) { datalen = *(data); } else { @@ -149,7 +149,7 @@ bool parseDV(Telegram *t, } DEBUG_PARSER("(dvparser debug) remaining data %d len=%d\n", remaining, datalen); if (remaining < datalen) { - warning("(dvparser) warning: unexpected end of data\n"); + debug("(dvparser) warning: unexpected end of data\n"); datalen = remaining; } @@ -164,6 +164,10 @@ bool parseDV(Telegram *t, t->addExplanation(data, datalen, "%s", value.c_str()); DEBUG_PARSER("(dvparser debug) data \"%s\"\n", value.c_str()); } + if (remaining == datalen) { + // We are done here! + break; + } } string format_string = bin2hex(format_bytes); diff --git a/meter_iperl.cc b/meter_iperl.cc index aee3bae..8f47b6d 100644 --- a/meter_iperl.cc +++ b/meter_iperl.cc @@ -43,6 +43,10 @@ struct MeterIperl : public virtual WaterMeter, public virtual MeterCommonImpleme bool hasTargetWaterConsumption(); double maxFlow(); bool hasMaxFlow(); + double flowTemperature(); + bool hasFlowTemperature(); + double externalTemperature(); + bool hasExternalTemperature(); string statusHumanReadable(); string status(); @@ -225,6 +229,26 @@ bool MeterIperl::hasMaxFlow() return false; } +double MeterIperl::flowTemperature() +{ + return 127; +} + +bool MeterIperl::hasFlowTemperature() +{ + return false; +} + +double MeterIperl::externalTemperature() +{ + return 127; +} + +bool MeterIperl::hasExternalTemperature() +{ + return false; +} + string MeterIperl::statusHumanReadable() { return ""; diff --git a/meter_multical21.cc b/meter_multical21.cc index 607dc89..c77cf49 100644 --- a/meter_multical21.cc +++ b/meter_multical21.cc @@ -59,6 +59,12 @@ struct MeterMultical21 : public virtual WaterMeter, public virtual MeterCommonIm // Max flow during last month or last 24 hours depending on meter configuration. double maxFlow(); bool hasMaxFlow(); + // Water temperature + double flowTemperature(); + bool hasFlowTemperature(); + // Surrounding temperature + double externalTemperature(); + bool hasExternalTemperature(); // statusHumanReadable: DRY,REVERSED,LEAK,BURST if that status is detected right now, followed by // (dry 15-21 days) which means that, even it DRY is not active right now, @@ -87,6 +93,10 @@ private: bool has_target_volume_ {}; double max_flow_ {}; bool has_max_flow_ {}; + double flow_temperature_ { 127 }; + bool has_flow_temperature_ {}; + double external_temperature_ { 127 }; + bool has_external_temperature_ {}; const char *meter_name_; // multical21 or flowiq3100 int expected_version_ {}; // 0x1b for Multical21 and 0x1d for FlowIQ3100 @@ -138,6 +148,26 @@ bool MeterMultical21::hasMaxFlow() return has_max_flow_; } +double MeterMultical21::flowTemperature() +{ + return flow_temperature_; +} + +bool MeterMultical21::hasFlowTemperature() +{ + return has_flow_temperature_; +} + +double MeterMultical21::externalTemperature() +{ + return external_temperature_; +} + +bool MeterMultical21::hasExternalTemperature() +{ + return has_external_temperature_; +} + WaterMeter *createMultical21(WMBus *bus, const char *name, const char *id, const char *key, MeterType mt) { if (mt != MULTICAL21_METER && mt != FLOWIQ3100_METER) { @@ -215,13 +245,6 @@ void MeterMultical21::processContent(Telegram *t) if (frame_type == 0x79) { - if (t->content.size() != 15) { - warning("(%s) warning: Unexpected length of short frame %zu. Expected 15 bytes! ", meter_name_, - t->content.size()); - padWithZeroesTo(&t->content, 15, &t->content); - warning("\n"); - } - // 0,1 = crc for format signature = hash over DRH (Data Record Header) // The DRH is the dif(dife)vif(vife) bytes for all the records... // This hash should be used to pick up a suitable format string. @@ -270,18 +293,8 @@ void MeterMultical21::processContent(Telegram *t) else if (frame_type == 0x78) { - if (t->content.size() != 22) { - warning("(%s) warning: Unexpected length of long frame %zu. Expected 22 bytes! ", meter_name_, t->content.size()); - padWithZeroesTo(&t->content, 22, &t->content); - warning("\n"); - } - map> values; - parseDV(t, t->content.begin()+3, t->content.size()-3-2, &values); - - // There are two more bytes in the data. Unknown purpose. - int val0 = t->content[20]; - int val1 = t->content[21]; + parseDV(t, t->content.begin()+3, t->content.size()-3, &values); int offset; @@ -293,13 +306,19 @@ void MeterMultical21::processContent(Telegram *t) t->addMoreExplanation(offset, " total consumption (%f m3)", total_water_consumption_); extractDVdouble(&values, "4413", &offset, &target_volume_); - has_target_volume_ = true; + has_target_volume_ = true; t->addMoreExplanation(offset, " target consumption (%f m3)", target_volume_); - // To unknown bytes, seems to be very constant. - vector::iterator unknowns = t->content.begin()+20; - t->addExplanation(unknowns, 2, "%02x%02x unknown", val0, val1); - } else { + extractDVdouble(&values, "615B", &offset, &flow_temperature_); + has_flow_temperature_ = true; + t->addMoreExplanation(offset, " flow temperature (%f °C)", flow_temperature_); + + extractDVdouble(&values, "6167", &offset, &external_temperature_); + has_external_temperature_ = true; + t->addMoreExplanation(offset, " external temperature (%f °C)", external_temperature_); + } + else + { warning("(%s) warning: unknown frame %02x (did you use the correct encryption key?)\n", meter_name_, frame_type); } } @@ -434,21 +453,25 @@ void MeterMultical21::printMeter(string *human_readable, char buf[65536]; buf[65535] = 0; - snprintf(buf, sizeof(buf)-1, "%s\t%s\t% 3.3f m3\t% 3.3f m3\t%s\t%s", + snprintf(buf, sizeof(buf)-1, "%s\t%s\t% 3.3f m3\t% 3.3f m3\t% 2.0f°C\t% 2.0f°C\t%s\t%s", name().c_str(), id().c_str(), totalWaterConsumption(), targetWaterConsumption(), + flowTemperature(), + externalTemperature(), statusHumanReadable().c_str(), datetimeOfUpdateHumanReadable().c_str()); *human_readable = buf; - snprintf(buf, sizeof(buf)-1, "%s%c%s%c%f%c%f%c%s%c%s", + snprintf(buf, sizeof(buf)-1, "%s%c" "%s%c" "%f%c" "%f%c" "%.0f%c" "%.0f%c" "%s%c" "%s", name().c_str(), separator, id().c_str(), separator, totalWaterConsumption(), separator, targetWaterConsumption(), separator, + flowTemperature(), separator, + externalTemperature(), separator, statusHumanReadable().c_str(), separator, datetimeOfUpdateRobot().c_str()); @@ -465,6 +488,8 @@ void MeterMultical21::printMeter(string *human_readable, QS(id,%s) Q(total_m3,%f) Q(target_m3,%f) + Q(flow_temperature,%.0f) + Q(external_temperature,%.0f) QS(current_status,%s) QS(time_dry,%s) QS(time_reversed,%s) @@ -478,6 +503,8 @@ void MeterMultical21::printMeter(string *human_readable, id().c_str(), totalWaterConsumption(), targetWaterConsumption(), + flowTemperature(), + externalTemperature(), status().c_str(), // DRY REVERSED LEAK BURST timeDry().c_str(), timeReversed().c_str(), @@ -492,6 +519,8 @@ void MeterMultical21::printMeter(string *human_readable, envs->push_back(string("METER_ID=")+id()); envs->push_back(string("METER_TOTAL_M3=")+to_string(totalWaterConsumption())); envs->push_back(string("METER_TARGET_M3=")+to_string(targetWaterConsumption())); + envs->push_back(string("METER_FLOW_TEMPERATURE=")+to_string(flowTemperature())); + envs->push_back(string("METER_EXTERNAL_TEMPERATURE=")+to_string(externalTemperature())); envs->push_back(string("METER_STATUS=")+status()); envs->push_back(string("METER_TIME_DRY=")+timeDry()); envs->push_back(string("METER_TIME_REVERSED=")+timeReversed()); diff --git a/meter_multical302.cc b/meter_multical302.cc index 9c58de8..1221610 100644 --- a/meter_multical302.cc +++ b/meter_multical302.cc @@ -119,11 +119,12 @@ void MeterMultical302::processContent(Telegram *t) { t->addExplanation(bytes, 1, "%02x frame type (%s)", frame_type, frameTypeKamstrupC1(frame_type).c_str()); if (frame_type == 0x79) { - if (t->content.size() != 17) { + /*if (t->content.size() != 17) { + fprintf(stderr, "(multical302) warning: Unexpected length of frame %zu. Expected 17 bytes! ", t->content.size()); padWithZeroesTo(&t->content, 17, &t->content); warning("\n"); - } + }*/ // This code should be rewritten to use parseDV see the Multical21 code. // But I cannot do this without more examples of 302 telegrams. @@ -151,11 +152,11 @@ void MeterMultical302::processContent(Telegram *t) { } else if (frame_type == 0x78) { - if (t->content.size() != 26) { + /*if (t->content.size() != 26) { fprintf(stderr, "(multical302) warning: Unexpected length of frame %zu. Expected 26 bytes! ", t->content.size()); padWithZeroesTo(&t->content, 26, &t->content); warning("\n"); - } + }*/ // This code should be rewritten to use parseDV see the Multical21 code. // But I cannot do this without more examples of 302 telegrams. diff --git a/meter_supercom587.cc b/meter_supercom587.cc index 421eb1c..72ad2f8 100644 --- a/meter_supercom587.cc +++ b/meter_supercom587.cc @@ -42,6 +42,10 @@ struct MeterSupercom587 : public virtual WaterMeter, public virtual MeterCommonI bool hasTargetWaterConsumption(); double maxFlow(); bool hasMaxFlow(); + double flowTemperature(); + bool hasFlowTemperature(); + double externalTemperature(); + bool hasExternalTemperature(); string statusHumanReadable(); string status(); @@ -223,6 +227,26 @@ bool MeterSupercom587::hasMaxFlow() return false; } +double MeterSupercom587::flowTemperature() +{ + return 127; +} + +bool MeterSupercom587::hasFlowTemperature() +{ + return false; +} + +double MeterSupercom587::externalTemperature() +{ + return 127; +} + +bool MeterSupercom587::hasExternalTemperature() +{ + return false; +} + string MeterSupercom587::statusHumanReadable() { return ""; diff --git a/meters.h b/meters.h index 28cb3a5..388f0b3 100644 --- a/meters.h +++ b/meters.h @@ -73,6 +73,10 @@ struct WaterMeter : public virtual Meter { virtual bool hasTargetWaterConsumption() = 0; virtual double maxFlow() = 0; virtual bool hasMaxFlow() = 0; + virtual double flowTemperature() = 0; // °C + virtual bool hasFlowTemperature() = 0; + virtual double externalTemperature() = 0; // °C + virtual bool hasExternalTemperature() = 0; virtual string statusHumanReadable() = 0; virtual string status() = 0; diff --git a/simulation_c1.txt b/simulation_c1.txt index 9f7e1cf..3f28683 100644 --- a/simulation_c1.txt +++ b/simulation_c1.txt @@ -1,12 +1,12 @@ # Test Multical21 C1 telegrams # short telegram -telegram=|23442D2C998734761B168D2093E13CBA20|967F79EDA8047B7100F4180000E918| -{"media":"cold water","meter":"multical21","name":"MyTapWater","id":"76348799","total_m3":6.388000,"target_m3":6.377000,"current_status":"DRY","time_dry":"22-31 days","time_reversed":"","time_leaking":"","time_bursting":"","timestamp":"1111-11-11T11:11:11Z"} +telegram=|23442D2C998734761B168D208870F81821|09EA79EDA869F57100F8180000F41800007F17| +{"media":"cold water","meter":"multical21","name":"MyTapWater","id":"76348799","total_m3":6.392000,"target_m3":6.388000,"flow_temperature":0,"external_temperature":0,"current_status":"DRY","time_dry":"22-31 days","time_reversed":"","time_leaking":"","time_bursting":"","timestamp":"1111-11-11T11:11:11Z"} # full telegram -telegram=|2A442D2C998734761B168D2049F03FBA20|39A17802FF2071000413F41800004413E9180000615B| -{"media":"cold water","meter":"multical21","name":"MyTapWater","id":"76348799","total_m3":6.388000,"target_m3":6.377000,"current_status":"DRY","time_dry":"22-31 days","time_reversed":"","time_leaking":"","time_bursting":"","timestamp":"1111-11-11T11:11:11Z"} +telegram=|2A442D2C998734761B168D208971F81821|542F7802FF2071000413F81800004413F4180000615B7F616717| +{"media":"cold water","meter":"multical21","name":"MyTapWater","id":"76348799","total_m3":6.392000,"target_m3":6.388000,"flow_temperature":127,"external_temperature":23,"current_status":"DRY","time_dry":"22-31 days","time_reversed":"","time_leaking":"","time_bursting":"","timestamp":"1111-11-11T11:11:11Z"} # Test Multical302 C1 telegrams diff --git a/simulation_t1.txt b/simulation_t1.txt index c3cd10c..5fe5b5a 100644 --- a/simulation_t1.txt +++ b/simulation_t1.txt @@ -1,13 +1,12 @@ # Test Supercom587 T1 telegrams -telegram=|A244EE4D785634123C067A73000000|0C1334190000426CE1F14C130000000082046C21298C0413330000008D04931E3A3CFE3300000033000000330000003300000033000000330000003300000033000000330000003300000033000000330000004300000034180000046D0113412B03FD6CDE120082206C5C290BFD0F0200018C4079678885238310FD3100000082106C01018110FD610002FD66020002| -{"media":"warm water","meter":"supercom587","name":"MyWarmWater","id":"12345678","total_m3":1.934000,"timestamp":"1111-11-11T11:11:11Z"} +telegram=|A244EE4D785634123C067A8F000000|0C1348550000426CE1F14C130000000082046C21298C0413330000008D04931E3A3CFE3300000033000000330000003300000033000000330000003300000033000000330000003300000033000000330000004300000034180000046D0D0B5C2B03FD6C5E150082206C5C290BFD0F0200018C4079678885238310FD3100000082106C01018110FD610002FD66020002FD170000| +{"media":"warm water","meter":"supercom587","name":"MyWarmWater","id":"12345678","total_m3":5.548000,"timestamp":"1111-11-11T11:11:11Z"} -telegram=|A244EE4D111111113C077A72000000|0C1374140000426CE1F14C130000000082046C21298C0413010000008D04931E3A3CFE0100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000001600000031130000046D0113412B03FD6CDF120082206C5C290BFD0F0200018C4079629885238310FD3100000082106C01018110FD610002FD66020002| -{"media":"water","meter":"supercom587","name":"MyColdWater","id":"11111111","total_m3":1.474000,"timestamp":"1111-11-11T11:11:11Z"} +telegram=|A244EE4D111111113C077AAC000000|0C1389490000426CE1F14C130000000082046C21298C0413010000008D04931E3A3CFE0100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000001600000031130000046D0A0C5C2B03FD6C60150082206C5C290BFD0F0200018C4079629885238310FD3100000082106C01018110FD610002FD66020002FD170000| +{"media":"water","meter":"supercom587","name":"MyColdWater","id":"11111111","total_m3":4.989000,"timestamp":"1111-11-11T11:11:11Z"} # Test iPerl T1 telegram -# 12345678 "1234567890ABCDEF1234567890ABCDEF" -telegram=|1E44AE4C7856341268077AB5000000|53cb05c02cf40b38e4cfe6a9f6565ec27261ae620df9257179197ef2dc6512f2| -{"media":"water","meter":"iperl","name":"MoreWater","id":"12345678","total_m3":3.699000,"timestamp":"1111-11-11T11:11:11Z"} +telegram=|1E44AE4C9956341268077A36001005|2F2F0413181E0000023B00002F2F2F2F| +{"media":"water","meter":"iperl","name":"MoreWater","id":"12345699","total_m3":7.704000,"timestamp":"1111-11-11T11:11:11Z"} diff --git a/test.sh b/test.sh index b378736..8f4439b 100755 --- a/test.sh +++ b/test.sh @@ -14,7 +14,7 @@ then diff test_expected.txt test_responses.txt if [ "$?" == "0" ] then - echo OK + echo C1 OK fi else Failure. @@ -24,7 +24,7 @@ cat simulation_t1.txt | grep '^{' > test_expected.txt $PROG --robot=json simulation_t1.txt \ MyWarmWater supercom587 12345678 "" \ MyColdWater supercom587 11111111 "" \ - MoreWater iperl 12345678 "1234567890ABCDEF1234567890ABCDEF" \ + MoreWater iperl 12345699 "" \ > test_output.txt if [ "$?" == "0" ] then @@ -32,7 +32,7 @@ then diff test_expected.txt test_responses.txt if [ "$?" == "0" ] then - echo OK + echo T1 OK fi else Failure. diff --git a/util.cc b/util.cc index e715ca8..e02966f 100644 --- a/util.cc +++ b/util.cc @@ -406,3 +406,35 @@ uint16_t crc16_EN13757(uchar *data, size_t len) return (~crc); } + +#define CRC16_INIT_VALUE 0xFFFF +#define CRC16_GOOD_VALUE 0x0F47 +#define CRC16_POLYNOM 0x8408 + +uint16_t crc16_CCITT(uchar *data, uint16_t length) +{ + uint16_t initVal = CRC16_INIT_VALUE; + uint16_t crc = initVal; + while(length--) + { + int bits = 8; + uchar byte = *data++; + while(bits--) + { + if((byte & 1) ^ (crc & 1)) + { + crc = (crc >> 1) ^ CRC16_POLYNOM; + } + else + crc >>= 1; + byte >>= 1; + } + } + return crc; +} + +bool crc16_CCITT_check(uchar *data, uint16_t length) +{ + uint16_t crc = ~crc16_CCITT(data, length); + return crc == CRC16_GOOD_VALUE; +} diff --git a/util.h b/util.h index 298801c..590716b 100644 --- a/util.h +++ b/util.h @@ -72,4 +72,8 @@ int parseTime(std::string time); uint16_t crc16_EN13757(uchar *data, size_t len); +// This crc is used by im871a for its serial communication. +uint16_t crc16_CCITT(uchar *data, uint16_t length); +bool crc16_CCITT_check(uchar *data, uint16_t length); + #endif diff --git a/wmbus.h b/wmbus.h index 1fd55e0..aadba6a 100644 --- a/wmbus.h +++ b/wmbus.h @@ -26,7 +26,7 @@ #define LIST_OF_LINK_MODES X(LinkModeC1)X(LinkModeT1)X(UNKNOWN_LINKMODE) -// In link mode T1, the meter transmits a telegram every few seconds. +// In link mode T1, the meter transmits a telegram every few seconds or minutes. // Suitable for drive-by/walk-by collection of meter values. // Link mode C1 is like T1 but uses less energy when transmitting due to diff --git a/wmbus_amb8465.cc b/wmbus_amb8465.cc index 36a0885..367fbfd 100644 --- a/wmbus_amb8465.cc +++ b/wmbus_amb8465.cc @@ -222,7 +222,10 @@ void WMBusAmber::waitForResponse() { } FrameStatus WMBusAmber::checkAMB8465Frame(vector &data, - size_t *frame_length, int *msgid_out, int *payload_len_out, int *payload_offset) + size_t *frame_length, + int *msgid_out, + int *payload_len_out, + int *payload_offset) { if (data.size() == 0) return PartialFrame; int payload_len = 0; @@ -387,9 +390,6 @@ bool detectAMB8465(string device, SerialCommunicationManager *manager) serial->close(); - string sent = bin2hex(msg); - string recv = bin2hex(data); - if (data.size() < 8 || data[0] != 0xff || data[1] != (0x80 | msg[1]) || diff --git a/wmbus_im871a.cc b/wmbus_im871a.cc index b3fc6f7..a4f40a5 100644 --- a/wmbus_im871a.cc +++ b/wmbus_im871a.cc @@ -251,19 +251,21 @@ void WMBusIM871A::setLinkMode(LinkMode lm) } pthread_mutex_lock(&command_lock_); - vector msg(8); + vector msg(10); msg[0] = IM871A_SERIAL_SOF; msg[1] = DEVMGMT_ID; sent_command_ = msg[2] = DEVMGMT_MSG_SET_CONFIG_REQ; - msg[3] = 3; // Len + msg[3] = 6; // Len msg[4] = 0; // Temporary - msg[5] = 2; // iff1 bits: Set Radio Mode only + msg[5] = 2; // iff1 bits: Set Radio Mode if (lm == LinkModeC1) { msg[6] = (int)im871a_C1a; } else { msg[6] = (int)im871a_T1; } - msg[7] = 0; // iff2 bits: Set nothing + msg[7] = 16+32; // iff2 bits: Set rssi+timestamp + msg[8] = 1; // Enable rssi + msg[9] = 1; // Enable timestamp verbose("(im871a) set link mode %02x\n", msg[6]); serial()->send(msg); @@ -293,6 +295,7 @@ FrameStatus WMBusIM871A::checkFrame(vector &data, { if (data.size() == 0) return PartialFrame; if (data[0] != 0xa5) return ErrorInFrame; + int ctrlbits = (data[1] & 0xf0) >> 4; if (ctrlbits & 1) return ErrorInFrame; // Bit 1 is reserved, we do not expect it.... bool has_timestamp = ((ctrlbits&2)==2); @@ -319,6 +322,35 @@ FrameStatus WMBusIM871A::checkFrame(vector &data, *frame_length = *payload_offset+payload_len+(has_timestamp?4:0)+(has_rssi?1:0)+(has_crc16?2:0); if (data.size() < *frame_length) return PartialFrame; + int i = *payload_offset + payload_len; + if (has_timestamp) { + uint32_t a = data[i]; + uint32_t b = data[i+1]; + uint32_t c = data[i+2]; + uint32_t d = data[i+3]; + + uint32_t ts = a+b*256+c*256*256+d*256*256*256; + debug("(im871a) timestamp %08x\n", ts); + i += 4; + } + if (has_rssi) { + uint32_t rssi = data[i]; + debug("(im871a) rssi %02x\n", rssi); + i++; + } + if (has_crc16) { + uint32_t a = data[i]; + uint32_t b = data[i+1]; + uint32_t crc16 = a+b*256; + i+=2; + uint16_t gotcrc = ~crc16_CCITT(&data[1], i-1-2); + bool crcok = crc16_CCITT_check(&data[1], i-1); + debug("(im871a) got crc16 %04x expected %04x\n", crc16, gotcrc); + if (!crcok) { + warning("(im871a) warning: got wrong crc %04x expected %04x\n", gotcrc, crc16); + } + } + return FullFrame; } @@ -348,14 +380,18 @@ void WMBusIM871A::processSerialData() if (status == FullFrame) { vector payload; - if (payload_len > 0) { + if (payload_len > 0) + { if (endpoint == RADIOLINK_ID && msgid == RADIOLINK_MSG_WMBUSMSG_IND) { uchar l = payload_len; payload.insert(payload.begin(), &l, &l+1); // Re-insert the len byte. } - payload.insert(payload.end(), read_buffer_.begin()+payload_offset, read_buffer_.begin()+payload_len); + // Insert the payload. + payload.insert(payload.end(), + read_buffer_.begin()+payload_offset, + read_buffer_.begin()+payload_offset+payload_len); } read_buffer_.erase(read_buffer_.begin(), read_buffer_.begin()+frame_length); diff --git a/wmbus_utils.cc b/wmbus_utils.cc index 0fbc6a8..94a89bb 100644 --- a/wmbus_utils.cc +++ b/wmbus_utils.cc @@ -57,10 +57,6 @@ void decryptMode1_AES_CTR(Telegram *t, vector &aeskey) vector dec(decrypt, decrypt+remaining); debugPayload("(Mode1) decrypted first block", dec); - if (content.size() > 22) { - warning("(Mode1) warning: decryption received too many bytes of content! " - "Got %zu bytes, expected at most 22.\n", content.size()); - } if (content.size() > 16) { // Yay! Lets decrypt a second block. Full frame content is 22 bytes. // So a second block should enough for everyone! @@ -146,8 +142,10 @@ bool loadFormatBytesFromSignature(uint16_t format_signature, vector *form { hex2bin("02FF2004134413", format_bytes); // The hash of this string should equal the format signature above. - uint16_t format_hash = crc16_EN13757(&(*format_bytes)[0], 7); - debug("(utils) format signature %4X format hash %4X\n", format_signature, format_hash); + uint16_t format_hash1 = crc16_EN13757(&(*format_bytes)[0], 7); + uint16_t format_hash2 = ~crc16_CCITT(&(*format_bytes)[0], 7); + debug("(utils) format signature %4X format hash a=%4X b=%4X c=%4X d=%4X\n", + format_signature, format_hash1, (uint16_t)(~format_hash1), format_hash2, (uint16_t)(~format_hash2)); return true; } // Unknown format signature.