New advanced addressing works.

pull/1091/head
Fredrik Öhrström 2024-03-02 15:30:25 +01:00
rodzic 78e7c47503
commit 7634b95438
22 zmienionych plików z 505 dodań i 272 usunięć

12
CHANGES
Wyświetl plik

@ -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.

Wyświetl plik

@ -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

Wyświetl plik

@ -22,6 +22,8 @@
using namespace std;
vector<string> 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<string> splitSequenceOfAddressExpressionsAtCommas(const string& mes)
{
vector<string> v = splitMatchExpressions(mes);
vector<string> r;
bool eof, err;
vector<uchar> 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<string> 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<AddressExpression> splitAddressExpressions(const string &aes)
{
vector<string> v = splitSequenceOfAddressExpressionsAtCommas(aes);
for (size_t i=0; i<id.length(); ++i)
vector<AddressExpression> 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<string> &ids, vector<string>& mes, bool *used_wildcard)
bool doesIdsMatchExpressionss(vector<string> &ids, vector<string>& 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<string> &ids, vector<string>& mes, bool *use
return match;
}
bool doesIdMatchExpressions(const string& id, vector<string>& mes, bool *used_wildcard)
bool doesIdMatchExpressionss(const string& id, vector<string>& mes, bool *used_wildcard)
{
bool found_match = false;
bool found_negative_match = false;
@ -315,6 +342,18 @@ string toIdsCommaSeparated(vector<string> &ids)
return cs;
}
string toIdsCommaSeparated(vector<AddressExpression> &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<string> 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<Address> &addresses)
{
string s;
for (Address& a: addresses)
{
if (s.size() > 0) s.append(",");
s.append(a.str());
}
return s;
}
string AddressExpression::concat(std::vector<AddressExpression> &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<uchar>::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<uchar>::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<Address> &addresses,
std::vector<AddressExpression>& 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<AddressExpression>& 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;
}

Wyświetl plik

@ -21,6 +21,20 @@
#include "util.h"
#include <string>
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<uchar>::iterator &pos);
void decodeIdFirst(const std::vector<uchar>::iterator &pos);
std::string str();
static std::string concat(std::vector<Address> &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<AddressExpression> &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<std::string>& match_rules,
bool *used_wildcard);
bool doesIdsMatchExpressions(std::vector<std::string> &ids,
bool doesIdsMatchExpressionss(std::vector<std::string> &ids,
std::vector<std::string>& match_rules,
bool *used_wildcard);
std::string toIdsCommaSeparated(std::vector<std::string> &ids);
std::string toIdsCommaSeparated(std::vector<AddressExpression> &ids);
bool isValidId(const std::string& id);
std::vector<std::string> splitMatchExpressions(const std::string& mes);
std::vector<AddressExpression> splitAddressExpressions(const std::string &aes);
bool flagToManufacturer(const char *s, uint16_t *out_mfct);
std::string manufacturerFlag(int m_field);
bool doesTelegramMatchExpressions(std::vector<Address> &addresses,
std::vector<AddressExpression>& address_expressions,
bool *used_wildcard);
bool doesAddressMatchExpressions(Address &address,
std::vector<AddressExpression>& address_expressions,
bool *used_wildcard);
#endif

Wyświetl plik

@ -740,38 +740,7 @@ static shared_ptr<Configuration> 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<Configuration>(c);

Wyświetl plik

@ -179,34 +179,20 @@ void parseMeterConfig(Configuration *c, vector<char> &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);
}

Wyświetl plik

@ -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);

Wyświetl plik

@ -160,8 +160,11 @@ namespace
vector<uchar> 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();

Wyświetl plik

@ -581,12 +581,12 @@ bool start(Configuration *config)
vector<string> 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<string> args;

Wyświetl plik

@ -144,11 +144,12 @@ public:
bool handled = false;
bool exact_id_match = false;
string verbose_info;
string ids;
vector<Address> 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<string> tmp_ids;
tmp_ids.push_back(t.ids.back());
meter_info.ids = tmp_ids;
meter_info.idsc = t.ids.back();
vector<AddressExpression> 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<Address> 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; k<should_profile_; ++k)
{
meter->handleTelegram(about, input_frame, simulated, &id, &match, &t);
vector<Address> addresses;
meter->handleTelegram(about, input_frame, simulated, &addresses, &match, &t);
string hr, fields, json;
vector<string> envs, more_json, selected_fields;
@ -500,7 +512,8 @@ public:
return;
}
meter->handleTelegram(about, input_frame, simulated, &id, &match, &t);
vector<Address> addresses;
meter->handleTelegram(about, input_frame, simulated, &addresses, &match, &t);
int u = 0;
int l = 0;

Wyświetl plik

