diff --git a/CHANGES b/CHANGES index ba1dc58..97927a1 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,15 @@ + +New improved address specification. E.g. use 12345678.M=KAM.V=1b.T=16 +to listen to exactly the telegrams with id 12345678 manufacturer KAM, +version 0x1b and type 0x16. You if you do not specify any M,V or T, they +become wildcards which will be the old default behaviour. + +If you receive multiple telegram versions from the same id, and you want to +filter out some versions, do: 12345678,!12345678.V=77 + +You can now specify p0 to p250, to read from an mbus using the primary address. +E.g. wmbusmeters --pollinterval=5s /dev/ttyUSB1:mbus:2400 TEMP piigth:mbus p0 NOKEY + Version 1.16.1 2024-02-22 Fix docker file generation. diff --git a/README.md b/README.md index 6fec072..3a58fd6 100644 --- a/README.md +++ b/README.md @@ -130,9 +130,11 @@ bus the mbus poll request should be sent to. wmbusmeters --pollinterval=60s MAIN=/dev/ttyUSB0:mbus:2400 MyTempMeter piigth:MAIN:mbus 12001932 NOKEY ``` -If you want to poll an mbus meter using the primary address, just use -a number between 0 and 250 instead of the full 8 digit secondary -address. +If you want to poll an mbus meter using the primary address, use p0 to p250 (deciman numbers) +instead of the full 8 digit secondary address. +``` +wmbusmeters --pollinterval=60s MAIN=/dev/ttyUSB0:mbus:2400 MyTempMeter piigth:MAIN:mbus p0 NOKEY +``` # Example wmbusmeter.conf file @@ -217,9 +219,13 @@ The latest reading of the meter can also be found here: `/var/lib/wmbusmeters/me You can use several ids using `id=1111111,2222222,3333333` or you can listen to all meters of a certain type `id=*` or you can suffix with star `id=8765*` to match all meters with a given prefix. If you supply at least one positive match rule, then you -can add negative match rules as well. For example `id=*,!2222*` +can add filter out rules as well. For example `id=*,!2222*` which will match all meter ids, except those that begin with 2222. +You can also specify the exact manufacturer, version and type: `id=11111111.M=KAM.V=1b.T=16` +or a subset: `id=11111111.T=16` or all telegrams from 22222222 except those with version 77: +`id=22222222,!22222222.V=77` + When matching all meters from the command line you can use `ANYID` instead of `*` to avoid shell quotes. # Add static and calculated fields to the output diff --git a/src/address.cc b/src/address.cc index 40de4ec..e6384c0 100644 --- a/src/address.cc +++ b/src/address.cc @@ -22,6 +22,8 @@ using namespace std; +vector splitSequenceOfAddressExpressionsAtCommas(const string& mes); + bool isValidMatchExpression(const string& s, bool *has_wildcard) { string me = s; @@ -37,9 +39,12 @@ bool isValidMatchExpression(const string& s, bool *has_wildcard) // A match expression cannot be empty. if (me.length() == 0) return false; - // An me can be negated with an exclamation mark first. + // An me can be filtered out with an exclamation mark first. if (me.front() == '!') me.erase(0, 1); + // More than one negation is not allowed. + if (me.front() == '!') return false; + // A match expression cannot be only a negation mark. if (me.length() == 0) return false; @@ -76,29 +81,51 @@ bool isValidMatchExpression(const string& s, bool *has_wildcard) return count <= 7; } -bool isValidMatchExpressions(const string& mes) +vector splitSequenceOfAddressExpressionsAtCommas(const string& mes) { - vector v = splitMatchExpressions(mes); + vector r; + bool eof, err; + vector v (mes.begin(), mes.end()); + auto i = v.begin(); + + for (;;) { + auto id = eatTo(v, i, ',', 16, &eof, &err); + if (err) break; + trimWhitespace(&id); + if (id == "ANYID") id = "*"; + r.push_back(id); + if (eof) break; + } + return r; +} + +bool isValidSequenceOfAddressExpressions(const string& mes) +{ + vector v = splitSequenceOfAddressExpressionsAtCommas(mes); for (string me : v) { - if (!isValidMatchExpression(me, NULL)) return false; + AddressExpression ae; + if (!ae.parse(me)) return false; } return true; } -bool isValidId(const string& id) +vector splitAddressExpressions(const string &aes) { + vector v = splitSequenceOfAddressExpressionsAtCommas(aes); - for (size_t i=0; i r; + + for (string me : v) { - if (id[i] >= '0' && id[i] <= '9') continue; - // Some non-compliant meters have hex in their id. - if (id[i] >= 'a' && id[i] <= 'f') continue; - if (id[i] >= 'A' && id[i] <= 'F') continue; - return false; + AddressExpression ae; + if (ae.parse(me)) + { + r.push_back(ae); + } } - return true; + return r; } bool doesIdMatchExpression(const string& s, string match) @@ -153,12 +180,12 @@ bool hasWildCard(const string& mes) return mes.find('*') != string::npos; } -bool doesIdsMatchExpressions(vector &ids, vector& mes, bool *used_wildcard) +bool doesIdsMatchExpressionss(vector &ids, vector& mes, bool *used_wildcard) { bool match = false; for (string &id : ids) { - if (doesIdMatchExpressions(id, mes, used_wildcard)) + if (doesIdMatchExpressionss(id, mes, used_wildcard)) { match = true; } @@ -168,7 +195,7 @@ bool doesIdsMatchExpressions(vector &ids, vector& mes, bool *use return match; } -bool doesIdMatchExpressions(const string& id, vector& mes, bool *used_wildcard) +bool doesIdMatchExpressionss(const string& id, vector& mes, bool *used_wildcard) { bool found_match = false; bool found_negative_match = false; @@ -315,6 +342,18 @@ string toIdsCommaSeparated(vector &ids) return cs; } +string toIdsCommaSeparated(vector &ids) +{ + string cs; + for (AddressExpression& ae: ids) + { + cs += ae.str(); + cs += ","; + } + if (cs.length() > 0) cs.pop_back(); + return cs; +} + bool AddressExpression::match(const std::string &i, uint16_t m, uchar v, uchar t) { if (!(mfct == 0xffff || mfct == m)) return false; @@ -351,8 +390,9 @@ bool AddressExpression::parse(const string &in) { filter_out = true; s = s.substr(1); + // Double ! not allowed. + if (s.size() > 1 && s[0] == '!') return false; } - vector parts = splitString(s, '.'); assert(parts.size() > 0); @@ -425,3 +465,176 @@ bool flagToManufacturer(const char *s, uint16_t *out_mfct) *out_mfct = MANFCODE(s[0],s[1],s[2]); return true; } + +string AddressExpression::str() +{ + string s; + + if (filter_out) s = "!"; + + s.append(id); + if (mfct != 0xffff) + { + s += ".M="+manufacturerFlag(mfct); + } + if (version != 0xff) + { + s += ".V="+tostrprintf("%02x", version); + } + if (type != 0xff) + { + s += ".T="+tostrprintf("%02x", type); + } + + return s; +} + +string Address::str() +{ + string s; + + s.append(id); + if (mfct != 0xffff) + { + s += ".M="+manufacturerFlag(mfct); + } + if (version != 0xff) + { + s += ".V="+tostrprintf("%02x", version); + } + if (type != 0xff) + { + s += ".T="+tostrprintf("%02x", type); + } + + return s; +} + +string Address::concat(std::vector
&addresses) +{ + string s; + for (Address& a: addresses) + { + if (s.size() > 0) s.append(","); + s.append(a.str()); + } + return s; +} + +string AddressExpression::concat(std::vector &address_expressions) +{ + string s; + for (AddressExpression& a: address_expressions) + { + if (s.size() > 0) s.append(","); + s.append(a.str()); + } + return s; +} + +string manufacturerFlag(int m_field) { + char a = (m_field/1024)%32+64; + char b = (m_field/32)%32+64; + char c = (m_field)%32+64; + + string flag; + flag += a; + flag += b; + flag += c; + return flag; +} + +void Address::decodeMfctFirst(const vector::iterator &pos) +{ + mfct = *(pos+1) << 8 | *(pos+0); + id = tostrprintf("%02x%02x%02x%02x", *(pos+5), *(pos+4), *(pos+3), *(pos+2)); + version = *(pos+6); + type = *(pos+7); +} + +void Address::decodeIdFirst(const vector::iterator &pos) +{ + id = tostrprintf("%02x%02x%02x%02x", *(pos+3), *(pos+2), *(pos+1), *(pos+0)); + mfct = *(pos+5) << 8 | *(pos+4); + version = *(pos+6); + type = *(pos+7); +} + +bool doesTelegramMatchExpressions(std::vector
&addresses, + std::vector& address_expressions, + bool *used_wildcard) +{ + bool match = false; + for (Address &a : addresses) + { + if (doesAddressMatchExpressions(a, address_expressions, used_wildcard)) + { + match = true; + } + // Go through all ids even though there is an early match. + // This way we can see if theres an exact match later. + } + return match; +} + +bool doesAddressMatchExpressions(Address &address, + vector& address_expressions, + bool *used_wildcard) +{ + bool found_match = false; + bool found_negative_match = false; + bool exact_match = false; + + // Goes through all possible match expressions. + // If no expression matches, neither positive nor negative, + // then the result is false. (ie no match) + + // If more than one positive match is found, and no negative, + // then the result is true. + + // If more than one negative match is found, irrespective + // if there is any positive matches or not, then the result is false. + + // If a positive match is found, using a wildcard not any exact match, + // then *used_wildcard is set to true. + for (AddressExpression &ae : address_expressions) + { + bool has_wildcard = ae.has_wildcard; + bool is_negative_rule = ae.filter_out; + + bool m = doesIdMatchExpression(address.id, ae.id); + + if (is_negative_rule) + { + if (m) found_negative_match = true; + } + else + { + if (m) + { + found_match = true; + if (!has_wildcard) + { + exact_match = true; + } + } + } + } + if (found_negative_match) + { + return false; + } + if (found_match) + { + if (exact_match) + { + *used_wildcard = false; + } + else + { + *used_wildcard = true; + } + return true; + } + return false; +} diff --git a/src/address.h b/src/address.h index 318256a..6aed8f7 100644 --- a/src/address.h +++ b/src/address.h @@ -21,6 +21,20 @@ #include "util.h" #include +struct Address +{ + std::string id; // p1 or 12345678 or non-compliant hex: 1234abcd + uint16_t mfct {}; + uchar type {}; + uchar version {}; + + void decodeMfctFirst(const std::vector::iterator &pos); + void decodeIdFirst(const std::vector::iterator &pos); + + std::string str(); + static std::string concat(std::vector
&addresses); +}; + struct AddressExpression { // An address expression is used to select which telegrams to decode for a driver. @@ -35,37 +49,61 @@ struct AddressExpression // Or every telegram which is does not start with 12 and is not from ABB: // !12*.M!=ABB - std::string id; // 1 or 12345678 or non-compliant hex: 1234abcd + std::string id; // p1 or 12345678 or non-compliant hex: 1234abcd bool has_wildcard {}; // The id contains a * bool mbus_primary {}; // Signals that the id is 0-250 uint16_t mfct {}; // If 0xffff then any mfct matches this address. - uchar type {}; // If 0xff then any type matches this address. uchar version {}; // If 0xff then any version matches this address. + uchar type {}; // If 0xff then any type matches this address. bool filter_out {}; // Telegrams matching this rule should be filtered out! + AddressExpression() {} + AddressExpression(Address &a) : id(a.id), mfct(a.mfct), version(a.version), type(a.type) { } bool parse(const std::string &s); bool match(const std::string &id, uint16_t mfct, uchar version, uchar type); + std::string str(); + static std::string concat(std::vector &address_expressions); }; +/** + isValidSequenceOfAddressExpressions: + + Valid sequenes look like this: + 12345678 + 12345678,22334455,34* + 12*.T=16,!*.M=XYZ + !*.V=33 +*/ +bool isValidSequenceOfAddressExpressions(const std::string& s); + bool isValidMatchExpression(const std::string& s, bool *has_wildcard); -bool isValidMatchExpressions(const std::string& s); + bool doesIdMatchExpression(const std::string& id, std::string match_rule); -bool doesIdMatchExpressions(const std::string& id, +bool doesIdMatchExpressionss(const std::string& id, std::vector& match_rules, bool *used_wildcard); -bool doesIdsMatchExpressions(std::vector &ids, +bool doesIdsMatchExpressionss(std::vector &ids, std::vector& match_rules, bool *used_wildcard); std::string toIdsCommaSeparated(std::vector &ids); +std::string toIdsCommaSeparated(std::vector &ids); -bool isValidId(const std::string& id); - -std::vector splitMatchExpressions(const std::string& mes); +std::vector splitAddressExpressions(const std::string &aes); bool flagToManufacturer(const char *s, uint16_t *out_mfct); +std::string manufacturerFlag(int m_field); + +bool doesTelegramMatchExpressions(std::vector
&addresses, + std::vector& address_expressions, + bool *used_wildcard); + +bool doesAddressMatchExpressions(Address &address, + std::vector& address_expressions, + bool *used_wildcard); + #endif diff --git a/src/cmdline.cc b/src/cmdline.cc index b27ec52..7589a15 100644 --- a/src/cmdline.cc +++ b/src/cmdline.cc @@ -740,38 +740,7 @@ static shared_ptr parseNormalCommandLine(Configuration *c, int ar error("Not a valid meter driver \"%s\"\n", driver.c_str()); } - //LinkModeSet default_modes = toMeterLinkModeSet(mi.driver); - - /* - if (default_modes.has(LinkMode::MBUS)) - { - // MBus primary address 0-250 - // secondary hex address iiiiiiiimmmmvvmm - } - else - { - // WMBus ids are 8 hex digits iiiiiiii - if (!isValidMatchExpressions(id, true)) error("Not a valid id nor a valid meter match expression \"%s\"\n", id.c_str()); - } - if (!isValidKey(key, mi)) error("Not a valid meter key \"%s\"\n", key.c_str()); - */ - c->meters.push_back(mi); - - // Check if the devices can listen to the meter link mode(s). - /* - Ignore this check for now until all meters have been refactored. - if (!default_modes.hasAll(mi.link_modes)) - { - string want = mi.link_modes.hr(); - string has = default_modes.hr(); - error("(cmdline) cannot set link modes to: %s because meter %s only transmits on: %s\n", - want.c_str(), mi.driverName().str().c_str(), has.c_str()); - } - string modeshr = mi.link_modes.hr(); - debug("(cmdline) setting link modes to %s for meter %s\n", - mi.link_modes.hr().c_str(), name.c_str()); - */ } return shared_ptr(c); diff --git a/src/config.cc b/src/config.cc index e63c48d..d780519 100644 --- a/src/config.cc +++ b/src/config.cc @@ -179,34 +179,20 @@ void parseMeterConfig(Configuration *c, vector &buf, string file) mi.parse(name, driver, id, key); // sets driver, extras, name, bus, bps, link_modes, ids, name, key mi.poll_interval = poll_interval; - /* - Ignore link mode checking until all drivers have been refactored. - LinkModeSet default_modes = toMeterLinkModeSet(mi.driver); - if (!default_modes.hasAll(mi.link_modes)) - { - string want = mi.link_modes.hr(); - string has = default_modes.hr(); - error("(cmdline) cannot set link modes to: %s because meter %s only transmits on: %s\n", - want.c_str(), mi.driverName().str().c_str(), has.c_str()); - } - string modeshr = mi.link_modes.hr(); - debug("(cmdline) setting link modes to %s for meter %s\n", - mi.link_modes.hr().c_str(), name.c_str()); - */ - if (!isValidMatchExpressions(id)) { - warning("Not a valid meter id nor a valid meter match expression \"%s\"\n", id.c_str()); + if (!isValidSequenceOfAddressExpressions(id)) { + warning("Not a valid meter id nor a valid sequence of match expression \"%s\"\n", id.c_str()); use = false; } if (!isValidKey(key, mi)) { warning("Not a valid meter key \"%s\"\n", key.c_str()); use = false; } - if (use) { + if (use) + { mi.extra_constant_fields = extra_constant_fields; mi.extra_calculated_fields = extra_calculated_fields; mi.shells = telegram_shells; mi.meter_shells = meter_shells; - mi.idsc = toIdsCommaSeparated(mi.ids); mi.selected_fields = selected_fields; c->meters.push_back(mi); } diff --git a/src/driver_dynamic.cc b/src/driver_dynamic.cc index 1f5539f..6061511 100644 --- a/src/driver_dynamic.cc +++ b/src/driver_dynamic.cc @@ -105,6 +105,7 @@ bool DriverDynamic::load(DriverInfo *di, const string &file_name, const char *co catch (...) { xmqFreeDoc(doc); + di->setDynamic(file, NULL); return false; } } @@ -150,7 +151,7 @@ XMQProceed DriverDynamic::add_detect(XMQDoc *doc, XMQNode *detect, DriverInfo *d mvt.c_str(), line, line); - throw 1; + return XMQ_CONTINUE; } string mfct = fields[0]; @@ -175,7 +176,7 @@ XMQProceed DriverDynamic::add_detect(XMQDoc *doc, XMQNode *detect, DriverInfo *d mfct.c_str(), line, line); - throw 1; + return XMQ_CONTINUE; } mfct_code = toMfctCode(a, b, c); } @@ -193,7 +194,7 @@ XMQProceed DriverDynamic::add_detect(XMQDoc *doc, XMQNode *detect, DriverInfo *d mfct.c_str(), line, line); - throw 1; + return XMQ_CONTINUE; } } @@ -207,7 +208,7 @@ XMQProceed DriverDynamic::add_detect(XMQDoc *doc, XMQNode *detect, DriverInfo *d version, line, line); - throw 1; + return XMQ_CONTINUE; } if (type > 255 || type < 0) @@ -220,7 +221,7 @@ XMQProceed DriverDynamic::add_detect(XMQDoc *doc, XMQNode *detect, DriverInfo *d type, line, line); - throw 1; + return XMQ_CONTINUE; } string mfct_flag = manufacturerFlag(mfct_code); diff --git a/src/driver_qheat.cc b/src/driver_qheat.cc index d9bae6e..aac01e4 100644 --- a/src/driver_qheat.cc +++ b/src/driver_qheat.cc @@ -160,8 +160,11 @@ namespace vector v; auto entry = it->second.second; hex2bin(entry.value.substr(0, 8), &v); - t->addId(v.begin()); - std::string info = "*** " + entry.value.substr(0, 8) + " tpl-id (" + t->ids.back() + ")"; + // FIXME PROBLEM + Address a; + a.id = tostrprintf("%02x%02x%02x%02x", v[3], v[2], v[1], v[0]); + t->addresses.push_back(a); + std::string info = "*** " + entry.value.substr(0, 8) + " tpl-id (" + t->addresses.back().id + ")"; t->addSpecialExplanation(entry.offset, 4, KindOfData::CONTENT, Understanding::FULL, info.c_str()); v.clear(); diff --git a/src/main.cc b/src/main.cc index 1f30e3c..ebd95ef 100644 --- a/src/main.cc +++ b/src/main.cc @@ -581,12 +581,12 @@ bool start(Configuration *config) vector envs; string id = ""; - if (meter->ids().size() > 0) + if (meter->addressExpressions().size() > 0) { - id = meter->idsc().c_str(); + id = meter->addressExpressions().back().id; } - meter->createMeterEnv(&id, &envs, &config->extra_constant_fields); + meter->createMeterEnv(id, &envs, &config->extra_constant_fields); for (auto &s : *shells) { vector args; diff --git a/src/metermanager.cc b/src/metermanager.cc index 6dd782d..c5d1579 100644 --- a/src/metermanager.cc +++ b/src/metermanager.cc @@ -144,11 +144,12 @@ public: bool handled = false; bool exact_id_match = false; + string verbose_info; - string ids; + vector
addresses; for (auto &m : meters_) { - bool h = m->handleTelegram(about, input_frame, simulated, &ids, &exact_id_match); + bool h = m->handleTelegram(about, input_frame, simulated, &addresses, &exact_id_match); if (h) handled = true; } @@ -156,7 +157,12 @@ public: // then lets check if there is a template that can create a meter for it. if (!handled && !exact_id_match) { - debug("(meter) no meter handled %s checking %d templates.\n", ids.c_str(), meter_templates_.size()); + if (isDebugEnabled()) + { + string idsc = Address::concat(addresses); + debug("(meter) no meter handled %s checking %d templates.\n", + idsc.c_str(), meter_templates_.size()); + } // Not handled, maybe we have a template to create a new meter instance for this telegram? Telegram t; t.about = about; @@ -165,7 +171,6 @@ public: if (ok) { - ids = t.idsc; for (auto &mi : meter_templates_) { if (MeterCommonImplementation::isTelegramForMeter(&t, NULL, &mi)) @@ -178,10 +183,9 @@ public: // This will pick the tpl_id. // Or a telegram can have a single dll_id, // then the dll_id will be picked. - vector tmp_ids; - tmp_ids.push_back(t.ids.back()); - meter_info.ids = tmp_ids; - meter_info.idsc = t.ids.back(); + vector aes; + aes.push_back(AddressExpression(t.addresses.back())); + meter_info.address_expressions = aes; if (meter_info.driverName().str() == "auto") { @@ -203,47 +207,55 @@ public: // Now build a meter object with for this exact id. auto meter = createMeter(&meter_info); addMeter(meter); - string idsc = toIdsCommaSeparated(t.ids); - verbose("(meter) used meter template %s %s %s to match %s\n", - mi.name.c_str(), - mi.idsc.c_str(), - mi.driverName().str().c_str(), - idsc.c_str()); + if (isVerboseEnabled()) + { + string idsc = Address::concat(t.addresses); + string mi_idsc = AddressExpression::concat(mi.address_expressions); + verbose("(meter) used meter template %s %s %s to match %s\n", + mi.name.c_str(), + mi_idsc.c_str(), + mi.driverName().str().c_str(), + idsc.c_str()); + } if (is_daemon_) { + string mi_idsc = AddressExpression::concat(mi.address_expressions); notice("(wmbusmeters) started meter %d (%s %s %s)\n", meter->index(), mi.name.c_str(), - meter_info.idsc.c_str(), + mi_idsc.c_str(), mi.driverName().str().c_str()); } else { + string mi_idsc = AddressExpression::concat(mi.address_expressions); verbose("(meter) started meter %d (%s %s %s)\n", meter->index(), mi.name.c_str(), - meter_info.idsc.c_str(), + mi_idsc.c_str(), mi.driverName().str().c_str()); } bool match = false; - bool h = meter->handleTelegram(about, input_frame, simulated, &ids, &match); + bool h = meter->handleTelegram(about, input_frame, simulated, &addresses, &match); if (!match) { + string aesc = AddressExpression::concat(meter->addressExpressions()); // Oups, we added a new meter object tailored for this telegram // but it still did not match! This is probably an error in wmbusmeters! warning("(meter) newly created meter (%s %s %s) did not match telegram! ", "Please open an issue at https://github.com/wmbusmeters/wmbusmeters/\n", - meter->name().c_str(), meter->idsc().c_str(), meter->driverName().str().c_str()); + meter->name().c_str(), aesc.c_str(), meter->driverName().str().c_str()); } else if (!h) { + string aesc = AddressExpression::concat(meter->addressExpressions()); // Oups, we added a new meter object tailored for this telegram // but it still did not handle it! This can happen if the wrong // decryption key was used. warning("(meter) newly created meter (%s %s %s) did not handle telegram!\n", - meter->name().c_str(), meter->idsc().c_str(), meter->driverName().str().c_str()); + meter->name().c_str(), aesc.c_str(), meter->driverName().str().c_str()); } else { @@ -259,7 +271,7 @@ public: } if (isVerboseEnabled() && !handled) { - verbose("(wmbus) telegram from %s ignored by all configured meters!\n", ids.c_str()); + verbose("(wmbus) telegram from %s ignored by all configured meters!\n", "TODO"); } return handled; } @@ -344,8 +356,8 @@ public: auto meter = createMeter(&mi); bool match = false; - string id; - bool h = meter->handleTelegram(about, input_frame, simulated, &id, &match, &t); + vector
addresses; + bool h = meter->handleTelegram(about, input_frame, simulated, &addresses, &match, &t); if (!match) { @@ -353,11 +365,12 @@ public: } else if (!h) { + string aesc = AddressExpression::concat(meter->addressExpressions()); // Oups, we added a new meter object tailored for this telegram // but it still did not handle it! This can happen if the wrong // decryption key was used. But it is ok if analyzing.... debug("Newly created meter (%s %s %s) did not handle telegram!\n", - meter->name().c_str(), meter->idsc().c_str(), meter->driverName().str().c_str()); + meter->name().c_str(), aesc.c_str(), meter->driverName().str().c_str()); } else { @@ -406,9 +419,8 @@ public: // Overwrite the id with the id from the telegram to be analyzed. MeterInfo mi; mi.key = analyze_key_; - mi.ids.clear(); - mi.ids.push_back(t.ids.back()); - mi.idsc = t.ids.back(); + mi.address_expressions.clear(); + mi.address_expressions.push_back(AddressExpression(t.addresses.back())); // This will be the driver that will actually decode and print with. string using_driver; @@ -459,7 +471,6 @@ public: assert(meter != NULL); bool match = false; - string id; if (should_profile_ > 0) { @@ -473,7 +484,8 @@ public: for (int k=0; khandleTelegram(about, input_frame, simulated, &id, &match, &t); + vector
addresses; + meter->handleTelegram(about, input_frame, simulated, &addresses, &match, &t); string hr, fields, json; vector envs, more_json, selected_fields; @@ -500,7 +512,8 @@ public: return; } - meter->handleTelegram(about, input_frame, simulated, &id, &match, &t); + vector
addresses; + meter->handleTelegram(about, input_frame, simulated, &addresses, &match, &t); int u = 0; int l = 0; diff --git a/src/meters.cc b/src/meters.cc index 9008a73..40eb3cf 100644 --- a/src/meters.cc +++ b/src/meters.cc @@ -327,8 +327,7 @@ MeterCommonImplementation::MeterCommonImplementation(MeterInfo &mi, has_process_content_(di.hasProcessContent()), waiting_for_poll_response_sem_("waiting_for_poll_response") { - ids_ = mi.ids; - idsc_ = toIdsCommaSeparated(ids_); + address_expressions_ = mi.address_expressions; link_modes_ = mi.link_modes; poll_interval_= mi.poll_interval; @@ -673,25 +672,25 @@ void MeterCommonImplementation::poll(shared_ptr bus_manager) if (!bus_device) { - warning("(meter) warning! no bus specified for meter %s %s\n", name().c_str(), idsc().c_str()); + string aesc = AddressExpression::concat(addressExpressions()); + warning("(meter) warning! no bus specified for meter %s %s\n", name().c_str(), aesc.c_str()); return; } - string id = ids().back(); - if (id.length() != 2 && id.length() != 3 && id.length() != 8) + AddressExpression &ae = addressExpressions().back(); + if (ae.has_wildcard) { - debug("(meter) not polling from bad id \"%s\" with wrong length\n", id.c_str()); + debug("(meter) not polling from id \"%s\" since poll id must not have a wildcard\n", ae.id.c_str()); return; } - if (id.length() == 2 || id.length() == 3) + if (ae.mbus_primary) { - vector idhex; - int idnum = atoi(id.c_str()); + int idnum = atoi(ae.id.c_str()+1); - if (idnum < 0 || idnum > 250 || idhex.size() != 1) + if (idnum < 0 || idnum > 250) { - debug("(meter) not polling from bad id \"%s\"\n", id.c_str()); + debug("(meter) not polling from bad id \"%s\"\n", ae.id.c_str()); return; } @@ -699,7 +698,7 @@ void MeterCommonImplementation::poll(shared_ptr bus_manager) buf.resize(5); buf[0] = 0x10; // Start buf[1] = 0x5b; // REQ_UD2 - buf[2] = idhex[0]; + buf[2] = idnum & 0xff; uchar cs = 0; for (int i=1; i<3; ++i) cs += buf[i]; buf[3] = cs; // checksum @@ -707,21 +706,21 @@ void MeterCommonImplementation::poll(shared_ptr bus_manager) verbose("(meter) polling %s %s (primary) with req ud2 on bus %s\n", name().c_str(), - id.c_str(), - bus_device->busAlias().c_str(),id.c_str()); + ae.id.c_str(), + bus_device->busAlias().c_str(),ae.id.c_str()); bus_device->serial()->send(buf); } - if (id.length() == 8) + if (!ae.mbus_primary) { // A full secondary address 12345678 was specified. vector idhex; - bool ok = hex2bin(id, &idhex); + bool ok = hex2bin(ae.id, &idhex); if (!ok || idhex.size() != 4) { - debug("(meter) not polling from bad id \"%s\"\n", id.c_str()); + debug("(meter) not polling from bad id \"%s\"\n", ae.id.c_str()); return; } @@ -739,19 +738,19 @@ void MeterCommonImplementation::poll(shared_ptr bus_manager) buf[8] = idhex[2]; // id 56 buf[9] = idhex[1]; // id 34 buf[10] = idhex[0]; // id 12 - // Use wildcards instead of exact matching here. - // TODO add selection based on these values as well. - buf[11] = 0xff; // mfct - buf[12] = 0xff; // mfct - buf[13] = 0xff; // version/generation - buf[14] = 0xff; // type/media/device + buf[11] = (ae.mfct >> 8) & 0xff; // use 0xff as a wildcard + buf[12] = ae.mfct & 0xff; // mfct + buf[13] = ae.version; // version/generation + buf[14] = ae.type; // type/media/device uchar cs = 0; for (int i=4; i<15; ++i) cs += buf[i]; buf[15] = cs; // checksum buf[16] = 0x16; // Stop - debug("(meter) secondary addressing bus %s to address %s\n", bus_device->busAlias().c_str(), id.c_str()); + debug("(meter) secondary addressing bus %s to address %s\n", + bus_device->busAlias().c_str(), + ae.id.c_str()); bus_device->serial()->send(buf); usleep(1000*500); @@ -767,26 +766,21 @@ void MeterCommonImplementation::poll(shared_ptr bus_manager) verbose("(meter) polling %s %s (secondary) with req ud2 bus %s\n", name().c_str(), - id.c_str(), + ae.id.c_str(), bus_device->busAlias().c_str()); bus_device->serial()->send(buf); } bool ok = waiting_for_poll_response_sem_.wait(); if (!ok) { - warning("(meter) %s %s did not send a response!\n", name().c_str(), idsc().c_str()); + warning("(meter) %s %s did not send a response!\n", name().c_str(), ae.id.c_str()); } } } -vector& MeterCommonImplementation::ids() +vector& MeterCommonImplementation::addressExpressions() { - return ids_; -} - -string MeterCommonImplementation::idsc() -{ - return idsc_; + return address_expressions_; } vector &MeterCommonImplementation::fieldInfos() @@ -852,7 +846,10 @@ void MeterCommonImplementation::setPollInterval(time_t interval) poll_interval_ = interval; if (usesPolling() && poll_interval_ == 0) { - warning("(meter) %s %s needs polling but has no pollinterval set!\n", name().c_str(), idsc().c_str()); + string aesc = AddressExpression::concat(addressExpressions()); + warning("(meter) %s %s needs polling but has no pollinterval set!\n", + name().c_str(), + aesc.c_str()); } } @@ -906,8 +903,7 @@ string toString(DriverInfo &di) bool MeterCommonImplementation::isTelegramForMeter(Telegram *t, Meter *meter, MeterInfo *mi) { string name; - vector ids; - string idsc; + vector address_expressions; string driver_name; assert((meter && !mi) || @@ -916,22 +912,27 @@ bool MeterCommonImplementation::isTelegramForMeter(Telegram *t, Meter *meter, Me if (meter) { name = meter->name(); - ids = meter->ids(); - idsc = meter->idsc(); + address_expressions = meter->addressExpressions(); driver_name = meter->driverName().str(); } else { name = mi->name; - ids = mi->ids; - idsc = mi->idsc; + address_expressions = mi->address_expressions; driver_name = mi->driver_name.str(); } - debug("(meter) %s: for me? %s in %s\n", name.c_str(), t->idsc.c_str(), idsc.c_str()); + if (isDebugEnabled()) + { + // Telegram addresses + string t_idsc = Address::concat(t->addresses); + // Meter/MeterInfo address expressions + string m_idsc = AddressExpression::concat(address_expressions); + debug("(meter) %s: for me? %s in %s\n", name.c_str(), t_idsc.c_str(), m_idsc.c_str()); + } bool used_wildcard = false; - bool id_match = doesIdsMatchExpressions(t->ids, ids, &used_wildcard); + bool id_match = doesTelegramMatchExpressions(t->addresses, address_expressions, &used_wildcard); if (!id_match) { // The id must match. @@ -1050,7 +1051,7 @@ bool checkCommonField(string *buf, string desired_field, Meter *m, Telegram *t, } if (desired_field == "id") { - *buf += t->ids.back() + c; + *buf += t->addresses.back().id + c; return true; } if (desired_field == "timestamp") @@ -1194,7 +1195,8 @@ string concatFields(Meter *m, Telegram *t, char c, vector &prints, bo } bool MeterCommonImplementation::handleTelegram(AboutTelegram &about, vector input_frame, - bool simulated, string *ids, bool *id_match, Telegram *out_analyzed) + bool simulated, vector
*addresses, + bool *id_match, Telegram *out_analyzed) { Telegram t; t.about = about; @@ -1203,7 +1205,7 @@ bool MeterCommonImplementation::handleTelegram(AboutTelegram &about, vector *envs, - vector *extra_constant_fields) +void MeterCommonImplementation::createMeterEnv(string id, + vector *envs, + vector *extra_constant_fields) { - envs->push_back(string("METER_ID="+*id)); + envs->push_back(string("METER_ID="+id)); envs->push_back(string("METER_NAME=")+name()); envs->push_back(string("METER_TYPE=")+driverName().str()); @@ -1791,9 +1800,9 @@ void MeterCommonImplementation::printMeter(Telegram *t, } string id = ""; - if (t->ids.size() > 0) + if (t->addresses.size() > 0) { - id = t->ids.back(); + id = t->addresses.back().id; } string indent = ""; @@ -1941,7 +1950,7 @@ void MeterCommonImplementation::printMeter(Telegram *t, s += "}"; *json = s; - createMeterEnv(&id, envs, extra_constant_fields); + createMeterEnv(id, envs, extra_constant_fields); envs->push_back(string("METER_JSON=")+*json); envs->push_back(string("METER_MEDIA=")+media); @@ -2093,11 +2102,15 @@ shared_ptr createMeter(MeterInfo *mi) { newm->setSelectedFields(di->defaultFields()); } - verbose("(meter) created %s %s %s %s\n", - mi->name.c_str(), - di->name().str().c_str(), - mi->idsc.c_str(), - keymsg); + if (isVerboseEnabled()) + { + string aesc = AddressExpression::concat(mi->address_expressions); + verbose("(meter) created %s %s %s %s\n", + mi->name.c_str(), + di->name().str().c_str(), + aesc.c_str(), + keymsg); + } return newm; } @@ -2165,12 +2178,12 @@ string MeterInfo::str() return r; } -bool MeterInfo::parse(string n, string d, string i, string k) +bool MeterInfo::parse(string n, string d, string aes, string k) { clear(); name = n; - ids = splitMatchExpressions(i); + address_expressions = splitAddressExpressions(aes); key = k; bool driverextras_checked = false; bool bus_checked = false; diff --git a/src/meters.h b/src/meters.h index 0d247f5..933282a 100644 --- a/src/meters.h +++ b/src/meters.h @@ -90,8 +90,7 @@ struct MeterInfo string name; // User specified name of this (group of) meters. DriverName driver_name; // Will replace MeterDriver. string extras; // Extra driver specific settings. - vector ids; // Match expressions for ids. - string idsc; // Comma separated ids. + vector address_expressions; // Match expressions for ids. string key; // Decryption key. LinkModeSet link_modes; int bps {}; // For mbus communication you need to know the baud rate. @@ -111,13 +110,12 @@ struct MeterInfo string str(); DriverName driverName(); - MeterInfo(string b, string n, string e, vector i, string k, LinkModeSet lms, int baud, vector &s, vector &ms, vector &j, vector &calcfs) + MeterInfo(string b, string n, string e, vector aes, string k, LinkModeSet lms, int baud, vector &s, vector &ms, vector &j, vector &calcfs) { bus = b; name = n; extras = e, - ids = i; - idsc = toIdsCommaSeparated(ids); + address_expressions = aes; key = k; shells = s; meter_shells = ms; @@ -131,8 +129,7 @@ struct MeterInfo { bus = ""; name = ""; - ids.clear(); - idsc = ""; + address_expressions.clear(); key = ""; shells.clear(); meter_shells.clear(); @@ -374,10 +371,8 @@ struct Meter virtual void setIndex(int i) = 0; // Use this bus to send messages to the meter. virtual string bus() = 0; - // This meter listens to these ids. - virtual vector &ids() = 0; - // Comma separated ids. - virtual string idsc() = 0; + // This meter listens to these address expressions. + virtual std::vector& addressExpressions() = 0; // This meter can report these fields, like total_m3, temp_c. virtual vector &fieldInfos() = 0; virtual vector &extraConstantFields() = 0; @@ -407,7 +402,7 @@ struct Meter virtual void onUpdate(std::function cb) = 0; virtual int numUpdates() = 0; - virtual void createMeterEnv(string *id, + virtual void createMeterEnv(string id, vector *envs, vector *more_json) = 0; virtual void printMeter(Telegram *t, @@ -423,7 +418,8 @@ struct Meter // Returns true of this meter handled this telegram! // Sets id_match to true, if there was an id match, even though the telegram could not be properly handled. virtual bool handleTelegram(AboutTelegram &about, vector input_frame, - bool simulated, string *id, bool *id_match, Telegram *out_t = NULL) = 0; + bool simulated, std::vector
*addresses, + bool *id_match, Telegram *out_t = NULL) = 0; virtual MeterKeys *meterKeys() = 0; virtual void addExtraCalculatedField(std::string ecf) = 0; diff --git a/src/meters_common_implementation.h b/src/meters_common_implementation.h index c1c87cd..71071ba 100644 --- a/src/meters_common_implementation.h +++ b/src/meters_common_implementation.h @@ -59,8 +59,7 @@ struct MeterCommonImplementation : public virtual Meter int index(); void setIndex(int i); string bus(); - vector& ids(); - string idsc(); + vector& addressExpressions(); vector &fieldInfos(); vector &extraConstantFields(); string name(); @@ -163,8 +162,9 @@ protected: // Override for mbus meters that need to be queried and likewise for C2/T2 wmbus-meters. void poll(shared_ptr bus); bool handleTelegram(AboutTelegram &about, vector frame, - bool simulated, string *id, bool *id_match, Telegram *out_analyzed = NULL); - void createMeterEnv(string *id, + bool simulated, std::vector
*addresses, + bool *id_match, Telegram *out_analyzed = NULL); + void createMeterEnv(string id, vector *envs, vector *more_json); // Add this json "key"="value" strings. void printMeter(Telegram *t, @@ -221,8 +221,7 @@ private: ELLSecurityMode expected_ell_sec_mode_ {}; TPLSecurityMode expected_tpl_sec_mode_ {}; string name_; - vector ids_; - string idsc_; + vector address_expressions_; vector> on_update_; int num_updates_ {}; time_t datetime_of_update_ {}; diff --git a/src/printer.cc b/src/printer.cc index 83b0654..2ea5658 100644 --- a/src/printer.cc +++ b/src/printer.cc @@ -92,10 +92,10 @@ void Printer::printFiles(Meter *meter, Telegram *t, string &human_readable, stri snprintf(filename, 127, "%s/%s", meterfiles_dir_.c_str(), meter->name().c_str()); break; case MeterFileNaming::Id: - snprintf(filename, 127, "%s/%s", meterfiles_dir_.c_str(), t->ids.back().c_str()); + snprintf(filename, 127, "%s/%s", meterfiles_dir_.c_str(), t->addresses.back().id.c_str()); break; case MeterFileNaming::NameId: - snprintf(filename, 127, "%s/%s-%s", meterfiles_dir_.c_str(), meter->name().c_str(), t->ids.back().c_str()); + snprintf(filename, 127, "%s/%s-%s", meterfiles_dir_.c_str(), meter->name().c_str(), t->addresses.back().id.c_str()); break; } string stamp; diff --git a/src/testinternals.cc b/src/testinternals.cc index 8685e42..c2c7d6e 100644 --- a/src/testinternals.cc +++ b/src/testinternals.cc @@ -39,7 +39,6 @@ bool verbose_ = false; #define LIST_OF_TESTS \ X(addresses) \ - /* X(dynamic_loading) \ X(crc) \ X(dvparser) \ @@ -77,8 +76,6 @@ bool verbose_ = false; X(formulas_dventries) \ X(formulas_stringinterpolation) \ - */ - #define X(t) void test_##t(); LIST_OF_TESTS #undef X @@ -427,7 +424,7 @@ void test_linkmodes() void test_valid_match_expression(string s, bool expected) { - bool b = isValidMatchExpressions(s); + bool b = isValidSequenceOfAddressExpressions(s); if (b == expected) return; if (expected == true) { @@ -441,9 +438,13 @@ void test_valid_match_expression(string s, bool expected) void test_does_id_match_expression(string id, string mes, bool expected, bool expected_uw) { - vector expressions = splitMatchExpressions(mes); + Address a; + a.id = id; + vector
as; + as.push_back(a); + vector expressions = splitAddressExpressions(mes); bool uw = false; - bool b = doesIdMatchExpressions(id, expressions, &uw); + bool b = doesTelegramMatchExpressions(as, expressions, &uw); if (b != expected) { if (expected == true) @@ -2254,9 +2255,9 @@ void test_formulas_building_meters() MeterKeys mk; t.parse(frame, &mk, true); - string id; + vector
addresses; bool match; - meter->handleTelegram(t.about, frame, true, &id, &match, &t); + meter->handleTelegram(t.about, frame, true, &addresses, &match, &t); f->clear(); f->setMeter(meter.get()); @@ -2305,7 +2306,7 @@ void test_formulas_building_meters() MeterKeys mk; t.parse(frame, &mk, true); - string id; + vector
id; bool match; meter->handleTelegram(t.about, frame, true, &id, &match, &t); @@ -2489,7 +2490,7 @@ void test_formulas_parsing_1() MeterKeys mk; t.parse(frame, &mk, true); - string id; + vector
id; bool match; meter->handleTelegram(t.about, frame, true, &id, &match, &t); @@ -2539,7 +2540,7 @@ void test_formulas_parsing_2() MeterKeys mk; t.parse(frame, &mk, true); - string id; + vector
id; bool match; meter->handleTelegram(t.about, frame, true, &id, &match, &t); diff --git a/src/util.cc b/src/util.cc index b2b10ff..087fa45 100644 --- a/src/util.cc +++ b/src/util.cc @@ -676,24 +676,6 @@ bool isNumber(const string& fq) return true; } -vector splitMatchExpressions(const string& mes) -{ - vector r; - bool eof, err; - vector v (mes.begin(), mes.end()); - auto i = v.begin(); - - for (;;) { - auto id = eatTo(v, i, ',', 16, &eof, &err); - if (err) break; - trimWhitespace(&id); - if (id == "ANYID") id = "*"; - r.push_back(id); - if (eof) break; - } - return r; -} - void incrementIV(uchar *iv, size_t len) { uchar *p = iv+len-1; while (p >= iv) { diff --git a/src/wmbus.cc b/src/wmbus.cc index d485705..fc29461 100644 --- a/src/wmbus.cc +++ b/src/wmbus.cc @@ -229,17 +229,18 @@ LIST_OF_MANUFACTURERS } -void Telegram::addId(const vector::iterator &pos) +void Telegram::addAddressMfctFirst(const vector::iterator &pos) { -// string id = tostrprintf("%02x%02x%02x%02x_%02x_%02x", *(pos+3), *(pos+2), *(pos+1), *(pos+0), *(pos+4), *(pos+5)); - string id = tostrprintf("%02x%02x%02x%02x", *(pos+3), *(pos+2), *(pos+1), *(pos+0)); - ids.push_back(id); - if (idsc.empty()) { - idsc = id; - } - else { - idsc += "," + id; - } + Address a; + a.decodeMfctFirst(pos); + addresses.push_back(a); +} + +void Telegram::addAddressIdFirst(const vector::iterator &pos) +{ + Address a; + a.decodeIdFirst(pos); + addresses.push_back(a); } void Telegram::print() @@ -453,18 +454,6 @@ string manufacturer(int m_field) { return "Unknown"; } -string manufacturerFlag(int m_field) { - char a = (m_field/1024)%32+64; - char b = (m_field/32)%32+64; - char c = (m_field)%32+64; - - string flag; - flag += a; - flag += b; - flag += c; - return flag; -} - string mediaType(int a_field_device_type, int m_field) { switch (a_field_device_type) { case 0: return "Other"; @@ -915,9 +904,10 @@ bool Telegram::parseMBusDLLandTPL(vector::iterator &pos) addExplanationAndIncrementPos(pos, 1, KindOfData::PROTOCOL, Understanding::FULL, "%02x dll-a primary (%d)", mbus_primary_address, mbus_primary_address); // Add dll_id to ids. - string id = tostrprintf("%02x", mbus_primary_address); - ids.push_back(id); - idsc = id; + string id = tostrprintf("p%d", mbus_primary_address); + Address a; + a.id = id; + addresses.push_back(a); mbus_ci = *pos; addExplanationAndIncrementPos(pos, 1, KindOfData::PROTOCOL, Understanding::FULL, "%02x tpl-ci (%s)", mbus_ci, mbusCiField(mbus_ci)); @@ -943,6 +933,9 @@ bool Telegram::parseDLL(vector::iterator &pos) dll_c = *pos; addExplanationAndIncrementPos(pos, 1, KindOfData::PROTOCOL, Understanding::FULL, "%02x dll-c (%s)", dll_c, cType(dll_c).c_str()); + CHECK(8) + addAddressMfctFirst(pos); + dll_mfct_b[0] = *(pos+0); dll_mfct_b[1] = *(pos+1); dll_mfct = dll_mfct_b[1] <<8 | dll_mfct_b[0]; @@ -962,9 +955,8 @@ bool Telegram::parseDLL(vector::iterator &pos) } } // Add dll_id to ids. - addId(pos); addExplanationAndIncrementPos(pos, 4, KindOfData::PROTOCOL, Understanding::FULL, "%02x%02x%02x%02x dll-id (%s)", - *(pos+0), *(pos+1), *(pos+2), *(pos+3), ids.back().c_str()); + *(pos+0), *(pos+1), *(pos+2), *(pos+3), addresses.back().id.c_str()); dll_version = *(pos+0); dll_type = *(pos+1); @@ -1038,6 +1030,9 @@ bool Telegram::parseELL(vector::iterator &pos) if (has_target_mft_address) { + CHECK(8); + addAddressMfctFirst(pos); + ell_mfct_b[0] = *(pos+0); ell_mfct_b[1] = *(pos+1); ell_mfct = ell_mfct_b[1] << 8 | ell_mfct_b[0]; @@ -1052,7 +1047,6 @@ bool Telegram::parseELL(vector::iterator &pos) ell_id_b[3] = *(pos+3); // Add ell_id to ids. - addId(pos); addExplanationAndIncrementPos(pos, 4, KindOfData::PROTOCOL, Understanding::FULL, "%02x%02x%02x%02x ell-id", ell_id_b[0], ell_id_b[1], ell_id_b[2], ell_id_b[3]); @@ -1448,7 +1442,9 @@ bool Telegram::parseShortTPL(std::vector::iterator &pos) bool Telegram::parseLongTPL(std::vector::iterator &pos) { - CHECK(4); + CHECK(8); + addAddressIdFirst(pos); + tpl_id_found = true; tpl_id_b[0] = *(pos+0); tpl_id_b[1] = *(pos+1); @@ -1461,9 +1457,6 @@ bool Telegram::parseLongTPL(std::vector::iterator &pos) tpl_a[i] = *(pos+i); } - // Add the tpl_id to ids. - addId(pos); - addExplanationAndIncrementPos(pos, 4, KindOfData::PROTOCOL, Understanding::FULL, "%02x%02x%02x%02x tpl-id (%02x%02x%02x%02x)", tpl_id_b[0], tpl_id_b[1], tpl_id_b[2], tpl_id_b[3], diff --git a/src/wmbus.h b/src/wmbus.h index a8db705..388f61a 100644 --- a/src/wmbus.h +++ b/src/wmbus.h @@ -18,6 +18,7 @@ #ifndef WMBUS_H #define WMBUS_H +#include"address.h" #include"dvparser.h" #include"manufacturers.h" #include"serial.h" @@ -416,10 +417,9 @@ public: // If a warning is printed mark this. bool triggered_warning {}; - // The different ids found, the first is th dll_id, ell_id, nwl_id, and the last is the tpl_id. - vector ids; - // Ids separated by commas - string idsc; + // The different addresses found, + // the first is the dll_id_mvt, ell_id_mvt, nwl_id_mvt, and the last is the tpl_id_mvt. + vector
addresses; // If decryption failed, set this to true, to prevent further processing. bool decryption_failed {}; @@ -536,7 +536,8 @@ public: bool parseHANHeader(vector &input_frame); bool parseHAN(vector &input_frame, MeterKeys *mk, bool warn); - void addId(const vector::iterator &pos); + void addAddressMfctFirst(const vector::iterator &pos); + void addAddressIdFirst(const vector::iterator &pos); void print(); @@ -741,7 +742,6 @@ shared_ptr openSimulator(Detected detected, shared_ptr serial_override); string manufacturer(int m_field); -string manufacturerFlag(int m_field); 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); diff --git a/tests/test_aes.sh b/tests/test_aes.sh index 06f2950..309e68b 100755 --- a/tests/test_aes.sh +++ b/tests/test_aes.sh @@ -36,11 +36,11 @@ TESTRESULT="ERROR" cat > $TEST/test_expected.txt < $TEST/test_expected.txt < $TEST/expected_err.txt < $TEST/expected_err.txt < $TEST/test_expected.txt Started config rtlwmbus on stdin listening on any (wmbus) WARNING!! decrypted content failed check, did you use the correct decryption key? Permanently ignoring telegrams from id: 88888888 mfct: (APA) Apator, Poland (0x601) type: Water meter (0x07) ver: 0x05 -(meter) newly created meter (ApWater 88888888 apator162) did not handle telegram! +(meter) newly created meter (ApWater 88888888.M=APA.V=05.T=07 apator162) did not handle telegram! (wmbus) WARNING! decrypted payload crc failed check, did you use the correct decryption key? 979f payload crc (calculated 3431) Permanently ignoring telegrams from id: 76348799 mfct: (KAM) Kamstrup Energi (0x2c2d) type: Cold water meter (0x16) ver: 0x1b -(meter) newly created meter (Vatten 76348799 multical21) did not handle telegram! +(meter) newly created meter (Vatten 76348799.M=KAM.V=1b.T=16 multical21) did not handle telegram! EOF diff $TEST/test_expected.txt $TEST/test_stderr.txt