Log telegrams now print the crc and 0x16 at the end of mbus telegrams.

pull/599/head
Fredrik Öhrström 2022-09-01 21:15:09 +02:00
rodzic eafa1d9fc1
commit b011127510
4 zmienionych plików z 67 dodań i 47 usunięć

Wyświetl plik

@ -36,7 +36,7 @@ namespace
{
addStringField(
"status",
"Meter error flags.",
"Meter status.",
PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT |
PrintProperty::STATUS | PrintProperty::JOIN_TPL_STATUS);

Wyświetl plik

@ -27,6 +27,7 @@ namespace
static bool ok = registerDriver([](DriverInfo&di)
{
di.setName("piigth");
di.setDefaultFields("name,id,status,temperature_c,relative_humidity_rh,timestamp");
di.setMeterType(MeterType::TempHygroMeter);
di.addLinkMode(LinkMode::MBUS);
di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr<Meter>(new Driver(mi, di)); });
@ -37,13 +38,11 @@ namespace
{
addOptionalCommonFields();
/*
addStringField(
"status",
"Meter status from tpl status field.",
PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT |
PrintProperty::STATUS | PrintProperty::JOIN_TPL_STATUS);
*/
addNumericFieldWithExtractor(
"temperature",
@ -120,9 +119,9 @@ namespace
// Test: Tempo piigth 10000284 NOKEY
// telegram=|68383868080072840200102941011B04000000_0265C0094265A509B20165000002FB1A900142FB1A6901B201FB1A00000C788402001002FD0F21000FC016|
// {"media":"room sensor","meter":"piigth","name":"Tempo","id":"10000284","fabrication_no":"10000284","software_version":"0021","temperature_c":24.96,"average_temperature_1h_c":24.69,"average_temperature_24h_c":null,"relative_humidity_rh":40,"relative_humidity_1h_rh":36.1,"relative_humidity_24h_rh":null,"timestamp":"1111-11-11T11:11:11Z"}
// |Tempo;10000284;24.960000;24.690000;nan;40.000000;36.100000;nan;1111-11-11 11:11.11
// {"media":"room sensor","meter":"piigth","name":"Tempo","id":"10000284","fabrication_no":"10000284","software_version":"0021","status":"OK","temperature_c":24.96,"average_temperature_1h_c":24.69,"average_temperature_24h_c":null,"relative_humidity_rh":40,"relative_humidity_1h_rh":36.1,"relative_humidity_24h_rh":null,"timestamp":"1111-11-11T11:11:11Z"}
// |Tempo;10000284;OK;24.96;40;1111-11-11 11:11.11
// telegram=|68383868080072840200102941011B06000000_02653F0A4265000A820165CA0902FB1A4F0142FB1A53018201FB1A5E010C788402001002FD0F21000F1916|
// {"media":"room sensor","meter":"piigth","name":"Tempo","id":"10000284","fabrication_no":"10000284","software_version":"0021","temperature_c":26.23,"average_temperature_1h_c":25.6,"average_temperature_24h_c":25.06,"relative_humidity_rh":33.5,"relative_humidity_1h_rh":33.9,"relative_humidity_24h_rh":35,"timestamp":"1111-11-11T11:11:11Z"}
// |Tempo;10000284;26.230000;25.600000;25.060000;33.500000;33.900000;35.000000;1111-11-11 11:11.11
// {"media":"room sensor","meter":"piigth","name":"Tempo","id":"10000284","fabrication_no":"10000284","software_version":"0021","status":"OK","temperature_c":26.23,"average_temperature_1h_c":25.6,"average_temperature_24h_c":25.06,"relative_humidity_rh":33.5,"relative_humidity_1h_rh":33.9,"relative_humidity_24h_rh":35,"timestamp":"1111-11-11T11:11:11Z"}
// |Tempo;10000284;OK;26.23;33.5;1111-11-11 11:11.11

Wyświetl plik

@ -640,11 +640,7 @@ string mediaTypeJSON(int a_field_device_type, int m_field)
X(0x8E, ELL_III, "ELL: III", 10, CI_TYPE::ELL, "CC, ACC, M2, A2") \
X(0x8F, ELL_IV, "ELL: IV", 16, CI_TYPE::ELL, "CC, ACC, M2, A2, SN, Payload CRC") \
X(0x86, ELL_V, "ELL: V", -1, CI_TYPE::ELL, "Variable length") \
X(0x90, AFL, "AFL", 10, CI_TYPE::AFL, "") \
X(0xA0, MFCT_SPECIFIC_A0, "MFCT SPECIFIC", 0, CI_TYPE::TPL, "") \
X(0xA1, MFCT_SPECIFIC_A1, "MFCT SPECIFIC", 0, CI_TYPE::TPL, "") \
X(0xA2, MFCT_SPECIFIC_A2, "MFCT SPECIFIC", 0, CI_TYPE::TPL, "") \
X(0xA3, MFCT_SPECIFIC_A3, "MFCT SPECIFIC", 0, CI_TYPE::TPL, "")
X(0x90, AFL, "AFL", 10, CI_TYPE::AFL, "")
enum CI_Field_Values {
#define X(val,name,cname,len,citype,explain) name = val,
@ -668,6 +664,11 @@ LIST_OF_CI_FIELDS
return -2;
}
bool isCiFieldManufacturerSpecific(int ci_field)
{
return ci_field >= 0xA0 && ci_field <= 0xB7;
}
string ciType(int ci_field)
{
if (ci_field >= 0xA0 && ci_field <= 0xB7) {
@ -795,6 +796,20 @@ void Telegram::addExplanationAndIncrementPos(vector<uchar>::iterator &pos, int l
pos += len;
}
void Telegram::setExplanation(vector<uchar>::iterator &pos, int len, KindOfData k, Understanding u, const char* fmt, ...)
{
char buf[1024];
buf[1023] = 0;
va_list args;
va_start(args, fmt);
vsnprintf(buf, 1023, fmt, args);
va_end(args);
Explanation e(distance(frame.begin(),pos), len, buf, k, u);
explanations.push_back(e);
}
void Telegram::addMoreExplanation(int pos, string json)
{
addMoreExplanation(pos, " (%s)", json.c_str());
@ -879,6 +894,19 @@ bool Telegram::parseMBusDLLandTPL(vector<uchar>::iterator &pos)
if (remaining < dll_len) return expectedMore(__LINE__);
// Last byte should be 0x16
auto end = frame.end();
end--;
if (*end != 0x16) return false;
setExplanation(end, 1, KindOfData::PROTOCOL, Understanding::FULL, "16 end");
// Second last byte should be crc. Should have been checked before! No need to check again here?
end--;
setExplanation(end, 1, KindOfData::PROTOCOL, Understanding::FULL, "%02X crc", *end);
// Mark crc and end as suffix, ie should not be parsed by dvparser.
suffix_size = 2;
dll_c = *pos;
addExplanationAndIncrementPos(pos, 1, KindOfData::PROTOCOL, Understanding::FULL, "%02x dll-c (%s)", dll_c, mbusCField(dll_c));
@ -1753,8 +1781,7 @@ bool Telegram::parse_TPL_72(vector<uchar>::iterator &pos)
bool decrypt_ok = potentiallyDecrypt(pos);
header_size = distance(frame.begin(), pos);
int remaining = distance(pos, frame.end());
suffix_size = 0;
int remaining = distance(pos, frame.end())-suffix_size;
if (decrypt_ok)
{
@ -1771,8 +1798,7 @@ bool Telegram::parse_TPL_72(vector<uchar>::iterator &pos)
bool Telegram::parse_TPL_78(vector<uchar>::iterator &pos)
{
header_size = distance(frame.begin(), pos);
int remaining = distance(pos, frame.end());
suffix_size = 0;
int remaining = distance(pos, frame.end())-suffix_size;
parseDV(this, frame, pos, remaining, &dv_entries);
return true;
@ -1821,8 +1847,7 @@ bool Telegram::parse_TPL_79(vector<uchar>::iterator &pos)
"%02x%02x data crc", ecrc2, ecrc3);
header_size = distance(frame.begin(), pos);
int remaining = distance(pos, frame.end());
suffix_size = 0;
int remaining = distance(pos, frame.end())-suffix_size;
parseDV(this, frame, pos, remaining, &dv_entries, &format, format_bytes.size());
@ -1837,8 +1862,7 @@ bool Telegram::parse_TPL_7A(vector<uchar>::iterator &pos)
bool decrypt_ok = potentiallyDecrypt(pos);
header_size = distance(frame.begin(), pos);
int remaining = distance(pos, frame.end());
suffix_size = 0;
int remaining = distance(pos, frame.end())-suffix_size;
if (decrypt_ok)
{
@ -1859,7 +1883,9 @@ bool Telegram::parseTPL(vector<uchar>::iterator &pos)
debug("(wmbus) parseTPL @%d %d\n", distance(frame.begin(), pos), remaining);
CHECK(1);
int ci_field = *pos;
if (!isCiFieldOfType(ci_field, CI_TYPE::TPL))
int mfct_specific = isCiFieldManufacturerSpecific(ci_field);
if (!isCiFieldOfType(ci_field, CI_TYPE::TPL) && !mfct_specific)
{
if (parser_warns_)
{
@ -1875,7 +1901,7 @@ bool Telegram::parseTPL(vector<uchar>::iterator &pos)
tpl_ci, ciType(tpl_ci).c_str());
int len = ciFieldLength(tpl_ci);
if (remaining < len+1) return expectedMore(__LINE__);
if (remaining < len+1 && ! mfct_specific) return expectedMore(__LINE__);
switch (tpl_ci)
{
@ -1883,24 +1909,11 @@ bool Telegram::parseTPL(vector<uchar>::iterator &pos)
case CI_Field_Values::TPL_78: return parse_TPL_78(pos);
case CI_Field_Values::TPL_79: return parse_TPL_79(pos);
case CI_Field_Values::TPL_7A: return parse_TPL_7A(pos);
case CI_Field_Values::MFCT_SPECIFIC_A1:
case CI_Field_Values::MFCT_SPECIFIC_A0:
case CI_Field_Values::MFCT_SPECIFIC_A2:
default:
{
// A0 to B7 are manufacturer specific.
header_size = distance(frame.begin(), pos);
suffix_size = 0;
int num_mfct_bytes = frame.end()-pos;
string info = bin2hex(pos, frame.end(), num_mfct_bytes);
info += " mfct specific";
addExplanationAndIncrementPos(pos, num_mfct_bytes, KindOfData::CONTENT, Understanding::NONE, info.c_str());
return true; // Manufacturer specific telegram payload. Oh well....
}
case CI_Field_Values::MFCT_SPECIFIC_A3: // Another stoopid non-conformat wmbus Diehl/Sappel/Izar water meter addon.
{
header_size = distance(frame.begin(), pos);
suffix_size = 0;
int num_mfct_bytes = frame.end()-pos;
int num_mfct_bytes = frame.end()-pos-suffix_size;
string info = bin2hex(pos, frame.end(), num_mfct_bytes);
info += " mfct specific";
addExplanationAndIncrementPos(pos, num_mfct_bytes, KindOfData::CONTENT, Understanding::NONE, info.c_str());
@ -1910,7 +1923,6 @@ bool Telegram::parseTPL(vector<uchar>::iterator &pos)
}
header_size = distance(frame.begin(), pos);
suffix_size = 0;
if (parser_warns_)
{
warning("(wmbus) Not implemented tpl-ci %02x\n", tpl_ci);
@ -1964,6 +1976,7 @@ bool Telegram::parseWMBUSHeader(vector<uchar> &input_frame)
parser_warns_ = false;
decryption_failed = false;
explanations.clear();
suffix_size = 0;
frame = input_frame;
vector<uchar>::iterator pos = frame.begin();
// Parsed accumulates parsed bytes.
@ -1999,6 +2012,7 @@ bool Telegram::parseWMBUS(vector<uchar> &input_frame, MeterKeys *mk, bool warn)
parser_warns_ = warn;
decryption_failed = false;
explanations.clear();
suffix_size = 0;
meter_keys = mk;
assert(meter_keys != NULL);
bool ok;
@ -2079,6 +2093,7 @@ bool Telegram::parseMBUSHeader(vector<uchar> &input_frame)
parser_warns_ = false;
decryption_failed = false;
explanations.clear();
suffix_size = 0;
frame = input_frame;
vector<uchar>::iterator pos = frame.begin();
// Parsed accumulates parsed bytes.
@ -2097,6 +2112,7 @@ bool Telegram::parseMBUS(vector<uchar> &input_frame, MeterKeys *mk, bool warn)
parser_warns_ = warn;
decryption_failed = false;
explanations.clear();
suffix_size = 0;
meter_keys = mk;
assert(meter_keys != NULL);
bool ok;
@ -2232,6 +2248,9 @@ string Telegram::analyzeParse(OutputFormat format, int *content_length, int *und
int u = 0;
int l = 0;
sort(explanations.begin(), explanations.end(),
[](const Explanation & a, const Explanation & b) -> bool { return a.pos < b.pos; });
// Calculate how much is understood.
for (auto& e : explanations)
{
@ -4099,12 +4118,6 @@ bool BusDeviceCommonImplementation::handleTelegram(AboutTelegram &about, vector<
bool handled = false;
last_received_ = time(NULL);
if (ignore_duplicate_telegrams_ && about.type == FrameType::WMBUS && seen_this_telegram_before(frame))
{
verbose("(wmbus) skipping already handled telegram leng=%zu.\n", frame.size());
return true;
}
if (about.type == FrameType::MBUS && frame.size() == 1)
{
if (frame[0] == 0xe5)
@ -4116,6 +4129,12 @@ bool BusDeviceCommonImplementation::handleTelegram(AboutTelegram &about, vector<
return false;
}
if (ignore_duplicate_telegrams_ && about.type == FrameType::WMBUS && seen_this_telegram_before(frame))
{
verbose("(wmbus) skipping already handled telegram leng=%zu.\n", frame.size());
return true;
}
for (auto f : telegram_listeners_)
{
if (f)
@ -4927,8 +4946,8 @@ FrameStatus checkMBusFrame(vector<uchar> &data,
return ErrorInFrame;
}
*payload_len_out = *frame_length - 2; // Drop checksum byte and stop byte.
*payload_offset = 0; // Drop 0x68 len len 0x68.
*payload_len_out = *frame_length;
*payload_offset = 0;
if (!only_test)
{
debug("(mbus) received full frame.\n");

Wyświetl plik

@ -536,6 +536,7 @@ public:
// below the raw data bytes to explain the telegram content.
vector<Explanation> explanations;
void addExplanationAndIncrementPos(vector<uchar>::iterator &pos, int len, KindOfData k, Understanding u, const char* fmt, ...);
void setExplanation(vector<uchar>::iterator &pos, int len, KindOfData k, Understanding u, const char* fmt, ...);
void addMoreExplanation(int pos, const char* fmt, ...);
void addMoreExplanation(int pos, string json);
@ -738,6 +739,7 @@ string mediaType(int a_field_device_type, int m_field);
string mediaTypeJSON(int a_field_device_type, int m_field);
bool isCiFieldOfType(int ci_field, CI_TYPE type);
int ciFieldLength(int ci_field);
bool isCiFieldManufacturerSpecific(int ci_field);
string ciType(int ci_field);
string cType(int c_field);
bool isValidWMBusCField(int c_field);