Add dynaic driver add_combinable and storage_nr.

pull/1185/head
Fredrik Öhrström 2024-02-15 11:40:30 +01:00
rodzic dbd99698b8
commit 097f91fac0
8 zmienionych plików z 155 dodań i 45 usunięć

Wyświetl plik

@ -1,5 +1,7 @@
FROM alpine AS build
RUN apk add --no-cache alpine-sdk gcc linux-headers libxml2-dev cmake libusb-dev bash samurai
ADD https://api.github.com/repos/wmbusmeters/wmbusmeters/git/refs/heads/master version.json
RUN git clone https://github.com/steve-m/librtlsdr.git && \
git clone https://github.com/wmbusmeters/wmbusmeters.git && \
git clone https://github.com/weetmuts/rtl-wmbus.git && \

Wyświetl plik

@ -35,8 +35,12 @@ 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);
void check_set_measurement_type(const char *measurement_type_s, FieldMatcher *fm, DriverDynamic *dd);
void check_set_vif_range(const char *vif_range_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);
void checked_add_vif_combinable(const char *vif_range_s, FieldMatcher *fm, DriverDynamic *dd);
const char *line = "-------------------------------------------------------------------------------";
@ -107,26 +111,19 @@ bool DriverDynamic::load(DriverInfo *di, const string &file_name, const char *co
DriverDynamic::DriverDynamic(MeterInfo &mi, DriverInfo &di) :
MeterCommonImplementation(mi, di), file_name_(di.getDynamicFileName())
{
XMQDoc *doc = di.getDynamicDriver();
assert(doc);
verbose("(driver) constructing driver %s from already loaded file %s\n",
di.name().str().c_str(),
fileName().c_str());
try
{
XMQDoc *doc = di.getDynamicDriver();
assert(doc);
verbose("(driver) constructing driver %s from already loaded file %s\n",
di.name().str().c_str(),
fileName().c_str());
xmqForeach(doc, NULL, "/driver/use", (XMQNodeCallback)add_use, this);
}
catch (...)
{
}
try
{
xmqForeach(doc, NULL, "/driver/field", (XMQNodeCallback)add_field, this);
}
catch (...)
catch(...)
{
}
}
@ -163,9 +160,9 @@ XMQProceed DriverDynamic::add_detect(XMQDoc *doc, XMQNode *detect, DriverInfo *d
char a = mfct[0];
char b = mfct[1];
char c = mfct[2];
if (!(a >= 'A' && a < 'Z' &&
b >= 'A' && b < 'Z' &&
c >= 'A' && c < 'Z'))
if (!(a >= 'A' && a <= 'Z' &&
b >= 'A' && b <= 'Z' &&
c >= 'A' && c <= 'Z'))
{
warning("(driver) error in %s, bad manufacturer in mvt triplet: %s\n"
"%s\n"
@ -339,22 +336,22 @@ XMQProceed DriverDynamic::add_match(XMQDoc *doc, XMQNode *match, DriverDynamic *
{
FieldMatcher *fm = dd->tmp_matcher_;
check_set_measurement_type(xmqGetString(doc, match, "measurement_type"), fm, dd);
checked_set_measurement_type(xmqGetString(doc, match, "measurement_type"), fm, dd);
check_set_vif_range(xmqGetString(doc, match, "vif_range"), fm, dd);
checked_set_vif_range(xmqGetString(doc, match, "vif_range"), fm, dd);
const char *vif_range_s = xmqGetString(doc, match, "vif_range");
checked_set_storagenr_range(xmqGetString(doc, match, "storage_nr"), fm, dd);
if (vif_range_s)
{
VIFRange vif_range = toVIFRange(vif_range_s);
if (vif_range == VIFRange::None)
{
warning("(driver) error unknown measurement type %s\n", vif_range_s);
throw 1;
}
fm->set(vif_range);
}
xmqForeach(doc, match, "add_combinable", (XMQNodeCallback)add_combinable, dd);
return XMQ_CONTINUE;
}
XMQProceed DriverDynamic::add_combinable(XMQDoc *doc, XMQNode *match, DriverDynamic *dd)
{
FieldMatcher *fm = dd->tmp_matcher_;
checked_add_vif_combinable(xmqGetString(doc, match, "."), fm, dd);
return XMQ_CONTINUE;
}
@ -622,7 +619,7 @@ Unit check_display_unit(const char *display_unit_s, DriverDynamic *dd)
return u;
}
void check_set_measurement_type(const char *measurement_type_s, FieldMatcher *fm, DriverDynamic *dd)
void checked_set_measurement_type(const char *measurement_type_s, FieldMatcher *fm, DriverDynamic *dd)
{
if (!measurement_type_s)
{
@ -665,7 +662,7 @@ void check_set_measurement_type(const char *measurement_type_s, FieldMatcher *fm
fm->set(measurement_type);
}
void check_set_vif_range(const char *vif_range_s, FieldMatcher *fm, DriverDynamic *dd)
void checked_set_vif_range(const char *vif_range_s, FieldMatcher *fm, DriverDynamic *dd)
{
if (!vif_range_s)
{
@ -701,3 +698,58 @@ void check_set_vif_range(const char *vif_range_s, FieldMatcher *fm, DriverDynami
fm->set(vif_range);
}
void checked_set_storagenr_range(const char *storagenr_range_s, FieldMatcher *fm, DriverDynamic *dd)
{
if (!storagenr_range_s) return;
auto fields = splitString(storagenr_range_s, ',');
bool ok = isNumber(fields[0]);
if (fields.size() > 1)
{
ok &= isNumber(fields[1]);
}
if (!ok || fields.size() > 2)
{
warning("(driver) error in %s, bad storagenr_range: %s\n"
"%s\n",
dd->fileName().c_str(),
storagenr_range_s,
line);
throw 1;
}
if (fields.size() == 1)
{
fm->set(StorageNr(atoi(fields[0].c_str())));
}
else
{
fm->set(StorageNr(atoi(fields[0].c_str())),
StorageNr(atoi(fields[1].c_str())));
}
}
void checked_add_vif_combinable(const char *vif_combinable_s, FieldMatcher *fm, DriverDynamic *dd)
{
if (!vif_combinable_s) return;
VIFCombinable vif_combinable = toVIFCombinable(vif_combinable_s);
if (vif_combinable == VIFCombinable::None)
{
warning("(driver) error in %s, bad vif_combinable: %s\n"
"%s\n"
"Available vif combinables:\n"
"%s\n"
"%s\n",
dd->fileName().c_str(),
vif_combinable_s,
line,
availableVIFCombinables().c_str(),
line);
throw 1;
}
fm->add(vif_combinable);
}

Wyświetl plik

@ -29,6 +29,7 @@ struct DriverDynamic : public virtual MeterCommonImplementation
static XMQProceed add_use(XMQDoc *doc, XMQNode *field, DriverDynamic *dd);
static XMQProceed add_field(XMQDoc *doc, XMQNode *field, DriverDynamic *dd);
static XMQProceed add_match(XMQDoc *doc, XMQNode *match, DriverDynamic *dd);
static XMQProceed add_combinable(XMQDoc *doc, XMQNode *match, DriverDynamic *dd);
const string &fileName() { return file_name_; }

Wyświetl plik

@ -62,6 +62,17 @@ LIST_OF_VIF_RANGES
return VIFRange::None;
}
VIFCombinable toVIFCombinable(const char *s)
{
if (!strcmp(s, "None")) return VIFCombinable::None;
if (!strcmp(s, "Any")) return VIFCombinable::Any;
#define X(name,from,to) if (!strcmp(s, #name)) return VIFCombinable::name;
LIST_OF_VIF_COMBINABLES
#undef X
return VIFCombinable::None;
}
const char *toString(VIFCombinable v)
{
switch (v) {
@ -1299,13 +1310,16 @@ bool FieldMatcher::matches(DVEntry &dv_entry)
}
// Test ranges and types.
bool b =
(!match_vif_range || isInsideVIFRange(dv_entry.vif, vif_range)) &&
(!match_vif_raw || dv_entry.vif == vif_raw) &&
(!match_measurement_type || dv_entry.measurement_type == measurement_type) &&
(!match_storage_nr || (dv_entry.storage_nr >= storage_nr_from && dv_entry.storage_nr <= storage_nr_to)) &&
(!match_tariff_nr || (dv_entry.tariff_nr >= tariff_nr_from && dv_entry.tariff_nr <= tariff_nr_to)) &&
(!match_subunit_nr || (dv_entry.subunit_nr >= subunit_nr_from && dv_entry.subunit_nr <= subunit_nr_to));
bool range = (!match_vif_range || isInsideVIFRange(dv_entry.vif, vif_range));
bool raw = (!match_vif_raw || dv_entry.vif == vif_raw);
bool type = (!match_measurement_type || dv_entry.measurement_type == measurement_type);
bool storage = (!match_storage_nr || (dv_entry.storage_nr >= storage_nr_from && dv_entry.storage_nr <= storage_nr_to));
bool tariff = (!match_tariff_nr || (dv_entry.tariff_nr >= tariff_nr_from && dv_entry.tariff_nr <= tariff_nr_to));
bool subunit = (!match_subunit_nr || (dv_entry.subunit_nr >= subunit_nr_from && dv_entry.subunit_nr <= subunit_nr_to));
//printf("Match? range=%d raw=%d type=%d storage=%d tariff=%d subunit=%d \n", range, raw, type, storage, tariff, subunit);
bool b = range & raw & type & storage & tariff & subunit;
if (!b) return false;
@ -1501,3 +1515,18 @@ LIST_OF_VIF_RANGES
available_vif_ranges_.pop_back();
return available_vif_ranges_;
}
string available_vif_combinables_;
const string &availableVIFCombinables()
{
if (available_vif_combinables_ != "") return available_vif_combinables_;
#define X(n,from,to) available_vif_combinables_ += string(#n) + "\n";
LIST_OF_VIF_COMBINABLES
#undef X
// Remove last newline
available_vif_combinables_.pop_back();
return available_vif_combinables_;
}

Wyświetl plik

@ -39,7 +39,7 @@
X(ExternalTemperature,0x64,0x67, Quantity::Temperature, Unit::C) \
X(Pressure,0x68,0x6B, Quantity::Pressure, Unit::BAR) \
X(HeatCostAllocation,0x6E,0x6E, Quantity::HCA, Unit::HCA) \
X(Date,0x6C,0x6C, Quantity::PointInTime, Unit::DateTimeLT) \
X(Date,0x6C,0x6C, Quantity::PointInTime, Unit::DateLT) \
X(DateTime,0x6D,0x6D, Quantity::PointInTime, Unit::DateTimeLT) \
X(EnergyMJ,0x08,0x0F, Quantity::Energy, Unit::MJ) \
X(EnergyWh,0x00,0x07, Quantity::Energy, Unit::KWH) \
@ -208,6 +208,7 @@ struct VIFCombinableRaw {
uint16_t value;
};
VIFCombinable toVIFCombinable(const char *s);
VIFCombinable toVIFCombinable(int i);
const char *toString(VIFCombinable v);
@ -588,5 +589,6 @@ bool extractDVdate(std::map<std::string,std::pair<int,DVEntry>> *values,
const std::string &availableVIFRanges();
const std::string &availableVIFCombinables();
#endif

Wyświetl plik

@ -1313,7 +1313,6 @@ void MeterCommonImplementation::processFieldExtractors(Telegram *t)
if (fi.hasMatcher() && fi.matches(dve))
{
current_match_nr++;
if (fi.matcher().index_nr != IndexNr(current_match_nr) &&
!fi.matcher().expectedToMatchAgainstMultipleEntries())
{

Wyświetl plik

@ -37,6 +37,7 @@ using namespace std;
bool verbose_ = false;
#define LIST_OF_TESTS \
X(dynamic_loading)\
X(crc) \
X(dvparser) \
X(devices) \
@ -2028,6 +2029,8 @@ LIST_OF_QUANTITIES
test_si_convert(2211717, 2211717, Unit::FACTOR, "counter", Unit::COUNTER, "counter", Quantity::Dimensionless, &from_set, &to_set);
test_si_convert(2211717, 2211717, Unit::NUMBER, "counter", Unit::COUNTER, "counter", Quantity::Dimensionless, &from_set, &to_set);
test_si_convert(2211717, 2211717, Unit::FACTOR, "counter", Unit::NUMBER, "counter", Quantity::Dimensionless, &from_set, &to_set);
test_si_convert(2211717, 2211717, Unit::PERCENTAGE, "counter", Unit::NUMBER, "counter", Quantity::Dimensionless, &from_set, &to_set);
test_si_convert(2211717, 2211717, Unit::NUMBER, "counter", Unit::PERCENTAGE, "counter", Quantity::Dimensionless, &from_set, &to_set);
check_units_tested(from_set, to_set, Quantity::Dimensionless);
@ -2588,3 +2591,22 @@ void test_formulas_stringinterpolation()
}
}
void test_dynamic_loading()
{
VIFRange vr = toVIFRange("Date");
if (vr != VIFRange::Date)
{
printf("ERROR in dynamic loading got %s but expected %s!\n",
toString(vr), toString(VIFRange::Date));
}
vr = toVIFRange("DateTime");
if (vr != VIFRange::DateTime)
{
printf("ERROR in dynamic loading got %s but expected %s!\n",
toString(vr), toString(VIFRange::DateTime));
}
}

Wyświetl plik

@ -63,6 +63,8 @@ using namespace std;
X(NUMBER, COUNTER, {vto=vfrom;}) \
X(FACTOR, NUMBER, {vto=vfrom;}) \
X(NUMBER, FACTOR, {vto=vfrom;}) \
X(PERCENTAGE, NUMBER, {vto=vfrom;}) \
X(NUMBER, PERCENTAGE, {vto=vfrom;}) \
X(UnixTimestamp,DateTimeLT, {vto=vfrom; }) \
X(DateTimeLT,UnixTimestamp, {vto=vfrom; }) \
X(DateLT,UnixTimestamp, {vto=vfrom; }) \
@ -122,6 +124,7 @@ using namespace std;
X(COUNTER, 1.0, SIExp()) \
X(FACTOR, 1.0, SIExp()) \
X(NUMBER, 1.0, SIExp()) \
X(PERCENTAGE, 1.0, SIExp()) \
X(TXT, 1.0, SIExp()) \
@ -830,7 +833,7 @@ const char *availableUnits()
if (available_units_[0]) return available_units_;
#define X(n,suffix,sn,q,ln) if (Unit::n != Unit::Unknown) { \
strcat(available_units_, #suffix); strcat(available_units_, "\n"); \
strcat(available_units_, #suffix); strcat(available_units_, " "); \
assert(strlen(available_units_) < 1024); }
LIST_OF_UNITS
#undef X