From 23f2279a6433f6798a508537c96100ac45f87289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20=C3=96hrstr=C3=B6m?= Date: Tue, 9 Apr 2024 10:41:30 +0200 Subject: [PATCH] Separate VIF scaling and DIF signedness. Default to signed DIF binary integers. --- src/driver_amiplus.cc | 14 +++++++ src/driver_dynamic.cc | 36 +++++++++++++++- src/dvparser.cc | 32 +++++++------- src/dvparser.h | 4 +- src/meters.cc | 67 ++++++++++++++++++++++++------ src/meters.h | 17 ++++++-- src/meters_common_implementation.h | 1 + 7 files changed, 136 insertions(+), 35 deletions(-) diff --git a/src/driver_amiplus.cc b/src/driver_amiplus.cc index e23b658..020e0ce 100644 --- a/src/driver_amiplus.cc +++ b/src/driver_amiplus.cc @@ -44,6 +44,7 @@ namespace DEFAULT_PRINT_PROPERTIES, Quantity::Energy, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::AnyEnergyVIF) @@ -55,6 +56,7 @@ namespace DEFAULT_PRINT_PROPERTIES, Quantity::Power, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::PowerW) @@ -66,6 +68,7 @@ namespace DEFAULT_PRINT_PROPERTIES, Quantity::Energy, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(DifVifKey("0E833C")) ); @@ -76,6 +79,7 @@ namespace DEFAULT_PRINT_PROPERTIES, Quantity::Power, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(DifVifKey("0BAB3C")) ); @@ -86,6 +90,7 @@ namespace DEFAULT_PRINT_PROPERTIES, Quantity::Voltage, VifScaling::None, + DifSignedness::Signed, FieldMatcher::build() .set(DifVifKey("0AFDC9FC01")) ); @@ -96,6 +101,7 @@ namespace DEFAULT_PRINT_PROPERTIES, Quantity::Voltage, VifScaling::None, + DifSignedness::Signed, FieldMatcher::build() .set(DifVifKey("0AFDC9FC02")) ); @@ -106,6 +112,7 @@ namespace DEFAULT_PRINT_PROPERTIES, Quantity::Voltage, VifScaling::None, + DifSignedness::Signed, FieldMatcher::build() .set(DifVifKey("0AFDC9FC03")) ); @@ -125,6 +132,7 @@ namespace DEFAULT_PRINT_PROPERTIES, // , Quantity::Energy, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::AnyEnergyVIF) @@ -137,6 +145,7 @@ namespace DEFAULT_PRINT_PROPERTIES, // , Quantity::Energy, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::AnyEnergyVIF) @@ -149,6 +158,7 @@ namespace DEFAULT_PRINT_PROPERTIES, Quantity::Energy, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::AnyEnergyVIF) @@ -161,6 +171,7 @@ namespace DEFAULT_PRINT_PROPERTIES, Quantity::Energy, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(DifVifKey("8E10833C")) ); @@ -171,6 +182,7 @@ namespace DEFAULT_PRINT_PROPERTIES, Quantity::Energy, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(DifVifKey("8E20833C")) ); @@ -181,6 +193,7 @@ namespace DEFAULT_PRINT_PROPERTIES, Quantity::Energy, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(DifVifKey("8E30833C")) ); @@ -191,6 +204,7 @@ namespace DEFAULT_PRINT_PROPERTIES, Quantity::Power, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Maximum) .set(VIFRange::AnyPowerVIF) diff --git a/src/driver_dynamic.cc b/src/driver_dynamic.cc index 288c2fb..9ccc95a 100644 --- a/src/driver_dynamic.cc +++ b/src/driver_dynamic.cc @@ -30,6 +30,7 @@ void check_detection_triplets(DriverInfo *di, string file); string check_field_name(const char *name, DriverDynamic *dd); Quantity check_field_quantity(const char *quantity_s, DriverDynamic *dd); VifScaling check_vif_scaling(const char *vif_scaling_s, DriverDynamic *dd); +DifSignedness check_dif_signedness(const char *dif_signedness_s, DriverDynamic *dd); PrintProperties check_print_properties(const char *print_properties_s, DriverDynamic *dd); string get_translation(XMQDoc *doc, XMQNode *node, string name, string lang); string check_calculate(const char *formula, DriverDynamic *dd); @@ -269,6 +270,9 @@ XMQProceed DriverDynamic::add_field(XMQDoc *doc, XMQNode *field, DriverDynamic * // The vif scaling is by default Auto but can be overriden for pesky fields. VifScaling vif_scaling = check_vif_scaling(xmqGetString(doc, field, "vif_scaling"), dd); + // The dif signedness is by default Signed but can be overriden for pesky fields. + DifSignedness dif_signedness = check_dif_signedness(xmqGetString(doc, field, "dif_signedness"), dd); + // The properties are by default empty but can be specified for specific fields. PrintProperties properties = check_print_properties(xmqGetString(doc, field, "attributes"), dd); @@ -313,6 +317,7 @@ XMQProceed DriverDynamic::add_field(XMQDoc *doc, XMQNode *field, DriverDynamic * properties, quantity, vif_scaling, + dif_signedness, match, display_unit ); @@ -635,12 +640,12 @@ VifScaling check_vif_scaling(const char *vif_scaling_s, DriverDynamic *dd) warning("(driver) error in %s, bad vif scaling: %s\n", "%s\n" "Available vif scalings:\n" - "%s\n" + "Auto\n" + "None\n" "%s\n", dd->fileName().c_str(), vif_scaling_s, line, - "???", line); throw 1; } @@ -648,6 +653,33 @@ VifScaling check_vif_scaling(const char *vif_scaling_s, DriverDynamic *dd) return vif_scaling; } +DifSignedness check_dif_signedness(const char *dif_signedness_s, DriverDynamic *dd) +{ + if (!dif_signedness_s) + { + return DifSignedness::Signed; + } + + DifSignedness dif_signedness = toDifSignedness(dif_signedness_s); + + if (dif_signedness == DifSignedness::Unknown) + { + warning("(driver) error in %s, bad dif signedness: %s\n", + "%s\n" + "Available dif signedness:\n" + "Signed\n" + "Unsigned\n" + "%s\n", + dd->fileName().c_str(), + dif_signedness_s, + line, + line); + throw 1; + } + + return dif_signedness; +} + PrintProperties check_print_properties(const char *print_properties_s, DriverDynamic *dd) { if (!print_properties_s) diff --git a/src/dvparser.cc b/src/dvparser.cc index 88679e9..9373990 100644 --- a/src/dvparser.cc +++ b/src/dvparser.cc @@ -762,7 +762,7 @@ bool extractDVdouble(map> *dv_entries, int *offset, double *value, bool auto_scale, - bool assume_signed) + bool force_unsigned) { if ((*dv_entries).count(key) == 0) { verbose("(dvparser) warning: cannot extract double from non-existant key \"%s\"\n", key.c_str()); @@ -780,7 +780,7 @@ bool extractDVdouble(map> *dv_entries, return false; } - return p.second.extractDouble(value, auto_scale, assume_signed); + return p.second.extractDouble(value, auto_scale, force_unsigned); } bool checkSizeHex(size_t expected_len, DifVifKey &dvk, string &v) @@ -801,7 +801,7 @@ bool is_all_F(string &v) return true; } -bool DVEntry::extractDouble(double *out, bool auto_scale, bool assume_signed) +bool DVEntry::extractDouble(double *out, bool auto_scale, bool force_unsigned) { int t = dif_vif_key.dif() & 0xf; if (t == 0x0 || @@ -830,17 +830,17 @@ bool DVEntry::extractDouble(double *out, bool auto_scale, bool assume_signed) if (!checkSizeHex(2, dif_vif_key, value)) return false; assert(v.size() == 1); raw = v[0]; - if (assume_signed && (raw & (uint64_t)0x80UL) != 0) { negate = true; negate_mask = ~((uint64_t)0)<<8; } + if (!force_unsigned && (raw & (uint64_t)0x80UL) != 0) { negate = true; negate_mask = ~((uint64_t)0)<<8; } } else if (t == 0x2) { if (!checkSizeHex(4, dif_vif_key, value)) return false; assert(v.size() == 2); raw = v[1]*256 + v[0]; - if (assume_signed && (raw & (uint64_t)0x8000UL) != 0) { negate = true; negate_mask = ~((uint64_t)0)<<16; } + if (!force_unsigned && (raw & (uint64_t)0x8000UL) != 0) { negate = true; negate_mask = ~((uint64_t)0)<<16; } } else if (t == 0x3) { if (!checkSizeHex(6, dif_vif_key, value)) return false; assert(v.size() == 3); raw = v[2]*256*256 + v[1]*256 + v[0]; - if (assume_signed && (raw & (uint64_t)0x800000UL) != 0) { negate = true; negate_mask = ~((uint64_t)0)<<24; } + if (!force_unsigned && (raw & (uint64_t)0x800000UL) != 0) { negate = true; negate_mask = ~((uint64_t)0)<<24; } } else if (t == 0x4) { if (!checkSizeHex(8, dif_vif_key, value)) return false; assert(v.size() == 4); @@ -848,7 +848,7 @@ bool DVEntry::extractDouble(double *out, bool auto_scale, bool assume_signed) + ((unsigned int)v[2])*256*256 + ((unsigned int)v[1])*256 + ((unsigned int)v[0]); - if (assume_signed && (raw & (uint64_t)0x80000000UL) != 0) { negate = true; negate_mask = ~((uint64_t)0)<<32; } + if (!force_unsigned && (raw & (uint64_t)0x80000000UL) != 0) { negate = true; negate_mask = ~((uint64_t)0)<<32; } } else if (t == 0x6) { if (!checkSizeHex(12, dif_vif_key, value)) return false; assert(v.size() == 6); @@ -858,7 +858,7 @@ bool DVEntry::extractDouble(double *out, bool auto_scale, bool assume_signed) + ((uint64_t)v[2])*256*256 + ((uint64_t)v[1])*256 + ((uint64_t)v[0]); - if (assume_signed && (raw & (uint64_t)0x800000000000UL) != 0) { negate = true; negate_mask = ~((uint64_t)0)<<48; } + if (!force_unsigned && (raw & (uint64_t)0x800000000000UL) != 0) { negate = true; negate_mask = ~((uint64_t)0)<<48; } } else if (t == 0x7) { if (!checkSizeHex(16, dif_vif_key, value)) return false; assert(v.size() == 8); @@ -870,7 +870,7 @@ bool DVEntry::extractDouble(double *out, bool auto_scale, bool assume_signed) + ((uint64_t)v[2])*256*256 + ((uint64_t)v[1])*256 + ((uint64_t)v[0]); - if (assume_signed && (raw & (uint64_t)0x8000000000000000UL) != 0) { negate = true; negate_mask = 0; } + if (!force_unsigned && (raw & (uint64_t)0x8000000000000000UL) != 0) { negate = true; negate_mask = 0; } } double scale = 1.0; double draw = (double)raw; @@ -888,8 +888,8 @@ bool DVEntry::extractDouble(double *out, bool auto_scale, bool assume_signed) t == 0xC || // 8 digit BCD t == 0xE) // 12 digit BCD { - // Signed BCD values are always visible in bcd! Top nybble is f. We can force assume_signed to true. - assume_signed = true; + // Negative BCD values are always visible in bcd. I.e. they are always signed. + // Ignore assumption on signedness. // 74140000 -> 00001474 string& v = value; uint64_t raw = 0; @@ -902,29 +902,29 @@ bool DVEntry::extractDouble(double *out, bool auto_scale, bool assume_signed) } if (t == 0x9) { if (!checkSizeHex(2, dif_vif_key, v)) return false; - if (assume_signed && v[0] == 'F') { negate = true; v[0] = '0'; } + if (v[0] == 'F') { negate = true; v[0] = '0'; } raw = (v[0]-'0')*10 + (v[1]-'0'); } else if (t == 0xA) { if (!checkSizeHex(4, dif_vif_key, v)) return false; - if (assume_signed && v[2] == 'F') { negate = true; v[2] = '0'; } + if (v[2] == 'F') { negate = true; v[2] = '0'; } raw = (v[2]-'0')*10*10*10 + (v[3]-'0')*10*10 + (v[0]-'0')*10 + (v[1]-'0'); } else if (t == 0xB) { if (!checkSizeHex(6, dif_vif_key, v)) return false; - if (assume_signed && v[4] == 'F') { negate = true; v[4] = '0'; } + if (v[4] == 'F') { negate = true; v[4] = '0'; } raw = (v[4]-'0')*10*10*10*10*10 + (v[5]-'0')*10*10*10*10 + (v[2]-'0')*10*10*10 + (v[3]-'0')*10*10 + (v[0]-'0')*10 + (v[1]-'0'); } else if (t == 0xC) { if (!checkSizeHex(8, dif_vif_key, v)) return false; - if (assume_signed && v[6] == 'F') { negate = true; v[6] = '0'; } + if (v[6] == 'F') { negate = true; v[6] = '0'; } raw = (v[6]-'0')*10*10*10*10*10*10*10 + (v[7]-'0')*10*10*10*10*10*10 + (v[4]-'0')*10*10*10*10*10 + (v[5]-'0')*10*10*10*10 + (v[2]-'0')*10*10*10 + (v[3]-'0')*10*10 + (v[0]-'0')*10 + (v[1]-'0'); } else if (t == 0xE) { if (!checkSizeHex(12, dif_vif_key, v)) return false; - if (assume_signed && v[10] == 'F') { negate = true; v[10] = '0'; } + if (v[10] == 'F') { negate = true; v[10] = '0'; } raw =(v[10]-'0')*10*10*10*10*10*10*10*10*10*10*10 + (v[11]-'0')*10*10*10*10*10*10*10*10*10*10 + (v[8]-'0')*10*10*10*10*10*10*10*10*10 + (v[9]-'0')*10*10*10*10*10*10*10*10 + (v[6]-'0')*10*10*10*10*10*10*10 + (v[7]-'0')*10*10*10*10*10*10 diff --git a/src/dvparser.h b/src/dvparser.h index 5df1ffe..ebc5962 100644 --- a/src/dvparser.h +++ b/src/dvparser.h @@ -381,7 +381,7 @@ struct DVEntry { } - bool extractDouble(double *out, bool auto_scale, bool assume_signed); + bool extractDouble(double *out, bool auto_scale, bool force_unsigned); bool extractLong(uint64_t *out); bool extractDate(struct tm *out); bool extractReadableString(std::string *out); @@ -561,7 +561,7 @@ bool extractDVdouble(std::map> *values, int *offset, double *value, bool auto_scale = true, - bool assume_signed = false); + bool force_unsigned = false); // Extract a value without scaling. Works for 8bits to 64 bits, binary and bcd. bool extractDVlong(std::map> *values, diff --git a/src/meters.cc b/src/meters.cc index d2efca5..69ed5fd 100644 --- a/src/meters.cc +++ b/src/meters.cc @@ -461,6 +461,7 @@ void MeterCommonImplementation::addNumericFieldWithExtractor(string vname, PrintProperties print_properties, Quantity vquantity, VifScaling vif_scaling, + DifSignedness dif_signedness, FieldMatcher matcher, Unit display_unit, double scale) @@ -471,6 +472,7 @@ void MeterCommonImplementation::addNumericFieldWithExtractor(string vname, vquantity, display_unit == Unit::Unknown ? defaultUnitForQuantity(vquantity) : display_unit, vif_scaling, + dif_signedness, scale, matcher, help, @@ -510,6 +512,7 @@ void MeterCommonImplementation::addNumericFieldWithCalculator(string vname, vquantity, display_unit == Unit::Unknown ? defaultUnitForQuantity(vquantity) : display_unit, VifScaling::Auto, + DifSignedness::Signed, 1.0, FieldMatcher::noMatcher(), help, @@ -550,6 +553,7 @@ void MeterCommonImplementation::addNumericFieldWithCalculatorAndMatcher(string v vquantity, display_unit == Unit::Unknown ? defaultUnitForQuantity(vquantity) : display_unit, VifScaling::Auto, + DifSignedness::Signed, 1.0, matcher, help, @@ -577,6 +581,7 @@ void MeterCommonImplementation::addNumericField( vquantity, display_unit == Unit::Unknown ? defaultUnitForQuantity(vquantity) : display_unit, VifScaling::None, + DifSignedness::Signed, 1.0, FieldMatcher::noMatcher(), help, @@ -601,6 +606,7 @@ void MeterCommonImplementation::addStringFieldWithExtractor(string vname, Quantity::Text, defaultUnitForQuantity(Quantity::Text), VifScaling::None, + DifSignedness::Signed, 1.0, matcher, help, @@ -626,6 +632,7 @@ void MeterCommonImplementation::addStringFieldWithExtractorAndLookup(string vnam Quantity::Text, defaultUnitForQuantity(Quantity::Text), VifScaling::None, + DifSignedness::Signed, 1.0, matcher, help, @@ -649,6 +656,7 @@ void MeterCommonImplementation::addStringField(string vname, Quantity::Text, defaultUnitForQuantity(Quantity::Text), VifScaling::None, + DifSignedness::Signed, 1.0, FieldMatcher(), help, @@ -1670,6 +1678,7 @@ FieldInfo::FieldInfo(int index, Quantity xuantity, Unit display_unit, VifScaling vif_scaling, + DifSignedness dif_signedness, double scale, FieldMatcher matcher, string help, @@ -1686,6 +1695,7 @@ FieldInfo::FieldInfo(int index, xuantity_(xuantity), display_unit_(display_unit), vif_scaling_(vif_scaling), + dif_signedness_(dif_signedness), scale_(scale), matcher_(matcher), help_(help), @@ -2336,11 +2346,11 @@ bool FieldInfo::extractNumeric(Meter *m, Telegram *t, DVEntry *dve) } double extracted_double_value = NAN; - if (dve->extractDouble(&extracted_double_value, - vifScaling() == VifScaling::Auto || - vifScaling() == VifScaling::AutoSigned, - vifScaling() == VifScaling::NoneSigned || - vifScaling() == VifScaling::AutoSigned)) + + bool auto_vif_scaling = vifScaling() == VifScaling::Auto; + bool force_unsigned = difSignedness() == DifSignedness::Unsigned; + + if (dve->extractDouble(&extracted_double_value, auto_vif_scaling, force_unsigned)) { Unit decoded_unit = displayUnit(); if (matcher_.vif_range == VIFRange::DateTime) @@ -2607,6 +2617,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names) DEFAULT_PRINT_PROPERTIES, Quantity::Time, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::ActualityDuration), @@ -2622,6 +2633,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names) DEFAULT_PRINT_PROPERTIES, Quantity::Time, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::ActualityDuration) @@ -2744,6 +2756,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names) DEFAULT_PRINT_PROPERTIES, Quantity::Time, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::OperatingTime) @@ -2758,6 +2771,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names) DEFAULT_PRINT_PROPERTIES, Quantity::Time, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::OnTime) @@ -2772,6 +2786,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names) DEFAULT_PRINT_PROPERTIES, Quantity::Time, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::AtError) .set(VIFRange::OnTime) @@ -2834,6 +2849,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names) DEFAULT_PRINT_PROPERTIES, Quantity::Volume, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::Volume) @@ -2848,6 +2864,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names) DEFAULT_PRINT_PROPERTIES, Quantity::Volume, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::Volume) @@ -2863,6 +2880,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names) DEFAULT_PRINT_PROPERTIES, Quantity::PointInTime, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::Date) @@ -2879,6 +2897,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names) DEFAULT_PRINT_PROPERTIES, Quantity::Volume, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::Volume) @@ -2894,6 +2913,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names) DEFAULT_PRINT_PROPERTIES, Quantity::Volume, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::Volume) @@ -2909,6 +2929,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names) DEFAULT_PRINT_PROPERTIES, Quantity::Temperature, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::FlowTemperature) @@ -2923,6 +2944,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names) DEFAULT_PRINT_PROPERTIES, Quantity::Temperature, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::ExternalTemperature) @@ -2937,6 +2959,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names) DEFAULT_PRINT_PROPERTIES, Quantity::Temperature, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::ReturnTemperature) @@ -2950,7 +2973,8 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names) "The difference between flow and return media temperatures.", DEFAULT_PRINT_PROPERTIES, Quantity::Temperature, - VifScaling::AutoSigned, + VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::TemperatureDifference) @@ -2965,6 +2989,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names) DEFAULT_PRINT_PROPERTIES, Quantity::Flow, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::VolumeFlow) @@ -2979,6 +3004,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names) DEFAULT_PRINT_PROPERTIES, Quantity::Dimensionless, VifScaling::None, + DifSignedness::Unsigned, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::AccessNumber) @@ -2993,6 +3019,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names) DEFAULT_PRINT_PROPERTIES, Quantity::HCA, VifScaling::Auto, + DifSignedness::Signed, FieldMatcher::build() .set(MeasurementType::Instantaneous) .set(VIFRange::HeatCostAllocation) @@ -3010,10 +3037,8 @@ const char *toString(VifScaling s) { switch (s) { - case VifScaling::None: return "None"; case VifScaling::Auto: return "Auto"; - case VifScaling::NoneSigned: return "NoneSigned"; - case VifScaling::AutoSigned: return "AutoSigned"; + case VifScaling::None: return "None"; case VifScaling::Unknown: return "Unknown"; } return "?"; @@ -3022,14 +3047,32 @@ const char *toString(VifScaling s) VifScaling toVifScaling(const char *s) { if (!s) return VifScaling::Unknown; - if (!strcmp(s, "None")) return VifScaling::None; if (!strcmp(s, "Auto")) return VifScaling::Auto; - if (!strcmp(s, "NoneSigned")) return VifScaling::NoneSigned; - if (!strcmp(s, "AutoSigned")) return VifScaling::AutoSigned; + if (!strcmp(s, "None")) return VifScaling::None; if (!strcmp(s, "Unknown")) return VifScaling::Unknown; return VifScaling::Unknown; } +const char *toString(DifSignedness s) +{ + switch (s) + { + case DifSignedness::Signed: return "Signed"; + case DifSignedness::Unsigned: return "Unsigned"; + case DifSignedness::Unknown: return "Unknown"; + } + return "?"; +} + +DifSignedness toDifSignedness(const char *s) +{ + if (!s) return DifSignedness::Unknown; + if (!strcmp(s, "Signed")) return DifSignedness::Signed; + if (!strcmp(s, "Unsigned")) return DifSignedness::Unsigned; + if (!strcmp(s, "Unknown")) return DifSignedness::Unknown; + return DifSignedness::Unknown; +} + const char* toString(PrintProperty p) { switch(p) diff --git a/src/meters.h b/src/meters.h index 691f7af..8f84611 100644 --- a/src/meters.h +++ b/src/meters.h @@ -229,16 +229,24 @@ vector& allDrivers(); enum class VifScaling { - None, // No auto scaling. Auto, // Scale to normalized VIF unit (ie kwh, m3, m3h etc) - NoneSigned, // No auto scaling however assume the value is signed. - AutoSigned, // Scale and assume the value is signed. + None, // No auto scaling. Unknown }; const char* toString(VifScaling s); VifScaling toVifScaling(const char *s); +enum class DifSignedness +{ + Signed, // By default the binary values are interpreted as signed. + Unsigned, // We can override for non-compliant meters. + Unknown +}; + +const char* toString(DifSignedness s); +DifSignedness toDifSignedness(const char *s); + enum PrintProperty { REQUIRED = 1, // If no data has arrived, then print this field anyway with NaN or null. @@ -283,6 +291,7 @@ struct FieldInfo Quantity quantity, Unit display_unit, VifScaling vif_scaling, + DifSignedness dif_signedness, double scale, FieldMatcher matcher, string help, @@ -300,6 +309,7 @@ struct FieldInfo Quantity xuantity() { return xuantity_; } Unit displayUnit() { return display_unit_; } VifScaling vifScaling() { return vif_scaling_; } + DifSignedness difSignedness() { return dif_signedness_; } double scale() { return scale_; } FieldMatcher& matcher() { return matcher_; } string help() { return help_; } @@ -337,6 +347,7 @@ private: Quantity xuantity_; // Quantity: Energy, Volume Unit display_unit_; // Selected display unit for above quantity: KWH, M3 VifScaling vif_scaling_; + DifSignedness dif_signedness_; double scale_; // A hardcoded scale factor. Used only for manufacturer specific values with unknown units for the vifs. FieldMatcher matcher_; string help_; // Helpful information on this meters use of this value. diff --git a/src/meters_common_implementation.h b/src/meters_common_implementation.h index 85ee8fd..f04dcfa 100644 --- a/src/meters_common_implementation.h +++ b/src/meters_common_implementation.h @@ -111,6 +111,7 @@ protected: PrintProperties print_properties, // Should this be printed by default in fields,json and hr. Quantity vquantity, // Value belongs to this quantity, this quantity determines the default unit. VifScaling vif_scaling, // How should any Vif value be scaled. + DifSignedness dif_signedness, // Should we override the default signed assumption for binary values? FieldMatcher matcher, Unit display_unit = Unit::Unknown, // If specified use this unit for the json field instead instead of the default unit. double scale = 1.0); // A hard coded extra scale factor. Useful for manufacturer specific values.