kopia lustrzana https://github.com/weetmuts/wmbusmeters
Add handling of combinables.
rodzic
3282c19344
commit
19ec79fc41
|
@ -66,7 +66,7 @@ void MeterApator08::processContent(Telegram *t)
|
|||
string total;
|
||||
strprintf(total, "%02x%02x%02x%02x", content[0], content[1], content[2], content[3]);
|
||||
|
||||
vendor_values["0413"] = { 25, DVEntry(25, DifVifKey("0413"), MeasurementType::Instantaneous, 0x13, 0, 0, 0, total) };
|
||||
vendor_values["0413"] = { 25, DVEntry(25, DifVifKey("0413"), MeasurementType::Instantaneous, 0x13, {}, 0, 0, 0, total) };
|
||||
int offset;
|
||||
string key;
|
||||
if(findKey(MeasurementType::Instantaneous, VIFRange::Volume, 0, 0, &key, &vendor_values))
|
||||
|
|
182
src/dvparser.cc
182
src/dvparser.cc
|
@ -42,6 +42,26 @@ LIST_OF_VIF_RANGES
|
|||
assert(0);
|
||||
}
|
||||
|
||||
const char *toString(VIFCombinable v)
|
||||
{
|
||||
switch (v) {
|
||||
case VIFCombinable::None: return "None";
|
||||
case VIFCombinable::Any: return "Any";
|
||||
#define X(name,from,to) case VIFCombinable::name: return #name;
|
||||
LIST_OF_VIF_COMBINABLES
|
||||
#undef X
|
||||
}
|
||||
assert(0);
|
||||
}
|
||||
|
||||
VIFCombinable toVIFCombinable(int i)
|
||||
{
|
||||
#define X(name,from,to) if (from <= i && i <= to) return VIFCombinable::name;
|
||||
LIST_OF_VIF_COMBINABLES
|
||||
#undef X
|
||||
return VIFCombinable::None;
|
||||
}
|
||||
|
||||
Unit toDefaultUnit(VIFRange v)
|
||||
{
|
||||
switch (v) {
|
||||
|
@ -221,8 +241,10 @@ bool parseDV(Telegram *t,
|
|||
|
||||
bool has_another_dife = (dif & 0x80) == 0x80;
|
||||
|
||||
while (has_another_dife) {
|
||||
while (has_another_dife)
|
||||
{
|
||||
if (*format == format_end) { debug("(dvparser) warning: unexpected end of data (dife expected)\n"); break; }
|
||||
|
||||
uchar dife = **format;
|
||||
int subunit_bit = (dife & 0x40) >> 6;
|
||||
subunit |= subunit_bit << difenr;
|
||||
|
@ -231,15 +253,18 @@ bool parseDV(Telegram *t,
|
|||
int storage_nr_bits = (dife & 0x0f);
|
||||
storage_nr |= storage_nr_bits << (1+difenr*4);
|
||||
|
||||
DEBUG_PARSER("(dvparser debug) dife=%02x (subunit=%d tariff=%d storagenr=%d)\n",
|
||||
dife, subunit, tariff, storage_nr);
|
||||
if (data_has_difvifs) {
|
||||
DEBUG_PARSER("(dvparser debug) dife=%02x (subunit=%d tariff=%d storagenr=%d)\n", dife, subunit, tariff, storage_nr);
|
||||
|
||||
if (data_has_difvifs)
|
||||
{
|
||||
format_bytes.push_back(dife);
|
||||
id_bytes.push_back(dife);
|
||||
t->addExplanationAndIncrementPos(*format, 1, KindOfData::PROTOCOL, Understanding::FULL,
|
||||
"%02X dife (subunit=%d tariff=%d storagenr=%d)",
|
||||
dife, subunit, tariff, storage_nr);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
id_bytes.push_back(**format);
|
||||
(*format)++;
|
||||
}
|
||||
|
@ -251,17 +276,32 @@ bool parseDV(Telegram *t,
|
|||
if (*format == format_end) { debug("(dvparser) warning: unexpected end of data (vif expected)\n"); break; }
|
||||
|
||||
uchar vif = **format;
|
||||
DEBUG_PARSER("(dvparser debug) vif=%02x \"%s\"\n", vif, vifType(vif).c_str());
|
||||
if (data_has_difvifs) {
|
||||
int full_vif = vif & 0x7f;
|
||||
bool extension_vif = false;
|
||||
set<VIFCombinable> found_combinable_vifs;
|
||||
|
||||
DEBUG_PARSER("(dvparser debug) vif=%04x \"%s\"\n", vif, vifType(vif).c_str());
|
||||
|
||||
if (data_has_difvifs)
|
||||
{
|
||||
format_bytes.push_back(vif);
|
||||
id_bytes.push_back(vif);
|
||||
t->addExplanationAndIncrementPos(*format, 1, KindOfData::PROTOCOL, Understanding::FULL,
|
||||
"%02X vif (%s)", vif, vifType(vif).c_str());
|
||||
} else {
|
||||
} else
|
||||
{
|
||||
id_bytes.push_back(**format);
|
||||
(*format)++;
|
||||
}
|
||||
|
||||
// Check if this is marker for one of the extended sets of vifs: first, second and thir.
|
||||
if (vif == 0xfb || vif == 0xfd || vif == 0xef)
|
||||
{
|
||||
// Extension vifs.
|
||||
full_vif <<= 8;
|
||||
extension_vif = true;
|
||||
}
|
||||
|
||||
// Grabbing a variable length vif. This does not currently work
|
||||
// with the compact format.
|
||||
if (vif == 0x7c)
|
||||
|
@ -282,21 +322,52 @@ bool parseDV(Telegram *t,
|
|||
}
|
||||
}
|
||||
|
||||
// Do we have another vife byte? We better have one, if extension_vif is true.
|
||||
bool has_another_vife = (vif & 0x80) == 0x80;
|
||||
while (has_another_vife) {
|
||||
while (has_another_vife)
|
||||
{
|
||||
if (*format == format_end) { debug("(dvparser) warning: unexpected end of data (vife expected)\n"); break; }
|
||||
|
||||
uchar vife = **format;
|
||||
DEBUG_PARSER("(dvparser debug) vife=%02x (%s)\n", vife, vifeType(dif, vif, vife).c_str());
|
||||
if (data_has_difvifs) {
|
||||
|
||||
if (data_has_difvifs)
|
||||
{
|
||||
// Collect the difvifs to create signature for future use.
|
||||
format_bytes.push_back(vife);
|
||||
id_bytes.push_back(vife);
|
||||
t->addExplanationAndIncrementPos(*format, 1, KindOfData::PROTOCOL, Understanding::FULL,
|
||||
"%02X vife (%s)", vife, vifeType(dif, vif, vife).c_str());
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reuse the existing
|
||||
id_bytes.push_back(**format);
|
||||
(*format)++;
|
||||
}
|
||||
|
||||
has_another_vife = (vife & 0x80) == 0x80;
|
||||
|
||||
if (extension_vif)
|
||||
{
|
||||
// First vife after the extension marker is the real vif.
|
||||
full_vif |= (vife & 0x7f);
|
||||
extension_vif = false;
|
||||
if (data_has_difvifs)
|
||||
{
|
||||
t->addExplanationAndIncrementPos(*format, 1, KindOfData::PROTOCOL, Understanding::FULL,
|
||||
"%02X vife (%s)", vife, vifeType(dif, vif, vife).c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the full vif is now handled, then the rest are combinable vifs.
|
||||
VIFCombinable vc = toVIFCombinable(vife & 0x7f);
|
||||
found_combinable_vifs.insert(vc);
|
||||
if (data_has_difvifs)
|
||||
{
|
||||
t->addExplanationAndIncrementPos(*format, 1, KindOfData::PROTOCOL, Understanding::FULL,
|
||||
"%02X combinable vif (%s)", vife, toString(vc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dv = "";
|
||||
|
@ -337,7 +408,8 @@ bool parseDV(Telegram *t,
|
|||
(*dv_entries)[key] = { offset, DVEntry(offset,
|
||||
key,
|
||||
mt,
|
||||
Vif(vif&0x7f),
|
||||
Vif(full_vif),
|
||||
found_combinable_vifs,
|
||||
StorageNr(storage_nr),
|
||||
TariffNr(tariff),
|
||||
SubUnitNr(subunit),
|
||||
|
@ -345,6 +417,11 @@ bool parseDV(Telegram *t,
|
|||
|
||||
DVEntry *dve = &(*dv_entries)[key].second;
|
||||
|
||||
if (isDebugEnabled())
|
||||
{
|
||||
debug("(dvparser) entry %s\n", dve->str().c_str());
|
||||
}
|
||||
|
||||
assert(key == dve->dif_vif_key.str());
|
||||
|
||||
if (value.length() > 0) {
|
||||
|
@ -376,18 +453,17 @@ bool hasKey(std::map<std::string,std::pair<int,DVEntry>> *dv_entries, std::strin
|
|||
return dv_entries->count(key) > 0;
|
||||
}
|
||||
|
||||
bool findKey(MeasurementType mit, VIFRange vif, StorageNr storagenr, TariffNr tariffnr,
|
||||
bool findKey(MeasurementType mit, VIFRange vif_range, StorageNr storagenr, TariffNr tariffnr,
|
||||
std::string *key, std::map<std::string,std::pair<int,DVEntry>> *dv_entries)
|
||||
{
|
||||
return findKeyWithNr(mit, vif, storagenr, tariffnr, 1, key, dv_entries);
|
||||
return findKeyWithNr(mit, vif_range, storagenr, tariffnr, 1, key, dv_entries);
|
||||
}
|
||||
|
||||
bool findKeyWithNr(MeasurementType mit, VIFRange vif_range, StorageNr storagenr, TariffNr tariffnr, int nr,
|
||||
std::string *key, std::map<std::string,std::pair<int,DVEntry>> *dv_entries)
|
||||
{
|
||||
/*debug("(dvparser) looking for type=%s vif=%s storagenr=%d value_ran_low=%02x value_ran_hi=%02x\n",
|
||||
measurementTypeName(mit).c_str(), toString(vif), storagenr,
|
||||
low, hi);*/
|
||||
/*debug("(dvparser) looking for type=%s vifrange=%s storagenr=%d tariffnr=%d\n",
|
||||
measurementTypeName(mit).c_str(), toString(vif_range), storagenr.intValue(), tariffnr.intValue());*/
|
||||
|
||||
for (auto& v : *dv_entries)
|
||||
{
|
||||
|
@ -396,9 +472,9 @@ bool findKeyWithNr(MeasurementType mit, VIFRange vif_range, StorageNr storagenr,
|
|||
StorageNr sn = v.second.second.storage_nr;
|
||||
TariffNr tn = v.second.second.tariff_nr;
|
||||
|
||||
/*debug("(dvparser) match? %s type=%s vif=%02x (%s) and storagenr=%d\n",
|
||||
/* debug("(dvparser) match? %s type=%s vife=%x (%s) and storagenr=%d\n",
|
||||
v.first.c_str(),
|
||||
measurementTypeName(ty).c_str(), vi, toString(toVIFRange(vi)), storagenr, sn);*/
|
||||
measurementTypeName(ty).c_str(), vi.intValue(), storagenr, sn);*/
|
||||
|
||||
if (isInsideVIFRange(vi, vif_range) &&
|
||||
(mit == MeasurementType::Instantaneous || mit == ty) &&
|
||||
|
@ -408,9 +484,9 @@ bool findKeyWithNr(MeasurementType mit, VIFRange vif_range, StorageNr storagenr,
|
|||
*key = v.first;
|
||||
nr--;
|
||||
if (nr <= 0) return true;
|
||||
/*debug("(dvparser) found key %s for type=%s vif=%02x (%s) storagenr=%d\n",
|
||||
debug("(dvparser) found key %s for type=%s vif=%x storagenr=%d\n",
|
||||
v.first.c_str(), measurementTypeName(ty).c_str(),
|
||||
vi, toString(toVIFRange(vi)), storagenr);*/
|
||||
vi.intValue(), storagenr.intValue());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -893,6 +969,23 @@ bool DVEntry::extractReadableString(string *out)
|
|||
return true;
|
||||
}
|
||||
|
||||
string DVEntry::str()
|
||||
{
|
||||
string s =
|
||||
tostrprintf("%d: %s %s vif=%x %s st=%d ta=%d su=%d",
|
||||
offset,
|
||||
dif_vif_key.str().c_str(),
|
||||
toString(measurement_type),
|
||||
vif.intValue(),
|
||||
combinable_vifs.size() > 0 ? "HASCOMB ":"",
|
||||
storage_nr.intValue(),
|
||||
tariff_nr.intValue(),
|
||||
subunit_nr.intValue()
|
||||
);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
bool extractDate(uchar hi, uchar lo, struct tm *date)
|
||||
{
|
||||
// | hi | lo |
|
||||
|
@ -991,12 +1084,6 @@ bool FieldMatcher::matches(DVEntry &dv_entry)
|
|||
return b;
|
||||
}
|
||||
|
||||
if (dv_entry.dif_vif_key.hasVifes())
|
||||
{
|
||||
// Currently we cannot match vifes. They must be selected using expicit dif_vif_keys above.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool b =
|
||||
(!match_vif_range || isInsideVIFRange(dv_entry.vif, vif_range)) &&
|
||||
(!match_measurement_type || dv_entry.measurement_type == measurement_type) &&
|
||||
|
@ -1004,5 +1091,40 @@ bool FieldMatcher::matches(DVEntry &dv_entry)
|
|||
(!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));
|
||||
|
||||
return b;
|
||||
if (!b) return false;
|
||||
|
||||
// If field matcher has no combinables, then do NOT match any dventry with a combinable!
|
||||
if (vif_combinables.size()== 0)
|
||||
{
|
||||
if (dv_entry.combinable_vifs.size() == 0) return true;
|
||||
// Oups, field matcher does not expect any combinables, but the dv_entry has combinables.
|
||||
// This means no match for us since combinables must be handled explicitly.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Lets check that the dv_entry combinables contains the field matcher requested combinables.
|
||||
for (VIFCombinable vc : vif_combinables)
|
||||
{
|
||||
if (dv_entry.combinable_vifs.count(vc) == 0)
|
||||
{
|
||||
// Ouch, one of the requested combinables did not exist in the dv_entry. No match!
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Yay, they were all found.
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *toString(MeasurementType mt)
|
||||
{
|
||||
switch (mt)
|
||||
{
|
||||
case MeasurementType::Any: return "Any";
|
||||
case MeasurementType::Instantaneous: return "Instantaneous";
|
||||
case MeasurementType::Minimum: return "Minimum";
|
||||
case MeasurementType::Maximum: return "Maximum";
|
||||
case MeasurementType::AtError: return "AtError";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
|
150
src/dvparser.h
150
src/dvparser.h
|
@ -22,6 +22,7 @@
|
|||
#include"units.h"
|
||||
|
||||
#include<map>
|
||||
#include<set>
|
||||
#include<stdint.h>
|
||||
#include<time.h>
|
||||
#include<functional>
|
||||
|
@ -44,6 +45,8 @@
|
|||
X(ActualityDuration,0x74,0x77, Quantity::Time, Unit::Second) \
|
||||
X(FabricationNo,0x78,0x78, Quantity::Text, Unit::TXT) \
|
||||
X(EnhancedIdentification,0x79,0x79, Quantity::Text, Unit::TXT) \
|
||||
X(ParameterSet,0x7D0B,0x7D0B, Quantity::Text, Unit::TXT) \
|
||||
X(ModelVersion,0x7D0C,0x7D0C, Quantity::Text, Unit::TXT) \
|
||||
X(AnyVolumeVIF,0x00,0x00, Quantity::Volume, Unit::Unknown) \
|
||||
X(AnyEnergyVIF,0x00,0x00, Quantity::Energy, Unit::Unknown) \
|
||||
X(AnyPowerVIF,0x00,0x00, Quantity::Power, Unit::Unknown) \
|
||||
|
@ -62,6 +65,108 @@ Unit toDefaultUnit(VIFRange v);
|
|||
VIFRange toVIFRange(int i);
|
||||
bool isInsideVIFRange(int i, VIFRange range);
|
||||
|
||||
#define LIST_OF_VIF_COMBINABLES \
|
||||
X(Reserved,0x00,0x11) \
|
||||
X(Average,0x12,0x12) \
|
||||
X(InverseCompactProfile,0x13,0x13) \
|
||||
X(RelativeDeviation,0x14,0x14) \
|
||||
X(RecordErrorCodeMeterToController,0x15,0x1c) \
|
||||
X(StandardConformDataContent,0x1d,0x1d) \
|
||||
X(CompactProfileWithRegister,0x1e,0x1e) \
|
||||
X(CompactProfile,0x1f,0x1f) \
|
||||
X(PerSecond,0x20,0x20) \
|
||||
X(PerMinute,0x21,0x21) \
|
||||
X(PerHour,0x22,0x22) \
|
||||
X(PerDay,0x23,0x23) \
|
||||
X(PerWeek,0x24,0x24) \
|
||||
X(PerMonth,0x25,0x25) \
|
||||
X(PerYear,0x26,0x26) \
|
||||
X(PerRevolutionMeasurement,0x27,0x27) \
|
||||
X(IncrPerInputPulseChannel0,0x28,0x28) \
|
||||
X(IncrPerInputPulseChannel1,0x29,0x29) \
|
||||
X(IncrPerOutputPulseChannel0,0x2a,0x2a) \
|
||||
X(IncrPerOutputPulseChannel1,0x2b,0x2b) \
|
||||
X(PerLitre,0x2c,0x2c) \
|
||||
X(PerM3,0x2d,0x2d) \
|
||||
X(PerKg,0x2e,0x2e) \
|
||||
X(PerKelvin,0x2f,0x2f) \
|
||||
X(PerKWh,0x30,0x30) \
|
||||
X(PerGJ,0x31,0x31) \
|
||||
X(PerKW,0x32,0x32) \
|
||||
X(PerKelvinLitreW,0x33,0x33) \
|
||||
X(PerVolt,0x34,0x34) \
|
||||
X(PerAmpere,0x35,0x35) \
|
||||
X(MultipliedByS,0x36,0x36) \
|
||||
X(MultipliedBySDivV,0x37,0x37) \
|
||||
X(MultipliedBySDivA,0x38,0x38) \
|
||||
X(StartDateTimeOfAB,0x39,0x39) \
|
||||
X(UncorrectedMeterUnit,0x3a,0x3a) \
|
||||
X(ForwardFlow,0x3b,0x3b) \
|
||||
X(BackwardFlow,0x3c,0x3c) \
|
||||
X(ReservedNonMetric,0x3d,0x3d) \
|
||||
X(ValueAtBaseCondC,0x3e,0x3e) \
|
||||
X(ObisDeclaration,0x3f,0x3f) \
|
||||
X(LowerLimit,0x40,0x40) \
|
||||
X(ExceedsLowerLimit,0x41,0x41) \
|
||||
X(DateTimeExceedsLowerFirstBegin, 0x42,0x42) \
|
||||
X(DateTimeExceedsLowerFirstEnd, 0x43,0x43) \
|
||||
X(DateTimeExceedsLowerLastBegin, 0x46,0x46) \
|
||||
X(DateTimeExceedsLowerLastEnd, 0x47,0x47) \
|
||||
X(UpperLimit,0x48,0x48) \
|
||||
X(ExceedsUpperLimit,0x49,0x49) \
|
||||
X(DateTimeExceedsUpperFirstBegin, 0x4a,0x4a) \
|
||||
X(DateTimeExceedsUpperFirstEnd, 0x4b,0x4b) \
|
||||
X(DateTimeExceedsUpperLastBegin, 0x4d,0x4d) \
|
||||
X(DateTimeExceedsUpperLastEnd, 0x4e,0x4e) \
|
||||
X(DurationExceedsLowerFirst,0x50,0x53) \
|
||||
X(DurationExceedsLowerLast,0x54,0x57) \
|
||||
X(DurationExceedsUpperFirst,0x58,0x5b) \
|
||||
X(DurationExceedsUpperLast,0x5c,0x5f) \
|
||||
X(DurationOfDFirst,0x60,0x63) \
|
||||
X(DurationOfDLast,0x64,0x67) \
|
||||
X(ValueDuringLowerLimitExceeded,0x68,0x68) \
|
||||
X(LeakageValues,0x69,0x69) \
|
||||
X(OverflowValues,0x6a,0x6a) \
|
||||
X(ValueDuringUpperLimitExceeded,0x6c,0x6c) \
|
||||
X(DateTimeOfDEFirstBegin,0x6a,0x6a) \
|
||||
X(DateTimeOfDEFirstEnd,0x6b,0x6b) \
|
||||
X(DateTimeOfDELastBegin,0x6e,0x6e) \
|
||||
X(DateTimeOfDELastEnd,0x6f,0x6f) \
|
||||
X(MultiplicativeCorrectionFactorForValue,0x70,0x77) \
|
||||
X(AdditiveCorrectionConstant,0x78,0x7b) \
|
||||
X(CombinableVIFExtension,0x7c,0x7c) \
|
||||
X(MultiplicativeCorrectionFactorForValue103,0x7d,0x7d) \
|
||||
X(FutureValue,0x7e,0x7e) \
|
||||
X(MfctSpecific,0x7f,0x7f) \
|
||||
X(AtPhase1,0x7c01,0x7c01) \
|
||||
X(AtPhase2,0x7c02,0x7c02) \
|
||||
X(AtPhase3,0x7c03,0x7c03) \
|
||||
X(AtNeutral,0x7c04,0x7c04) \
|
||||
X(BetweenPhaseL1AndL2,0x7c05,0x7c05) \
|
||||
X(BetweenPhaseL2AndL3,0x7c06,0x7c06) \
|
||||
X(BetweenPhaseL3AndL1,0x7c07,0x7c07) \
|
||||
X(AtQuadrantQ1,0x7c08,0x7c08) \
|
||||
X(AtQuadrantQ2,0x7c09,0x7c09) \
|
||||
X(AtQuadrantQ3,0x7c0a,0x7c0a) \
|
||||
X(AtQuadrantQ4,0x7c0b,0x7c0b) \
|
||||
X(DeltaBetweenImportAndExport,0x7c0c,0x7c0c) \
|
||||
X(AccumulationOfAbsoluteValue,0x7c10,0x7c10) \
|
||||
X(DataPresentedWithTypeC,0x7c11,0x7c11) \
|
||||
X(DataPresentedWithTypeD,0x7c12,0x7c12) \
|
||||
|
||||
|
||||
enum class VIFCombinable
|
||||
{
|
||||
None,
|
||||
Any,
|
||||
#define X(name,from,to) name,
|
||||
LIST_OF_VIF_COMBINABLES
|
||||
#undef X
|
||||
};
|
||||
|
||||
VIFCombinable toVIFCombinable(int i);
|
||||
const char *toString(VIFCombinable v);
|
||||
|
||||
enum class MeasurementType
|
||||
{
|
||||
Any,
|
||||
|
@ -71,6 +176,8 @@ enum class MeasurementType
|
|||
AtError
|
||||
};
|
||||
|
||||
const char *toString(MeasurementType mt);
|
||||
|
||||
void extractDV(std::string &s, uchar *dif, uchar *vif, bool *has_difes, bool *has_vifes);
|
||||
|
||||
struct DifVifKey
|
||||
|
@ -170,23 +277,52 @@ struct DVEntry
|
|||
DifVifKey dif_vif_key;
|
||||
MeasurementType measurement_type;
|
||||
Vif vif;
|
||||
std::set<VIFCombinable> combinable_vifs;
|
||||
StorageNr storage_nr;
|
||||
TariffNr tariff_nr;
|
||||
SubUnitNr subunit_nr;
|
||||
std::string value;
|
||||
|
||||
DVEntry(int off, DifVifKey dvk, MeasurementType mt, Vif vi, StorageNr st, TariffNr ta, SubUnitNr su, std::string &val) :
|
||||
offset(off), dif_vif_key(dvk), measurement_type(mt), vif(vi), storage_nr(st), tariff_nr(ta), subunit_nr(su), value(val) {}
|
||||
DVEntry(int off,
|
||||
DifVifKey dvk,
|
||||
MeasurementType mt,
|
||||
Vif vi,
|
||||
std::set<VIFCombinable> vc,
|
||||
StorageNr st,
|
||||
TariffNr ta,
|
||||
SubUnitNr su,
|
||||
std::string &val) :
|
||||
offset(off),
|
||||
dif_vif_key(dvk),
|
||||
measurement_type(mt),
|
||||
vif(vi),
|
||||
combinable_vifs(vc),
|
||||
storage_nr(st),
|
||||
tariff_nr(ta),
|
||||
subunit_nr(su),
|
||||
value(val)
|
||||
{
|
||||
}
|
||||
|
||||
DVEntry() :
|
||||
offset(999999), dif_vif_key("????"), measurement_type(MeasurementType::Instantaneous), vif(0), storage_nr(0), tariff_nr(0), subunit_nr(0), value("x") {}
|
||||
offset(999999),
|
||||
dif_vif_key("????"),
|
||||
measurement_type(MeasurementType::Instantaneous),
|
||||
vif(0),
|
||||
storage_nr(0),
|
||||
tariff_nr(0),
|
||||
subunit_nr(0),
|
||||
value("x")
|
||||
{
|
||||
}
|
||||
|
||||
bool extractDouble(double *out, bool auto_scale, bool assume_signed);
|
||||
bool extractLong(uint64_t *out);
|
||||
bool extractDate(struct tm *out);
|
||||
bool extractReadableString(std::string *out);
|
||||
bool hasVifes();
|
||||
void setFieldInfo(FieldInfo *fi) { field_info_ = fi; }
|
||||
FieldInfo *getFieldInfo() { return field_info_; }
|
||||
std::string str();
|
||||
|
||||
private:
|
||||
FieldInfo *field_info_ {}; // The field info selected to decode this entry.
|
||||
|
@ -209,6 +345,9 @@ struct FieldMatcher
|
|||
bool match_vif_range = false;
|
||||
VIFRange vif_range { VIFRange::Any };
|
||||
|
||||
// Match any vif combinables.
|
||||
std::set<VIFCombinable> vif_combinables;
|
||||
|
||||
// Match the storage nr. If no storage is specified, default to match only 0.
|
||||
bool match_storage_nr = true;
|
||||
StorageNr storage_nr_from { 0 };
|
||||
|
@ -242,6 +381,9 @@ struct FieldMatcher
|
|||
vif_range = v;
|
||||
match_vif_range = (v != VIFRange::Any);
|
||||
return *this; }
|
||||
FieldMatcher &add(VIFCombinable v) {
|
||||
vif_combinables.insert(v);
|
||||
return *this; }
|
||||
FieldMatcher &set(StorageNr s) {
|
||||
storage_nr_from = storage_nr_to = s;
|
||||
match_storage_nr = (s != AnyStorageNr);
|
||||
|
|
|
@ -126,7 +126,7 @@ void MeterApator162::processContent(Telegram *t)
|
|||
string total;
|
||||
strprintf(total, "%02x%02x%02x%02x", content[i+0], content[i+1], content[i+2], content[i+3]);
|
||||
int offset = i-1+t->header_size;
|
||||
vendor_values["0413"] = {offset, DVEntry(offset, DifVifKey("0413"), MeasurementType::Instantaneous, 0x13, 0, 0, 0, total) };
|
||||
vendor_values["0413"] = {offset, DVEntry(offset, DifVifKey("0413"), MeasurementType::Instantaneous, 0x13, {}, 0, 0, 0, total) };
|
||||
extractDVdouble(&vendor_values, "0413", &offset, &total_water_consumption_m3_);
|
||||
total = "*** 10-"+total+" total consumption (%f m3)";
|
||||
t->addSpecialExplanation(offset, 4, KindOfData::CONTENT, Understanding::FULL, total.c_str(), total_water_consumption_m3_);
|
||||
|
|
|
@ -110,7 +110,7 @@ void MeterCompact5::processContent(Telegram *t)
|
|||
string prevs;
|
||||
strprintf(prevs, "%02x%02x", prev_lo, prev_hi);
|
||||
int offset = t->parsed.size()+3;
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x15, 0, 0, 0, prevs) };
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x15, {}, 0, 0, 0, prevs) };
|
||||
Explanation pe(offset, 2, prevs, KindOfData::CONTENT, Understanding::FULL);
|
||||
t->explanations.push_back(pe);
|
||||
t->addMoreExplanation(offset, " energy used in previous billing period (%f KWH)", prev);
|
||||
|
@ -122,7 +122,7 @@ void MeterCompact5::processContent(Telegram *t)
|
|||
string currs;
|
||||
strprintf(currs, "%02x%02x", curr_lo, curr_hi);
|
||||
offset = t->parsed.size()+7;
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x15, 0, 0, 0, currs) };
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x15, {}, 0, 0, 0, currs) };
|
||||
Explanation ce(offset, 2, currs, KindOfData::CONTENT, Understanding::FULL);
|
||||
t->explanations.push_back(ce);
|
||||
t->addMoreExplanation(offset, " energy used in current billing period (%f KWH)", curr);
|
||||
|
|
|
@ -111,9 +111,6 @@
|
|||
X(UNISMART, MANUFACTURER_AMX, 0x03, 0x01) \
|
||||
X(VARIO451, MANUFACTURER_TCH, 0x04, 0x27) \
|
||||
X(VARIO451, MANUFACTURER_TCH, 0xc3, 0x27) \
|
||||
X(WATERSTARM, MANUFACTURER_DWZ, 0x06, 0x02) \
|
||||
X(WATERSTARM, MANUFACTURER_DWZ, 0x07, 0x02) \
|
||||
X(WATERSTARM, MANUFACTURER_EFE, 0x07, 0x03) \
|
||||
X(WHE46X, MANUFACTURER_LSE, 0x08, 0x18) \
|
||||
X(WHE5X, MANUFACTURER_LSE, 0x08, 0x34) \
|
||||
X(WEH_07, MANUFACTURER_WEH, 0x07, 0xfe) \
|
||||
|
|
|
@ -100,7 +100,7 @@ void MKRadio3::processContent(Telegram *t)
|
|||
string prev_date_str;
|
||||
strprintf(prev_date_str, "%04x", prev_date);
|
||||
uint offset = t->parsed.size() + 1;
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x6c, 0, 0, 0, prev_date_str) };
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x6c, {}, 0, 0, 0, prev_date_str) };
|
||||
t->explanations.push_back(Explanation(offset, 1, prev_date_str, KindOfData::CONTENT, Understanding::FULL));
|
||||
t->addMoreExplanation(offset, " previous date (%s)", previous_date_.c_str());
|
||||
|
||||
|
@ -112,7 +112,7 @@ void MKRadio3::processContent(Telegram *t)
|
|||
string prevs;
|
||||
strprintf(prevs, "%02x%02x", prev_lo, prev_hi);
|
||||
offset = t->parsed.size()+3;
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x15, 0, 0, 0, prevs) };
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x15, {}, 0, 0, 0, prevs) };
|
||||
t->explanations.push_back(Explanation(offset, 2, prevs, KindOfData::CONTENT, Understanding::FULL));
|
||||
t->addMoreExplanation(offset, " prev consumption (%f m3)", prev);
|
||||
|
||||
|
@ -125,7 +125,7 @@ void MKRadio3::processContent(Telegram *t)
|
|||
string current_date_str;
|
||||
strprintf(current_date_str, "%04x", current_date);
|
||||
offset = t->parsed.size() + 5;
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x6c, 0, 0, 0, current_date_str) };
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x6c, {}, 0, 0, 0, current_date_str) };
|
||||
t->explanations.push_back(Explanation(offset, 1, current_date_str, KindOfData::CONTENT, Understanding::FULL));
|
||||
t->addMoreExplanation(offset, " current date (%s)", current_date_.c_str());
|
||||
|
||||
|
@ -137,7 +137,7 @@ void MKRadio3::processContent(Telegram *t)
|
|||
string currs;
|
||||
strprintf(currs, "%02x%02x", curr_lo, curr_hi);
|
||||
offset = t->parsed.size()+7;
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x15, 0, 0, 0, currs) };
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x15, {}, 0, 0, 0, currs) };
|
||||
t->explanations.push_back(Explanation(offset, 2, currs, KindOfData::CONTENT, Understanding::FULL));
|
||||
t->addMoreExplanation(offset, " curr consumption (%f m3)", curr);
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ void MKRadio4::processContent(Telegram *t)
|
|||
string prevs;
|
||||
strprintf(prevs, "%02x%02x", prev_lo, prev_hi);
|
||||
int offset = t->parsed.size()+3;
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x15, 0, 0, 0, prevs) };
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x15, {}, 0, 0, 0, prevs) };
|
||||
t->explanations.push_back(Explanation(offset, 2, prevs, KindOfData::CONTENT, Understanding::FULL));
|
||||
t->addMoreExplanation(offset, " prev consumption (%f m3)", prev);
|
||||
|
||||
|
@ -94,7 +94,7 @@ void MKRadio4::processContent(Telegram *t)
|
|||
string currs;
|
||||
strprintf(currs, "%02x%02x", curr_lo, curr_hi);
|
||||
offset = t->parsed.size()+7;
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x15, 0, 0, 0, currs) };
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x15, {}, 0, 0, 0, currs) };
|
||||
t->explanations.push_back(Explanation(offset, 2, currs, KindOfData::CONTENT, Understanding::FULL));
|
||||
t->addMoreExplanation(offset, " curr consumption (%f m3)", curr);
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ void MeterVario451::processContent(Telegram *t)
|
|||
string prevs;
|
||||
strprintf(prevs, "%02x%02x", prev_lo, prev_hi);
|
||||
int offset = t->parsed.size()+3;
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x15, 0, 0, 0, prevs) };
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x15, {}, 0, 0, 0, prevs) };
|
||||
t->explanations.push_back(Explanation(offset, 2, prevs, KindOfData::CONTENT, Understanding::FULL));
|
||||
t->addMoreExplanation(offset, " energy used in previous billing period (%f GJ)", prev);
|
||||
|
||||
|
@ -120,7 +120,7 @@ void MeterVario451::processContent(Telegram *t)
|
|||
string currs;
|
||||
strprintf(currs, "%02x%02x", curr_lo, curr_hi);
|
||||
offset = t->parsed.size()+7;
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x15, 0, 0, 0, currs) };
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x15, {}, 0, 0, 0, currs) };
|
||||
t->explanations.push_back(Explanation(offset, 2, currs, KindOfData::CONTENT, Understanding::FULL));
|
||||
t->addMoreExplanation(offset, " energy used in current billing period (%f GJ)", curr);
|
||||
|
||||
|
|
|
@ -2468,7 +2468,9 @@ bool FieldInfo::extractString(Meter *m, Telegram *t, DVEntry *dve)
|
|||
found = true;
|
||||
}
|
||||
else if (matcher_.vif_range == VIFRange::EnhancedIdentification ||
|
||||
matcher_.vif_range == VIFRange::FabricationNo)
|
||||
matcher_.vif_range == VIFRange::FabricationNo ||
|
||||
matcher_.vif_range == VIFRange::ModelVersion ||
|
||||
matcher_.vif_range == VIFRange::ParameterSet)
|
||||
{
|
||||
string extracted_id;
|
||||
dve->extractReadableString(&extracted_id);
|
||||
|
|
|
@ -105,7 +105,6 @@ LIST_OF_METER_TYPES
|
|||
X(sontex868, T1_bit, HeatCostAllocationMeter, SONTEX868, Sontex868) \
|
||||
X(topaseskr, T1_bit, WaterMeter, TOPASESKR, TopasEsKr) \
|
||||
X(vario451, T1_bit, HeatMeter, VARIO451, Vario451) \
|
||||
X(waterstarm, C1_bit|T1_bit, WaterMeter,WATERSTARM, WaterstarM) \
|
||||
X(whe46x, S1_bit, HeatCostAllocationMeter, WHE46X, Whe46x) \
|
||||
X(whe5x, S1_bit, HeatCostAllocationMeter, WHE5X, Whe5x) \
|
||||
X(lse_08, S1_bit|C1_bit, HeatCostAllocationMeter, LSE_08, LSE_08) \
|
||||
|
|
Ładowanie…
Reference in New Issue