Add dynamic driver lookup bits translation to strings.

pull/1231/head
Fredrik Öhrström 2024-04-04 20:58:51 +02:00
rodzic c1509f6139
commit ff72e1debc
58 zmienionych plików z 870 dodań i 470 usunięć

Wyświetl plik

@ -157,7 +157,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("07FFA600")),
Translate::Lookup()
.add(Translate::Rule("ERROR_FLAGS", Translate::Type::BitToString)
.add(Translate::Rule("ERROR_FLAGS", Translate::MapType::BitToString)
.set(MaskBits(0xffffffffffffffff))
.set(DefaultMessage("OK"))
));
@ -170,7 +170,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("07FFA700")),
Translate::Lookup()
.add(Translate::Rule("WARNING_FLAGS", Translate::Type::BitToString)
.add(Translate::Rule("WARNING_FLAGS", Translate::MapType::BitToString)
.set(MaskBits(0xffffffffffffffff))
.set(DefaultMessage("OK"))
));
@ -183,7 +183,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("07FFA800")),
Translate::Lookup()
.add(Translate::Rule("INFORMATION_FLAGS", Translate::Type::BitToString)
.add(Translate::Rule("INFORMATION_FLAGS", Translate::MapType::BitToString)
.set(MaskBits(0xffffffffffffffff))
.set(DefaultMessage(""))
));
@ -196,7 +196,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("07FFA900")),
Translate::Lookup()
.add(Translate::Rule("ALARM_FLAGS", Translate::Type::BitToString)
.add(Translate::Rule("ALARM_FLAGS", Translate::MapType::BitToString)
.set(MaskBits(0xfffffffffffffff))
.set(DefaultMessage("OK"))
));
@ -209,7 +209,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("01FFAD00")),
Translate::Lookup()
.add(Translate::Rule("UNKNOWN", Translate::Type::BitToString)
.add(Translate::Rule("UNKNOWN", Translate::MapType::BitToString)
.set(MaskBits(0xff))
.set(DefaultMessage("OK"))
));
@ -739,7 +739,7 @@ namespace
.set(SubUnitNr(1),SubUnitNr(2))
.add(VIFCombinableRaw(0)),
Translate::Lookup()
.add(Translate::Rule("OUTPUT", Translate::Type::BitToString)
.add(Translate::Rule("OUTPUT", Translate::MapType::BitToString)
.set(MaskBits(0xff))
));
@ -753,7 +753,7 @@ namespace
.set(SubUnitNr(3),SubUnitNr(4))
.add(VIFCombinableRaw(0)),
Translate::Lookup()
.add(Translate::Rule("INPUT", Translate::Type::BitToString)
.add(Translate::Rule("INPUT", Translate::MapType::BitToString)
.set(MaskBits(0xff))
));
@ -768,7 +768,7 @@ namespace
.set(SubUnitNr(3),SubUnitNr(4))
.add(VIFCombinableRaw(0)),
Translate::Lookup()
.add(Translate::Rule("INPUT", Translate::Type::BitToString)
.add(Translate::Rule("INPUT", Translate::MapType::BitToString)
.set(MaskBits(0xff))
));

Wyświetl plik

