kopia lustrzana https://github.com/weetmuts/wmbusmeters
				
				
				
			Merge pull request #241 from don-vip/izar-address-preprocessor
Add frame preprocessing to transform Diehl addressespull/247/head
						commit
						c94ed693f2
					
				| 
						 | 
				
			
			@ -3,5 +3,6 @@ build_debug
 | 
			
		|||
build_arm/
 | 
			
		||||
build_arm_debug/
 | 
			
		||||
archive/
 | 
			
		||||
testaes/
 | 
			
		||||
testoutput/
 | 
			
		||||
*~
 | 
			
		||||
*~
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										3
									
								
								Makefile
								
								
								
								
							| 
						 | 
				
			
			@ -150,7 +150,7 @@ METER_OBJS:=\
 | 
			
		|||
	$(BUILD)/meter_multical302.o \
 | 
			
		||||
	$(BUILD)/meter_multical403.o \
 | 
			
		||||
	$(BUILD)/meter_multical603.o \
 | 
			
		||||
    $(BUILD)/meter_multical803.o \
 | 
			
		||||
	$(BUILD)/meter_multical803.o \
 | 
			
		||||
	$(BUILD)/meter_omnipower.o \
 | 
			
		||||
	$(BUILD)/meter_q400.o \
 | 
			
		||||
	$(BUILD)/meter_qcaloric.o \
 | 
			
		||||
| 
						 | 
				
			
			@ -167,6 +167,7 @@ METER_OBJS:=\
 | 
			
		|||
	$(BUILD)/meter_whe5x.o \
 | 
			
		||||
	$(BUILD)/meter_sensostar.o \
 | 
			
		||||
	$(BUILD)/meter_gransystems_ccx01.o \
 | 
			
		||||
	$(BUILD)/manufacturer_specificities.o \
 | 
			
		||||
	$(BUILD)/printer.o \
 | 
			
		||||
	$(BUILD)/rtlsdr.o \
 | 
			
		||||
	$(BUILD)/serial.o \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,5 +2,5 @@
 | 
			
		|||
# that should be properly recognized and mapped to an existing driver.
 | 
			
		||||
# I.e. check that a driver can be deduced from each telegram.
 | 
			
		||||
 | 
			
		||||
# izar water meter with weird identification combo: mfct: DME (0x11a5) type: A/D converter (0x19) ver: 0x00
 | 
			
		||||
# izar water meter with address swapping: mfct: DME (0x11a5) type: water meter (0x07) ver: 0x78
 | 
			
		||||
telegram=||1944A511780758280019A2610F001328ACC7F38E4D812CFC0D36|
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,4 @@
 | 
			
		|||
# The design philosophy of the izar water meters, is never ever let
 | 
			
		||||
# a water meter report itself as a water meter....
 | 
			
		||||
 | 
			
		||||
# Test IZAR RC 868 I R4 PL water meter telegram, it reports itself as an oil meter... duh?
 | 
			
		||||
# But wmbusmeters politely translates this into water.
 | 
			
		||||
# Test IZAR RC 868 I R4 PL water meter telegram
 | 
			
		||||
 | 
			
		||||
telegram=|1944304C72242421D401A2|013D4013DD8B46A4999C1293E582CC|
 | 
			
		||||
{"media":"water","meter":"izar","name":"IzarWater","id":"21242472","total_m3":3.488,"last_month_total_m3":3.486,"last_month_measure_date":"2019-09-30","remaining_battery_life_y":14.5,"current_alarms":"meter_blocked,underflow","previous_alarms":"no_alarm","timestamp":"1111-11-11T11:11:11Z"}
 | 
			
		||||
| 
						 | 
				
			
			@ -10,14 +6,14 @@ telegram=|1944304C72242421D401A2|013D4013DD8B46A4999C1293E582CC|
 | 
			
		|||
# Test new version of IZAR
 | 
			
		||||
 | 
			
		||||
