Handle more address rules.

pull/868/merge
Fredrik Öhrström 2024-03-02 22:46:50 +01:00
rodzic 11c83c1f37
commit 5962e727ff
6 zmienionych plików z 103 dodań i 12 usunięć

Wyświetl plik

@ -27,7 +27,8 @@ bool isValidMatchExpression(const std::string& s, bool *has_wildcard);
bool doesIdMatchExpression(const std::string& id, std::string match_rule);
bool doesAddressMatchExpressions(Address &address,
std::vector<AddressExpression>& address_expressions,
bool *used_wildcard);
bool *used_wildcard,
bool *filtered_out);
bool isValidMatchExpression(const string& s, bool *has_wildcard)
{
@ -94,7 +95,7 @@ vector<string> splitSequenceOfAddressExpressionsAtCommas(const string& mes)
auto i = v.begin();
for (;;) {
auto id = eatTo(v, i, ',', 16, &eof, &err);
auto id = eatTo(v, i, ',', 64, &eof, &err);
if (err) break;
trimWhitespace(&id);
if (id == "ANYID") id = "*";
@ -277,6 +278,19 @@ bool AddressExpression::parse(const string &in)
bool ok = flagToManufacturer(&parts[i][2], &mfct);
if (!ok) return false;
}
else if (parts[i].size() == 6) // M=abcd explicit hex version
{
if (parts[i][1] != '=') return false;
if (parts[i][0] != 'M') return false;
vector<uchar> data;
bool ok = hex2bin(&parts[i][2], &data);
if (!ok) return false;
if (data.size() != 2) return false;
mfct = data[1] << 8 | data[0];
if (!ok) return false;
}
else
{
return false;
@ -396,21 +410,25 @@ bool doesTelegramMatchExpressions(std::vector<Address> &addresses,
bool *used_wildcard)
{
bool match = false;
bool filtered_out = false;
for (Address &a : addresses)
{
if (doesAddressMatchExpressions(a, address_expressions, used_wildcard))
if (doesAddressMatchExpressions(a, address_expressions, used_wildcard, &filtered_out))
{
match = true;
}
// Go through all ids even though there is an early match.
// This way we can see if theres an exact match later.
}
// If any expression triggered a filter out, then the whole telegram does not match.
if (filtered_out) match = false;
return match;
}
bool doesAddressMatchExpressions(Address &address,
vector<AddressExpression>& address_expressions,
bool *used_wildcard)
bool *used_wildcard,
bool *filtered_out)
{
bool found_match = false;
bool found_negative_match = false;
@ -433,7 +451,7 @@ bool doesAddressMatchExpressions(Address &address,
bool has_wildcard = ae.has_wildcard;
bool is_negative_rule = ae.filter_out;
bool m = doesIdMatchExpression(address.id, ae.id);
bool m = ae.match(address.id, address.mfct, address.version, address.type);
if (is_negative_rule)
{
@ -453,6 +471,7 @@ bool doesAddressMatchExpressions(Address &address,
}
if (found_negative_match)
{
*filtered_out = true;
return false;
}
if (found_match)

Wyświetl plik

@ -728,11 +728,11 @@ static shared_ptr<Configuration> parseNormalCommandLine(Configuration *c, int ar
string bus;
string name = argv[m*4+i+0];
string driver = argv[m*4+i+1];
string id = argv[m*4+i+2];
string address_expressions = argv[m*4+i+2];
string key = argv[m*4+i+3];
MeterInfo mi;
mi.parse(name, driver, id, key);
mi.parse(name, driver, address_expressions, key);
mi.poll_interval = c->pollinterval;
if (mi.driver_name.str() == "")

Wyświetl plik

@ -53,7 +53,7 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
string bus;
string name;
string driver = "auto";
string id;
string address_expressions;
string key = "";
string linkmodes;
int poll_interval = 0;
@ -108,7 +108,7 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
else
if (p.first == "driver") driver = p.second;
else
if (p.first == "id") id = p.second;
if (p.first == "id") address_expressions = p.second;
else
if (p.first == "key")
{
@ -176,11 +176,11 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
MeterInfo mi;
mi.parse(name, driver, id, key); // sets driver, extras, name, bus, bps, link_modes, ids, name, key
mi.parse(name, driver, address_expressions, key); // sets driver, extras, name, bus, bps, link_modes, ids, name, key
mi.poll_interval = poll_interval;
if (!isValidSequenceOfAddressExpressions(id)) {
warning("Not a valid meter id nor a valid sequence of match expression \"%s\"\n", id.c_str());
if (!isValidSequenceOfAddressExpressions(address_expressions)) {
warning("Not a valid meter id nor a valid sequence of match expression \"%s\"\n", address_expressions.c_str());
use = false;
}
if (!isValidKey(key, mi)) {

Wyświetl plik

@ -403,6 +403,14 @@ void log_start_information(Configuration *config)
verbose("(config) using device: %s \n", specified_device.str().c_str());
}
verbose("(config) number of meters: %d\n", config->meters.size());
if (isDebugEnabled())
{
for (MeterInfo &m : config->meters)
{
string aes = AddressExpression::concat(m.address_expressions);
debug("(config) template %s %s %s\n", m.name.c_str(), aes.c_str(), m.str().c_str());
}
}
}
void oneshot_check(Configuration *config, Telegram *t, Meter *meter)

Wyświetl plik

@ -187,6 +187,7 @@ public:
aes.push_back(AddressExpression(t.addresses.back()));
meter_info.address_expressions = aes;
// Overwrite the mfct,version and type.
if (meter_info.driverName().str() == "auto")
{
// Look up the proper meter driver!

Wyświetl plik

@ -575,6 +575,42 @@ void tst_address_match(string expr, string id, uint16_t m, uchar v, uchar t, boo
}
}
void tst_telegram_match(string addresses, string expressions, bool match, bool uw)
{
vector<AddressExpression> exprs = splitAddressExpressions(expressions);
vector<AddressExpression> as = splitAddressExpressions(addresses);
vector<Address> addrs;
for (auto &ad : as)
{
Address a;
a.id = ad.id;
a.mfct = ad.mfct;
a.version = ad.version;
a.type = ad.type;
addrs.push_back(a);
}
bool used_wildcard = false;
bool m = doesTelegramMatchExpressions(addrs, exprs, &used_wildcard);
if (m != match)
{
printf("Expected addresses %s to %smatch expressions %s\n",
addresses.c_str(),
match?"":"NOT ",
expressions.c_str());
}
if (uw != used_wildcard)
{
printf("Expected addresses %s from match expression %s %susing wildcard\n",
addresses.c_str(),
expressions.c_str(),
uw?"":"NOT ");
}
}
void test_addresses()
{
tst_address("12345678",
@ -634,6 +670,33 @@ void test_addresses()
tst_address_match("!9*.V=06", "89999999", MANUFACTURER_ABB, 0x06, 1, false, true);
tst_address_match("!9*.V=06", "99999999", MANUFACTURER_ABB, 0x07, 1, false, true);
tst_address_match("!9*.V=06", "89999999", MANUFACTURER_ABB, 0x07, 1, false, true);
tst_telegram_match("12345678", "12345678", true, false);
tst_telegram_match("11111111,22222222", "12345678,22*", true, true);
tst_telegram_match("11111111,22222222", "12345678,22222222", true, false);
tst_telegram_match("11111111.M=KAM,22222222.M=PII", "11111111.M=KAM", true, false);
tst_telegram_match("11111111.M=KAF", "11111111.M=KAM", false, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.M=KAM", true, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.M=KAF", false, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111", true, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.M=KAM", true, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.V=1b", true, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.T=16", true, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.M=KAM.T=16", true, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.M=KAM.V=1b", true, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.T=16.V=1b", true, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.M=KAL", false, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.V=1c", false, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.T=17", false, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.M=KAM.T=17", false, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.M=KAL.V=1b", false, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.T=17.V=1b", false, false);
// Test * matches both 11111111 and 2222222 but the only the 111111 matches the filter out V=1b.
// Verify that the filter out !1*.V=1b will override successfull match (with no filter out) * for 22222222.
tst_telegram_match("11111111.M=KAM.V=1b.T=16,22222222.M=XXX.V=aa.T=99", "*,!1*.V=1b", false, true);
}
void eq(string a, string b, const char *tn)