wmbusmeters/src/dvparser.h

300 wiersze
10 KiB
C
Czysty Zwykły widok Historia

2018-04-01 06:53:37 +00:00
/*
Copyright (C) 2018-2022 Fredrik Öhrström (gpl-3.0-or-later)
2018-04-01 06:53:37 +00:00
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/>.
*/
#ifndef DVPARSER_H
#define DVPARSER_H
#include"util.h"
2022-01-13 08:51:08 +00:00
#include"units.h"
2018-04-01 06:53:37 +00:00
#include<map>
#include<stdint.h>
#include<time.h>
2018-04-01 06:53:37 +00:00
#include<functional>
#include<vector>
2022-04-16 15:47:20 +00:00
#define LIST_OF_VIF_RANGES \
2022-01-13 08:51:08 +00:00
X(Volume,0x10,0x17,Quantity::Volume,Unit::M3) \
X(OperatingTime,0x24,0x27, Quantity::Time, Unit::Second) \
X(VolumeFlow,0x38,0x3F, Quantity::Flow, Unit::M3H) \
X(FlowTemperature,0x58,0x5B, Quantity::Temperature, Unit::C) \
X(ReturnTemperature,0x5C,0x5F, Quantity::Temperature, Unit::C) \
X(TemperatureDifference,0x60,0x63, Quantity::Temperature, Unit::C) \
X(ExternalTemperature,0x64,0x67, Quantity::Temperature, Unit::C) \
X(HeatCostAllocation,0x6E,0x6E, Quantity::HCA, Unit::HCA) \
X(Date,0x6C,0x6C, Quantity::PointInTime, Unit::DateTimeLT) \
X(DateTime,0x6D,0x6D, Quantity::PointInTime, Unit::DateTimeLT) \
X(EnergyMJ,0x0E,0x0F, Quantity::Energy, Unit::MJ) \
X(EnergyWh,0x00,0x07, Quantity::Energy, Unit::KWH) \
X(PowerW,0x28,0x2f, Quantity::Power, Unit::KW) \
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(AnyVolumeVIF,0x00,0x00, Quantity::Volume, Unit::Unknown) \
X(AnyEnergyVIF,0x00,0x00, Quantity::Energy, Unit::Unknown) \
X(AnyPowerVIF,0x00,0x00, Quantity::Power, Unit::Unknown) \
2022-04-16 15:47:20 +00:00
enum class VIFRange
{
2020-03-23 17:58:34 +00:00
None,
2022-01-06 17:28:22 +00:00
Any,
2022-01-13 08:51:08 +00:00
#define X(name,from,to,quantity,unit) name,
2022-04-16 15:47:20 +00:00
LIST_OF_VIF_RANGES
#undef X
};
2022-04-16 15:47:20 +00:00
const char *toString(VIFRange v);
Unit toDefaultUnit(VIFRange v);
VIFRange toVIFRange(int i);
bool isInsideVIFRange(int i, VIFRange range);
enum class MeasurementType
{
Instantaneous,
Minimum,
Maximum,
AtError
};
2022-01-06 17:28:22 +00:00
struct DifVifKey
{
2022-04-16 15:47:20 +00:00
DifVifKey(std::string key) : key_(key) {}
std::string str() { return key_; }
2022-04-17 09:23:45 +00:00
bool operator==(DifVifKey &dvk) { return key_ == dvk.key_; }
2022-01-06 17:28:22 +00:00
private:
2022-04-16 15:47:20 +00:00
std::string key_;
2022-01-06 17:28:22 +00:00
};
static DifVifKey NoDifVifKey = DifVifKey("");
2022-04-16 15:47:20 +00:00
struct Vif
{
Vif(int n) : nr_(n) {}
int intValue() { return nr_; }
bool operator==(Vif s) { return nr_ == s.nr_; }
private:
int nr_;
};
2022-01-06 17:28:22 +00:00
struct StorageNr
{
StorageNr(int n) : nr_(n) {}
int intValue() { return nr_; }
2022-04-16 15:47:20 +00:00
bool operator==(StorageNr s) { return nr_ == s.nr_; }
2022-04-17 09:23:45 +00:00
bool operator>=(StorageNr s) { return nr_ >= s.nr_; }
bool operator<=(StorageNr s) { return nr_ <= s.nr_; }
2022-01-06 17:28:22 +00:00
private:
int nr_;
};
static StorageNr AnyStorageNr = StorageNr(-1);
struct TariffNr
{
TariffNr(int n) : nr_(n) {}
int intValue() { return nr_; }
2022-04-16 15:47:20 +00:00
bool operator==(TariffNr s) { return nr_ == s.nr_; }
2022-04-17 09:23:45 +00:00
bool operator>=(TariffNr s) { return nr_ >= s.nr_; }
bool operator<=(TariffNr s) { return nr_ <= s.nr_; }
2022-01-06 17:28:22 +00:00
private:
int nr_;
};
static TariffNr AnyTariffNr = TariffNr(-1);
2022-04-16 15:47:20 +00:00
struct SubUnitNr
{
SubUnitNr(int n) : nr_(n) {}
int intValue() { return nr_; }
bool operator==(SubUnitNr s) { return nr_ == s.nr_; }
2022-04-17 09:23:45 +00:00
bool operator>=(SubUnitNr s) { return nr_ >= s.nr_; }
bool operator<=(SubUnitNr s) { return nr_ <= s.nr_; }
2022-04-16 15:47:20 +00:00
private:
int nr_;
};
2022-01-06 17:28:22 +00:00
struct IndexNr
{
IndexNr(int n) : nr_(n) {}
int intValue() { return nr_; }
2022-04-16 15:47:20 +00:00
bool operator==(IndexNr s) { return nr_ == s.nr_; }
2022-01-06 17:28:22 +00:00
private:
int nr_;
};
static IndexNr AnyIndexNr = IndexNr(-1);
2022-04-16 15:47:20 +00:00
struct DVEntry
{
2022-04-17 13:54:01 +00:00
int offset { 0 }; // Where in the telegram this dventry was found.
2022-04-17 09:23:45 +00:00
DifVifKey dif_vif_key { "" };
MeasurementType measurement_type {};
2022-04-16 16:15:30 +00:00
Vif vif { 0 };
2022-04-17 09:23:45 +00:00
StorageNr storage_nr { 0 };
TariffNr tariff_nr { 0 };
SubUnitNr subunit_nr { 0 };
2022-04-16 15:47:20 +00:00
std::string value;
DVEntry() {}
2022-04-17 13:54:01 +00:00
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) {}
2022-04-17 12:57:03 +00:00
bool extractDouble(double *out, bool auto_scale, bool assume_signed);
2022-04-17 13:05:34 +00:00
bool extractLong(uint64_t *out);
2022-04-16 15:47:20 +00:00
};
struct FieldMatcher
{
// Exact difvif hex string matching all other checks are ignored.
bool match_dif_vif_key = false;
DifVifKey dif_vif_key { "" };
// Match the measurement_type.
bool match_measurement_type = false;
MeasurementType measurement_type { MeasurementType::Instantaneous };
// Match the value information range. See dvparser.h
2022-04-17 09:23:45 +00:00
bool match_vif_range = false;
VIFRange vif_range { VIFRange::None };
2022-04-16 15:47:20 +00:00
// Match the storage nr.
bool match_storage_nr = false;
2022-04-17 09:23:45 +00:00
StorageNr storage_nr_from { 0 };
StorageNr storage_nr_to { 0 };
2022-04-16 15:47:20 +00:00
// Match the tariff nr.
bool match_tariff_nr = false;
2022-04-17 09:23:45 +00:00
TariffNr tariff_nr_from { 0 };
TariffNr tariff_nr_to { 0 };
2022-04-16 15:47:20 +00:00
// Match the subunit.
bool match_subunit_nr = false;
2022-04-17 09:23:45 +00:00
SubUnitNr subunit_nr_from { 0 };
SubUnitNr subunit_nr_to { 0 };
2022-04-16 15:47:20 +00:00
// If the telegram has multiple identical difvif entries, use entry with this index nr.
// First entry has nr 1, which is the default value.
bool match_index_nr = false;
IndexNr index_nr { 1 };
static FieldMatcher build() { return FieldMatcher(); }
void set(DifVifKey k) { dif_vif_key = k; }
FieldMatcher &set(MeasurementType mt) { measurement_type = mt; return *this; }
2022-04-17 09:23:45 +00:00
FieldMatcher &set(VIFRange v) { vif_range = v; return *this; }
FieldMatcher &set(StorageNr s) { storage_nr_from = storage_nr_to = s; return *this; }
FieldMatcher &set(StorageNr from, StorageNr to) { storage_nr_from = from; storage_nr_to = to; return *this; }
FieldMatcher &set(TariffNr s) { tariff_nr_from = tariff_nr_to = s; return *this; }
FieldMatcher &set(TariffNr from, TariffNr to) { tariff_nr_from = from; tariff_nr_to = to; return *this; }
FieldMatcher &set(SubUnitNr s) { subunit_nr_from = subunit_nr_to = s; return *this; }
FieldMatcher &set(SubUnitNr from, SubUnitNr to) { subunit_nr_from = from; subunit_nr_to = to; return *this; }
2022-04-16 15:47:20 +00:00
FieldMatcher &set(IndexNr i) { index_nr = i; return *this; }
2022-04-17 09:23:45 +00:00
bool matches(DVEntry &dv_entry);
2022-04-16 15:47:20 +00:00
};
bool loadFormatBytesFromSignature(uint16_t format_signature, std::vector<uchar> *format_bytes);
struct Telegram;
2018-04-01 06:53:37 +00:00
bool parseDV(Telegram *t,
std::vector<uchar> &databytes,
2018-04-01 06:53:37 +00:00
std::vector<uchar>::iterator data,
size_t data_len,
std::map<std::string,std::pair<int,DVEntry>> *dv_entries,
std::vector<DVEntry*> *dv_entries_ordered,
2018-04-01 06:53:37 +00:00
std::vector<uchar>::iterator *format = NULL,
size_t format_len = 0,
uint16_t *format_hash = NULL);
2018-04-01 06:53:37 +00:00
// Instead of using a hardcoded difvif as key in the extractDV... below,
// find an existing difvif entry in the values based on the desired value information type.
// Like: Volume, VolumeFlow, FlowTemperature, ExternalTemperature etc
// in combination with the storagenr. (Later I will add tariff/subunit)
2022-04-16 15:47:20 +00:00
bool findKey(MeasurementType mt, VIFRange vi, StorageNr storagenr, TariffNr tariffnr,
std::string *key, std::map<std::string,std::pair<int,DVEntry>> *values);
2021-10-02 09:36:33 +00:00
// Some meters have multiple identical DIF/VIF values! Meh, they are not using storage nrs or tariff nrs.
// So here we can pick for example nr 2 of an identical set if DIF/VIF values.
// Nr 1 means the first found value.
2022-04-16 15:47:20 +00:00
bool findKeyWithNr(MeasurementType mt, VIFRange vi, StorageNr storagenr, TariffNr tariffnr, int indexnr,
2021-10-02 09:36:33 +00:00
std::string *key, std::map<std::string,std::pair<int,DVEntry>> *values);
2019-03-01 14:41:11 +00:00
bool hasKey(std::map<std::string,std::pair<int,DVEntry>> *values, std::string key);
2019-11-26 15:12:32 +00:00
bool extractDVuint8(std::map<std::string,std::pair<int,DVEntry>> *values,
std::string key,
int *offset,
uchar *value);
bool extractDVuint16(std::map<std::string,std::pair<int,DVEntry>> *values,
2018-04-01 06:53:37 +00:00
std::string key,
int *offset,
uint16_t *value);
2020-07-30 10:19:54 +00:00
bool extractDVuint24(std::map<std::string,std::pair<int,DVEntry>> *values,
std::string key,
int *offset,
uint32_t *value);
bool extractDVuint32(std::map<std::string,std::pair<int,DVEntry>> *values,
std::string key,
int *offset,
uint32_t *value);
2021-03-06 06:42:37 +00:00
// All values are scaled according to the vif and wmbusmeters scaling defaults.
bool extractDVdouble(std::map<std::string,std::pair<int,DVEntry>> *values,
2022-01-13 14:06:53 +00:00
std::string key,
int *offset,
double *value,
bool auto_scale = true,
bool assume_signed = false);
2018-04-01 06:53:37 +00:00
2021-03-06 06:42:37 +00:00
// Extract a value without scaling. Works for 8bits to 64 bits, binary and bcd.
2022-04-16 15:47:20 +00:00
bool extractDVlong(std::map<std::string,std::pair<int,DVEntry>> *values,
std::string key,
2021-03-06 06:42:37 +00:00
int *offset,
uint64_t *value);
// Just copy the raw hex data into the string, not reversed or anything.
bool extractDVHexString(std::map<std::string,std::pair<int,DVEntry>> *values,
std::string key,
int *offset,
2022-04-16 15:47:20 +00:00
std::string *value);
// Read the content and attempt to reverse and transform it into a readble string
// based on the dif information.
bool extractDVReadableString(std::map<std::string,std::pair<int,DVEntry>> *values,
std::string key,
int *offset,
2022-04-16 15:47:20 +00:00
std::string *value);
bool extractDVdate(std::map<std::string,std::pair<int,DVEntry>> *values,
std::string key,
int *offset,
2019-03-01 14:41:11 +00:00
struct tm *value);
2022-04-16 15:47:20 +00:00
void extractDV(std::string &s, uchar *dif, uchar *vif);
2022-04-17 12:57:03 +00:00
void extractDV(DifVifKey &s, uchar *dif, uchar *vif);
2018-04-01 06:53:37 +00:00
#endif