telegram=|2944A511780729662366A20118001378D3B3DB8CEDD77731F25832AAF3DA8CADF9774EA673172E8C61F2|
 | 
			
		||||
{"media":"water","meter":"izar","name":"IzarWater2","id":"66290778","total_m3":16.76,"last_month_total_m3":11.84,"last_month_measure_date":"2019-11-30","remaining_battery_life_y":12,"current_alarms":"no_alarm","previous_alarms":"no_alarm","timestamp":"1111-11-11T11:11:11Z"}
 | 
			
		||||
{"media":"water","meter":"izar","name":"IzarWater2","id":"23662907","total_m3":16.76,"last_month_total_m3":11.84,"last_month_measure_date":"2019-11-30","remaining_battery_life_y":12,"current_alarms":"no_alarm","previous_alarms":"no_alarm","timestamp":"1111-11-11T11:11:11Z"}
 | 
			
		||||
 | 
			
		||||
# Yet another silly version of IZAR, come again, type 0x20 = Breaker (electricity) for a water meter!
 | 
			
		||||
# Yet another version of IZAR
 | 
			
		||||
 | 
			
		||||
telegram=|1944A511780779194820A1|21170013355F8EDB2D03C6912B1E37
 | 
			
		||||
{"media":"water","meter":"izar","name":"IzarWater3","id":"19790778","total_m3":4.366,"last_month_total_m3":0,"last_month_measure_date":"2020-12-31","remaining_battery_life_y":11.5,"current_alarms":"no_alarm","previous_alarms":"no_alarm","timestamp":"1111-11-11T11:11:11Z"}
 | 
			
		||||
{"media":"water","meter":"izar","name":"IzarWater3","id":"48197907","total_m3":4.366,"last_month_total_m3":0,"last_month_measure_date":"2020-12-31","remaining_battery_life_y":11.5,"current_alarms":"no_alarm","previous_alarms":"no_alarm","timestamp":"1111-11-11T11:11:11Z"}
 | 
			
		||||
 | 
			
		||||
# And another izar sillines, this time its a "heat meter" and a mfct specific tpl ci field a3.
 | 
			
		||||
# And another izar, with a mfct specific tpl ci field a3.
 | 
			
		||||
 | 
			
		||||
telegram=|1944304c9c5824210c04a363140013716577ec59e8663ab0d31c|
 | 
			
		||||
{"media":"water","meter":"izar","name":"IzarWater4","id":"2124589c","total_m3":38.944,"last_month_total_m3":38.691,"last_month_measure_date":"2021-02-01","remaining_battery_life_y":10,"current_alarms":"no_alarm","previous_alarms":"no_alarm","timestamp":"1111-11-11T11:11:11Z"}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1249,7 +1249,7 @@ bool start(Configuration *config)
 | 
			
		|||
                t.parse(frame, &mk, false); // Try a best effort parse, do not print any warnings.
 | 
			
		||||
                t.print();
 | 
			
		||||
                t.explainParse("(wmbus)",0);
 | 
			
		||||
                logTelegram(t.frame, 0, 0);
 | 
			
		||||
                logTelegram(t.original, t.frame, 0, 0);
 | 
			
		||||
                return true;
 | 
			
		||||
            });
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,116 @@
 | 
			
		|||