@ -48,7 +48,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{
@ -75,7 +75,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"",
{

Wyświetl plik

@ -49,7 +49,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{
@ -100,7 +100,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"",
{

Wyświetl plik

@ -101,7 +101,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::DecimalsToString,
Translate::MapType::DecimalsToString,
AlwaysTrigger, MaskBits(9999),
"OK",
{

Wyświetl plik

@ -77,7 +77,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(VIFRange::DigitalInput),
Translate::Lookup()
.add(Translate::Rule("BATTERY", Translate::Type::BitToString)
.add(Translate::Rule("BATTERY", Translate::MapType::BitToString)
.set(MaskBits(0xffff)))
);
}

Wyświetl plik

@ -47,7 +47,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{

Wyświetl plik

@ -35,11 +35,16 @@ string get_translation(XMQDoc *doc, XMQNode *node, string name, string lang);
string check_calculate(const char *formula, DriverDynamic *dd);
Unit check_display_unit(const char *display_unit, DriverDynamic *dd);
bool checked_set_difvifkey(const char *difvifkey_s, FieldMatcher *fm, DriverDynamic *dd);
void checked_set_measurement_type(const char *measurement_type_s, FieldMatcher *fm, DriverDynamic *dd);
void checked_set_vif_range(const char *vif_range_s, FieldMatcher *fm, DriverDynamic *dd);
void checked_set_storagenr_range(const char *storagenr_range_s, FieldMatcher *fm, DriverDynamic *dd);
void checked_set_tariffnr_range(const char *tariffnr_range_s, FieldMatcher *fm, DriverDynamic *dd);
void checked_set_subunitnr_range(const char *subunitnr_range_s, FieldMatcher *fm, DriverDynamic *dd);
Translate::MapType checked_map_type(const char *map_type_s, DriverDynamic *dd);
uint64_t checked_mask_bits(const char *mask_bits_s, DriverDynamic *dd);
uint64_t checked_value(const char *value_s, DriverDynamic *dd);
TestBit checked_test_type(const char *test_s, DriverDynamic *dd);
void checked_add_vif_combinable(const char *vif_range_s, FieldMatcher *fm, DriverDynamic *dd);
const char *line = "-------------------------------------------------------------------------------";
@ -59,12 +64,12 @@ bool DriverDynamic::load(DriverInfo *di, const string &file_name, const char *co
if (!content)
{
ok = xmqParseFile(doc, file.c_str(), NULL);
ok = xmqParseFile(doc, file.c_str(), NULL, 0);
}
else
{
file = "builtin";
ok = xmqParseBuffer(doc, content, content+strlen(content), NULL);
ok = xmqParseBuffer(doc, content, content+strlen(content), NULL, 0);
}
if (!ok) {
@ -283,6 +288,21 @@ XMQProceed DriverDynamic::add_field(XMQDoc *doc, XMQNode *field, DriverDynamic *
// Check if there were any matches at all, if not, then disable the matcher.
match.active = num_matches > 0;
// Now find all matchers.
Translate::Lookup lookup = Translate::Lookup();
/*
.add(Translate::Rule("ERROR_FLAGS", Translate::Type::BitToString)
.set(MaskBits(0x000f))
.set(DefaultMessage("OK"))
.add(Translate::Map(0x01 ,"DRY", TestBit::Set))
.add(Translate::Map(0x02 ,"REVERSE", TestBit::Set))
.add(Translate::Map(0x04 ,"LEAK", TestBit::Set))
.add(Translate::Map(0x08 ,"BURST", TestBit::Set))
));
*/
dd->tmp_lookup_ = &lookup;
int num_lookups = xmqForeach(doc, field, "lookup", (XMQNodeCallback)add_lookup, dd);
if (is_numeric)
{
if (calculate == "")
@ -326,12 +346,25 @@ XMQProceed DriverDynamic::add_field(XMQDoc *doc, XMQNode *field, DriverDynamic *
}
else
{
dd->addStringFieldWithExtractor(
name,
info,
properties,
match
);
if (num_lookups > 0)
{
dd->addStringFieldWithExtractorAndLookup(
name,
info,
properties,
match,
lookup
);
}
else
{
dd->addStringFieldWithExtractor(
name,
info,
properties,
match
);
}
}
return XMQ_CONTINUE;
}
@ -340,6 +373,8 @@ XMQProceed DriverDynamic::add_match(XMQDoc *doc, XMQNode *match, DriverDynamic *
{
FieldMatcher *fm = dd->tmp_matcher_;
if (checked_set_difvifkey(xmqGetString(doc, match, "difvifkey"), fm, dd)) return XMQ_CONTINUE;
checked_set_measurement_type(xmqGetString(doc, match, "measurement_type"), fm, dd);
checked_set_vif_range(xmqGetString(doc, match, "vif_range"), fm, dd);
@ -360,6 +395,61 @@ XMQProceed DriverDynamic::add_combinable(XMQDoc *doc, XMQNode *match, DriverDyna
return XMQ_CONTINUE;
}
/**
add_map:
Add a mapping from a value (bits,index,decimal) to a string name.
map {
name = SURGE
info = 'Unexpected increase in pressure in relation to average pressure.'
value = 0x02
test = set
}
*/
XMQProceed DriverDynamic::add_map(XMQDoc *doc, XMQNode *map, DriverDynamic *dd)
{
const char *name = xmqGetString(doc, map, "name");
uint64_t value = checked_value(xmqGetString(doc, map, "value"), dd);
TestBit test_type = checked_test_type(xmqGetString(doc, map, "test"), dd);
dd->tmp_rule_->add(Translate::Map(value, name, test_type));
return XMQ_CONTINUE;
}
/**
add_lookup:
Add a lookup from bits,index or decimal to a sequence of string tokens.
Or fallback to the name (ERROR_FLAGS_8) suffixed by the untranslateable bits.
lookup {
name = ERROR_FLAGS
map_type = BitToString
mask_bits = 0xffff
default_message = OK
map { } map {}
}
*/
XMQProceed DriverDynamic::add_lookup(XMQDoc *doc, XMQNode *lookup, DriverDynamic *dd)
{
const char *name = xmqGetString(doc, lookup, "name");
Translate::MapType map_type = checked_map_type(xmqGetString(doc, lookup, "map_type"), dd);
uint64_t mask_bits = checked_mask_bits(xmqGetString(doc, lookup, "mask_bits"), dd);
const char *default_message = xmqGetString(doc, lookup, "default_message");
Translate::Rule rule = Translate::Rule(name, map_type);
dd->tmp_rule_ = &rule;
rule.set(MaskBits(mask_bits));
rule.set(DefaultMessage(default_message));
xmqForeach(doc, lookup, "map", (XMQNodeCallback)add_map, dd);
dd->tmp_lookup_->add(rule);
return XMQ_CONTINUE;
}
string check_driver_name(const char *name, string file)
{
if (!name)
@ -623,6 +713,31 @@ Unit check_display_unit(const char *display_unit_s, DriverDynamic *dd)
return u;
}
bool checked_set_difvifkey(const char *difvifkey_s, FieldMatcher *fm, DriverDynamic *dd)
{
if (!difvifkey_s) return false;
bool invalid_hex = false;
bool hex = isHexStringStrict(difvifkey_s, &invalid_hex);
if (!hex || invalid_hex)
{
warning("(driver) error in %s, bad divfikey: %s\n"
"%s\n"
"Should be all hex.\n"
"%s\n",
dd->fileName().c_str(),
difvifkey_s,
line,
line);
throw 1;
}
fm->set(DifVifKey(difvifkey_s));
return true;
}
void checked_set_measurement_type(const char *measurement_type_s, FieldMatcher *fm, DriverDynamic *dd)
{
if (!measurement_type_s)
@ -757,3 +872,118 @@ void checked_add_vif_combinable(const char *vif_combinable_s, FieldMatcher *fm,
fm->add(vif_combinable);
}
Translate::MapType checked_map_type(const char *map_type_s, DriverDynamic *dd)
{
if (!map_type_s)
{
warning("(driver) error in %s, cannot find: driver/field/lookup/map_type\n"
"%s\n"
"Remember to add for example: lookup { map_type = BitToString ... }\n"
"Available map types:\n"
"BitToString\n"
"IndexToString\n"
"DecimalsToString\n"
"%s\n",
dd->fileName().c_str(),
line,
line);
throw 1;
}
Translate::MapType map_type = toMapType(map_type_s);
if (map_type == Translate::MapType::Unknown)
{
warning("(driver) error in %s, bad map_type: %s\n"
"%s\n"
"Available map types:\n"
"BitToString\n"
"IndexToString\n"
"DecimalToString\n"
"%s\n",
dd->fileName().c_str(),
map_type_s,
line,
line);
throw 1;
}
return map_type;
}
uint64_t checked_mask_bits(const char *mask_bits_s, DriverDynamic *dd)
{
if (!mask_bits_s)
{
warning("(driver) error in %s, cannot find: driver/field/lookup/mask_bitse\n"
"%s\n"
"Remember to add for example: lookup { mask_bits = 0x00ff ... }\n"
"%s\n",
dd->fileName().c_str(),
line,
line);
throw 1;
}
uint64_t mask = strtol(mask_bits_s, NULL, 16);
return mask;
}
uint64_t checked_value(const char *value_s, DriverDynamic *dd)
{
if (!value_s)
{
warning("(driver) error in %s, cannot find: driver/field/lookup/map/value\n"
"%s\n"
"Remember to add for example: lookup { map { ... value = 0x01 ... }}\n"
"%s\n",
dd->fileName().c_str(),
line,
line);
throw 1;
}
uint64_t value = strtol(value_s, NULL, 16);
return value;
}
TestBit checked_test_type(const char *test_s, DriverDynamic *dd)
{
if (!test_s)
{
warning("(driver) error in %s, cannot find: driver/field/lookup/map/test\n"
"%s\n"
"Remember to add for example: lookup { map { test = Set } }\n"
"Available test types:\n"
"Set\n"
"NotSet\n"
"%s\n",
dd->fileName().c_str(),
line,
line);
throw 1;
}
TestBit test_type = toTestBit(test_s);
if (test_type == TestBit::Unknown)
{
warning("(driver) error in %s, bad test: %s\n"
"%s\n"
"Available test types:\n"
"Set\n"
"NotSet\n"
"%s\n",
dd->fileName().c_str(),
test_s,
line,
line);
throw 1;
}
return test_type;
}

Wyświetl plik

@ -1,5 +1,5 @@
/*
Copyright (C) 2023 Fredrik Öhrström (gpl-3.0-or-later)
Copyright (C) 2023-2024 Fredrik Öhrström (gpl-3.0-or-later)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -31,12 +31,17 @@ struct DriverDynamic : public virtual MeterCommonImplementation
static XMQProceed add_match(XMQDoc *doc, XMQNode *match, DriverDynamic *dd);
static XMQProceed add_combinable(XMQDoc *doc, XMQNode *match, DriverDynamic *dd);
static XMQProceed add_lookup(XMQDoc *doc, XMQNode *lookup, DriverDynamic *dd);
static XMQProceed add_map(XMQDoc *doc, XMQNode *map, DriverDynamic *dd);
const string &fileName() { return file_name_; }
private:
string file_name_;
FieldMatcher *tmp_matcher_;
Translate::Lookup *tmp_lookup_;
Translate::Rule *tmp_rule_;
};
#endif

Wyświetl plik

@ -38,7 +38,7 @@ namespace
{
setMfctTPLStatusBits(
Translate::Lookup()
.add(Translate::Rule("TPL_STS", Translate::Type::BitToString)
.add(Translate::Rule("TPL_STS", Translate::MapType::BitToString)
.set(MaskBits(0xe0))
.set(DefaultMessage("OK"))
.add(Translate::Map(0x04 ,"RTC_INVALID", TestBit::Set))));
@ -54,7 +54,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{
@ -208,7 +208,7 @@ namespace
{
{
"DUST",
Translate::Type::IndexToString,
Translate::MapType::IndexToString,
AlwaysTrigger, MaskBits(0x1f),
"",
{
@ -228,7 +228,7 @@ namespace
{
{
"BATTERY_VOLTAGE",
Translate::Type::IndexToString,
Translate::MapType::IndexToString,
AlwaysTrigger, MaskBits(0x0f00),
"",
{
@ -267,7 +267,7 @@ namespace
{
{
"OBSTACLE_DISTANCE",
Translate::Type::IndexToString,
Translate::MapType::IndexToString,
AlwaysTrigger, MaskBits(0x700000),
"",
{
@ -297,7 +297,7 @@ namespace
{
{
"HEAD_STATUS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xff8ff0e0),
"OK",
{

Wyświetl plik

@ -45,7 +45,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffffffff),
"OK",
{

Wyświetl plik

@ -53,7 +53,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xff),
"OK",
{
@ -80,7 +80,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xff),
"",
{

Wyświetl plik

@ -46,7 +46,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xff),
"OK",
{

Wyświetl plik

@ -50,7 +50,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{
@ -78,7 +78,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{

Wyświetl plik

@ -49,7 +49,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{

Wyświetl plik

@ -51,7 +51,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffffffff),
"OK",
{
@ -216,7 +216,7 @@ namespace
{
{
"DRY",
Translate::Type::IndexToString,
Translate::MapType::IndexToString,
AlwaysTrigger, MaskBits(0x0070),
"",
{
@ -243,7 +243,7 @@ namespace
{
{
"REVERSED",
Translate::Type::IndexToString,
Translate::MapType::IndexToString,
AlwaysTrigger, MaskBits(0x0380),
"",
{
@ -270,7 +270,7 @@ namespace
{
{
"LEAKING",
Translate::Type::IndexToString,
Translate::MapType::IndexToString,
AlwaysTrigger, MaskBits(0x1c00),
"",
{
@ -297,7 +297,7 @@ namespace
{
{
"BURSTING",
Translate::Type::IndexToString,
Translate::MapType::IndexToString,
AlwaysTrigger, MaskBits(0xe000),
"",
{

Wyświetl plik

@ -70,7 +70,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger,
AutoMask,
"OK",
@ -85,7 +85,7 @@ namespace
},
{
"ERROR_FLAGS_SINGLE_PHASE",
Translate::Type::BitToString,
Translate::MapType::BitToString,
TriggerBits(0x01020000),
AutoMask,
"OK",
@ -99,7 +99,7 @@ namespace
},
{
"ERROR_FLAGS_THREE_PHASE",
Translate::Type::BitToString,
Translate::MapType::BitToString,
TriggerBits(0x01010000),
AutoMask,
"OK",
@ -124,7 +124,7 @@ namespace
{
{
"INFO_FLAGS",
Translate::Type::IndexToString,
Translate::MapType::IndexToString,
AlwaysTrigger,
AutoMask,
"",

Wyświetl plik

@ -49,7 +49,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{

Wyświetl plik

@ -39,7 +39,7 @@ namespace
{
setMfctTPLStatusBits(
Translate::Lookup()
.add(Translate::Rule("TPL_STS", Translate::Type::BitToString)
.add(Translate::Rule("TPL_STS", Translate::MapType::BitToString)
.set(MaskBits(0xe0))
.set(DefaultMessage("OK"))
.add(Translate::Map(0x80 ,"SABOTAGE_ENCLOSURE", TestBit::Set))));

Wyświetl plik

@ -53,7 +53,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(VIFRange::ErrorFlags),
Translate::Lookup()
.add(Translate::Rule("ERROR_FLAGS", Translate::Type::IndexToString)
.add(Translate::Rule("ERROR_FLAGS", Translate::MapType::IndexToString)
.set(MaskBits(0xffffff))
.add(Translate::Map(0x000000, "CODE_101_EEPROM_ERROR", TestBit::Set))
.add(Translate::Map(0x000010, "CODE_102_NO_CALIBRATION_TABLE", TestBit::Set))
@ -203,7 +203,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("07FFA600")),
Translate::Lookup()
.add(Translate::Rule("ERROR_FLAGS", Translate::Type::BitToString)
.add(Translate::Rule("ERROR_FLAGS", Translate::MapType::BitToString)
.set(MaskBits(0xffffffffffffffff))
.set(DefaultMessage("OK"))
));
@ -216,7 +216,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("07FFA700")),
Translate::Lookup()
.add(Translate::Rule("WARNING_FLAGS", Translate::Type::BitToString)
.add(Translate::Rule("WARNING_FLAGS", Translate::MapType::BitToString)
.set(MaskBits(0xffffffffffffffff))
.set(DefaultMessage("OK"))
));
@ -229,7 +229,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("07FFA800")),
Translate::Lookup()
.add(Translate::Rule("INFORMATION_FLAGS", Translate::Type::BitToString)
.add(Translate::Rule("INFORMATION_FLAGS", Translate::MapType::BitToString)
.set(MaskBits(0xffffffffffffffff))
.set(DefaultMessage(""))
));
@ -242,7 +242,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("07FFA900")),
Translate::Lookup()
.add(Translate::Rule("ALARM_FLAGS", Translate::Type::BitToString)
.add(Translate::Rule("ALARM_FLAGS", Translate::MapType::BitToString)
.set(MaskBits(0xfffffffffffffff))
.set(DefaultMessage("OK"))
));
@ -255,7 +255,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("01FFAD00")),
Translate::Lookup()
.add(Translate::Rule("UNKNOWN", Translate::Type::BitToString)
.add(Translate::Rule("UNKNOWN", Translate::MapType::BitToString)
.set(MaskBits(0xff))
.set(DefaultMessage("OK"))
));
@ -1407,7 +1407,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(VIFRange::DigitalInput),
Translate::Lookup()
.add(Translate::Rule("INPUT", Translate::Type::BitToString)
.add(Translate::Rule("INPUT", Translate::MapType::BitToString)
.set(MaskBits(0xffffff))
));
@ -1419,7 +1419,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("02FF32")),
Translate::Lookup()
.add(Translate::Rule("INPUT_STATUS", Translate::Type::BitToString)
.add(Translate::Rule("INPUT_STATUS", Translate::MapType::BitToString)
.set(MaskBits(0xff))
));
@ -1431,7 +1431,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(VIFRange::DigitalOutput),
Translate::Lookup()
.add(Translate::Rule("OUTPUT", Translate::Type::BitToString)
.add(Translate::Rule("OUTPUT", Translate::MapType::BitToString)
.set(MaskBits(0xffffff))
));
@ -1443,7 +1443,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("03FF2D")),
Translate::Lookup()
.add(Translate::Rule("OUTPUT_ASSOCIATION", Translate::Type::BitToString)
.add(Translate::Rule("OUTPUT_ASSOCIATION", Translate::MapType::BitToString)
.set(MaskBits(0xffffff))
));
@ -1455,7 +1455,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("03FF30")),
Translate::Lookup()
.add(Translate::Rule("INPUT_ASSOCIATION", Translate::Type::BitToString)
.add(Translate::Rule("INPUT_ASSOCIATION", Translate::MapType::BitToString)
.set(MaskBits(0xffffff))
));
@ -1467,7 +1467,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey( "02FF36")),
Translate::Lookup()
.add(Translate::Rule("OUTPUT_ASSOCIATION", Translate::Type::BitToString)
.add(Translate::Rule("OUTPUT_ASSOCIATION", Translate::MapType::BitToString)
.set(MaskBits(0xffff))
));
@ -1479,7 +1479,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("02FF34")),
Translate::Lookup()
.add(Translate::Rule("OVERLOAD_ALARM", Translate::Type::BitToString)
.add(Translate::Rule("OVERLOAD_ALARM", Translate::MapType::BitToString)
.set(MaskBits(0xff))
));
@ -1500,7 +1500,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("02FF37")),
Translate::Lookup()
.add(Translate::Rule("ACTIVATED_STATUS", Translate::Type::BitToString)
.add(Translate::Rule("ACTIVATED_STATUS", Translate::MapType::BitToString)
.set(MaskBits(0xff))
));
@ -1512,7 +1512,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("02FF38")),
Translate::Lookup()
.add(Translate::Rule("UNACK_STATUS", Translate::Type::BitToString)
.add(Translate::Rule("UNACK_STATUS", Translate::MapType::BitToString)
.set(MaskBits(0xff))
));
@ -1643,7 +1643,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("03FF23")),
Translate::Lookup()
.add(Translate::Rule("POWER_SYS_CONFIG", Translate::Type::BitToString)
.add(Translate::Rule("POWER_SYS_CONFIG", Translate::MapType::BitToString)
.set(MaskBits(0xffffff))
));

Wyświetl plik

@ -60,7 +60,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffffff),
"OK",
{
@ -102,7 +102,7 @@ namespace
{
{
"WOOTA",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffffffff),
"",
{
@ -122,7 +122,7 @@ namespace
{
{
"WOOTB",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"",
{
@ -156,4 +156,3 @@ namespace
// telegram=|3A4497269820362300167AF60020A52F2F_04132E100000066D03260DE12B007413FEFEFEFE426C1F01047F1600060C027F9A2A0E79187103002300|
// {"enhanced_id": "002300037118", "id": "23362098", "media": "cold water", "meter": "itron", "meter_datetime": "2023-11-01 13:38:03", "name": "ColdWaterMeter", "status": "OK", "target_date": "2000-01-31", "timestamp": "1111-11-11T11:11:11Z", "total_m3": 4.142,"unknown_a": "WOOTA_C060016","unknown_b": "WOOTB_2A9A" }
// |ColdWaterMeter;23362098;4.142;null;1111-11-11 11:11.11

Wyświetl plik

@ -74,7 +74,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffffffff),
"OK",
{

Wyświetl plik

@ -1,130 +0,0 @@
/*
Copyright (C) 2022 Fredrik Öhrström (gpl-3.0-or-later)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include"meters_common_implementation.h"
namespace
{
struct Driver : public virtual MeterCommonImplementation
{
Driver(MeterInfo &mi, DriverInfo &di);
};
static bool ok = registerDriver([](DriverInfo&di)
{
di.setName("kampress");
di.setDefaultFields("name,id,status,pressure_bar,max_pressure_bar,min_pressure_bar,timestamp");
di.setMeterType(MeterType::PressureSensor);
di.addLinkMode(LinkMode::C1);
di.addDetection(MANUFACTURER_KAM, 0x18, 0x01);
di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr<Meter>(new Driver(mi, di)); });
});
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
{
addStringFieldWithExtractorAndLookup(
"status",
"Status and error flags.",
DEFAULT_PRINT_PROPERTIES | INCLUDE_TPL_STATUS,
FieldMatcher::build()
.set(VIFRange::ErrorFlags),
{
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{
{ 0x01, "DROP" }, // Unexpected drop in pressure in relation to average pressure.
{ 0x02, "SURGE" }, // Unexpected increase in pressure in relation to average pressure.
{ 0x04, "HIGH" }, // Average pressure has reached configurable limit. Default 15 bar
{ 0x08, "LOW" }, // Average pressure has reached configurable limit. Default 1.5 bar
{ 0x10, "TRANSIENT" }, // Pressure changes quickly over short timeperiods. Average is fluctuating.
{ 0x20, "COMM_ERROR" } // Cannot measure properly or bad internal communication.
}
},
},
});
addNumericFieldWithExtractor(
"pressure",
"The measured pressure.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Pressure,
VifScaling::Auto,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Pressure)
);
addNumericFieldWithExtractor(
"max_pressure",
"The maximum pressure measured during ?.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Pressure,
VifScaling::Auto,
FieldMatcher::build()
.set(MeasurementType::Maximum)
.set(VIFRange::Pressure)
);
addNumericFieldWithExtractor(
"min_pressure",
"The minimum pressure measured during ?.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Pressure,
VifScaling::Auto,
FieldMatcher::build()
.set(MeasurementType::Minimum)
.set(VIFRange::Pressure)
);
addNumericFieldWithExtractor(
"alfa",
"We do not know what this is.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
FieldMatcher::build()
.set(DifVifKey("05FF09"))
);
addNumericFieldWithExtractor(
"beta",
"We do not know what this is.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
FieldMatcher::build()
.set(DifVifKey("05FF0A"))
);
}
}
// Test: Pressing kampress 77000317 NOKEY
// telegram=|32442D2C1703007701188D280080E39322DB8F78_22696600126967000269660005FF091954A33A05FF0A99BD823A02FD170800|
// {"media":"pressure","meter":"kampress","name":"Pressing","id":"77000317","status":"LOW","pressure_bar":1.02,"max_pressure_bar":1.03,"min_pressure_bar":1.02,"alfa_counter":0.001246,"beta_counter":0.000997,"timestamp":"1111-11-11T11:11:11Z"}
// |Pressing;77000317;LOW;1.02;1.03;1.02;1111-11-11 11:11.11
// telegram=|27442D2C1703007701188D280194E393226EC679DE735657_660067006600962B913A21B9423A0800|
// {"media":"pressure","meter":"kampress","name":"Pressing","id":"77000317","status":"LOW","pressure_bar":1.02,"max_pressure_bar":1.03,"min_pressure_bar":1.02,"alfa_counter":0.001108,"beta_counter":0.000743,"timestamp":"1111-11-11T11:11:11Z"}
// |Pressing;77000317;LOW;1.02;1.03;1.02;1111-11-11 11:11.11
// telegram=|27442D2C1703007701188D289554F295224ED579DE73188A_650066006600E80EA43A6B97A3BA0800|
// {"media":"pressure","meter":"kampress","name":"Pressing","id":"77000317","status":"LOW","pressure_bar":1.02,"max_pressure_bar":1.02,"min_pressure_bar":1.01,"alfa_counter":0.001252,"beta_counter":-0.001248,"timestamp":"1111-11-11T11:11:11Z"}
// |Pressing;77000317;LOW;1.02;1.02;1.01;1111-11-11 11:11.11

Wyświetl plik

@ -44,7 +44,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(VIFRange::DigitalInput),
Translate::Lookup()
.add(Translate::Rule("INPUT_BITS", Translate::Type::IndexToString)
.add(Translate::Rule("INPUT_BITS", Translate::MapType::IndexToString)
.set(MaskBits(0xffff))
.add(Translate::Map(0x11 ,"CLOSED", TestBit::Set))
.add(Translate::Map(0x55 ,"OPEN", TestBit::Set))
@ -58,7 +58,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(VIFRange::ErrorFlags),
Translate::Lookup()
.add(Translate::Rule("ERROR_FLAGS", Translate::Type::BitToString)
.add(Translate::Rule("ERROR_FLAGS", Translate::MapType::BitToString)
.set(MaskBits(0xffff))
.set(DefaultMessage("OK"))
));

Wyświetl plik

@ -39,7 +39,7 @@ namespace
{
setMfctTPLStatusBits(
Translate::Lookup()
.add(Translate::Rule("TPL_STS", Translate::Type::BitToString)
.add(Translate::Rule("TPL_STS", Translate::MapType::BitToString)
.set(MaskBits(0xe0))
.set(DefaultMessage("OK"))
.add(Translate::Map(0x40 ,"SABOTAGE_ENCLOSURE", TestBit::Set))));

Wyświetl plik

@ -40,7 +40,7 @@ namespace
{
setMfctTPLStatusBits(
Translate::Lookup()
.add(Translate::Rule("TPL_STS", Translate::Type::BitToString)
.add(Translate::Rule("TPL_STS", Translate::MapType::BitToString)
.set(MaskBits(0xe0))
.set(DefaultMessage("OK"))
.add(Translate::Map(0x04 ,"LOW_BATTERY", TestBit::Set))));
@ -92,7 +92,7 @@ namespace
.set(VIFRange::Dimensionless)
.set(SubUnitNr(2)),
Translate::Lookup()
.add(Translate::Rule("INPUT_BITS", Translate::Type::IndexToString)
.add(Translate::Rule("INPUT_BITS", Translate::MapType::IndexToString)
.set(MaskBits(0x01))
.add(Translate::Map(0x00, "NO", TestBit::Set))
.add(Translate::Map(0x01, "YES", TestBit::Set))
@ -143,7 +143,7 @@ namespace
.set(VIFRange::Dimensionless)
.set(StorageNr(3)),
Translate::Lookup()
.add(Translate::Rule("INPUT_BITS", Translate::Type::BitToString)
.add(Translate::Rule("INPUT_BITS", Translate::MapType::BitToString)
.set(MaskBits(0xffff))
.add(Translate::Map(0x01 ,"SU", TestBit::Set))
.add(Translate::Map(0x02 ,"MO", TestBit::Set))

Wyświetl plik

@ -49,7 +49,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{

Wyświetl plik

@ -39,7 +39,7 @@ namespace
addOptionalLibraryFields("on_time_h");
setMfctTPLStatusBits(
Translate::Lookup()
.add(Translate::Rule("TPL_STS", Translate::Type::BitToString)
.add(Translate::Rule("TPL_STS", Translate::MapType::BitToString)
.set(MaskBits(0xe0))
.set(DefaultMessage("OK"))
.add(Translate::Map(0x40 ,"SABOTAGE_ENCLOSURE", TestBit::Set))));

Wyświetl plik

@ -105,7 +105,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{

Wyświetl plik

@ -51,7 +51,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xff),
"OK",
{

Wyświetl plik

@ -52,7 +52,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{

Wyświetl plik

@ -130,7 +130,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{

Wyświetl plik

@ -46,7 +46,7 @@ namespace
FieldMatcher::build()
.set(DifVifKey("02FF20")),
Translate::Lookup()
.add(Translate::Rule("ERROR_FLAGS", Translate::Type::BitToString)
.add(Translate::Rule("ERROR_FLAGS", Translate::MapType::BitToString)
.set(MaskBits(0x000f))
.set(DefaultMessage("OK"))
.add(Translate::Map(0x01 ,"DRY", TestBit::Set))
@ -136,7 +136,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0x000f),
"",
{
@ -159,7 +159,7 @@ namespace
{
{
"DRY",
Translate::Type::IndexToString,
Translate::MapType::IndexToString,
AlwaysTrigger, MaskBits(0x0070),
"",
{
@ -186,7 +186,7 @@ namespace
{
{
"REVERSED",
Translate::Type::IndexToString,
Translate::MapType::IndexToString,
AlwaysTrigger, MaskBits(0x0380),
"",
{
@ -213,7 +213,7 @@ namespace
{
{
"LEAKING",
Translate::Type::IndexToString,
Translate::MapType::IndexToString,
AlwaysTrigger, MaskBits(0x1c00),
"",
{
@ -240,7 +240,7 @@ namespace
{
{
"BURSTING",
Translate::Type::IndexToString,
Translate::MapType::IndexToString,
AlwaysTrigger, MaskBits(0xe000),
"",
{

Wyświetl plik

@ -47,7 +47,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{

Wyświetl plik

@ -174,7 +174,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(VIFRange::ErrorFlags),
Translate::Lookup()
.add(Translate::Rule("ERROR_FLAGS", Translate::Type::BitToString)
.add(Translate::Rule("ERROR_FLAGS", Translate::MapType::BitToString)
.set(MaskBits(0xff))
.set(DefaultMessage("OK"))
));

Wyświetl plik

@ -59,7 +59,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xff),
"OK",
{

Wyświetl plik

@ -54,7 +54,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{

Wyświetl plik

@ -49,7 +49,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{

Wyświetl plik

@ -53,7 +53,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffffffff),
"OK",
{

Wyświetl plik

@ -155,7 +155,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xff),
"OK",
{

Wyświetl plik

@ -51,7 +51,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(VIFRange::ErrorFlags),
Translate::Lookup()
.add(Translate::Rule("ERROR_FLAGS", Translate::Type::BitToString)
.add(Translate::Rule("ERROR_FLAGS", Translate::MapType::BitToString)
.set(MaskBits(0x0000))
.set(DefaultMessage("OK"))
));

Wyświetl plik

@ -48,7 +48,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(VIFRange::ErrorFlags),
Translate::Lookup()
.add(Translate::Rule("ERROR_FLAGS", Translate::Type::BitToString)
.add(Translate::Rule("ERROR_FLAGS", Translate::MapType::BitToString)
.set(MaskBits(0x000f))
.set(DefaultMessage("OK"))
));

Wyświetl plik

@ -114,7 +114,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{

Wyświetl plik

@ -68,7 +68,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffffff),
"OK",
{

Wyświetl plik

@ -49,7 +49,7 @@ namespace
{
{
"STATUS_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{
@ -68,7 +68,7 @@ namespace
{
{
"OTHER_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xff),
"",
{

Wyświetl plik

@ -52,7 +52,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{
@ -114,7 +114,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{

Wyświetl plik

@ -48,7 +48,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{

Wyświetl plik

@ -15,12 +15,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Generated 2024-02-12_01:46
// Generated 2024-04-04_20:51
BuiltinDriver builtins_[] =
{
{ "elster", "driver{name=elster meter_type=GasMeter default_fields=name,id,total_m3,timestamp detect{mvt=ELS,81,03}use=actuality_duration_s field{name=total quantity=Volume match{measurement_type=Instantaneous vif_range=Volume}about{de='Der Gesamtwasserverbrauch.'en='The total water consumption.'fr='''La consommation totale d'eau.'''sv='Den totala vattenförbrukningen.'}}}", false },
{ "iperl", "driver{name=iperl meter_type=WaterMeter default_fields=name,id,total_m3,max_flow_m3h,timestamp detect{mvt=SEN,68,06 mvt=SEN,68,07 mvt=SEN,7c,07}field{name=total quantity=Volume match{measurement_type=Instantaneous vif_range=Volume}about{de='Der Gesamtwasserverbrauch.'en='The total water consumption.'fr='''La consommation totale d'eau.'''sv='Den totala vattenförbrukningen.'}}field{name=max_flow quantity=Flow match{measurement_type=Instantaneous vif_range=VolumeFlow}about{en='The maximum flow recorded during previous period.'}}}", false },
{ "kampress", "driver{name=kampress default_fields=name,id,status,pressure_bar,max_pressure_bar,min_pressure_bar,timestamp meter_type=PressureSensor detect{mvt=KAM,01,18}field{name=status quantity=Text info=status_and_error_flags match{measurement_type=Instantaneous vif_range=ErrorFlags}lookup{name=ERROR_FLAGS map_type=BitToString mask_bits=0xffff default_message=OK map{name=DROP info='Unexpected drop in pressure in relation to average pressure.'value=0x01 test=Set}map{name=SURGE info='Unexpected increase in pressure in relation to average pressure.'value=0x02 test=Set}map{name=HIGH info='Average pressure has reached configurable limit. Default 15 bar.'value=0x04 test=Set}map{name=LOW info='Average pressure has reached configurable limit. Default 1.5 bar.'value=0x08 test=Set}map{name=TRANSIENT info='Pressure changes quickly over short timeperiods. Average is fluctuating.'value=0x10 test=Set}map{name=COMM_ERROR info='Cannot measure properly or bad internal communication.'value=0x20 test=Set}}}field{name=pressure quantity=Pressure info='The measured pressure.'match{measurement_type=Instantaneous vif_range=Pressure}}field{name=max_pressure quantity=Pressure info='The maximum pressure measured during ?'match{measurement_type=Maximum vif_range=Pressure}}field{name=min_pressure quantity=Pressure info='The minimum pressure measured during ?'match{measurement_type=Minimum vif_range=Pressure}}field{name=alfa info='We do not know what this is.'quantity=Dimensionless vif_scaling=None match{difvifkey=05FF09}}field{name=beta info='We do not know what this is.'quantity=Dimensionless vif_scaling=None match{difvifkey=05FF0A}}}", false },
{ "werhlemodwm", "driver{name=werhlemodwm meter_type=WaterMeter default_fields=name,id,total_m3,timestamp detect{mvt=WZG,03,16}use=meter_datetime use=target_date use=target_m3 use=total_m3 use=fabrication_no field{name=next_target quantity=PointInTime display_unit=date match{measurement_type=Instantaneous vif_range=Date add_combinable=FutureValue storage_nr=1}}}", false },
};
MapToDriver builtins_mvts_[] =
@ -29,4 +31,6 @@ MapToDriver builtins_mvts_[] =
{ { MANUFACTURER_SEN,0x68,0x06 }, "iperl" },
{ { MANUFACTURER_SEN,0x68,0x07 }, "iperl" },
{ { MANUFACTURER_SEN,0x7c,0x07 }, "iperl" },
{ { MANUFACTURER_KAM,0x01,0x18 }, "kampress" },
{ { MANUFACTURER_WZG,0x03,0x16 }, "werhlemodwm" },
};

Wyświetl plik

@ -207,6 +207,7 @@ string loadDriver(const string &file, const char *content)
{
DriverInfo di;
debug("(meter) loading %s\n", file.c_str());
bool ok = DriverDynamic::load(&di, file, content);
if (!ok)
{
@ -217,8 +218,15 @@ string loadDriver(const string &file, const char *content)
DriverInfo *old = lookupDriver(di.name().str());
if (old != NULL)
{
debug("(meter) overriding %s\n", di.name().str().c_str());
if (old->getDynamicFileName() != "")
{
if (di.getDynamicFileName() == old->getDynamicFileName())
{
// Loading same file again, happens when using analyze. This is fine.
return di.name().str();
}
// New file source registering the same driver name, nono.
error("Newly loaded driver file %s tries to register the same name %s as driver file %s has already taken!\n",
file.c_str(), di.name().str().c_str(), old->getDynamicFileName().c_str());
}

Wyświetl plik

@ -1383,13 +1383,13 @@ void test_translate()
{
Translate::Lookup lookup1 =
Translate::Lookup()
.add(Translate::Rule("ACCESS_BITS", Translate::Type::BitToString)
.add(Translate::Rule("ACCESS_BITS", Translate::MapType::BitToString)
.set(MaskBits(0xf0))
.add(Translate::Map(0x10, "NO_ACCESS", TestBit::Set))
.add(Translate::Map(0x20, "ALL_ACCESS", TestBit::Set))
.add(Translate::Map(0x40, "TEMP_ACCESS", TestBit::Set))
)
.add(Translate::Rule("ACCESSOR_TYPE", Translate::Type::IndexToString)
.add(Translate::Rule("ACCESSOR_TYPE", Translate::MapType::IndexToString)
.set(MaskBits(0x0f))
.add(Translate::Map(0x00, "ACCESSOR_RED", TestBit::Set))
.add(Translate::Map(0x07, "ACCESSOR_GREEN", TestBit::Set))
@ -1401,7 +1401,7 @@ void test_translate()
{
{
"FLOW_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger,
MaskBits(0x3f),
"OOOK",
@ -1420,7 +1420,7 @@ void test_translate()
{
{
"NO_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger,
MaskBits(0x03),
"OK",

Wyświetl plik

@ -19,6 +19,7 @@
#include"util.h"
#include<assert.h>
#include<string.h>
using namespace Translate;
using namespace std;
@ -210,15 +211,15 @@ void handleRule(Rule& rule, string &s, uint64_t bits)
{
switch (rule.type)
{
case Type::BitToString:
case MapType::BitToString:
handleBitToString(rule, s, bits);
break;
case Type::IndexToString:
case MapType::IndexToString:
handleIndexToString(rule, s, bits);
break;
case Type::DecimalsToString:
case MapType::DecimalsToString:
handleDecimalsToString(rule, s, bits);
break;
@ -259,11 +260,19 @@ string Lookup::str()
return x;
}
Translate::MapType toMapType(const char *s)
{
if (!strcmp(s, "BitToString")) return Translate::MapType::BitToString;
if (!strcmp(s, "IndexToString")) return Translate::MapType::IndexToString;
if (!strcmp(s, "DecimalsToString")) return Translate::MapType::DecimalsToString;
return Translate::MapType::Unknown;
}
Lookup NoLookup = {};
Map m = { 123, "howdy" };
vector<Map> vm = { { 123, "howdy" } };
Rule r = { "name", Translate::Type::IndexToString,
Rule r = { "name", Translate::MapType::IndexToString,
AlwaysTrigger, MaskBits(0xe000), "", { } };

Wyświetl plik

@ -66,8 +66,9 @@ private:
namespace Translate
{
enum class Type
enum class MapType
{
Unknown,
BitToString, // A bit translates to a text string.
IndexToString, // A masked set of bits (a number) translates to a lookup index with text strings.
DecimalsToString // Numbers are successively subtracted from input, each successfull subtraction translate into a text string.
@ -86,16 +87,16 @@ namespace Translate
struct Rule
{
std::string name;
Type type;
MapType type;
TriggerBits trigger; // Bits that must be set.
MaskBits mask; // Bits to be used are set as 1.
DefaultMessage default_message; // If no bits are set print this, typically "OK" or "".
std::vector<Map> map;
Rule() {};
Rule(std::string n, Type t, TriggerBits tr, MaskBits mb, std::string dm, std::vector<Map> m)
Rule(std::string n, MapType t, TriggerBits tr, MaskBits mb, std::string dm, std::vector<Map> m)
: name(n), type(t), trigger(tr), mask(mb), default_message(dm), map(m) {}
Rule(std::string n, Type t) :
Rule(std::string n, MapType t) :
name(n), type(t), trigger(AlwaysTrigger), mask(AutoMask), default_message(DefaultMessage("")) {}
Rule &set(TriggerBits t) { trigger = t; return *this; }
Rule &set(MaskBits m) { mask = m; return *this; }
@ -116,6 +117,8 @@ namespace Translate
};
};
Translate::MapType toMapType(const char *s);
extern Translate::Lookup NoLookup;
#endif

Wyświetl plik

@ -2227,3 +2227,10 @@ const std::string &language()
return lang_;
}
TestBit toTestBit(const char *s)
{
if (!strcmp(s, "Set")) return TestBit::Set;
if (!strcmp(s, "NotSet")) return TestBit::NotSet;
return TestBit::Unknown;
}

Wyświetl plik

@ -42,6 +42,7 @@ typedef unsigned char uchar;
enum class TestBit
{
Unknown,
Set,
NotSet
};
@ -305,6 +306,8 @@ bool is_lowercase_alnum_text(const char *text);
// The language that the user expects driver and other messages in.
const std::string &language();
TestBit toTestBit(const char *s);
#ifndef FUZZING
#define FUZZING false
#endif

603
src/xmq.c

Plik diff jest za duży Load Diff

Wyświetl plik

@ -1,4 +1,4 @@
/* libxmq - Copyright (C) 2023 Fredrik Öhrström (spdx: MIT)
/* libxmq - Copyright (C) 2023-2024 Fredrik Öhrström (spdx: MIT)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -124,25 +124,34 @@ typedef enum
} XMQRenderFormat;
/**
XMQTrimType:
@XMQ_TRIM_DEFAULT: Use the default, ie no-trim for xmq/json, normal-trim for xml/html.
@XMQ_TRIM_NONE: Do not trim at all. Keep unnecessary xml/html indentation and newlines.
@XMQ_TRIM_HEURISTIC: Normal trim heuristic. Remove leading/ending whitespace, remove incidental indentation.
@XMQ_TRIM_EXTRA: Like normal but remove all indentation (not just incidental) and collapse whitespace.
@XMQ_TRIM_RESHUFFLE: Like extra but also reflow all content at word boundaries to limit line lengths.
XMQFlagBits:
@XMQ_FLAG_TRIM_NONE: Do not trim any whitespace.
@XMQ_FLAG_TRIM_HEURISTIC: Remove leading/ending whitespace, but try to keep significant, remove incidental indentation.
@XMQ_FLAG_TRIM_EXACT: Trim exactly according to XML rules. Depends on your XSD,space:preserve and more and is COMPLICATED!
@XMQ_FLAG_NOMERGE: Do not merge text and character entities.
If a 0 is provided as the flags to the parse functions, then it will parse using the these default settings:
When loading xml/html:
trim the whitespace from the input to generate the most likely desired xmq output.
merge character entities
When loading xmq/htmq:
no trimming but
merge character entities such as &#10; and consecutive text quotes
When loading xml/html trim the whitespace from the input to generate the most likely desired xmq output.
When loading xmq/htmq, the whitespace is never trimmed since xmq explicitly encodes all important whitespace.
If you load xml with XMQ_TRIM_NONE (--trim=none) there will be a lot of unnecessary whitespace stored in
the xmq, like &#32;&#9;&#10; etc.
You can then view the xmq with XMQ_TRIM_HEURISTIC (--trim=heuristic) to drop the whitespace.
If you load xmq with --nomerge then character entities and separate text blocks will be kept as is.
The --nomerge currently does not work for XML/HTML since libxml2 does not have a setting for merge.
*/
typedef enum
{
XMQ_TRIM_DEFAULT = 0,
XMQ_TRIM_NONE = 1,
XMQ_TRIM_HEURISTIC = 2,
} XMQTrimType;
XMQ_FLAG_TRIM_NONE = 1,
XMQ_FLAG_TRIM_HEURISTIC = 2,
XMQ_FLAG_TRIM_EXACT = 4,
XMQ_FLAG_NOMERGE = 8,
} XMQFlagBits;
/**
XMQSyntax:
@ -351,7 +360,7 @@ void xmqFreeParseCallbacks(XMQParseCallbacks *cb);
Used to colorize xmq input, without building a parse tree.
*/
void xmqSetupParseCallbacksColorizeTokens(XMQParseCallbacks *state, XMQRenderFormat render_format, bool dark_mode);
void xmqSetupParseCallbacksColorizeTokens(XMQParseCallbacks *state, XMQRenderFormat render_format);
/**
xmqSetupParseCallbacksDebugTokens:
@ -486,7 +495,7 @@ void xmqFreeDoc(XMQDoc *doc);
Parse a file, or if file is NULL, read from stdin.
*/
bool xmqParseFile(XMQDoc *doc, const char *file, const char *implicit_root);
bool xmqParseFile(XMQDoc *doc, const char *file, const char *implicit_root, int flags);
/**
xmqParseBuffer:
@ -498,7 +507,7 @@ bool xmqParseFile(XMQDoc *doc, const char *file, const char *implicit_root);
Parse a buffer or a file and create a document.
The xmq format permits multiple root nodes if an implicit root is supplied.
*/
bool xmqParseBuffer(XMQDoc *doc, const char *start, const char *stop, const char *implicit_root);
bool xmqParseBuffer(XMQDoc *doc, const char *start, const char *stop, const char *implicit_root, int flags);
/**
xmqParseReader:
@ -509,7 +518,7 @@ bool xmqParseBuffer(XMQDoc *doc, const char *start, const char *stop, const char
Parse data fetched with a reader and create a document.
The xmq format permits multiple root nodes if an implicit root is supplied.
*/
bool xmqParseReader(XMQDoc *doc, XMQReader *reader, const char *implicit_root);
bool xmqParseReader(XMQDoc *doc, XMQReader *reader, const char *implicit_root, int flags);
/** Allocate the print settings structure and zero it. */
XMQOutputSettings *xmqNewOutputSettings();
@ -520,13 +529,14 @@ void xmqFreeOutputSettings(XMQOutputSettings *os);
void xmqSetAddIndent(XMQOutputSettings *os, int add_indent);
void xmqSetCompact(XMQOutputSettings *os, bool compact);
void xmqSetUseColor(XMQOutputSettings *os, bool use_color);
void xmqSetBackgroundMode(XMQOutputSettings *os, bool bg_dark_mode);
void xmqSetEscapeNewlines(XMQOutputSettings *os, bool escape_newlines);
void xmqSetEscapeNon7bit(XMQOutputSettings *os, bool escape_non_7bit);
void xmqSetOutputFormat(XMQOutputSettings *os, XMQContentType output_format);
void xmqSetRenderFormat(XMQOutputSettings *os, XMQRenderFormat render_to);
void xmqSetRenderTheme(XMQOutputSettings *os, const char *theme_name);
void xmqSetRenderRaw(XMQOutputSettings *os, bool render_raw);
void xmqSetRenderOnlyStyle(XMQOutputSettings *os, bool only_style);
void xmqSetRenderStyle(XMQOutputSettings *os, const char *render_style);
void xmqSetWriterContent(XMQOutputSettings *os, XMQWriter content);
void xmqSetWriterError(XMQOutputSettings *os, XMQWriter error);
@ -546,7 +556,7 @@ void xmqSetupPrintMemory(XMQOutputSettings *ps, char **start, char **stop);
void xmqPrint(XMQDoc *doc, XMQOutputSettings *settings);
/** Trim xml whitespace. */
void xmqTrimWhitespace(XMQDoc *doc, XMQTrimType tt);
void xmqTrimWhitespace(XMQDoc *doc, int flags);
/** A parsing error will be described here! */
const char *xmqDocError(XMQDoc *doc);
@ -661,7 +671,7 @@ bool xmqParseBufferWithType(XMQDoc *doc,
const char *stop,
const char *implicit_root,
XMQContentType ct,
XMQTrimType tt);
int flags);
/**
xmqParseFileWithType:
@ -672,14 +682,14 @@ bool xmqParseFileWithType(XMQDoc *doc,
const char *file,
const char *implicit_root,
XMQContentType ct,
XMQTrimType tt);
int flags);
/**
xmqSetupDefaultColors:
Set the default colors for settings based on the background color.
Set the default colors for settings based on the theme and background color.
*/
void xmqSetupDefaultColors(XMQOutputSettings *settings, bool dark_mode);
void xmqSetupDefaultColors(XMQOutputSettings *settings);
/**
xmqOverrideSetting: Change the default strings for spaces etc.

Wyświetl plik

@ -1,4 +1,4 @@
// Generated 2024-02-12_08:58
// Generated 2024-04-04_20:51
test {
args = 'Gas elster 05105025 NOKEY'
telegram = 3644A511640010253837722550100593158103E70020052F2F_0374E602000C137034220302FD74EE0F2F2F2F2F2F2F2F2F2F2F2F2F2F2F
@ -19,3 +19,23 @@ test {
json = '{"media":"water","meter":"iperl","name":"MoreWater","id":"12345699","total_m3":7.704,"max_flow_m3h":0,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'MoreWater;12345699;7.704;0;1111-11-11 11:11.11'
}
test {
args = 'Pressing kampress 77000317 NOKEY'
telegram = '32442D2C1703007701188D280080E39322DB8F78_22696600126967000269660005FF091954A33A05FF0A99BD823A02FD170800
27442D2C1703007701188D289554F295224ED579DE73188A_650066006600E80EA43A6B97A3BA0800'
json = '{"media":"pressure","meter":"kampress","name":"Pressing","id":"77000317","status":"LOW","pressure_bar":1.02,"max_pressure_bar":1.02,"min_pressure_bar":1.01,"alfa_counter":0.001252,"beta_counter":-0.001248,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'Pressing;77000317;LOW;1.02;1.02;1.01;1111-11-11 11:11.11'
}
test {
args = 'Pressing kampress 77000317 NOKEY'
telegram = '32442D2C1703007701188D280080E39322DB8F78_22696600126967000269660005FF091954A33A05FF0A99BD823A02FD170800
27442D2C1703007701188D280194E393226EC679DE735657_660067006600962B913A21B9423A0800'
json = '{"media":"pressure","meter":"kampress","name":"Pressing","id":"77000317","status":"LOW","pressure_bar":1.02,"max_pressure_bar":1.03,"min_pressure_bar":1.02,"alfa_counter":0.001108,"beta_counter":0.000743,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'Pressing;77000317;LOW;1.02;1.03;1.02;1111-11-11 11:11.11'
}
test {
args = 'Pressing kampress 77000317 NOKEY'
telegram = 32442D2C1703007701188D280080E39322DB8F78_22696600126967000269660005FF091954A33A05FF0A99BD823A02FD170800
json = '{"media":"pressure","meter":"kampress","name":"Pressing","id":"77000317","status":"LOW","pressure_bar":1.02,"max_pressure_bar":1.03,"min_pressure_bar":1.02,"alfa_counter":0.001246,"beta_counter":0.000997,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'Pressing;77000317;LOW;1.02;1.03;1.02;1111-11-11 11:11.11'
}

Wyświetl plik

@ -497,3 +497,22 @@ EOF
$PROG --format=hr --selectfields=name,total_m3 1844AE4C4455223399077A55000000_041389E20100023B0000 Hej $TEST/driver.xmq 33225544 NOKEY > $TEST/test_output.txt 2>&1 || true
performCheck
TESTNAME="Test lookup of bits"
TESTRESULT="ERROR"
cat > $TEST/driver.xmq <<EOF
driver{name=kampress meter_type=PressureSensor detect{mvt=KAM,01,18} default_fields=name,pressure,status
field{name=status quantity=Text match{measurement_type=Instantaneous vif_range=ErrorFlags}
lookup{name=ERROR_FLAGS map_type=BitToString mask_bits=0xffff default_message=OK
map{name=DROP value=0x01 test=Set}map{name=LOW value=0x08 test=Set}}}
field{name=pressure quantity=Pressure match{measurement_type=Instantaneous vif_range=Pressure}}
}
EOF
cat > $TEST/test_expected.txt <<EOF
Hej 1.02 bar LOW
EOF
$PROG --format=hr --selectfields=name,pressure_bar,status 32442D2C1703007701188D280080E39322DB8F78_22696600126967000269660005FF091954A33A05FF0A99BD823A02FD170800 Hej $TEST/driver.xmq 77000317 NOKEY > $TEST/test_output.txt 2>&1 || true
performCheck

Wyświetl plik

@ -11,9 +11,12 @@ FIELDS="$5"
OK=true
rm -f $TEST/test_output.txt $TEST/test_expected.txt
rm -f $TEST/test_output.txt $TEST/test_expected.txt $TEST/simulation_tmp.txt
$PROG --format=json $HEX $ARGS \
echo "$HEX" | sed 's/^/telegram=/g' > $TEST/simulation_tmp.txt
$PROG --format=json $TEST/simulation_tmp.txt $ARGS \
| tail -n 1 \
| jq . --sort-keys \
| sed 's/"timestamp": "....-..-..T..:..:..Z"/"timestamp": "1111-11-11T11:11:11Z"/' \
> $TEST/test_output.txt
@ -31,7 +34,8 @@ fi
rm -f $TEST/test_output.txt $TEST/test_expected.txt
$PROG --format=fields $HEX $ARGS \
$PROG --format=fields $TEST/simulation_tmp.txt $ARGS \
| tail -n 1 \
| sed 's/....-..-.. ..:..:../1111-11-11 11:11.11/' \
> $TEST/test_output.txt