kopia lustrzana https://github.com/weetmuts/wmbusmeters
Add dynamic driver lookup bits translation to strings.
rodzic
c1509f6139
commit
ff72e1debc
|
@ -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))
|
||||
));
|
||||
|
||||
|
|
|
@ -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),
|
||||
"",
|
||||
{
|
||||
|
|
|
@ -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),
|
||||
"",
|
||||
{
|
||||
|
|
|
@ -101,7 +101,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::DecimalsToString,
|
||||
Translate::MapType::DecimalsToString,
|
||||
AlwaysTrigger, MaskBits(9999),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -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)))
|
||||
);
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -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 == "")
|
||||
|
@ -325,6 +345,18 @@ XMQProceed DriverDynamic::add_field(XMQDoc *doc, XMQNode *field, DriverDynamic *
|
|||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (num_lookups > 0)
|
||||
{
|
||||
dd->addStringFieldWithExtractorAndLookup(
|
||||
name,
|
||||
info,
|
||||
properties,
|
||||
match,
|
||||
lookup
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
dd->addStringFieldWithExtractor(
|
||||
name,
|
||||
|
@ -333,6 +365,7 @@ XMQProceed DriverDynamic::add_field(XMQDoc *doc, XMQNode *field, DriverDynamic *
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
{
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffffffff),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -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),
|
||||
"",
|
||||
{
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xff),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -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",
|
||||
{
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -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),
|
||||
"",
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
"",
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -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))));
|
||||
|
|
|
@ -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))
|
||||
));
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffffffff),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -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
|
|
@ -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"))
|
||||
));
|
||||
|
|
|
@ -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))));
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -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))));
|
||||
|
|
|
@ -105,7 +105,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xff),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -130,7 +130,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -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),
|
||||
"",
|
||||
{
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -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"))
|
||||
));
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xff),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffffffff),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -155,7 +155,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xff),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -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"))
|
||||
));
|
||||
|
|
|
@ -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"))
|
||||
));
|
||||
|
|
|
@ -114,7 +114,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -68,7 +68,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffffff),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -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),
|
||||
"",
|
||||
{
|
||||
|
|
|
@ -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",
|
||||
{
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -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" },
|
||||
};
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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), "", { } };
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
56
src/xmq.h
56
src/xmq.h
|
@ -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 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  	 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.
|
||||
|
|
|
@ -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'
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue