2018-04-01 06:53:37 +00:00
/*
2022-04-17 09:23:45 +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/>.
*/
# include "dvparser.h"
2022-04-16 15:47:20 +00:00
# include "wmbus.h"
2018-04-01 06:53:37 +00:00
# include "util.h"
2018-12-28 17:35:32 +00:00
# include <assert.h>
2019-01-01 20:04:06 +00:00
# include <memory.h>
2022-11-19 13:40:03 +00:00
# include <limits>
2018-12-28 17:35:32 +00:00
2018-04-16 18:47:27 +00:00
// The parser should not crash on invalid data, but yeah, when I
// need to debug it because it crashes on invalid data, then
// I enable the following define...
2018-11-01 18:56:42 +00:00
//#define DEBUG_PARSER(...) fprintf(stdout, __VA_ARGS__)
2018-04-16 18:47:27 +00:00
# define DEBUG_PARSER(...)
2018-04-01 06:53:37 +00:00
using namespace std ;
2022-05-25 14:59:55 +00:00
union RealConversion
{
uint32_t i ;
float f ;
} ;
2022-04-16 15:47:20 +00:00
const char * toString ( VIFRange v )
2019-01-27 23:03:25 +00:00
{
switch ( v ) {
2022-04-16 15:47:20 +00:00
case VIFRange : : None : return " None " ;
case VIFRange : : Any : return " Any " ;
# define X(name,from,to,quantity,unit) case VIFRange::name: return #name;
LIST_OF_VIF_RANGES
2022-01-13 08:51:08 +00:00
# undef X
}
assert ( 0 ) ;
}
2022-05-07 17:16:34 +00:00
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 ;
}
2022-11-26 21:21:34 +00:00
Unit toDefaultUnit ( Vif v )
{
# define X(name,from,to,quantity,unit) { if (from <= v.intValue() && v.intValue() <= to) return unit; }
LIST_OF_VIF_RANGES
# undef X
return Unit : : Unknown ;
}
2022-04-16 15:47:20 +00:00
Unit toDefaultUnit ( VIFRange v )
2022-01-13 08:51:08 +00:00
{
switch ( v ) {
2022-04-16 15:47:20 +00:00
case VIFRange : : Any :
case VIFRange : : None :
2022-01-13 08:51:08 +00:00
assert ( 0 ) ;
break ;
2022-04-16 15:47:20 +00:00
# define X(name,from,to,quantity,unit) case VIFRange::name: return unit;
LIST_OF_VIF_RANGES
2019-01-27 23:03:25 +00:00
# undef X
}
assert ( 0 ) ;
}
2022-04-16 15:47:20 +00:00
VIFRange toVIFRange ( int i )
2020-01-28 18:09:39 +00:00
{
2022-04-16 15:47:20 +00:00
# define X(name,from,to,quantity,unit) if (from <= i && i <= to) return VIFRange::name;
LIST_OF_VIF_RANGES
2020-01-28 18:09:39 +00:00
# undef X
2022-04-16 15:47:20 +00:00
return VIFRange : : None ;
}
bool isInsideVIFRange ( Vif vif , VIFRange vif_range )
{
if ( vif_range = = VIFRange : : AnyVolumeVIF )
{
// There are more volume units in the standard that will be added here.
return isInsideVIFRange ( vif , VIFRange : : Volume ) ;
}
if ( vif_range = = VIFRange : : AnyEnergyVIF )
{
return
isInsideVIFRange ( vif , VIFRange : : EnergyWh ) | |
isInsideVIFRange ( vif , VIFRange : : EnergyMJ ) ;
}
if ( vif_range = = VIFRange : : AnyPowerVIF )
{
// There are more power units in the standard that will be added here.
return isInsideVIFRange ( vif , VIFRange : : PowerW ) ;
}
# define X(name,from,to,quantity,unit) if (VIFRange::name == vif_range) { return from <= vif.intValue() && vif.intValue() <= to; }
LIST_OF_VIF_RANGES
# undef X
return false ;
2020-01-28 18:09:39 +00:00
}
2019-01-27 23:03:25 +00:00
map < uint16_t , string > hash_to_format_ ;
bool loadFormatBytesFromSignature ( uint16_t format_signature , vector < uchar > * format_bytes )
{
if ( hash_to_format_ . count ( format_signature ) > 0 ) {
debug ( " (dvparser) found remembered format for hash %x \n " , format_signature ) ;
// Return the proper hash!
hex2bin ( hash_to_format_ [ format_signature ] , format_bytes ) ;
return true ;
}
// Unknown format signature.
return false ;
}
2018-04-01 06:53:37 +00:00
bool parseDV ( Telegram * t ,
2018-12-28 17:35:32 +00:00
vector < uchar > & databytes ,
2018-04-01 06:53:37 +00:00
vector < uchar > : : iterator data ,
size_t data_len ,
2022-04-17 10:47:06 +00:00
map < string , pair < int , DVEntry > > * dv_entries ,
2018-04-01 06:53:37 +00:00
vector < uchar > : : iterator * format ,
size_t format_len ,
2019-08-12 09:47:39 +00:00
uint16_t * format_hash )
2018-04-01 06:53:37 +00:00
{
map < string , int > dv_count ;
vector < uchar > format_bytes ;
2019-01-01 20:04:06 +00:00
vector < uchar > id_bytes ;
2018-04-01 06:53:37 +00:00
vector < uchar > data_bytes ;
string dv , key ;
2018-04-16 18:47:27 +00:00
size_t start_parse_here = t - > parsed . size ( ) ;
2018-04-01 06:53:37 +00:00
vector < uchar > : : iterator data_start = data ;
vector < uchar > : : iterator data_end = data + data_len ;
vector < uchar > : : iterator format_end ;
2019-01-01 20:04:06 +00:00
bool data_has_difvifs = true ;
2018-11-01 18:56:42 +00:00
bool variable_length = false ;
2022-09-28 19:20:43 +00:00
int force_mfct_index = t - > force_mfct_index ;
2018-04-01 06:53:37 +00:00
if ( format = = NULL ) {
2019-01-01 20:04:06 +00:00
// No format string was supplied, we therefore assume
// that the difvifs necessary to parse the data is
// part of the data! This is the default.
2018-04-01 06:53:37 +00:00
format = & data ;
format_end = data_end ;
} else {
2019-01-01 20:04:06 +00:00
// A format string has been supplied. The data is compressed,
// and can only be decoded using the supplied difvifs.
// Since the data does not have the difvifs.
data_has_difvifs = false ;
2018-04-01 06:53:37 +00:00
format_end = * format + format_len ;
2019-03-15 13:21:50 +00:00
string s = bin2hex ( * format , format_end , format_len ) ;
2018-04-01 06:53:37 +00:00
debug ( " (dvparser) using format \" %s \" \n " , s . c_str ( ) ) ;
}
2022-04-19 07:10:14 +00:00
dv_entries - > clear ( ) ;
2018-04-01 06:53:37 +00:00
// Data format is:
2019-01-01 20:04:06 +00:00
2022-04-17 09:23:45 +00:00
// DIF byte (defines how the binary data bits should be decoded and howy man data bytes there are)
2019-01-01 20:04:06 +00:00
// Sometimes followed by one or more dife bytes, if the 0x80 high bit is set.
// The last dife byte does not have the 0x80 bit set.
2018-04-01 06:53:37 +00:00
// VIF byte (defines what the decoded value means, water,energy,power,etc.)
2019-01-01 20:04:06 +00:00
// Sometimes followed by one or more vife bytes, if the 0x80 high bit is set.
// The last vife byte does not have the 0x80 bit set.
// Data bytes, the number of data bytes are defined by the dif format.
// Or if the dif says variable length, then the first data byte specifies the number of data bytes.
2018-04-01 06:53:37 +00:00
// DIF again...
2019-01-01 20:04:06 +00:00
// A Dif(Difes)Vif(Vifes) identifier can be for example be the 02FF20 for the Multical21
// vendor specific status bits. The parser then uses this identifier as a key to store the
2019-03-20 21:16:45 +00:00
// data bytes in a map. The same identifier could occur several times in a telegram,
2019-01-01 20:04:06 +00:00
// even though it often don't. Since the first occurence is stored under 02FF20,
// the second identical identifier stores its data under the key "02FF20_2" etc for 3 and forth...
2019-03-20 21:16:45 +00:00
// A proper meter would use storagenr etc to differentiate between different measurements of
// the same value.
2018-04-01 06:53:37 +00:00
format_bytes . clear ( ) ;
2019-01-01 20:04:06 +00:00
id_bytes . clear ( ) ;
for ( ; ; )
{
id_bytes . clear ( ) ;
2018-11-25 11:33:14 +00:00
DEBUG_PARSER ( " (dvparser debug) Remaining format data %ju \n " , std : : distance ( * format , format_end ) ) ;
2018-04-01 06:53:37 +00:00
if ( * format = = format_end ) break ;
2022-09-28 19:20:43 +00:00
if ( force_mfct_index ! = - 1 )
{
// This is an old meter without a proper 0f or other hear start manufacturer data marker.
int index = std : : distance ( data_start , data ) ;
if ( index > = force_mfct_index )
{
DEBUG_PARSER ( " (dvparser) manufacturer specific data, parsing is done. \n " , dif ) ;
size_t datalen = std : : distance ( data , data_end ) ;
string value = bin2hex ( data , data_end , datalen ) ;
t - > addExplanationAndIncrementPos ( data , datalen , KindOfData : : CONTENT , Understanding : : NONE , " manufacturer specific data %s " , value . c_str ( ) ) ;
break ;
}
}
2018-04-01 06:53:37 +00:00
uchar dif = * * format ;
2018-04-02 14:51:17 +00:00
2019-10-14 18:26:31 +00:00
MeasurementType mt = difMeasurementType ( dif ) ;
2018-11-02 17:06:48 +00:00
int datalen = difLenBytes ( dif ) ;
2019-10-14 18:26:31 +00:00
DEBUG_PARSER ( " (dvparser debug) dif=%02x datalen=%d \" %s \" type=%s \n " , dif , datalen , difType ( dif ) . c_str ( ) ,
measurementTypeName ( mt ) . c_str ( ) ) ;
2022-09-28 19:20:43 +00:00
2020-04-01 15:21:11 +00:00
if ( datalen = = - 2 )
{
if ( dif = = 0x0f )
{
2022-09-27 17:27:37 +00:00
DEBUG_PARSER ( " (dvparser) reached dif %02x manufacturer specific data, parsing is done. \n " , dif ) ;
2020-04-01 15:21:11 +00:00
datalen = std : : distance ( data , data_end ) ;
string value = bin2hex ( data + 1 , data_end , datalen - 1 ) ;
t - > mfct_0f_index = 1 + std : : distance ( data_start , data ) ;
assert ( t - > mfct_0f_index > = 0 ) ;
2022-09-28 19:20:43 +00:00
t - > addExplanationAndIncrementPos ( data , datalen , KindOfData : : CONTENT , Understanding : : NONE , " %02X manufacturer specific data %s " , dif , value . c_str ( ) ) ;
2020-04-01 15:21:11 +00:00
break ;
}
2022-09-27 17:27:37 +00:00
DEBUG_PARSER ( " (dvparser) reached unknown dif %02x treating remaining data as manufacturer specific, parsing is done. \n " , dif ) ;
datalen = std : : distance ( data , data_end ) ;
string value = bin2hex ( data + 1 , data_end , datalen - 1 ) ;
t - > mfct_0f_index = 1 + std : : distance ( data_start , data ) ;
assert ( t - > mfct_0f_index > = 0 ) ;
2022-09-28 19:20:43 +00:00
t - > addExplanationAndIncrementPos ( data , datalen , KindOfData : : CONTENT , Understanding : : NONE , " %02X unknown dif treating remaining data as mfct specific %s " , dif , value . c_str ( ) ) ;
2019-01-01 20:04:06 +00:00
break ;
2018-11-25 11:33:14 +00:00
}
2018-04-02 14:51:17 +00:00
if ( dif = = 0x2f ) {
2021-12-07 22:56:29 +00:00
t - > addExplanationAndIncrementPos ( * format , 1 , KindOfData : : PROTOCOL , Understanding : : FULL , " %02X skip " , dif ) ;
2019-01-01 20:04:06 +00:00
DEBUG_PARSER ( " \n " ) ;
2018-04-02 14:51:17 +00:00
continue ;
}
2018-11-02 17:06:48 +00:00
if ( datalen = = - 1 ) {
2018-11-01 18:56:42 +00:00
variable_length = true ;
} else {
variable_length = false ;
}
2019-01-01 20:04:06 +00:00
if ( data_has_difvifs ) {
2018-04-01 06:53:37 +00:00
format_bytes . push_back ( dif ) ;
2019-01-01 20:04:06 +00:00
id_bytes . push_back ( dif ) ;
2021-12-07 22:56:29 +00:00
t - > addExplanationAndIncrementPos ( * format , 1 , KindOfData : : PROTOCOL , Understanding : : FULL , " %02X dif (%s) " , dif , difType ( dif ) . c_str ( ) ) ;
2018-04-01 06:53:37 +00:00
} else {
2019-01-01 20:04:06 +00:00
id_bytes . push_back ( * * format ) ;
2018-04-01 06:53:37 +00:00
( * format ) + + ;
}
2019-01-01 23:20:10 +00:00
int difenr = 0 ;
int subunit = 0 ;
int tariff = 0 ;
2019-01-27 23:03:25 +00:00
int lsb_of_storage_nr = ( dif & 0x40 ) > > 6 ;
int storage_nr = lsb_of_storage_nr ;
2019-01-01 23:20:10 +00:00
2019-01-01 20:04:06 +00:00
bool has_another_dife = ( dif & 0x80 ) = = 0x80 ;
2019-01-01 23:20:10 +00:00
2022-05-07 17:16:34 +00:00
while ( has_another_dife )
{
2019-03-15 13:27:09 +00:00
if ( * format = = format_end ) { debug ( " (dvparser) warning: unexpected end of data (dife expected) \n " ) ; break ; }
2022-05-07 17:16:34 +00:00
2019-01-01 20:04:06 +00:00
uchar dife = * * format ;
2019-01-01 23:20:10 +00:00
int subunit_bit = ( dife & 0x40 ) > > 6 ;
subunit | = subunit_bit < < difenr ;
int tariff_bits = ( dife & 0x30 ) > > 4 ;
tariff | = tariff_bits < < ( difenr * 2 ) ;
int storage_nr_bits = ( dife & 0x0f ) ;
2019-01-27 23:03:25 +00:00
storage_nr | = storage_nr_bits < < ( 1 + difenr * 4 ) ;
2019-01-01 23:20:10 +00:00
2022-05-07 17:16:34 +00:00
DEBUG_PARSER ( " (dvparser debug) dife=%02x (subunit=%d tariff=%d storagenr=%d) \n " , dife , subunit , tariff , storage_nr ) ;
if ( data_has_difvifs )
{
2019-01-01 20:04:06 +00:00
format_bytes . push_back ( dife ) ;
id_bytes . push_back ( dife ) ;
2021-12-07 22:56:29 +00:00
t - > addExplanationAndIncrementPos ( * format , 1 , KindOfData : : PROTOCOL , Understanding : : FULL ,
" %02X dife (subunit=%d tariff=%d storagenr=%d) " ,
dife , subunit , tariff , storage_nr ) ;
2022-05-07 17:16:34 +00:00
}
else
{
2019-01-01 20:04:06 +00:00
id_bytes . push_back ( * * format ) ;
( * format ) + + ;
}
2019-01-01 23:20:10 +00:00
2019-01-01 20:04:06 +00:00
has_another_dife = ( dife & 0x80 ) = = 0x80 ;
2019-01-01 23:20:10 +00:00
difenr + + ;
2019-01-01 20:04:06 +00:00
}
2019-03-15 13:27:09 +00:00
if ( * format = = format_end ) { debug ( " (dvparser) warning: unexpected end of data (vif expected) \n " ) ; break ; }
2018-04-01 06:53:37 +00:00
uchar vif = * * format ;
2022-05-07 17:16:34 +00:00
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 )
{
2018-04-01 06:53:37 +00:00
format_bytes . push_back ( vif ) ;
2019-01-01 20:04:06 +00:00
id_bytes . push_back ( vif ) ;
2021-12-07 22:56:29 +00:00
t - > addExplanationAndIncrementPos ( * format , 1 , KindOfData : : PROTOCOL , Understanding : : FULL ,
" %02X vif (%s) " , vif , vifType ( vif ) . c_str ( ) ) ;
2022-05-07 17:16:34 +00:00
} else
{
2019-01-01 20:04:06 +00:00
id_bytes . push_back ( * * format ) ;
2018-04-01 06:53:37 +00:00
( * format ) + + ;
}
2022-12-12 12:51:27 +00:00
// Check if this is marker for one of the extended sets of vifs: first, second and third or manufacturer.
if ( vif = = 0xfb | | vif = = 0xfd | | vif = = 0xef | | vif = = 0xff )
2022-05-07 17:16:34 +00:00
{
// Extension vifs.
full_vif < < = 8 ;
extension_vif = true ;
}
2021-11-28 17:23:42 +00:00
// Grabbing a variable length vif. This does not currently work
// with the compact format.
if ( vif = = 0x7c )
{
DEBUG_PARSER ( " (dvparser debug) variable length vif found \n " ) ;
if ( * format = = format_end ) { debug ( " (dvparser) warning: unexpected end of data (vif varlen expected) \n " ) ; break ; }
uchar viflen = * * format ;
2022-09-06 20:18:36 +00:00
id_bytes . push_back ( viflen ) ;
2021-12-07 22:56:29 +00:00
t - > addExplanationAndIncrementPos ( * format , 1 , KindOfData : : PROTOCOL , Understanding : : FULL ,
" %02X viflen (%d) " , viflen , viflen ) ;
2021-11-28 17:23:42 +00:00
for ( uchar i = 0 ; i < viflen ; + + i )
{
if ( * format = = format_end ) { debug ( " (dvparser) warning: unexpected end of data (vif varlen byte %d/%d expected) \n " ,
i + 1 , viflen ) ; break ; }
uchar v = * * format ;
2021-12-07 22:56:29 +00:00
t - > addExplanationAndIncrementPos ( * format , 1 , KindOfData : : PROTOCOL , Understanding : : FULL ,
" %02X vif (%c) " , v , v ) ;
2021-11-28 17:23:42 +00:00
id_bytes . push_back ( v ) ;
}
}
2022-05-07 17:16:34 +00:00
// Do we have another vife byte? We better have one, if extension_vif is true.
2019-01-01 20:04:06 +00:00
bool has_another_vife = ( vif & 0x80 ) = = 0x80 ;
2022-05-07 17:16:34 +00:00
while ( has_another_vife )
{
2019-03-15 13:27:09 +00:00
if ( * format = = format_end ) { debug ( " (dvparser) warning: unexpected end of data (vife expected) \n " ) ; break ; }
2022-05-07 17:16:34 +00:00
2018-04-01 06:53:37 +00:00
uchar vife = * * format ;
2019-01-01 23:20:10 +00:00
DEBUG_PARSER ( " (dvparser debug) vife=%02x (%s) \n " , vife , vifeType ( dif , vif , vife ) . c_str ( ) ) ;
2022-05-07 17:16:34 +00:00
if ( data_has_difvifs )
{
// Collect the difvifs to create signature for future use.
2018-04-01 06:53:37 +00:00
format_bytes . push_back ( vife ) ;
2019-01-01 20:04:06 +00:00
id_bytes . push_back ( vife ) ;
2022-05-07 17:16:34 +00:00
}
else
{
// Reuse the existing
2019-01-01 20:04:06 +00:00
id_bytes . push_back ( * * format ) ;
2018-04-01 06:53:37 +00:00
( * format ) + + ;
}
2022-05-07 17:16:34 +00:00
2019-01-01 20:04:06 +00:00
has_another_vife = ( vife & 0x80 ) = = 0x80 ;
2022-05-07 17:16:34 +00:00
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 ) ) ;
}
}
2019-01-01 20:04:06 +00:00
}
dv = " " ;
for ( uchar c : id_bytes ) {
char hex [ 3 ] ;
hex [ 2 ] = 0 ;
snprintf ( hex , 3 , " %02X " , c ) ;
dv . append ( hex ) ;
2018-04-01 06:53:37 +00:00
}
2019-01-01 20:04:06 +00:00
DEBUG_PARSER ( " (dvparser debug) key \" %s \" \n " , dv . c_str ( ) ) ;
2018-04-01 06:53:37 +00:00
2018-04-16 18:47:27 +00:00
int count = + + dv_count [ dv ] ;
2018-04-01 06:53:37 +00:00
if ( count > 1 ) {
2022-11-01 11:14:48 +00:00
strprintf ( & key , " %s_%d " , dv . c_str ( ) , count ) ;
2018-04-01 06:53:37 +00:00
} else {
2022-11-01 11:14:48 +00:00
strprintf ( & key , " %s " , dv . c_str ( ) ) ;
2018-04-01 06:53:37 +00:00
}
2018-11-25 11:33:14 +00:00
DEBUG_PARSER ( " (dvparser debug) DifVif key is %s \n " , key . c_str ( ) ) ;
2018-04-01 06:53:37 +00:00
2018-11-01 18:56:42 +00:00
int remaining = std : : distance ( data , data_end ) ;
2022-09-04 14:20:16 +00:00
if ( remaining < 1 )
{
debug ( " (dvparser) warning: unexpected end of data \n " ) ;
break ;
}
2018-11-01 18:56:42 +00:00
if ( variable_length ) {
2018-12-28 17:35:32 +00:00
DEBUG_PARSER ( " (dvparser debug) varlen %02x \n " , * ( data + 0 ) ) ;
2021-11-06 19:30:09 +00:00
datalen = * ( data ) ;
2022-10-10 19:43:11 +00:00
t - > addExplanationAndIncrementPos ( data , 1 , KindOfData : : PROTOCOL , Understanding : : FULL , " %02X varlen=%d " , * ( data + 0 ) , datalen ) ;
remaining - - ; // Drop the length byte.
2018-11-01 18:56:42 +00:00
}
2018-11-25 11:33:14 +00:00
DEBUG_PARSER ( " (dvparser debug) remaining data %d len=%d \n " , remaining , datalen ) ;
2022-09-04 14:20:16 +00:00
if ( remaining < datalen )
{
2018-11-29 21:25:50 +00:00
debug ( " (dvparser) warning: unexpected end of data \n " ) ;
2019-03-15 13:21:50 +00:00
datalen = remaining - 1 ;
2018-04-16 18:47:27 +00:00
}
2019-03-15 13:21:50 +00:00
string value = bin2hex ( data , data_end , datalen ) ;
2019-03-01 14:41:11 +00:00
int offset = start_parse_here + data - data_start ;
2022-04-17 10:47:06 +00:00
2022-04-17 13:54:01 +00:00
( * dv_entries ) [ key ] = { offset , DVEntry ( offset ,
key ,
mt ,
2022-05-07 17:16:34 +00:00
Vif ( full_vif ) ,
found_combinable_vifs ,
2022-04-17 13:54:01 +00:00
StorageNr ( storage_nr ) ,
TariffNr ( tariff ) ,
SubUnitNr ( subunit ) ,
value ) } ;
2022-04-17 10:47:06 +00:00
2022-04-23 14:28:54 +00:00
DVEntry * dve = & ( * dv_entries ) [ key ] . second ;
2022-04-17 10:47:06 +00:00
2022-10-10 19:43:11 +00:00
if ( isTraceEnabled ( ) )
2022-05-07 17:16:34 +00:00
{
2022-10-10 19:43:11 +00:00
trace ( " [DVPARSER] entry %s \n " , dve - > str ( ) . c_str ( ) ) ;
}
2022-05-07 17:16:34 +00:00
2022-04-23 14:28:54 +00:00
assert ( key = = dve - > dif_vif_key . str ( ) ) ;
2022-04-17 15:34:51 +00:00
2018-11-02 15:20:46 +00:00
if ( value . length ( ) > 0 ) {
2018-11-25 11:33:14 +00:00
// This call increments data with datalen.
2021-12-07 22:56:29 +00:00
t - > addExplanationAndIncrementPos ( data , datalen , KindOfData : : CONTENT , Understanding : : NONE , " %s " , value . c_str ( ) ) ;
2019-01-01 20:04:06 +00:00
DEBUG_PARSER ( " (dvparser debug) data \" %s \" \n \n " , value . c_str ( ) ) ;
2018-11-02 15:20:46 +00:00
}
2019-03-15 13:21:50 +00:00
if ( remaining = = datalen | | data = = databytes . end ( ) ) {
2018-11-29 21:25:50 +00:00
// We are done here!
break ;
}
2018-04-01 06:53:37 +00:00
}
string format_string = bin2hex ( format_bytes ) ;
2022-06-16 14:01:31 +00:00
uint16_t hash = crc16_EN13757 ( safeButUnsafeVectorPtr ( format_bytes ) , format_bytes . size ( ) ) ;
2018-04-01 06:53:37 +00:00
2019-01-01 20:04:06 +00:00
if ( data_has_difvifs ) {
2019-01-27 23:03:25 +00:00
if ( hash_to_format_ . count ( hash ) = = 0 ) {
hash_to_format_ [ hash ] = format_string ;
debug ( " (dvparser) found new format \" %s \" with hash %x, remembering! \n " , format_string . c_str ( ) , hash ) ;
}
2018-04-01 06:53:37 +00:00
}
return true ;
}
2022-04-17 10:47:06 +00:00
bool hasKey ( std : : map < std : : string , std : : pair < int , DVEntry > > * dv_entries , std : : string key )
2019-03-01 14:41:11 +00:00
{
2022-04-17 10:47:06 +00:00
return dv_entries - > count ( key ) > 0 ;
2019-03-01 14:41:11 +00:00
}
2022-05-07 17:16:34 +00:00
bool findKey ( MeasurementType mit , VIFRange vif_range , StorageNr storagenr , TariffNr tariffnr ,
2022-04-17 10:47:06 +00:00
std : : string * key , std : : map < std : : string , std : : pair < int , DVEntry > > * dv_entries )
2021-10-02 09:36:33 +00:00
{
2022-05-07 17:16:34 +00:00
return findKeyWithNr ( mit , vif_range , storagenr , tariffnr , 1 , key , dv_entries ) ;
2021-10-02 09:36:33 +00:00
}
2022-04-16 15:47:20 +00:00
bool findKeyWithNr ( MeasurementType mit , VIFRange vif_range , StorageNr storagenr , TariffNr tariffnr , int nr ,
2022-04-17 10:47:06 +00:00
std : : string * key , std : : map < std : : string , std : : pair < int , DVEntry > > * dv_entries )
2019-01-27 23:03:25 +00:00
{
2022-05-07 17:16:34 +00:00
/*debug("(dvparser) looking for type=%s vifrange=%s storagenr=%d tariffnr=%d\n",
measurementTypeName ( mit ) . c_str ( ) , toString ( vif_range ) , storagenr . intValue ( ) , tariffnr . intValue ( ) ) ; */
2019-10-14 18:26:31 +00:00
2022-04-17 10:47:06 +00:00
for ( auto & v : * dv_entries )
2019-01-27 23:03:25 +00:00
{
2022-04-17 09:23:45 +00:00
MeasurementType ty = v . second . second . measurement_type ;
2022-04-16 16:15:30 +00:00
Vif vi = v . second . second . vif ;
2022-04-17 09:23:45 +00:00
StorageNr sn = v . second . second . storage_nr ;
TariffNr tn = v . second . second . tariff_nr ;
2022-05-07 17:16:34 +00:00
/* debug("(dvparser) match? %s type=%s vife=%x (%s) and storagenr=%d\n",
2020-01-28 18:09:39 +00:00
v . first . c_str ( ) ,
2022-05-07 17:16:34 +00:00
measurementTypeName ( ty ) . c_str ( ) , vi . intValue ( ) , storagenr , sn ) ; */
2019-10-14 18:26:31 +00:00
2022-04-16 15:47:20 +00:00
if ( isInsideVIFRange ( vi , vif_range ) & &
2022-04-17 09:23:45 +00:00
( mit = = MeasurementType : : Instantaneous | | mit = = ty ) & &
2022-04-16 15:47:20 +00:00
( storagenr = = AnyStorageNr | | storagenr = = sn ) & &
( tariffnr = = AnyTariffNr | | tariffnr = = tn ) )
2019-10-14 18:26:31 +00:00
{
2019-01-27 23:03:25 +00:00
* key = v . first ;
2021-10-02 09:36:33 +00:00
nr - - ;
if ( nr < = 0 ) return true ;
2022-05-07 17:16:34 +00:00
debug ( " (dvparser) found key %s for type=%s vif=%x storagenr=%d \n " ,
2020-01-28 18:09:39 +00:00
v . first . c_str ( ) , measurementTypeName ( ty ) . c_str ( ) ,
2022-05-07 17:16:34 +00:00
vi . intValue ( ) , storagenr . intValue ( ) ) ;
2019-01-27 23:03:25 +00:00
}
}
return false ;
}
2022-05-21 18:25:18 +00:00
void extractDV ( DifVifKey & dvk , uchar * dif , int * vif , bool * has_difes , bool * has_vifes )
2022-04-17 12:57:03 +00:00
{
string tmp = dvk . str ( ) ;
2022-04-19 07:10:14 +00:00
extractDV ( tmp , dif , vif , has_difes , has_vifes ) ;
2022-04-17 12:57:03 +00:00
}
2022-05-21 18:25:18 +00:00
void extractDV ( string & s , uchar * dif , int * vif , bool * has_difes , bool * has_vifes )
2018-04-01 06:53:37 +00:00
{
vector < uchar > bytes ;
hex2bin ( s , & bytes ) ;
2022-04-19 07:10:14 +00:00
size_t i = 0 ;
* has_difes = false ;
* has_vifes = false ;
if ( bytes . size ( ) = = 0 )
{
* dif = 0 ;
* vif = 0 ;
return ;
}
* dif = bytes [ i ] ;
while ( i < bytes . size ( ) & & ( bytes [ i ] & 0x80 ) )
{
2019-01-01 20:04:06 +00:00
i + + ;
2022-04-19 07:10:14 +00:00
* has_difes = true ;
}
i + + ;
if ( i > = bytes . size ( ) )
{
* vif = 0 ;
return ;
2018-04-01 06:53:37 +00:00
}
2019-01-01 20:04:06 +00:00
* vif = bytes [ i ] ;
2022-05-21 18:25:18 +00:00
if ( * vif = = 0xfb | | // first extension
* vif = = 0xfd | | // second extensio
* vif = = 0xef | | // third extension
* vif = = 0xff ) // vendor extension
{
if ( i + 1 < bytes . size ( ) )
{
// Create an extended vif, like 0xfd31 for example.
* vif = bytes [ i ] < < 8 | bytes [ i + 1 ] ;
i + + ;
}
}
2022-04-19 07:10:14 +00:00
while ( i < bytes . size ( ) & & ( bytes [ i ] & 0x80 ) )
{
i + + ;
* has_vifes = true ;
}
2018-04-01 06:53:37 +00:00
}
2022-04-17 10:47:06 +00:00
bool extractDVuint8 ( map < string , pair < int , DVEntry > > * dv_entries ,
2019-11-26 15:12:32 +00:00
string key ,
int * offset ,
uchar * value )
{
2022-04-17 10:47:06 +00:00
if ( ( * dv_entries ) . count ( key ) = = 0 ) {
2022-01-08 17:09:17 +00:00
verbose ( " (dvparser) warning: cannot extract uint8 from non-existant key \" %s \" \n " , key . c_str ( ) ) ;
2019-11-26 15:12:32 +00:00
* offset = - 1 ;
* value = 0 ;
return false ;
}
2022-04-17 10:47:06 +00:00
pair < int , DVEntry > & p = ( * dv_entries ) [ key ] ;
2019-11-26 15:12:32 +00:00
* offset = p . first ;
vector < uchar > v ;
hex2bin ( p . second . value , & v ) ;
* value = v [ 0 ] ;
return true ;
}
2022-04-17 10:47:06 +00:00
bool extractDVuint16 ( map < string , pair < int , DVEntry > > * dv_entries ,
2018-04-01 06:53:37 +00:00
string key ,
int * offset ,
uint16_t * value )
{
2022-04-17 10:47:06 +00:00
if ( ( * dv_entries ) . count ( key ) = = 0 ) {
2018-12-01 10:26:40 +00:00
verbose ( " (dvparser) warning: cannot extract uint16 from non-existant key \" %s \" \n " , key . c_str ( ) ) ;
2018-04-01 06:53:37 +00:00
* offset = - 1 ;
* value = 0 ;
return false ;
}
2022-04-17 10:47:06 +00:00
pair < int , DVEntry > & p = ( * dv_entries ) [ key ] ;
2018-04-01 06:53:37 +00:00
* offset = p . first ;
vector < uchar > v ;
2019-01-27 23:03:25 +00:00
hex2bin ( p . second . value , & v ) ;
2018-04-01 06:53:37 +00:00
* value = v [ 1 ] < < 8 | v [ 0 ] ;
return true ;
}
2022-04-17 10:47:06 +00:00
bool extractDVuint24 ( map < string , pair < int , DVEntry > > * dv_entries ,
2020-07-30 10:19:54 +00:00
string key ,
int * offset ,
uint32_t * value )
{
2022-04-17 10:47:06 +00:00
if ( ( * dv_entries ) . count ( key ) = = 0 ) {
2020-07-30 10:19:54 +00:00
verbose ( " (dvparser) warning: cannot extract uint24 from non-existant key \" %s \" \n " , key . c_str ( ) ) ;
* offset = - 1 ;
* value = 0 ;
return false ;
}
2022-04-17 10:47:06 +00:00
pair < int , DVEntry > & p = ( * dv_entries ) [ key ] ;
2020-07-30 10:19:54 +00:00
* offset = p . first ;
vector < uchar > v ;
hex2bin ( p . second . value , & v ) ;
* value = v [ 2 ] < < 16 | v [ 1 ] < < 8 | v [ 0 ] ;
return true ;
}
2022-04-17 10:47:06 +00:00
bool extractDVuint32 ( map < string , pair < int , DVEntry > > * dv_entries ,
2020-09-24 11:10:34 +00:00
string key ,
int * offset ,
uint32_t * value )
{
2022-04-17 10:47:06 +00:00
if ( ( * dv_entries ) . count ( key ) = = 0 ) {
2020-09-24 11:10:34 +00:00
verbose ( " (dvparser) warning: cannot extract uint32 from non-existant key \" %s \" \n " , key . c_str ( ) ) ;
* offset = - 1 ;
* value = 0 ;
return false ;
}
2022-04-17 10:47:06 +00:00
pair < int , DVEntry > & p = ( * dv_entries ) [ key ] ;
2020-09-24 11:10:34 +00:00
* offset = p . first ;
vector < uchar > v ;
hex2bin ( p . second . value , & v ) ;
2021-01-29 16:20:54 +00:00
* value = ( uint32_t ( v [ 3 ] ) < < 24 ) | ( uint32_t ( v [ 2 ] ) < < 16 ) | ( uint32_t ( v [ 1 ] ) < < 8 ) | uint32_t ( v [ 0 ] ) ;
2020-09-24 11:10:34 +00:00
return true ;
}
2022-04-17 10:47:06 +00:00
bool extractDVdouble ( map < string , pair < int , DVEntry > > * dv_entries ,
2018-11-02 17:57:56 +00:00
string key ,
int * offset ,
2019-10-14 14:53:02 +00:00
double * value ,
2022-01-13 14:06:53 +00:00
bool auto_scale ,
bool assume_signed )
2018-04-01 06:53:37 +00:00
{
2022-04-17 10:47:06 +00:00
if ( ( * dv_entries ) . count ( key ) = = 0 ) {
2018-12-01 10:26:40 +00:00
verbose ( " (dvparser) warning: cannot extract double from non-existant key \" %s \" \n " , key . c_str ( ) ) ;
2018-04-01 06:53:37 +00:00
* offset = 0 ;
* value = 0 ;
return false ;
}
2022-04-17 10:47:06 +00:00
pair < int , DVEntry > & p = ( * dv_entries ) [ key ] ;
2018-04-01 06:53:37 +00:00
* offset = p . first ;
2019-01-27 23:03:25 +00:00
if ( p . second . value . length ( ) = = 0 ) {
2018-12-01 10:26:40 +00:00
verbose ( " (dvparser) warning: key found but no data \" %s \" \n " , key . c_str ( ) ) ;
* offset = 0 ;
* value = 0 ;
return false ;
}
2022-04-17 12:57:03 +00:00
return p . second . extractDouble ( value , auto_scale , assume_signed ) ;
}
2022-08-16 14:57:15 +00:00
bool checkSizeHex ( size_t expected_len , DifVifKey & dvk , string & v )
{
if ( v . length ( ) = = expected_len ) return true ;
warning ( " (dvparser) bad decode since difvif %s expected %d hex chars but got \" %s \" \n " ,
dvk . str ( ) . c_str ( ) , expected_len , v . c_str ( ) ) ;
return false ;
}
2022-04-17 12:57:03 +00:00
bool DVEntry : : extractDouble ( double * out , bool auto_scale , bool assume_signed )
{
2022-04-19 07:10:14 +00:00
int t = dif_vif_key . dif ( ) & 0xf ;
if ( t = = 0x0 | |
t = = 0x8 | |
t = = 0xd | |
t = = 0xf )
{
// Cannot extract from nothing, selection for readout, variable length or special.
// Variable length is used for compact varlen history. Should be added in the future.
return false ;
}
else
2018-11-02 17:57:56 +00:00
if ( t = = 0x1 | | // 8 Bit Integer/Binary
t = = 0x2 | | // 16 Bit Integer/Binary
t = = 0x3 | | // 24 Bit Integer/Binary
t = = 0x4 | | // 32 Bit Integer/Binary
t = = 0x6 | | // 48 Bit Integer/Binary
t = = 0x7 ) // 64 Bit Integer/Binary
{
vector < uchar > v ;
2022-04-17 12:57:03 +00:00
hex2bin ( value , & v ) ;
2022-01-06 17:28:22 +00:00
uint64_t raw = 0 ;
2022-01-13 14:06:53 +00:00
bool negate = false ;
uint64_t negate_mask = 0 ;
2018-11-02 17:57:56 +00:00
if ( t = = 0x1 ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 2 , dif_vif_key , value ) ) return false ;
2019-01-27 23:03:25 +00:00
assert ( v . size ( ) = = 1 ) ;
2018-11-02 17:57:56 +00:00
raw = v [ 0 ] ;
2022-01-13 14:06:53 +00:00
if ( assume_signed & & ( raw & ( uint64_t ) 0x80UL ) ! = 0 ) { negate = true ; negate_mask = ~ ( ( uint64_t ) 0 ) < < 8 ; }
2018-11-02 17:57:56 +00:00
} else if ( t = = 0x2 ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 4 , dif_vif_key , value ) ) return false ;
2019-01-27 23:03:25 +00:00
assert ( v . size ( ) = = 2 ) ;
2018-11-02 17:57:56 +00:00
raw = v [ 1 ] * 256 + v [ 0 ] ;
2022-01-13 14:06:53 +00:00
if ( assume_signed & & ( raw & ( uint64_t ) 0x8000UL ) ! = 0 ) { negate = true ; negate_mask = ~ ( ( uint64_t ) 0 ) < < 16 ; }
2018-11-02 17:57:56 +00:00
} else if ( t = = 0x3 ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 6 , dif_vif_key , value ) ) return false ;
2019-01-27 23:03:25 +00:00
assert ( v . size ( ) = = 3 ) ;
2018-11-02 17:57:56 +00:00
raw = v [ 2 ] * 256 * 256 + v [ 1 ] * 256 + v [ 0 ] ;
2022-01-13 14:06:53 +00:00
if ( assume_signed & & ( raw & ( uint64_t ) 0x800000UL ) ! = 0 ) { negate = true ; negate_mask = ~ ( ( uint64_t ) 0 ) < < 24 ; }
2018-11-02 17:57:56 +00:00
} else if ( t = = 0x4 ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 8 , dif_vif_key , value ) ) return false ;
2019-01-27 23:03:25 +00:00
assert ( v . size ( ) = = 4 ) ;
2018-11-02 17:57:56 +00:00
raw = ( ( unsigned int ) v [ 3 ] ) * 256 * 256 * 256
+ ( ( unsigned int ) v [ 2 ] ) * 256 * 256
+ ( ( unsigned int ) v [ 1 ] ) * 256
+ ( ( unsigned int ) v [ 0 ] ) ;
2022-01-13 14:06:53 +00:00
if ( assume_signed & & ( raw & ( uint64_t ) 0x80000000UL ) ! = 0 ) { negate = true ; negate_mask = ~ ( ( uint64_t ) 0 ) < < 32 ; }
2020-01-28 18:09:39 +00:00
} else if ( t = = 0x6 ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 12 , dif_vif_key , value ) ) return false ;
2020-01-28 18:09:39 +00:00
assert ( v . size ( ) = = 6 ) ;
raw = ( ( uint64_t ) v [ 5 ] ) * 256 * 256 * 256 * 256 * 256
+ ( ( uint64_t ) v [ 4 ] ) * 256 * 256 * 256 * 256
+ ( ( uint64_t ) v [ 3 ] ) * 256 * 256 * 256
+ ( ( uint64_t ) v [ 2 ] ) * 256 * 256
+ ( ( uint64_t ) v [ 1 ] ) * 256
+ ( ( uint64_t ) v [ 0 ] ) ;
2022-01-13 14:06:53 +00:00
if ( assume_signed & & ( raw & ( uint64_t ) 0x800000000000UL ) ! = 0 ) { negate = true ; negate_mask = ~ ( ( uint64_t ) 0 ) < < 48 ; }
2020-01-28 18:09:39 +00:00
} else if ( t = = 0x7 ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 16 , dif_vif_key , value ) ) return false ;
2020-01-28 18:09:39 +00:00
assert ( v . size ( ) = = 8 ) ;
raw = ( ( uint64_t ) v [ 7 ] ) * 256 * 256 * 256 * 256 * 256 * 256 * 256
+ ( ( uint64_t ) v [ 6 ] ) * 256 * 256 * 256 * 256 * 256 * 256
+ ( ( uint64_t ) v [ 5 ] ) * 256 * 256 * 256 * 256 * 256
+ ( ( uint64_t ) v [ 4 ] ) * 256 * 256 * 256 * 256
+ ( ( uint64_t ) v [ 3 ] ) * 256 * 256 * 256
+ ( ( uint64_t ) v [ 2 ] ) * 256 * 256
+ ( ( uint64_t ) v [ 1 ] ) * 256
+ ( ( uint64_t ) v [ 0 ] ) ;
2022-01-13 14:06:53 +00:00
if ( assume_signed & & ( raw & ( uint64_t ) 0x8000000000000000UL ) ! = 0 ) { negate = true ; negate_mask = 0 ; }
2018-11-02 17:57:56 +00:00
}
2019-10-14 14:53:02 +00:00
double scale = 1.0 ;
2022-01-13 14:06:53 +00:00
double draw = ( double ) raw ;
if ( negate )
{
draw = ( double ) ( ( int64_t ) ( negate_mask | raw ) ) ;
}
2022-04-19 07:10:14 +00:00
if ( auto_scale ) scale = vifScale ( dif_vif_key . vif ( ) ) ;
2022-04-17 12:57:03 +00:00
* out = ( draw ) / scale ;
2018-11-02 17:57:56 +00:00
}
else
if ( t = = 0x9 | | // 2 digit BCD
t = = 0xA | | // 4 digit BCD
t = = 0xB | | // 6 digit BCD
t = = 0xC | | // 8 digit BCD
t = = 0xE ) // 12 digit BCD
{
// 74140000 -> 00001474
2022-04-17 12:57:03 +00:00
string & v = value ;
2022-01-06 17:28:22 +00:00
uint64_t raw = 0 ;
2022-02-18 17:58:01 +00:00
bool negate = false ;
2018-11-02 17:57:56 +00:00
if ( t = = 0x9 ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 2 , dif_vif_key , v ) ) return false ;
2022-02-18 17:58:01 +00:00
if ( assume_signed & & v [ 0 ] = = ' F ' ) { negate = true ; v [ 0 ] = ' 0 ' ; }
2018-11-02 17:57:56 +00:00
raw = ( v [ 0 ] - ' 0 ' ) * 10 + ( v [ 1 ] - ' 0 ' ) ;
} else if ( t = = 0xA ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 4 , dif_vif_key , v ) ) return false ;
2022-02-18 17:58:01 +00:00
if ( assume_signed & & v [ 2 ] = = ' F ' ) { negate = true ; v [ 2 ] = ' 0 ' ; }
2018-11-02 17:57:56 +00:00
raw = ( v [ 2 ] - ' 0 ' ) * 10 * 10 * 10 + ( v [ 3 ] - ' 0 ' ) * 10 * 10
+ ( v [ 0 ] - ' 0 ' ) * 10 + ( v [ 1 ] - ' 0 ' ) ;
} else if ( t = = 0xB ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 6 , dif_vif_key , v ) ) return false ;
2022-02-18 17:58:01 +00:00
if ( assume_signed & & v [ 4 ] = = ' F ' ) { negate = true ; v [ 4 ] = ' 0 ' ; }
2018-11-02 17:57:56 +00:00
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 ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 8 , dif_vif_key , v ) ) return false ;
2022-02-18 17:58:01 +00:00
if ( assume_signed & & v [ 6 ] = = ' F ' ) { negate = true ; v [ 6 ] = ' 0 ' ; }
2018-11-02 17:57:56 +00:00
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 ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 12 , dif_vif_key , v ) ) return false ;
2022-02-18 17:58:01 +00:00
if ( assume_signed & & v [ 10 ] = = ' F ' ) { negate = true ; v [ 10 ] = ' 0 ' ; }
2018-11-02 17:57:56 +00:00
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
+ ( 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 ' ) ;
}
2019-10-14 14:53:02 +00:00
double scale = 1.0 ;
2022-02-18 17:58:01 +00:00
double draw = ( double ) raw ;
if ( negate )
{
draw = ( double ) draw * - 1 ;
}
2022-04-19 07:10:14 +00:00
if ( auto_scale ) scale = vifScale ( dif_vif_key . vif ( ) ) ;
2022-04-17 12:57:03 +00:00
* out = ( draw ) / scale ;
2022-05-25 14:59:55 +00:00
}
else
if ( t = = 0x5 ) // 32 Bit Real
{
vector < uchar > v ;
hex2bin ( value , & v ) ;
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 8 , dif_vif_key , value ) ) return false ;
2022-05-25 14:59:55 +00:00
assert ( v . size ( ) = = 4 ) ;
RealConversion rc ;
rc . i = v [ 3 ] < < 24 | v [ 2 ] < < 16 | v [ 1 ] < < 8 | v [ 0 ] ;
// Assumes float uses the standard IEEE 754 bit set.
// 1 bit sign, 8 bit exp, 23 bit mantissa
// RealConversion is tested on an amd64 platform. How about
// other platsforms with different byte ordering?
double draw = rc . f ;
double scale = 1.0 ;
if ( auto_scale ) scale = vifScale ( dif_vif_key . vif ( ) ) ;
* out = ( draw ) / scale ;
2018-11-02 17:57:56 +00:00
}
else
{
2022-08-16 14:57:15 +00:00
warning ( " (dvparser) Unsupported dif format for extraction to double! dif=%02x \n " , dif_vif_key . dif ( ) ) ;
return false ;
2018-11-02 17:57:56 +00:00
}
2018-04-01 06:53:37 +00:00
return true ;
}
2022-04-17 10:47:06 +00:00
bool extractDVlong ( map < string , pair < int , DVEntry > > * dv_entries ,
2021-03-06 06:42:37 +00:00
string key ,
int * offset ,
2022-04-17 13:05:34 +00:00
uint64_t * out )
2021-03-06 06:42:37 +00:00
{
2022-04-17 10:47:06 +00:00
if ( ( * dv_entries ) . count ( key ) = = 0 ) {
2021-03-06 06:42:37 +00:00
verbose ( " (dvparser) warning: cannot extract long from non-existant key \" %s \" \n " , key . c_str ( ) ) ;
* offset = 0 ;
2022-04-17 13:05:34 +00:00
* out = 0 ;
2021-03-06 06:42:37 +00:00
return false ;
}
2022-04-17 10:47:06 +00:00
pair < int , DVEntry > & p = ( * dv_entries ) [ key ] ;
2021-03-06 06:42:37 +00:00
* offset = p . first ;
if ( p . second . value . length ( ) = = 0 ) {
verbose ( " (dvparser) warning: key found but no data \" %s \" \n " , key . c_str ( ) ) ;
* offset = 0 ;
2022-04-17 13:05:34 +00:00
* out = 0 ;
2021-03-06 06:42:37 +00:00
return false ;
}
2022-04-17 13:05:34 +00:00
return p . second . extractLong ( out ) ;
}
bool DVEntry : : extractLong ( uint64_t * out )
{
2022-04-19 07:10:14 +00:00
int t = dif_vif_key . dif ( ) & 0xf ;
2021-03-06 06:42:37 +00:00
if ( t = = 0x1 | | // 8 Bit Integer/Binary
t = = 0x2 | | // 16 Bit Integer/Binary
t = = 0x3 | | // 24 Bit Integer/Binary
t = = 0x4 | | // 32 Bit Integer/Binary
t = = 0x6 | | // 48 Bit Integer/Binary
t = = 0x7 ) // 64 Bit Integer/Binary
{
vector < uchar > v ;
2022-04-17 13:05:34 +00:00
hex2bin ( value , & v ) ;
2021-03-06 06:42:37 +00:00
uint64_t raw = 0 ;
if ( t = = 0x1 ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 2 , dif_vif_key , value ) ) return false ;
2021-03-06 06:42:37 +00:00
assert ( v . size ( ) = = 1 ) ;
raw = v [ 0 ] ;
} else if ( t = = 0x2 ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 4 , dif_vif_key , value ) ) return false ;
2021-03-06 06:42:37 +00:00
assert ( v . size ( ) = = 2 ) ;
raw = v [ 1 ] * 256 + v [ 0 ] ;
} else if ( t = = 0x3 ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 6 , dif_vif_key , value ) ) return false ;
2021-03-06 06:42:37 +00:00
assert ( v . size ( ) = = 3 ) ;
raw = v [ 2 ] * 256 * 256 + v [ 1 ] * 256 + v [ 0 ] ;
} else if ( t = = 0x4 ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 8 , dif_vif_key , value ) ) return false ;
2021-03-06 06:42:37 +00:00
assert ( v . size ( ) = = 4 ) ;
raw = ( ( unsigned int ) v [ 3 ] ) * 256 * 256 * 256
+ ( ( unsigned int ) v [ 2 ] ) * 256 * 256
+ ( ( unsigned int ) v [ 1 ] ) * 256
+ ( ( unsigned int ) v [ 0 ] ) ;
} else if ( t = = 0x6 ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 12 , dif_vif_key , value ) ) return false ;
2021-03-06 06:42:37 +00:00
assert ( v . size ( ) = = 6 ) ;
raw = ( ( uint64_t ) v [ 5 ] ) * 256 * 256 * 256 * 256 * 256
+ ( ( uint64_t ) v [ 4 ] ) * 256 * 256 * 256 * 256
+ ( ( uint64_t ) v [ 3 ] ) * 256 * 256 * 256
+ ( ( uint64_t ) v [ 2 ] ) * 256 * 256
+ ( ( uint64_t ) v [ 1 ] ) * 256
+ ( ( uint64_t ) v [ 0 ] ) ;
} else if ( t = = 0x7 ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 16 , dif_vif_key , value ) ) return false ;
2021-03-06 06:42:37 +00:00
assert ( v . size ( ) = = 8 ) ;
raw = ( ( uint64_t ) v [ 7 ] ) * 256 * 256 * 256 * 256 * 256 * 256 * 256
+ ( ( uint64_t ) v [ 6 ] ) * 256 * 256 * 256 * 256 * 256 * 256
+ ( ( uint64_t ) v [ 5 ] ) * 256 * 256 * 256 * 256 * 256
+ ( ( uint64_t ) v [ 4 ] ) * 256 * 256 * 256 * 256
+ ( ( uint64_t ) v [ 3 ] ) * 256 * 256 * 256
+ ( ( uint64_t ) v [ 2 ] ) * 256 * 256
+ ( ( uint64_t ) v [ 1 ] ) * 256
+ ( ( uint64_t ) v [ 0 ] ) ;
}
2022-04-17 13:05:34 +00:00
* out = raw ;
2021-03-06 06:42:37 +00:00
}
else
if ( t = = 0x9 | | // 2 digit BCD
t = = 0xA | | // 4 digit BCD
t = = 0xB | | // 6 digit BCD
t = = 0xC | | // 8 digit BCD
t = = 0xE ) // 12 digit BCD
{
// 74140000 -> 00001474
2022-04-17 13:05:34 +00:00
string & v = value ;
2021-03-06 06:42:37 +00:00
uint64_t raw = 0 ;
if ( t = = 0x9 ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 2 , dif_vif_key , value ) ) return false ;
2021-03-06 06:42:37 +00:00
assert ( v . size ( ) = = 2 ) ;
raw = ( v [ 0 ] - ' 0 ' ) * 10 + ( v [ 1 ] - ' 0 ' ) ;
} else if ( t = = 0xA ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 4 , dif_vif_key , value ) ) return false ;
2021-03-06 06:42:37 +00:00
assert ( v . size ( ) = = 4 ) ;
raw = ( v [ 2 ] - ' 0 ' ) * 10 * 10 * 10 + ( v [ 3 ] - ' 0 ' ) * 10 * 10
+ ( v [ 0 ] - ' 0 ' ) * 10 + ( v [ 1 ] - ' 0 ' ) ;
} else if ( t = = 0xB ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 6 , dif_vif_key , value ) ) return false ;
2021-03-06 06:42:37 +00:00
assert ( v . size ( ) = = 6 ) ;
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 ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 8 , dif_vif_key , value ) ) return false ;
2021-03-06 06:42:37 +00:00
assert ( v . size ( ) = = 8 ) ;
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 ) {
2022-08-16 14:57:15 +00:00
if ( ! checkSizeHex ( 12 , dif_vif_key , value ) ) return false ;
2021-03-06 06:42:37 +00:00
assert ( v . size ( ) = = 12 ) ;
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
+ ( 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 ' ) ;
}
2022-04-17 13:05:34 +00:00
* out = raw ;
2021-03-06 06:42:37 +00:00
}
else
{
2022-04-19 07:10:14 +00:00
error ( " Unsupported dif format for extraction to long! dif=%02x \n " , dif_vif_key . dif ( ) ) ;
2021-03-06 06:42:37 +00:00
}
return true ;
}
2022-04-17 10:47:06 +00:00
bool extractDVHexString ( map < string , pair < int , DVEntry > > * dv_entries ,
2022-02-06 10:21:15 +00:00
string key ,
int * offset ,
string * value )
2019-01-01 20:04:06 +00:00
{
2022-04-17 10:47:06 +00:00
if ( ( * dv_entries ) . count ( key ) = = 0 ) {
2019-01-01 20:04:06 +00:00
verbose ( " (dvparser) warning: cannot extract string from non-existant key \" %s \" \n " , key . c_str ( ) ) ;
* offset = - 1 ;
return false ;
}
2022-04-17 10:47:06 +00:00
pair < int , DVEntry > & p = ( * dv_entries ) [ key ] ;
2019-01-01 20:04:06 +00:00
* offset = p . first ;
2019-01-27 23:03:25 +00:00
* value = p . second . value ;
2022-02-06 10:21:15 +00:00
return true ;
}
2022-04-17 10:47:06 +00:00
bool extractDVReadableString ( map < string , pair < int , DVEntry > > * dv_entries ,
2022-02-06 10:21:15 +00:00
string key ,
int * offset ,
2022-04-17 15:34:51 +00:00
string * out )
2022-02-06 10:21:15 +00:00
{
2022-04-17 10:47:06 +00:00
if ( ( * dv_entries ) . count ( key ) = = 0 ) {
2022-02-06 10:21:15 +00:00
verbose ( " (dvparser) warning: cannot extract string from non-existant key \" %s \" \n " , key . c_str ( ) ) ;
* offset = - 1 ;
return false ;
}
2022-04-17 10:47:06 +00:00
pair < int , DVEntry > & p = ( * dv_entries ) [ key ] ;
2022-02-06 10:21:15 +00:00
* offset = p . first ;
2022-04-17 15:34:51 +00:00
return p . second . extractReadableString ( out ) ;
}
bool DVEntry : : extractReadableString ( string * out )
{
2022-04-19 07:10:14 +00:00
int t = dif_vif_key . dif ( ) & 0xf ;
2022-04-17 15:34:51 +00:00
string v = value ;
2022-02-06 10:21:15 +00:00
if ( t = = 0x1 | | // 8 Bit Integer/Binary
t = = 0x2 | | // 16 Bit Integer/Binary
t = = 0x3 | | // 24 Bit Integer/Binary
t = = 0x4 | | // 32 Bit Integer/Binary
t = = 0x6 | | // 48 Bit Integer/Binary
t = = 0x7 | | // 64 Bit Integer/Binary
t = = 0xD ) // Variable length
{
2022-05-07 17:40:46 +00:00
if ( isLikelyAscii ( v ) )
{
// For example an enhanced id 32 bits binary looks like:
// 44434241 and will be reversed to: 41424344 and translated using ascii
// to ABCD
v = reverseBinaryAsciiSafeToString ( v ) ;
}
else
{
v = reverseBCD ( v ) ;
}
2022-02-06 10:21:15 +00:00
}
if ( t = = 0x9 | | // 2 digit BCD
t = = 0xA | | // 4 digit BCD
t = = 0xB | | // 6 digit BCD
t = = 0xC | | // 8 digit BCD
t = = 0xE ) // 12 digit BCD
{
// For example an enhanced id 12 digit bcd looks like:
// 618171183100 and will be reversed to: 003118718161
v = reverseBCD ( v ) ;
}
2022-04-17 15:34:51 +00:00
* out = v ;
2019-01-01 20:04:06 +00:00
return true ;
}
2022-11-19 13:40:03 +00:00
double DVEntry : : getCounter ( DVEntryCounterType ct )
{
switch ( ct )
{
case DVEntryCounterType : : STORAGE_COUNTER : return storage_nr . intValue ( ) ;
case DVEntryCounterType : : TARIFF_COUNTER : return tariff_nr . intValue ( ) ;
case DVEntryCounterType : : SUBUNIT_COUNTER : return subunit_nr . intValue ( ) ;
case DVEntryCounterType : : UNKNOWN : break ;
}
return std : : numeric_limits < double > : : quiet_NaN ( ) ;
}
2022-05-07 17:16:34 +00:00
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 ;
}
2019-03-01 14:41:11 +00:00
bool extractDate ( uchar hi , uchar lo , struct tm * date )
{
// | hi | lo |
// | YYYY MMMM | YYY DDDDD |
int day = ( 0x1f ) & lo ;
int year1 = ( ( 0xe0 ) & lo ) > > 5 ;
int month = ( 0x0f ) & hi ;
int year2 = ( ( 0xf0 ) & hi ) > > 1 ;
int year = ( 2000 + year1 + year2 ) ;
date - > tm_mday = day ; /* Day of the month (1-31) */
date - > tm_mon = month - 1 ; /* Month (0-11) */
date - > tm_year = year - 1900 ; /* Year - 1900 */
if ( month > 12 ) return false ;
return true ;
}
bool extractTime ( uchar hi , uchar lo , struct tm * date )
{
// | hi | lo |
// | ...hhhhh | ..mmmmmm |
int min = ( 0x3f ) & lo ;
int hour = ( 0x1f ) & hi ;
date - > tm_min = min ;
date - > tm_hour = hour ;
if ( min > 59 ) return false ;
if ( hour > 23 ) return false ;
return true ;
}
2022-04-17 10:47:06 +00:00
bool extractDVdate ( map < string , pair < int , DVEntry > > * dv_entries ,
2019-01-01 20:04:06 +00:00
string key ,
int * offset ,
2022-04-17 15:34:51 +00:00
struct tm * out )
2019-01-01 20:04:06 +00:00
{
2022-04-17 10:47:06 +00:00
if ( ( * dv_entries ) . count ( key ) = = 0 )
2019-03-01 14:41:11 +00:00
{
2019-01-01 20:04:06 +00:00
verbose ( " (dvparser) warning: cannot extract date from non-existant key \" %s \" \n " , key . c_str ( ) ) ;
* offset = - 1 ;
2022-04-17 15:34:51 +00:00
memset ( out , 0 , sizeof ( struct tm ) ) ;
2019-01-01 20:04:06 +00:00
return false ;
}
2022-04-17 15:34:51 +00:00
pair < int , DVEntry > & p = ( * dv_entries ) [ key ] ;
* offset = p . first ;
return p . second . extractDate ( out ) ;
}
bool DVEntry : : extractDate ( struct tm * out )
{
2022-11-26 21:21:34 +00:00
memset ( out , 0 , sizeof ( * out ) ) ;
out - > tm_isdst = - 1 ; // Figure out the dst automatically!
2019-03-01 14:41:11 +00:00
2019-01-01 20:04:06 +00:00
vector < uchar > v ;
2022-04-17 15:34:51 +00:00
hex2bin ( value , & v ) ;
2019-01-01 20:04:06 +00:00
2019-03-01 14:41:11 +00:00
bool ok = true ;
if ( v . size ( ) = = 2 ) {
2022-04-17 15:34:51 +00:00
ok & = : : extractDate ( v [ 1 ] , v [ 0 ] , out ) ;
2019-03-01 14:41:11 +00:00
}
else if ( v . size ( ) = = 4 ) {
2022-04-17 15:34:51 +00:00
ok & = : : extractDate ( v [ 3 ] , v [ 2 ] , out ) ;
ok & = : : extractTime ( v [ 1 ] , v [ 0 ] , out ) ;
2019-03-01 14:41:11 +00:00
}
2019-03-20 21:16:45 +00:00
else if ( v . size ( ) = = 6 ) {
2022-04-17 15:34:51 +00:00
ok & = : : extractDate ( v [ 4 ] , v [ 3 ] , out ) ;
ok & = : : extractTime ( v [ 2 ] , v [ 1 ] , out ) ;
2019-03-20 21:16:45 +00:00
// ..ss ssss
int sec = ( 0x3f ) & v [ 0 ] ;
2022-04-17 15:34:51 +00:00
out - > tm_sec = sec ;
2022-11-12 15:30:10 +00:00
// There are also bits for day of week, week of year.
// A bit for if daylight saving is in use or not and its offset.
// A bit if it is a leap year.
// I am unsure how to deal with this here..... TODO
2019-03-20 21:16:45 +00:00
}
2019-01-01 20:04:06 +00:00
2019-03-01 14:41:11 +00:00
return ok ;
2019-01-01 20:04:06 +00:00
}
2022-04-17 09:23:45 +00:00
2022-04-17 10:47:06 +00:00
bool FieldMatcher : : matches ( DVEntry & dv_entry )
2022-04-17 09:23:45 +00:00
{
2022-04-19 07:10:14 +00:00
if ( ! active ) return false ;
2022-09-03 11:25:37 +00:00
// Test an explicit dif vif key.
2022-04-17 09:23:45 +00:00
if ( match_dif_vif_key )
{
2022-04-19 07:10:14 +00:00
bool b = dv_entry . dif_vif_key = = dif_vif_key ;
return b ;
}
2022-09-03 11:25:37 +00:00
// Test ranges and types.
2022-04-19 07:10:14 +00:00
bool b =
2022-04-17 09:23:45 +00:00
( ! match_vif_range | | isInsideVIFRange ( dv_entry . vif , vif_range ) ) & &
( ! 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 ) ) ;
2022-04-19 07:10:14 +00:00
2022-05-07 17:16:34 +00:00
if ( ! b ) return false ;
2022-09-03 11:25:37 +00:00
// So far so good, now test the combinables.
2022-05-07 17:16:34 +00:00
// 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 )
{
2022-09-03 11:25:37 +00:00
if ( vc ! = VIFCombinable : : Any & & dv_entry . combinable_vifs . count ( vc ) = = 0 )
2022-05-07 17:16:34 +00:00
{
// Ouch, one of the requested combinables did not exist in the dv_entry. No match!
return false ;
}
}
2022-09-03 11:25:37 +00:00
// Now if we have not selected the Any combinable match pattern,
// then we need to check if there are unmatched combinables in the telegram, if so fail the match.
if ( vif_combinables . count ( VIFCombinable : : Any ) = = 0 )
{
for ( VIFCombinable vc : dv_entry . combinable_vifs )
{
if ( vif_combinables . count ( vc ) = = 0 )
{
// Oups, the telegram entry had a combinable that we had no matcher for.
return false ;
}
}
}
2022-05-07 17:16:34 +00:00
// 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 " ? " ;
2022-04-17 09:23:45 +00:00
}
2022-09-10 06:44:55 +00:00
string FieldMatcher : : str ( )
{
string s = " " ;
if ( match_dif_vif_key )
{
s = s + " DVK( " + dif_vif_key . str ( ) + " ) " ;
}
if ( match_measurement_type )
{
s = s + " MT( " + toString ( measurement_type ) + " ) " ;
}
if ( match_vif_range )
{
s = s + " VR( " + toString ( vif_range ) + " ) " ;
}
if ( vif_combinables . size ( ) > 0 )
{
s + = " Comb( " ;
for ( auto vc : vif_combinables )
{
s = s + toString ( vc ) + " " ;
}
s . pop_back ( ) ;
s + = " ) " ;
}
if ( match_storage_nr )
{
s = s + " S( " + to_string ( storage_nr_from . intValue ( ) ) + " - " + to_string ( storage_nr_to . intValue ( ) ) + " ) " ;
}
if ( match_tariff_nr )
{
s = s + " T( " + to_string ( tariff_nr_from . intValue ( ) ) + " - " + to_string ( tariff_nr_to . intValue ( ) ) + " ) " ;
}
if ( match_subunit_nr )
{
s + = " U( " + to_string ( subunit_nr_from . intValue ( ) ) + " - " + to_string ( subunit_nr_to . intValue ( ) ) + " ) " ;
}
if ( index_nr . intValue ( ) ! = 1 )
{
s + = " I( " + to_string ( index_nr . intValue ( ) ) + " ) " ;
}
if ( s . size ( ) > 0 )
{
s . pop_back ( ) ;
}
return s ;
}
2022-11-19 13:40:03 +00:00
DVEntryCounterType toDVEntryCounterType ( const std : : string & s )
{
if ( s = = " storage_counter " ) return DVEntryCounterType : : STORAGE_COUNTER ;
if ( s = = " tariff_counter " ) return DVEntryCounterType : : TARIFF_COUNTER ;
if ( s = = " subunit_counter " ) return DVEntryCounterType : : SUBUNIT_COUNTER ;
return DVEntryCounterType : : UNKNOWN ;
}
const char * toString ( DVEntryCounterType ct )
{
switch ( ct )
{
case DVEntryCounterType : : UNKNOWN : return " unknown " ;
case DVEntryCounterType : : STORAGE_COUNTER : return " storage_counter " ;
case DVEntryCounterType : : TARIFF_COUNTER : return " tariff_counter " ;
case DVEntryCounterType : : SUBUNIT_COUNTER : return " subunit_counter " ;
}
return " unknown " ;
}