/*
 | 
			
		||||
 Copyright (C) 2021 Vincent Privat
 | 
			
		||||
 | 
			
		||||
 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<set>
 | 
			
		||||
#include"manufacturers.h"
 | 
			
		||||
#include"manufacturer_specificities.h"
 | 
			
		||||
 | 
			
		||||
std::set<int> diehl_manufacturers = {
 | 
			
		||||
    MANUFACTURER_DME,
 | 
			
		||||
    MANUFACTURER_EWT,
 | 
			
		||||
    MANUFACTURER_HYD,
 | 
			
		||||
    MANUFACTURER_SAP,
 | 
			
		||||
    MANUFACTURER_SPL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Diehl: is "A field" coded as version/type/serialnumber instead of standard serialnumber/version/type?
 | 
			
		||||
DiehlAddressTransformMethod mustTransformDiehlAddress(uchar c_field, int m_field, uchar ci_field, int tpl_cfg)
 | 
			
		||||
{
 | 
			
		||||
    if (diehl_manufacturers.find(m_field) != diehl_manufacturers.end())
 | 
			
		||||
    {
 | 
			
		||||
        if (c_field == 0x44 || c_field == 0x46) // SND_NR / SND_IR
 | 
			
		||||
        {
 | 
			
		||||
            switch (ci_field) {
 | 
			
		||||
                case 0x71: // Alarm
 | 
			
		||||
                    return DiehlAddressTransformMethod::SWAPPING; // Real Data
 | 
			
		||||
                case 0x7A: // EN 13757-3 Application Layer (short tplh)
 | 
			
		||||
                    if (((tpl_cfg >> 8) & 0x10) == 0x10)
 | 
			
		||||
                    {
 | 
			
		||||
                        return DiehlAddressTransformMethod::SWAPPING; // Real Data
 | 
			
		||||
                    }
 | 
			
		||||
                    break; // OMS
 | 
			
		||||
                case 0xA0: // Manufacturer specific
 | 
			
		||||
                case 0xA1: // Manufacturer specific
 | 
			
		||||
                case 0xA2: // Manufacturer specific
 | 
			
		||||
                case 0xA3: // Manufacturer specific
 | 
			
		||||
                case 0xA4: // Manufacturer specific
 | 
			
		||||
                case 0xA5: // Manufacturer specific
 | 
			
		||||
                case 0xA6: // Manufacturer specific
 | 
			
		||||
                case 0xA7: // Manufacturer specific
 | 
			
		||||
                    if (m_field == MANUFACTURER_SAP)
 | 
			
		||||
                    {
 | 
			
		||||
                        return DiehlAddressTransformMethod::SAP_PRIOS; // SAP PRIOS
 | 
			
		||||
                    }
 | 
			
		||||
                    return DiehlAddressTransformMethod::SWAPPING; // PRIOS
 | 
			
		||||
                case 0xB0: // Manufacturer specific
 | 
			
		||||
                    if (m_field == MANUFACTURER_SAP)
 | 
			
		||||
                    {
 | 
			
		||||
                        return DiehlAddressTransformMethod::SAP_PRIOS_STANDARD; // SAP PRIOS STD
 | 
			
		||||
                    }
 | 
			
		||||
                    break; // Reserved
 | 
			
		||||
                case 0xA8: // Manufacturer specific
 | 
			
		||||
                case 0xA9: // Manufacturer specific
 | 
			
		||||
                case 0xAA: // Manufacturer specific
 | 
			
		||||
                case 0xAB: // Manufacturer specific
 | 
			
		||||
                case 0xAC: // Manufacturer specific
 | 
			
		||||
                case 0xAD: // Manufacturer specific
 | 
			
		||||
                case 0xAE: // Manufacturer specific
 | 
			
		||||
                case 0xAF: // Manufacturer specific
 | 
			
		||||
                case 0xB4: // Manufacturer specific
 | 
			
		||||
                case 0xB5: // Manufacturer specific
 | 
			
		||||
                case 0xB6: // Manufacturer specific
 | 
			
		||||
                case 0xB7: // Manufacturer specific
 | 
			
		||||
                    break; // Reserved
 | 
			
		||||
                case 0xB1: // Manufacturer specific
 | 
			
		||||
                case 0xB2: // Manufacturer specific
 | 
			
		||||
                case 0xB3: // Manufacturer specific
 | 
			
		||||
                    return DiehlAddressTransformMethod::SWAPPING; // PRIOS SCR
 | 
			
		||||
                default:
 | 
			
		||||
                    break; // OMS
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return DiehlAddressTransformMethod::NONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Diehl: transform "A field" to make it compliant to standard
 | 
			
		||||
void transformDiehlAddress(std::vector<uchar>& frame, DiehlAddressTransformMethod transform_method)
 | 
			
		||||
{
 | 
			
		||||
    if (transform_method == DiehlAddressTransformMethod::SWAPPING)
 | 
			
		||||
    {
 | 
			
		||||
        debug("(diehl) Pre-processing: swapping address field\n");
 | 
			
		||||
        uchar version = frame[4];
 | 
			
		||||
        uchar type    = frame[5];
 | 
			
		||||
        for (int i = 4; i < 8; i++)
 | 
			
		||||
        {
 | 
			
		||||
            frame[i] = frame[i+1];
 | 
			
		||||
        }
 | 
			
		||||
        frame[8] = version;
 | 
			
		||||
        frame[9] = type;
 | 
			
		||||
    }
 | 
			
		||||
    else if (transform_method == DiehlAddressTransformMethod::SAP_PRIOS)
 | 
			
		||||
    {
 | 
			
		||||
        debug("(diehl) Pre-processing: setting device type to water meter for SAP PRIOS\n");
 | 
			
		||||
        frame[8] = 0x00; // version field is used by IZAR as part of meter id on 5 bytes instead of 4
 | 
			
		||||
        frame[9] = 0x07; // water meter
 | 
			
		||||
    }
 | 
			
		||||
    else if (transform_method == DiehlAddressTransformMethod::SAP_PRIOS_STANDARD)
 | 
			
		||||
    {
 | 
			
		||||
        warning("(diehl) Pre-processing: SAP PRIOS STANDARD transformation not implemented!\n"); // TODO
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,36 @@
 | 
			
		|||
/*
 | 
			
		||||
 Copyright (C) 2021 Vincent Privat
 | 
			
		||||
 | 
			
		||||
 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 MANUFACTURER_SPECIFICITIES_H
 | 
			
		||||
#define MANUFACTURER_SPECIFICITIES_H
 | 
			
		||||
 | 
			
		||||
#include"util.h"
 | 
			
		||||
 | 
			
		||||
enum class DiehlAddressTransformMethod {
 | 
			
		||||
    NONE,
 | 
			
		||||
    SWAPPING,
 | 
			
		||||
    SAP_PRIOS,
 | 
			
		||||
    SAP_PRIOS_STANDARD
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Diehl: Is "A field" coded as version/type/serialnumber instead of standard serialnumber/version/type?
 | 
			
		||||
DiehlAddressTransformMethod mustTransformDiehlAddress(uchar c_field, int m_field, uchar ci_field, int tpl_cfg);
 | 
			
		||||
 | 
			
		||||
// Diehl: swap "A field" to make it compliant to standard
 | 
			
		||||
void transformDiehlAddress(std::vector<uchar>& frame, DiehlAddressTransformMethod method);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -63,7 +63,7 @@ private:
 | 
			
		|||
    uint32_t convertKey(const char *hex);
 | 
			
		||||
    uint32_t convertKey(const vector<uchar> &bytes);
 | 
			
		||||
    uint32_t uint32FromBytes(const vector<uchar> &data, int offset, bool reverse = false);
 | 
			
		||||
    vector<uchar> decodePrios(const vector<uchar> &payload, uint32_t key);
 | 
			
		||||
    vector<uchar> decodePrios(const vector<uchar> &origin, const vector<uchar> &payload, uint32_t key);
 | 
			
		||||
 | 
			
		||||
    double remaining_battery_life;
 | 
			
		||||
    uint16_t h0_year;
 | 
			
		||||
| 
						 | 
				
			
			@ -95,14 +95,8 @@ MeterIzar::MeterIzar(MeterInfo &mi) :
 | 
			
		|||
        keys.push_back(convertKey(PRIOS_DEFAULT_KEY2));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // media 0x01 Oil meter? why?
 | 
			
		||||
    // media 0x15 Hot water
 | 
			
		||||
    // medua 0x66 Woot?
 | 
			
		||||
 | 
			
		||||
    addLinkMode(LinkMode::T1);
 | 
			
		||||
 | 
			
		||||
    // Meters with different versions exist, don't set any to avoid warnings
 | 
			
		||||
 | 
			
		||||
    addPrint("total", Quantity::Volume,
 | 
			
		||||
             [&](Unit u){ return totalWaterConsumption(u); },
 | 
			
		||||
             "The total water consumption recorded by this meter.",
 | 
			
		||||
| 
						 | 
				
			
			@ -251,7 +245,7 @@ void MeterIzar::processContent(Telegram *t)
 | 
			
		|||
 | 
			
		||||
    vector<uchar> decoded_content;
 | 
			
		||||
    for (auto& key : keys) {
 | 
			
		||||
        decoded_content = decodePrios(frame, key);
 | 
			
		||||
        decoded_content = decodePrios(t->original.empty() ? frame : t->original, frame, key);
 | 
			
		||||
        if (!decoded_content.empty())
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -293,16 +287,13 @@ void MeterIzar::processContent(Telegram *t)
 | 
			
		|||
    alarms.sensor_fraud_previously = frame[13] >> 2 & 0x1;
 | 
			
		||||
    alarms.mechanical_fraud_currently = frame[13] >> 1 & 0x1;
 | 
			
		||||
    alarms.mechanical_fraud_previously = frame[13] & 0x1;
 | 
			
		||||
 | 
			
		||||
    // override incorrectly reported medium (oil)
 | 
			
		||||
    t->dll_type = 7;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vector<uchar> MeterIzar::decodePrios(const vector<uchar> &frame, uint32_t key)
 | 
			
		||||
vector<uchar> MeterIzar::decodePrios(const vector<uchar> &origin, const vector<uchar> &frame, uint32_t key)
 | 
			
		||||
{
 | 
			
		||||
    // modify seed key with header values
 | 
			
		||||
    key ^= uint32FromBytes(frame, 2); // manufacturer + address[0-1]
 | 
			
		||||
    key ^= uint32FromBytes(frame, 6); // address[2-3] + version + type
 | 
			
		||||
    key ^= uint32FromBytes(origin, 2); // manufacturer + address[0-1]
 | 
			
		||||
    key ^= uint32FromBytes(origin, 6); // address[2-3] + version + type
 | 
			
		||||
    key ^= uint32FromBytes(frame, 10); // ci + some more bytes from the telegram...
 | 
			
		||||
 | 
			
		||||
    int size = frame.size() - 15;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -518,7 +518,7 @@ bool MeterCommonImplementation::handleTelegram(AboutTelegram &about, vector<ucha
 | 
			
		|||
 | 
			
		||||
    char log_prefix[256];
 | 
			
		||||
    snprintf(log_prefix, 255, "(%s) log", meterName().c_str());
 | 
			
		||||
    logTelegram(t.frame, t.header_size, t.suffix_size);
 | 
			
		||||
    logTelegram(t.original, t.frame, t.header_size, t.suffix_size);
 | 
			
		||||
 | 
			
		||||
    // Invoke meter specific parsing!
 | 
			
		||||
    processContent(&t);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -118,13 +118,10 @@
 | 
			
		|||
    X(IPERL,     MANUFACTURER_SEN,  0x06,  0x68) \
 | 
			
		||||
    X(IPERL,     MANUFACTURER_SEN,  0x07,  0x68) \
 | 
			
		||||
    X(IPERL,     MANUFACTURER_SEN,  0x07,  0x7c) \
 | 
			
		||||
    X(IZAR,      MANUFACTURER_SAP,  0x01,    -1) \
 | 
			
		||||
    X(IZAR,      MANUFACTURER_SAP,  0x15,    -1) \
 | 
			
		||||
    X(IZAR,      MANUFACTURER_SAP,  0x66,    -1) \
 | 
			
		||||
    X(IZAR,      MANUFACTURER_SAP,  0x04,    -1) \
 | 
			
		||||
    X(IZAR,      MANUFACTURER_DME,  0x66,    -1) \
 | 
			
		||||
    X(IZAR,      MANUFACTURER_DME,  0x19,  0x00) \
 | 
			
		||||
    X(IZAR,      MANUFACTURER_DME,  0x20,  0x48) \
 | 
			
		||||
    X(IZAR,      MANUFACTURER_SAP,  0x07,  0x00) \
 | 
			
		||||
    X(IZAR,      MANUFACTURER_DME,  0x07,  0x78) \
 | 
			
		||||
    X(IZAR3,     MANUFACTURER_SAP,  0x00,  0x88) \
 | 
			
		||||
    X(LANSENSM,  MANUFACTURER_LAS,  0x1a,  0x03) \
 | 
			
		||||
    X(LANSENTH,  MANUFACTURER_LAS,  0x1b,  0x07) \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										15
									
								
								src/util.cc
								
								
								
								
							
							
						
						
									
										15
									
								
								src/util.cc
								
								
								
								
							| 
						 | 
				
			
			@ -193,7 +193,7 @@ bool hex2bin(vector<uchar> &src, vector<uchar> *target)
 | 
			
		|||
 | 
			
		||||
char const hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A','B','C','D','E','F'};
 | 
			
		||||
 | 
			
		||||
std::string bin2hex(vector<uchar> &target) {
 | 
			
		||||
std::string bin2hex(const vector<uchar> &target) {
 | 
			
		||||
    std::string str;
 | 
			
		||||
    for (size_t i = 0; i < target.size(); ++i) {
 | 
			
		||||
        const char ch = target[i];
 | 
			
		||||
| 
						 | 
				
			
			@ -863,12 +863,21 @@ void debugPayload(string intro, vector<uchar> &payload, vector<uchar>::iterator
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void logTelegram(vector<uchar> &parsed, int header_size, int suffix_size)
 | 
			
		||||
void logTelegram(vector<uchar> &original, vector<uchar> &parsed, int header_size, int suffix_size)
 | 
			
		||||
{
 | 
			
		||||
    if (isLogTelegramsEnabled())
 | 
			
		||||
    {
 | 
			
		||||
        vector<uchar> logged = parsed;
 | 
			
		||||
        if (!original.empty())
 | 
			
		||||
        {
 | 
			
		||||
            logged = vector<uchar>(parsed);
 | 
			
		||||
            for (unsigned int i = 0; i < original.size(); i++)
 | 
			
		||||
            {
 | 
			
		||||
                logged[i] = original[i];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        time_t diff = time(NULL)-telegrams_start_time_;
 | 
			
		||||
        string parsed_hex = bin2hex(parsed);
 | 
			
		||||
        string parsed_hex = bin2hex(logged);
 | 
			
		||||
        string header = parsed_hex.substr(0, header_size*2);
 | 
			
		||||
        string content = parsed_hex.substr(header_size*2);
 | 
			
		||||
        if (suffix_size == 0)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,7 +43,7 @@ uchar reverse(uchar c);
 | 
			
		|||
bool hex2bin(const char* src, std::vector<uchar> *target);
 | 
			
		||||
bool hex2bin(std::string &src, std::vector<uchar> *target);
 | 
			
		||||
bool hex2bin(std::vector<uchar> &src, std::vector<uchar> *target);
 | 
			
		||||
std::string bin2hex(std::vector<uchar> &target);
 | 
			
		||||
std::string bin2hex(const std::vector<uchar> &target);
 | 
			
		||||
std::string bin2hex(std::vector<uchar>::iterator data, std::vector<uchar>::iterator end, int len);
 | 
			
		||||
std::string safeString(std::vector<uchar> &target);
 | 
			
		||||
void strprintf(std::string &s, const char* fmt, ...);
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +88,7 @@ bool isLogTelegramsEnabled();
 | 
			
		|||
 | 
			
		||||
void debugPayload(std::string intro, std::vector<uchar> &payload);
 | 
			
		||||
void debugPayload(std::string intro, std::vector<uchar> &payload, std::vector<uchar>::iterator &pos);
 | 
			
		||||
void logTelegram(std::vector<uchar> &parsed, int header_size, int suffix_size);
 | 
			
		||||
void logTelegram(std::vector<uchar> &original, std::vector<uchar> &parsed, int header_size, int suffix_size);
 | 
			
		||||
 | 
			
		||||
enum class Alarm
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										22
									
								
								src/wmbus.cc
								
								
								
								
							
							
						
						
									
										22
									
								
								src/wmbus.cc
								
								
								
								
							| 
						 | 
				
			
			@ -23,6 +23,7 @@
 | 
			
		|||
#include"wmbus_common_implementation.h"
 | 
			
		||||
#include"wmbus_utils.h"
 | 
			
		||||
#include"dvparser.h"
 | 
			
		||||
#include"manufacturer_specificities.h"
 | 
			
		||||
#include<assert.h>
 | 
			
		||||
#include<semaphore.h>
 | 
			
		||||
#include<stdarg.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -1579,6 +1580,23 @@ bool Telegram::parseTPL(vector<uchar>::iterator &pos)
 | 
			
		|||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Telegram::preProcess()
 | 
			
		||||
{
 | 
			
		||||
    if (frame.size() >= 15)
 | 
			
		||||
    {
 | 
			
		||||
        uchar c_field = frame[1];
 | 
			
		||||
        int m_field = frame[3] <<8 | frame[2];
 | 
			
		||||
        uchar ci_field = frame[10];
 | 
			
		||||
        int tpl_cfg = frame[14] <<8 | frame[13];
 | 
			
		||||
        DiehlAddressTransformMethod diehl_method = mustTransformDiehlAddress(c_field, m_field, ci_field, tpl_cfg);
 | 
			
		||||
        if (diehl_method != DiehlAddressTransformMethod::NONE)
 | 
			
		||||
        {
 | 
			
		||||
            original = vector<uchar>(frame.begin(), frame.begin() + 10);
 | 
			
		||||
            transformDiehlAddress(frame, diehl_method);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Telegram::parseHeader(vector<uchar> &input_frame)
 | 
			
		||||
{
 | 
			
		||||
    bool ok;
 | 
			
		||||
| 
						 | 
				
			
			@ -1592,6 +1610,8 @@ bool Telegram::parseHeader(vector<uchar> &input_frame)
 | 
			
		|||
    vector<uchar>::iterator pos = frame.begin();
 | 
			
		||||
    // Parsed accumulates parsed bytes.
 | 
			
		||||
    parsed.clear();
 | 
			
		||||
    // Fixes quirks from non-compliant meters to make telegram compatible with the standard
 | 
			
		||||
    preProcess();
 | 
			
		||||
 | 
			
		||||
    ok = parseDLL(pos);
 | 
			
		||||
    if (!ok) return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -1626,6 +1646,8 @@ bool Telegram::parse(vector<uchar> &input_frame, MeterKeys *mk, bool warn)
 | 
			
		|||
    vector<uchar>::iterator pos = frame.begin();
 | 
			
		||||
    // Parsed accumulates parsed bytes.
 | 
			
		||||
    parsed.clear();
 | 
			
		||||
    // Fixes quirks from non-compliant meters to make telegram compatible with the standard
 | 
			
		||||
    preProcess();
 | 
			
		||||
    //     ┌──────────────────────────────────────────────┐
 | 
			
		||||
    //     │                                              │
 | 
			
		||||
    //     │ Parse DLL Data Link Layer for Wireless MBUS. │
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -464,12 +464,18 @@ struct Telegram
 | 
			
		|||
 | 
			
		||||
    string autoDetectPossibleDrivers();
 | 
			
		||||
 | 
			
		||||
    // part of original telegram bytes, only filled if pre-processing modifies it
 | 
			
		||||
    vector<uchar> original;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
    bool is_simulated_ {};
 | 
			
		||||
    bool parser_warns_ = true;
 | 
			
		||||
    MeterKeys *meter_keys {};
 | 
			
		||||
 | 
			
		||||
    // Fixes quirks from non-compliant meters to make telegram compatible with the standard
 | 
			
		||||
    void preProcess();
 | 
			
		||||
 | 
			
		||||
    bool parseDLL(std::vector<uchar>::iterator &pos);
 | 
			
		||||
    bool parseELL(std::vector<uchar>::iterator &pos);
 | 
			
		||||
    bool parseNWL(std::vector<uchar>::iterator &pos);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,8 +14,8 @@ mkdir -p $TEST
 | 
			
		|||
rm -f $LOGFILE
 | 
			
		||||
 | 
			
		||||
METERS="IzarWater   izar        21242472 NOKEY
 | 
			
		||||
        IzarWater2  izar        66290778 NOKEY
 | 
			
		||||
        IzarWater3  izar        19790778 NOKEY
 | 
			
		||||
        IzarWater2  izar        23662907 NOKEY
 | 
			
		||||
        IzarWater3  izar        48197907 NOKEY
 | 
			
		||||
        IzarWater4  izar        2124589c NOKEY"
 | 
			
		||||
 | 
			
		||||
cat simulations/simulation_izars.txt | grep '^{' > $TEST/test_expected.txt
 | 
			
		||||
| 
						 | 
				
			
			@ -50,23 +50,23 @@ cat > $LOGFILE_EXPECTED <<EOF
 | 
			
		|||
No meters configured. Printing id:s of all telegrams heard!
 | 
			
		||||
Received telegram from: 21242472
 | 
			
		||||
          manufacturer: (SAP) Sappel (0x4c30)
 | 
			
		||||
                  type: Oil meter (0x01)
 | 
			
		||||
                   ver: 0xd4
 | 
			
		||||
                  type: Water meter (0x07)
 | 
			
		||||
                   ver: 0x00
 | 
			
		||||
                driver: izar
 | 
			
		||||
Received telegram from: 66290778
 | 
			
		||||
Received telegram from: 23662907
 | 
			
		||||
          manufacturer: (DME) DIEHL Metering, Germany (0x11a5)
 | 
			
		||||
                  type: Unknown (0x66)
 | 
			
		||||
                   ver: 0x23
 | 
			
		||||
                  type: Water meter (0x07)
 | 
			
		||||
                   ver: 0x78
 | 
			
		||||
                driver: izar
 | 
			
		||||
Received telegram from: 19790778
 | 
			
		||||
Received telegram from: 48197907
 | 
			
		||||
          manufacturer: (DME) DIEHL Metering, Germany (0x11a5)
 | 
			
		||||
                  type: Breaker (electricity) (0x20)
 | 
			
		||||
                   ver: 0x48
 | 
			
		||||
                  type: Water meter (0x07)
 | 
			
		||||
                   ver: 0x78
 | 
			
		||||
                driver: izar
 | 
			
		||||
Received telegram from: 2124589c
 | 
			
		||||
          manufacturer: (SAP) Sappel (0x4c30)
 | 
			
		||||
                  type: Heat meter (0x04)
 | 
			
		||||
                   ver: 0x0c
 | 
			
		||||
                  type: Water meter (0x07)
 | 
			
		||||
                   ver: 0x00
 | 
			
		||||
                driver: izar
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue