kopia lustrzana https://github.com/weetmuts/wmbusmeters
Add dynaic driver add_combinable and storage_nr.
rodzic
dbd99698b8
commit
097f91fac0
|
@ -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 && \
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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_; }
|
||||
|
||||
|
|
|
@ -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_;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Ładowanie…
Reference in New Issue