@ -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<BusManager> 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<uchar> 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<BusManager> 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<BusManager> 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<uchar> 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<BusManager> 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<BusManager> 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<string>& MeterCommonImplementation::ids()
vector<AddressExpression>& MeterCommonImplementation::addressExpressions()
{
return ids_;
}
string MeterCommonImplementation::idsc()
{
return idsc_;
return address_expressions_;
}
vector<FieldInfo> &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<string> ids;
string idsc;
vector<AddressExpression> 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<FieldInfo> &prints, bo
}
bool MeterCommonImplementation::handleTelegram(AboutTelegram &about, vector<uchar> input_frame,
bool simulated, string *ids, bool *id_match, Telegram *out_analyzed)
bool simulated, vector<Address> *addresses,
bool *id_match, Telegram *out_analyzed)
{
Telegram t;
t.about = about;
@ -1203,7 +1205,7 @@ bool MeterCommonImplementation::handleTelegram(AboutTelegram &about, vector<ucha
if (simulated) t.markAsSimulated();
if (out_analyzed != NULL) t.markAsBeingAnalyzed();
*ids = t.idsc;
*addresses = t.addresses;
if (!ok || !isTelegramForMeter(&t, this, NULL))
{
@ -1212,12 +1214,19 @@ bool MeterCommonImplementation::handleTelegram(AboutTelegram &about, vector<ucha
}
*id_match = true;
verbose("(meter) %s(%d) %s handling telegram from %s\n", name().c_str(), index(), driverName().str().c_str(), t.ids.back().c_str());
if (isVerboseEnabled())
{
verbose("(meter) %s(%d) %s handling telegram from %s\n",
name().c_str(),
index(),
driverName().str().c_str(),
t.addresses.back().str().c_str());
}
if (isDebugEnabled())
{
string msg = bin2hex(input_frame);
debug("(meter) %s %s \"%s\"\n", name().c_str(), t.ids.back().c_str(), msg.c_str());
debug("(meter) %s %s \"%s\"\n", name().c_str(), t.addresses.back().str().c_str(), msg.c_str());
}
// For older meters with manufacturer specific data without a nice 0f dif marker.
@ -1744,11 +1753,11 @@ string FieldInfo::renderJson(Meter *m, DVEntry *dve)
return s;
}
void MeterCommonImplementation::createMeterEnv( string *id,
vector<string> *envs,
vector<string> *extra_constant_fields)
void MeterCommonImplementation::createMeterEnv(string id,
vector<string> *envs,
vector<string> *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<Meter> 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;

Wyświetl plik

@ -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<string> ids; // Match expressions for ids.
string idsc; // Comma separated ids.
vector<AddressExpression> 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<string> i, string k, LinkModeSet lms, int baud, vector<string> &s, vector<string> &ms, vector<string> &j, vector<string> &calcfs)
MeterInfo(string b, string n, string e, vector<AddressExpression> aes, string k, LinkModeSet lms, int baud, vector<string> &s, vector<string> &ms, vector<string> &j, vector<string> &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<string> &ids() = 0;
// Comma separated ids.
virtual string idsc() = 0;
// This meter listens to these address expressions.
virtual std::vector<AddressExpression>& addressExpressions() = 0;
// This meter can report these fields, like total_m3, temp_c.
virtual vector<FieldInfo> &fieldInfos() = 0;
virtual vector<string> &extraConstantFields() = 0;
@ -407,7 +402,7 @@ struct Meter
virtual void onUpdate(std::function<void(Telegram*t,Meter*)> cb) = 0;
virtual int numUpdates() = 0;
virtual void createMeterEnv(string *id,
virtual void createMeterEnv(string id,
vector<string> *envs,
vector<string> *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<uchar> input_frame,
bool simulated, string *id, bool *id_match, Telegram *out_t = NULL) = 0;
bool simulated, std::vector<Address> *addresses,
bool *id_match, Telegram *out_t = NULL) = 0;
virtual MeterKeys *meterKeys() = 0;
virtual void addExtraCalculatedField(std::string ecf) = 0;

Wyświetl plik

@ -59,8 +59,7 @@ struct MeterCommonImplementation : public virtual Meter
int index();
void setIndex(int i);
string bus();
vector<string>& ids();
string idsc();
vector<AddressExpression>& addressExpressions();
vector<FieldInfo> &fieldInfos();
vector<string> &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<BusManager> bus);
bool handleTelegram(AboutTelegram &about, vector<uchar> frame,
bool simulated, string *id, bool *id_match, Telegram *out_analyzed = NULL);
void createMeterEnv(string *id,
bool simulated, std::vector<Address> *addresses,
bool *id_match, Telegram *out_analyzed = NULL);
void createMeterEnv(string id,
vector<string> *envs,
vector<string> *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<string> ids_;
string idsc_;
vector<AddressExpression> address_expressions_;
vector<function<void(Telegram*,Meter*)>> on_update_;
int num_updates_ {};
time_t datetime_of_update_ {};

Wyświetl plik

@ -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;

Wyświetl plik

@ -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<string> expressions = splitMatchExpressions(mes);
Address a;
a.id = id;
vector<Address> as;
as.push_back(a);
vector<AddressExpression> 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<Address> 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<Address> 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<Address> 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<Address> id;
bool match;
meter->handleTelegram(t.about, frame, true, &id, &match, &t);

Wyświetl plik

@ -676,24 +676,6 @@ bool isNumber(const string& fq)
return true;
}
vector<string> splitMatchExpressions(const string& mes)
{
vector<string> r;
bool eof, err;
vector<uchar> 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) {

Wyświetl plik

@ -229,17 +229,18 @@ LIST_OF_MANUFACTURERS
}
void Telegram::addId(const vector<uchar>::iterator &pos)
void Telegram::addAddressMfctFirst(const vector<uchar>::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<uchar>::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<uchar>::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<uchar>::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<uchar>::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<uchar>::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<uchar>::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<uchar>::iterator &pos)
bool Telegram::parseLongTPL(std::vector<uchar>::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<uchar>::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],

Wyświetl plik

@ -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<string> 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<Address> addresses;
// If decryption failed, set this to true, to prevent further processing.
bool decryption_failed {};
@ -536,7 +536,8 @@ public:
bool parseHANHeader(vector<uchar> &input_frame);
bool parseHAN(vector<uchar> &input_frame, MeterKeys *mk, bool warn);
void addId(const vector<uchar>::iterator &pos);
void addAddressMfctFirst(const vector<uchar>::iterator &pos);
void addAddressIdFirst(const vector<uchar>::iterator &pos);
void print();
@ -741,7 +742,6 @@ shared_ptr<BusDevice> openSimulator(Detected detected,
shared_ptr<SerialDevice> 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);

Wyświetl plik

@ -36,11 +36,11 @@ TESTRESULT="ERROR"
cat > $TEST/test_expected.txt <<EOF
(wmbus) WARNING!! telegram should have been fully encrypted, but was not! 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? e1d6 payload crc (calculated a528) 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!
(wmbus) WARNING!! telegram should have been fully encrypted, but was not! id: 77777777 mfct: (SON) Sontex, Switzerland (0x4dee) type: Water meter (0x07) ver: 0x3c
(meter) newly created meter (Wasser 77777777 supercom587) did not handle telegram!
(meter) newly created meter (Wasser 77777777.M=SON.V=3c.T=07 supercom587) did not handle telegram!
(wmbus) WARNING!!! telegram should have been encrypted, but was not! id: 77777777 mfct: (SON) Sontex, Switzerland (0x4dee) type: Water meter (0x07) ver: 0x3c
EOF

Wyświetl plik

@ -181,6 +181,14 @@ cat > $TEST/test_expected.txt <<EOF
-------------------------------------------------------------------------------
There should be three fields, for example: mvt = AAA,07,05
-------------------------------------------------------------------------------
(driver) error in testoutput/driver.xmq, cannot find any detection triplets: driver/detect/mvt
-------------------------------------------------------------------------------
Remember to add: detect { mvt = AAA,05,07 mvt = AAA,06,07 ... }
The triplets consists of MANUFACTURER,VERSION,TYPE
You can see these values when listening to all meters.
The manufacturer can be given as three uppercase characters A-Z
or as 4 lower case hex digits.
-------------------------------------------------------------------------------
Failed to load driver from file: testoutput/driver.xmq
EOF

Wyświetl plik

@ -13,7 +13,7 @@ $PROG --format=json simulations/simulation_bad_keys.txt room fhkvdataiv 03065716
cat > $TEST/expected_err.txt <<EOF
(wmbus) WARNING! no key to decrypt payload! Permanently ignoring telegrams from id: 03065716 mfct: (TCH) Techem Service (0x5068) type: Heat Cost Allocator (0x08) ver: 0x94
(meter) newly created meter (room 03065716 fhkvdataiv) did not handle telegram!
(meter) newly created meter (room 03065716.M=TCH.V=94.T=08 fhkvdataiv) did not handle telegram!
EOF
diff $TEST/test_stderr.txt $TEST/expected_err.txt
@ -28,7 +28,7 @@ $PROG --format=json simulations/simulation_bad_keys.txt room fhkvdataiv 03065716
cat > $TEST/expected_err.txt <<EOF
(wmbus) WARNING!! decrypted content failed check, did you use the correct decryption key? Permanently ignoring telegrams from id: 03065716 mfct: (TCH) Techem Service (0x5068) type: Heat Cost Allocator (0x08) ver: 0x94
(meter) newly created meter (room 03065716 fhkvdataiv) did not handle telegram!
(meter) newly created meter (room 03065716.M=TCH.V=94.T=08 fhkvdataiv) did not handle telegram!
EOF
diff $TEST/test_stderr.txt $TEST/expected_err.txt

Wyświetl plik

@ -28,9 +28,9 @@ fi
cat <<EOF > $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