kopia lustrzana https://github.com/weetmuts/wmbusmeters
Added mbus driver ultraheat.
rodzic
c20a63e5b7
commit
b322838b59
8
Makefile
8
Makefile
|
@ -135,8 +135,12 @@ PROG_OBJS:=\
|
||||||
$(BUILD)/wmbus_rc1180.o \
|
$(BUILD)/wmbus_rc1180.o \
|
||||||
$(BUILD)/wmbus_utils.o \
|
$(BUILD)/wmbus_utils.o \
|
||||||
|
|
||||||
|
ifeq ($(DRIVER),)
|
||||||
DRIVER_OBJS:=$(wildcard src/meter_*.cc)
|
DRIVER_OBJS:=$(wildcard src/meter_*.cc)
|
||||||
|
else
|
||||||
|
$(info Building a single driver $(DRIVER))
|
||||||
|
DRIVER_OBJS:=src/meter_auto.cc src/meter_unknown.cc src/meter_$(DRIVER).cc
|
||||||
|
endif
|
||||||
DRIVER_OBJS:=$(patsubst src/%.cc,$(BUILD)/%.o,$(DRIVER_OBJS))
|
DRIVER_OBJS:=$(patsubst src/%.cc,$(BUILD)/%.o,$(DRIVER_OBJS))
|
||||||
|
|
||||||
all: $(BUILD)/wmbusmeters $(BUILD)/wmbusmetersd $(BUILD)/wmbusmeters.g $(BUILD)/wmbusmeters-admin $(BUILD)/testinternals
|
all: $(BUILD)/wmbusmeters $(BUILD)/wmbusmetersd $(BUILD)/wmbusmeters.g $(BUILD)/wmbusmeters-admin $(BUILD)/testinternals
|
||||||
|
|
|
@ -92,7 +92,7 @@ telegram=|27442D2C5768663230028D20E900C91C2011BA79138CCCFB|1A0300000000000003000
|
||||||
{"media":"electricity","meter":"omnipower","name":"myomnipower","id":"32666857","total_energy_consumption_kwh":7.94,"total_energy_production_kwh":0,"current_power_consumption_kw":0.003,"current_power_production_kw":0,"timestamp":"1111-11-11T11:11:11Z"}
|
{"media":"electricity","meter":"omnipower","name":"myomnipower","id":"32666857","total_energy_consumption_kwh":7.94,"total_energy_production_kwh":0,"current_power_consumption_kw":0.003,"current_power_production_kw":0,"timestamp":"1111-11-11T11:11:11Z"}
|
||||||
|
|
||||||
# Test EI Electronics smoke detector
|
# Test EI Electronics smoke detector
|
||||||
telegram=|5E462515112801000C1A7A370050252F2F|0BFD0F060101046D300CAB2202FD17000082206CAB22426C01018440FF2C000F11008250FD61000082506C01018260FD6100008360FD3100000082606C01018270FD61010082706CAB222F2F2F2F|
|
telegram=|5E442515112801000C1A7A370050252F2F#0BFD0F060101046D300CAB2202FD17000082206CAB22426C01018440FF2C000F11008250FD61000082506C01018260FD6100008360FD3100000082606C01018270FD61010082706CAB222F2F2F2F|
|
||||||
{"media":"smoke detector","meter":"ei6500","name":"Smokey","id":"00012811","software_version":"1.1.6","message_datetime":"2021-02-11 12:48","last_alarm_date":"2000-01-01","smoke_alarm_counter":"0","total_remove_duration":"0 minutes","last_remove_date":"2000-01-01","removed_counter":"0","test_button_last_date":"2021-02-11","test_button_counter":"1","status":"NOT_INSTALLED","timestamp":"1111-11-11T11:11:11Z"}
|
{"media":"smoke detector","meter":"ei6500","name":"Smokey","id":"00012811","software_version":"1.1.6","message_datetime":"2021-02-11 12:48","last_alarm_date":"2000-01-01","smoke_alarm_counter":"0","total_remove_duration":"0 minutes","last_remove_date":"2000-01-01","removed_counter":"0","test_button_last_date":"2021-02-11","test_button_counter":"1","status":"NOT_INSTALLED","timestamp":"1111-11-11T11:11:11Z"}
|
||||||
|
|
||||||
# Test Techem radio convert + Wehrle water meter combo.
|
# Test Techem radio convert + Wehrle water meter combo.
|
||||||
|
|
|
@ -34,7 +34,21 @@ const char *toString(ValueInformation v)
|
||||||
switch (v) {
|
switch (v) {
|
||||||
case ValueInformation::None: return "None";
|
case ValueInformation::None: return "None";
|
||||||
case ValueInformation::Any: return "Any";
|
case ValueInformation::Any: return "Any";
|
||||||
#define X(name,from,to,quantity) case ValueInformation::name: return #name;
|
#define X(name,from,to,quantity,unit) case ValueInformation::name: return #name;
|
||||||
|
LIST_OF_VALUETYPES
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Unit toDefaultUnit(ValueInformation v)
|
||||||
|
{
|
||||||
|
switch (v) {
|
||||||
|
case ValueInformation::Any:
|
||||||
|
case ValueInformation::None:
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
#define X(name,from,to,quantity,unit) case ValueInformation::name: return unit;
|
||||||
LIST_OF_VALUETYPES
|
LIST_OF_VALUETYPES
|
||||||
#undef X
|
#undef X
|
||||||
}
|
}
|
||||||
|
@ -43,7 +57,7 @@ LIST_OF_VALUETYPES
|
||||||
|
|
||||||
ValueInformation toValueInformation(int i)
|
ValueInformation toValueInformation(int i)
|
||||||
{
|
{
|
||||||
#define X(name,from,to,quantity) if (from <= i && i <= to) return ValueInformation::name;
|
#define X(name,from,to,quantity,unit) if (from <= i && i <= to) return ValueInformation::name;
|
||||||
LIST_OF_VALUETYPES
|
LIST_OF_VALUETYPES
|
||||||
#undef X
|
#undef X
|
||||||
return ValueInformation::None;
|
return ValueInformation::None;
|
||||||
|
@ -321,7 +335,7 @@ void valueInfoRange(ValueInformation v, int *low, int *hi)
|
||||||
switch (v) {
|
switch (v) {
|
||||||
case ValueInformation::Any:
|
case ValueInformation::Any:
|
||||||
case ValueInformation::None: *low = 0; *hi = 0; return;
|
case ValueInformation::None: *low = 0; *hi = 0; return;
|
||||||
#define X(name,from,to,quantity) case ValueInformation::name: *low = from; *hi = to; return;
|
#define X(name,from,to,quantity,unit) case ValueInformation::name: *low = from; *hi = to; return;
|
||||||
LIST_OF_VALUETYPES
|
LIST_OF_VALUETYPES
|
||||||
#undef X
|
#undef X
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#define DVPARSER_H
|
#define DVPARSER_H
|
||||||
|
|
||||||
#include"util.h"
|
#include"util.h"
|
||||||
|
#include"units.h"
|
||||||
#include"wmbus.h"
|
#include"wmbus.h"
|
||||||
|
|
||||||
#include<map>
|
#include<map>
|
||||||
|
@ -28,31 +29,32 @@
|
||||||
#include<vector>
|
#include<vector>
|
||||||
|
|
||||||
#define LIST_OF_VALUETYPES \
|
#define LIST_OF_VALUETYPES \
|
||||||
X(Volume,0x10,0x17,Quantity::Volume) \
|
X(Volume,0x10,0x17,Quantity::Volume,Unit::M3) \
|
||||||
X(OperatingTime,0x24,0x27, Quantity::Time) \
|
X(OperatingTime,0x24,0x27, Quantity::Time, Unit::Second) \
|
||||||
X(VolumeFlow,0x38,0x3F, Quantity::Flow) \
|
X(VolumeFlow,0x38,0x3F, Quantity::Flow, Unit::M3H) \
|
||||||
X(FlowTemperature,0x58,0x5B, Quantity::Temperature) \
|
X(FlowTemperature,0x58,0x5B, Quantity::Temperature, Unit::C) \
|
||||||
X(ReturnTemperature,0x5C,0x5F, Quantity::Temperature) \
|
X(ReturnTemperature,0x5C,0x5F, Quantity::Temperature, Unit::C) \
|
||||||
X(TemperatureDifference,0x60,0x63, Quantity::Temperature) \
|
X(TemperatureDifference,0x60,0x63, Quantity::Temperature, Unit::C) \
|
||||||
X(ExternalTemperature,0x64,0x67, Quantity::Temperature) \
|
X(ExternalTemperature,0x64,0x67, Quantity::Temperature, Unit::C) \
|
||||||
X(HeatCostAllocation,0x6E,0x6E, Quantity::HCA) \
|
X(HeatCostAllocation,0x6E,0x6E, Quantity::HCA, Unit::HCA) \
|
||||||
X(Date,0x6C,0x6C, Quantity::PointInTime) \
|
X(Date,0x6C,0x6C, Quantity::PointInTime, Unit::DateTimeLT) \
|
||||||
X(DateTime,0x6D,0x6D, Quantity::PointInTime) \
|
X(DateTime,0x6D,0x6D, Quantity::PointInTime, Unit::DateTimeLT) \
|
||||||
X(EnergyMJ,0x0E,0x0F, Quantity::Energy) \
|
X(EnergyMJ,0x0E,0x0F, Quantity::Energy, Unit::MJ) \
|
||||||
X(EnergyWh,0x00,0x07, Quantity::Energy) \
|
X(EnergyWh,0x00,0x07, Quantity::Energy, Unit::KWH) \
|
||||||
X(PowerW,0x28,0x2f, Quantity::Power) \
|
X(PowerW,0x28,0x2f, Quantity::Power, Unit::KW) \
|
||||||
X(ActualityDuration,0x74,0x77, Quantity::Time) \
|
X(ActualityDuration,0x74,0x77, Quantity::Time, Unit::Second) \
|
||||||
|
|
||||||
enum class ValueInformation
|
enum class ValueInformation
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
Any,
|
Any,
|
||||||
#define X(name,from,to,quantity) name,
|
#define X(name,from,to,quantity,unit) name,
|
||||||
LIST_OF_VALUETYPES
|
LIST_OF_VALUETYPES
|
||||||
#undef X
|
#undef X
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *toString(ValueInformation v);
|
const char *toString(ValueInformation v);
|
||||||
|
Unit toDefaultUnit(ValueInformation v);
|
||||||
ValueInformation toValueInformation(int i);
|
ValueInformation toValueInformation(int i);
|
||||||
|
|
||||||
struct DifVifKey
|
struct DifVifKey
|
||||||
|
|
|
@ -120,7 +120,7 @@ void MBusRawTTY::processSerialData()
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
FrameStatus status = checkMBusFrame(read_buffer_, &frame_length, &payload_len, &payload_offset);
|
FrameStatus status = checkMBusFrame(read_buffer_, &frame_length, &payload_len, &payload_offset, false);
|
||||||
|
|
||||||
if (status == PartialFrame)
|
if (status == PartialFrame)
|
||||||
{
|
{
|
||||||
|
|
|
@ -90,6 +90,7 @@
|
||||||
X(FLOWIQ3100,MANUFACTURER_KAM, 0x16, 0x1d) \
|
X(FLOWIQ3100,MANUFACTURER_KAM, 0x16, 0x1d) \
|
||||||
X(MULTICAL302,MANUFACTURER_KAM, 0x04, 0x30) \
|
X(MULTICAL302,MANUFACTURER_KAM, 0x04, 0x30) \
|
||||||
X(MULTICAL302,MANUFACTURER_KAM, 0x0d, 0x30) \
|
X(MULTICAL302,MANUFACTURER_KAM, 0x0d, 0x30) \
|
||||||
|
X(MULTICAL302,MANUFACTURER_KAM, 0x0c, 0x30) \
|
||||||
X(MULTICAL403,MANUFACTURER_KAM, 0x0a, 0x34) \
|
X(MULTICAL403,MANUFACTURER_KAM, 0x0a, 0x34) \
|
||||||
X(MULTICAL403,MANUFACTURER_KAM, 0x0b, 0x34) \
|
X(MULTICAL403,MANUFACTURER_KAM, 0x0b, 0x34) \
|
||||||
X(MULTICAL403,MANUFACTURER_KAM, 0x0c, 0x34) \
|
X(MULTICAL403,MANUFACTURER_KAM, 0x0c, 0x34) \
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2022 Fredrik Öhrström
|
||||||
|
|
||||||
|
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"
|
||||||
|
#include"meters.h"
|
||||||
|
#include"meters_common_implementation.h"
|
||||||
|
#include"wmbus.h"
|
||||||
|
#include"wmbus_utils.h"
|
||||||
|
#include"util.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
struct MeterUltraHeat : public virtual MeterCommonImplementation
|
||||||
|
{
|
||||||
|
MeterUltraHeat(MeterInfo &mi, DriverInfo &di);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
double heat_mj_ {};
|
||||||
|
double volume_m3_ {};
|
||||||
|
double power_kw_ {};
|
||||||
|
double flow_m3h_ {};
|
||||||
|
double flow_c_ {};
|
||||||
|
double return_c_ {};
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool ok = registerDriver([](DriverInfo&di)
|
||||||
|
{
|
||||||
|
di.setName("ultraheat");
|
||||||
|
di.setMeterType(MeterType::HeatMeter);
|
||||||
|
di.addDetection(MANUFACTURER_LUG, 0x04, 0x04);
|
||||||
|
di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr<Meter>(new MeterUltraHeat(mi, di)); });
|
||||||
|
});
|
||||||
|
|
||||||
|
MeterUltraHeat::MeterUltraHeat(MeterInfo &mi, DriverInfo &di) :
|
||||||
|
MeterCommonImplementation(mi, di)
|
||||||
|
{
|
||||||
|
addFieldWithExtractor(
|
||||||
|
"heat",
|
||||||
|
Quantity::Energy,
|
||||||
|
NoDifVifKey,
|
||||||
|
VifScaling::Auto,
|
||||||
|
MeasurementType::Instantaneous,
|
||||||
|
ValueInformation::EnergyMJ,
|
||||||
|
StorageNr(0),
|
||||||
|
TariffNr(0),
|
||||||
|
IndexNr(1),
|
||||||
|
PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT,
|
||||||
|
"The total heat energy consumption recorded by this meter.",
|
||||||
|
SET_FUNC(heat_mj_, Unit::MJ),
|
||||||
|
GET_FUNC(heat_mj_, Unit::MJ));
|
||||||
|
|
||||||
|
addFieldWithExtractor(
|
||||||
|
"volume",
|
||||||
|
Quantity::Volume,
|
||||||
|
NoDifVifKey,
|
||||||
|
VifScaling::Auto,
|
||||||
|
MeasurementType::Instantaneous,
|
||||||
|
ValueInformation::Volume,
|
||||||
|
StorageNr(0),
|
||||||
|
TariffNr(0),
|
||||||
|
IndexNr(1),
|
||||||
|
PrintProperty::JSON ,
|
||||||
|
"The total heating media volume recorded by this meter.",
|
||||||
|
SET_FUNC(volume_m3_, Unit::M3),
|
||||||
|
GET_FUNC(volume_m3_, Unit::M3));
|
||||||
|
|
||||||
|
addFieldWithExtractor(
|
||||||
|
"power",
|
||||||
|
Quantity::Power,
|
||||||
|
NoDifVifKey,
|
||||||
|
VifScaling::Auto,
|
||||||
|
MeasurementType::Instantaneous,
|
||||||
|
ValueInformation::PowerW,
|
||||||
|
StorageNr(0),
|
||||||
|
TariffNr(0),
|
||||||
|
IndexNr(1),
|
||||||
|
PrintProperty::JSON ,
|
||||||
|
"The current power consumption.",
|
||||||
|
SET_FUNC(power_kw_, Unit::KW),
|
||||||
|
GET_FUNC(power_kw_, Unit::KW));
|
||||||
|
|
||||||
|
addFieldWithExtractor(
|
||||||
|
"flow",
|
||||||
|
Quantity::Flow,
|
||||||
|
NoDifVifKey,
|
||||||
|
VifScaling::Auto,
|
||||||
|
MeasurementType::Instantaneous,
|
||||||
|
ValueInformation::VolumeFlow,
|
||||||
|
StorageNr(0),
|
||||||
|
TariffNr(0),
|
||||||
|
IndexNr(1),
|
||||||
|
PrintProperty::JSON ,
|
||||||
|
"The current heat media volume flow.",
|
||||||
|
SET_FUNC(flow_m3h_, Unit::M3H),
|
||||||
|
GET_FUNC(flow_m3h_, Unit::M3H));
|
||||||
|
|
||||||
|
addFieldWithExtractor(
|
||||||
|
"flow",
|
||||||
|
Quantity::Temperature,
|
||||||
|
NoDifVifKey,
|
||||||
|
VifScaling::Auto,
|
||||||
|
MeasurementType::Instantaneous,
|
||||||
|
ValueInformation::FlowTemperature,
|
||||||
|
StorageNr(0),
|
||||||
|
TariffNr(0),
|
||||||
|
IndexNr(1),
|
||||||
|
PrintProperty::JSON ,
|
||||||
|
"The current forward heat media temperature.",
|
||||||
|
SET_FUNC(flow_c_, Unit::C),
|
||||||
|
GET_FUNC(flow_c_, Unit::C));
|
||||||
|
|
||||||
|
addFieldWithExtractor(
|
||||||
|
"return",
|
||||||
|
Quantity::Temperature,
|
||||||
|
NoDifVifKey,
|
||||||
|
VifScaling::Auto,
|
||||||
|
MeasurementType::Instantaneous,
|
||||||
|
ValueInformation::ReturnTemperature,
|
||||||
|
StorageNr(0),
|
||||||
|
TariffNr(0),
|
||||||
|
IndexNr(1),
|
||||||
|
PrintProperty::JSON ,
|
||||||
|
"The current return heat media temperature.",
|
||||||
|
SET_FUNC(return_c_, Unit::C),
|
||||||
|
GET_FUNC(return_c_, Unit::C));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test: MyUltra ultraheat 70444600 NOKEY
|
||||||
|
// telegram=|68F8F86808007200464470A7320404270000000974040970040C0E082303000C14079519000B2D0500000B3B0808000A5B52000A5F51000A6206004C14061818004C0E490603000C7800464470891071609B102D020100DB102D0201009B103B6009009A105B78009A105F74000C22726701003C22000000007C2200000000426C01018C2006000000008C3006000000008C80100600000000CC200600000000CC300600000000CC801006000000009A115B64009A115F63009B113B5208009B112D020100BC0122000000008C010E490603008C2106000000008C3106000000008C811006000000008C011406181800046D310ACA210F21040010A0C116|
|
||||||
|
// {"media":"heat","meter":"ultraheat","name":"MyUltra","id":"70444600","heat_kwh":8974.444444,"volume_m3":1995.07,"power_kw":0.5,"flow_m3h":0.808,"flow_c":52,"return_c":51,"timestamp":"1111-11-11T11:11:11Z"}
|
||||||
|
// |MyUltra;70444600;8974.444444;1111-11-11 11:11.11
|
|
@ -719,7 +719,13 @@ void MeterCommonImplementation::addFieldWithExtractor(
|
||||||
&extracted_double_value,
|
&extracted_double_value,
|
||||||
fi->vifScaling() == VifScaling::Auto))
|
fi->vifScaling() == VifScaling::Auto))
|
||||||
{
|
{
|
||||||
fi->setValueDouble(fi->defaultUnit(), extracted_double_value);
|
Unit decoded_unit = fi->defaultUnit();
|
||||||
|
if (fi->valueInformation() != ValueInformation::Any &&
|
||||||
|
fi->valueInformation() != ValueInformation::None)
|
||||||
|
{
|
||||||
|
decoded_unit = toDefaultUnit(fi->valueInformation());
|
||||||
|
}
|
||||||
|
fi->setValueDouble(decoded_unit, extracted_double_value);
|
||||||
t->addMoreExplanation(offset, fi->renderJson(&m->conversions()));
|
t->addMoreExplanation(offset, fi->renderJson(&m->conversions()));
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
|
|
176
src/wmbus.cc
176
src/wmbus.cc
|
@ -268,6 +268,8 @@ void Telegram::print()
|
||||||
|
|
||||||
void Telegram::printDLL()
|
void Telegram::printDLL()
|
||||||
{
|
{
|
||||||
|
if (about.type == FrameType::WMBUS)
|
||||||
|
{
|
||||||
string possible_drivers = autoDetectPossibleDrivers();
|
string possible_drivers = autoDetectPossibleDrivers();
|
||||||
|
|
||||||
string man = manufacturerFlag(dll_mfct);
|
string man = manufacturerFlag(dll_mfct);
|
||||||
|
@ -283,6 +285,16 @@ void Telegram::printDLL()
|
||||||
possible_drivers.c_str(),
|
possible_drivers.c_str(),
|
||||||
about.device.c_str(),
|
about.device.c_str(),
|
||||||
about.rssi_dbm);
|
about.rssi_dbm);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (about.type == FrameType::MBUS)
|
||||||
|
{
|
||||||
|
verbose("(telegram) DLL L=%02x C=%02x (%s) A=%02x\n",
|
||||||
|
dll_len,
|
||||||
|
dll_c, cType(dll_c).c_str(),
|
||||||
|
mbus_primary_address);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Telegram::printELL()
|
void Telegram::printELL()
|
||||||
|
@ -818,25 +830,46 @@ bool expectedMore(int line)
|
||||||
bool Telegram::parseMBusDLL(vector<uchar>::iterator &pos)
|
bool Telegram::parseMBusDLL(vector<uchar>::iterator &pos)
|
||||||
{
|
{
|
||||||
int remaining = distance(pos, frame.end());
|
int remaining = distance(pos, frame.end());
|
||||||
if (remaining == 0) return expectedMore(__LINE__);
|
if (remaining < 5) return expectedMore(__LINE__);
|
||||||
|
|
||||||
|
debug("(mbus) parse MBUS DLL @%d %d\n", distance(frame.begin(), pos), remaining);
|
||||||
|
debugPayload("(mbus) ", frame);
|
||||||
|
|
||||||
|
if (*pos != 0x68) return false;
|
||||||
|
addExplanationAndIncrementPos(pos, 1, KindOfData::PROTOCOL, Understanding::FULL, "68 start");
|
||||||
|
|
||||||
debug("(wmbus) parse MBUS DLL @%d %d\n", distance(frame.begin(), pos), remaining);
|
|
||||||
dll_len = *pos;
|
dll_len = *pos;
|
||||||
if (remaining < dll_len) return expectedMore(__LINE__);
|
|
||||||
addExplanationAndIncrementPos(pos, 1, KindOfData::PROTOCOL, Understanding::FULL, "%02x length (%d bytes)", dll_len, dll_len);
|
addExplanationAndIncrementPos(pos, 1, KindOfData::PROTOCOL, Understanding::FULL, "%02x length (%d bytes)", dll_len, dll_len);
|
||||||
|
|
||||||
|
// Two identical length bytes are expected!
|
||||||
|
if (*pos != dll_len) return false;
|
||||||
|
addExplanationAndIncrementPos(pos, 1, KindOfData::PROTOCOL, Understanding::FULL, "%02x length again (%d bytes)", dll_len, dll_len);
|
||||||
|
|
||||||
|
if (*pos != 0x68) return false;
|
||||||
|
addExplanationAndIncrementPos(pos, 1, KindOfData::PROTOCOL, Understanding::FULL, "68 start");
|
||||||
|
|
||||||
|
if (remaining < dll_len) return expectedMore(__LINE__);
|
||||||
|
|
||||||
dll_c = *pos;
|
dll_c = *pos;
|
||||||
addExplanationAndIncrementPos(pos, 1, KindOfData::PROTOCOL, Understanding::FULL, "%02x dll-c (%s)", dll_c, mbusCField(dll_c).c_str());
|
addExplanationAndIncrementPos(pos, 1, KindOfData::PROTOCOL, Understanding::FULL, "%02x dll-c (%s)", dll_c, mbusCField(dll_c));
|
||||||
|
|
||||||
mbus_primary_address = *pos;
|
mbus_primary_address = *pos;
|
||||||
addExplanationAndIncrementPos(pos, 1, KindOfData::PROTOCOL, Understanding::FULL, "%02x dll-a primary (%d)", mbus_primary_address, mbus_primary_address);
|
addExplanationAndIncrementPos(pos, 1, KindOfData::PROTOCOL, Understanding::FULL, "%02x dll-a primary (%d)", mbus_primary_address, mbus_primary_address);
|
||||||
|
|
||||||
// Add dll_id to ids.
|
// Add dll_id to ids.
|
||||||
string id = tostrprintf("%02x", dll_a[0]);
|
string id = tostrprintf("%02x", mbus_primary_address);
|
||||||
ids.push_back(id);
|
ids.push_back(id);
|
||||||
idsc = id;
|
idsc = id;
|
||||||
|
|
||||||
return true;
|
mbus_ci = *pos;
|
||||||
|
addExplanationAndIncrementPos(pos, 1, KindOfData::PROTOCOL, Understanding::FULL, "%02x dll-ci (%s)", mbus_ci, mbusCiField(mbus_ci));
|
||||||
|
|
||||||
|
if (mbus_ci == 0x72)
|
||||||
|
{
|
||||||
|
return parse_TPL_72(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Telegram::parseDLL(vector<uchar>::iterator &pos)
|
bool Telegram::parseDLL(vector<uchar>::iterator &pos)
|
||||||
|
@ -1918,8 +1951,7 @@ bool Telegram::parseMBUS(vector<uchar> &input_frame, MeterKeys *mk, bool warn)
|
||||||
vector<uchar>::iterator pos = frame.begin();
|
vector<uchar>::iterator pos = frame.begin();
|
||||||
// Parsed accumulates parsed bytes.
|
// Parsed accumulates parsed bytes.
|
||||||
parsed.clear();
|
parsed.clear();
|
||||||
// Fixes quirks from non-compliant meters to make telegram compatible with the standard
|
|
||||||
preProcess();
|
|
||||||
// ┌──────────────────────────────────────────────┐
|
// ┌──────────────────────────────────────────────┐
|
||||||
// │ │
|
// │ │
|
||||||
// │ Parse DLL Data Link Layer for Wireless MBUS. │
|
// │ Parse DLL Data Link Layer for Wireless MBUS. │
|
||||||
|
@ -2087,7 +2119,7 @@ string Telegram::autoDetectPossibleDrivers()
|
||||||
return possibles;
|
return possibles;
|
||||||
}
|
}
|
||||||
|
|
||||||
string mbusCField(uchar c_field)
|
const char *mbusCField(uchar c_field)
|
||||||
{
|
{
|
||||||
string s;
|
string s;
|
||||||
switch (c_field)
|
switch (c_field)
|
||||||
|
@ -2097,6 +2129,24 @@ string mbusCField(uchar c_field)
|
||||||
return "?";
|
return "?";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *mbusCiField(uchar c_field)
|
||||||
|
{
|
||||||
|
string s;
|
||||||
|
switch (c_field)
|
||||||
|
{
|
||||||
|
case 0x78: return "no header";
|
||||||
|
case 0x7a: return "short header";
|
||||||
|
case 0x72: return "long header";
|
||||||
|
case 0x79: return "no header compact frame";
|
||||||
|
case 0x7b: return "short header compact frame";
|
||||||
|
case 0x73: return "long header compact frame";
|
||||||
|
case 0x69: return "no header format frame";
|
||||||
|
case 0x6a: return "short header format frame";
|
||||||
|
case 0x6b: return "long header format frame";
|
||||||
|
}
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
|
||||||
string cType(int c_field)
|
string cType(int c_field)
|
||||||
{
|
{
|
||||||
string s;
|
string s;
|
||||||
|
@ -2131,6 +2181,22 @@ string cType(int c_field)
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isValidWMBusCField(int c_field)
|
||||||
|
{
|
||||||
|
// These are the currently seen valid C fields for wmbus telegrams.
|
||||||
|
// 0x46 is only from an ei6500 meter.... all else is ox44
|
||||||
|
// However in the future we might see relayed telegrams which will perhaps have
|
||||||
|
// some other c field.
|
||||||
|
return
|
||||||
|
c_field == 0x44 ||
|
||||||
|
c_field == 0x46;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValidMBusCField(int c_field)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
string ccType(int cc_field)
|
string ccType(int cc_field)
|
||||||
{
|
{
|
||||||
string s = "";
|
string s = "";
|
||||||
|
@ -4222,8 +4288,11 @@ bool trimCRCsFrameFormatAInternal(std::vector<uchar> &payload, bool fail_is_ok)
|
||||||
uint16_t check_crc = payload[10] << 8 | payload[11];
|
uint16_t check_crc = payload[10] << 8 | payload[11];
|
||||||
|
|
||||||
if (calc_crc != check_crc && !FUZZING)
|
if (calc_crc != check_crc && !FUZZING)
|
||||||
|
{
|
||||||
|
if (!fail_is_ok)
|
||||||
{
|
{
|
||||||
debug("(wmbus) ff a dll crc first (calculated %04x) did not match (expected %04x) for bytes 0-%zu!\n", calc_crc, check_crc, 10);
|
debug("(wmbus) ff a dll crc first (calculated %04x) did not match (expected %04x) for bytes 0-%zu!\n", calc_crc, check_crc, 10);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
out.insert(out.end(), payload.begin(), payload.begin()+10);
|
out.insert(out.end(), payload.begin(), payload.begin()+10);
|
||||||
|
@ -4276,10 +4345,7 @@ bool trimCRCsFrameFormatAInternal(std::vector<uchar> &payload, bool fail_is_ok)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fail_is_ok)
|
|
||||||
{
|
|
||||||
debugPayload("(wmbus) trimming frame A", payload);
|
debugPayload("(wmbus) trimming frame A", payload);
|
||||||
}
|
|
||||||
|
|
||||||
out[0] = out.size()-1;
|
out[0] = out.size()-1;
|
||||||
size_t new_len = out[0]+1;
|
size_t new_len = out[0]+1;
|
||||||
|
@ -4361,10 +4427,7 @@ bool trimCRCsFrameFormatBInternal(std::vector<uchar> &payload, bool fail_is_ok)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fail_is_ok)
|
|
||||||
{
|
|
||||||
debugPayload("(wmbus) trimming frame B", payload);
|
debugPayload("(wmbus) trimming frame B", payload);
|
||||||
}
|
|
||||||
|
|
||||||
out[0] = out.size()-1;
|
out[0] = out.size()-1;
|
||||||
size_t new_len = out[0]+1;
|
size_t new_len = out[0]+1;
|
||||||
|
@ -4397,7 +4460,8 @@ bool trimCRCsFrameFormatB(std::vector<uchar> &payload)
|
||||||
FrameStatus checkWMBusFrame(vector<uchar> &data,
|
FrameStatus checkWMBusFrame(vector<uchar> &data,
|
||||||
size_t *frame_length,
|
size_t *frame_length,
|
||||||
int *payload_len_out,
|
int *payload_len_out,
|
||||||
int *payload_offset)
|
int *payload_offset,
|
||||||
|
bool only_test)
|
||||||
{
|
{
|
||||||
// Nice clean: 2A442D2C998734761B168D2021D0871921|58387802FF2071000413F81800004413F8180000615B
|
// Nice clean: 2A442D2C998734761B168D2021D0871921|58387802FF2071000413F81800004413F8180000615B
|
||||||
// Ugly: 00615B2A442D2C998734761B168D2021D0871921|58387802FF2071000413F81800004413F8180000615B
|
// Ugly: 00615B2A442D2C998734761B168D2021D0871921|58387802FF2071000413F81800004413F8180000615B
|
||||||
|
@ -4414,17 +4478,17 @@ FrameStatus checkWMBusFrame(vector<uchar> &data,
|
||||||
int type = data[1];
|
int type = data[1];
|
||||||
int offset = 1;
|
int offset = 1;
|
||||||
|
|
||||||
if (type != 0x44)
|
if (!isValidWMBusCField(type))
|
||||||
{
|
{
|
||||||
// Ouch, we are out of sync with the wmbus frames that we expect!
|
// Ouch, we are out of sync with the wmbus frames that we expect!
|
||||||
// Since we currently do not handle any other type of frame, we can
|
// Since we currently do not handle any other type of frame, we can
|
||||||
// look for the byte 0x44 in the buffer. If we find a 0x44 byte and
|
// look for a valid c field (ie 0x44 0x46 etc) in the buffer.
|
||||||
// the length byte before it maps to the end of the buffer,
|
// If we find such a byte and the length byte before maps to the end
|
||||||
// then we have found a valid telegram.
|
// of the buffer, then we have found a valid telegram.
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (size_t i = 0; i < data.size()-2; ++i)
|
for (size_t i = 0; i < data.size()-2; ++i)
|
||||||
{
|
{
|
||||||
if (data[i+1] == 0x44)
|
if (isValidWMBusCField(data[i+1]))
|
||||||
{
|
{
|
||||||
payload_len = data[i];
|
payload_len = data[i];
|
||||||
size_t remaining = data.size()-i;
|
size_t remaining = data.size()-i;
|
||||||
|
@ -4440,8 +4504,15 @@ FrameStatus checkWMBusFrame(vector<uchar> &data,
|
||||||
if (!found)
|
if (!found)
|
||||||
{
|
{
|
||||||
// No sensible telegram in the buffer. Flush it!
|
// No sensible telegram in the buffer. Flush it!
|
||||||
|
if (!only_test)
|
||||||
|
{
|
||||||
verbose("(wmbus) no sensible telegram found, clearing buffer.\n");
|
verbose("(wmbus) no sensible telegram found, clearing buffer.\n");
|
||||||
data.clear();
|
data.clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
debug("(wmbus) not a proper wmbus frame.\n");
|
||||||
|
}
|
||||||
return ErrorInFrame;
|
return ErrorInFrame;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4449,19 +4520,26 @@ FrameStatus checkWMBusFrame(vector<uchar> &data,
|
||||||
*payload_offset = offset;
|
*payload_offset = offset;
|
||||||
*frame_length = payload_len+offset;
|
*frame_length = payload_len+offset;
|
||||||
if (data.size() < *frame_length)
|
if (data.size() < *frame_length)
|
||||||
|
{
|
||||||
|
if (!only_test)
|
||||||
{
|
{
|
||||||
debug("(wmbus) not enough bytes, partial frame %d %d\n", data.size(), *frame_length);
|
debug("(wmbus) not enough bytes, partial frame %d %d\n", data.size(), *frame_length);
|
||||||
|
}
|
||||||
return PartialFrame;
|
return PartialFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!only_test)
|
||||||
|
{
|
||||||
debug("(wmbus) received full frame.\n");
|
debug("(wmbus) received full frame.\n");
|
||||||
|
}
|
||||||
return FullFrame;
|
return FullFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameStatus checkMBusFrame(vector<uchar> &data,
|
FrameStatus checkMBusFrame(vector<uchar> &data,
|
||||||
size_t *frame_length,
|
size_t *frame_length,
|
||||||
int *payload_len_out,
|
int *payload_len_out,
|
||||||
int *payload_offset)
|
int *payload_offset,
|
||||||
|
bool only_test)
|
||||||
{
|
{
|
||||||
// Example:
|
// Example:
|
||||||
// E5
|
// E5
|
||||||
|
@ -4471,48 +4549,78 @@ FrameStatus checkMBusFrame(vector<uchar> &data,
|
||||||
// 5E checksum
|
// 5E checksum
|
||||||
// 16 stop
|
// 16 stop
|
||||||
|
|
||||||
debugPayload("(wmbus) checkMBUSFrame\n", data);
|
debugPayload("(mbus) checkMBUSFrame\n", data);
|
||||||
|
|
||||||
if (data.size() > 0 && data[0] == 0xe5)
|
if (data.size() > 0 && data[0] == 0xe5)
|
||||||
{
|
{
|
||||||
// Single character confirmation frame.
|
// Single character confirmation frame.
|
||||||
|
if (only_test)
|
||||||
|
{
|
||||||
|
// For testing purposes we require the frame to be a single char as well.
|
||||||
|
// This happens when we pass a frame on the command line or in a simulation file.
|
||||||
|
// Otherwise a normal wmbus telegram with length e5 will triggere this mbus command.
|
||||||
|
// (When reading from a serial line, we might have data coming after the e5,
|
||||||
|
// but then we know that we are talking mbus.)
|
||||||
|
if (data.size() != 1)
|
||||||
|
{
|
||||||
|
return ErrorInFrame;
|
||||||
|
}
|
||||||
|
}
|
||||||
*payload_len_out = 0;
|
*payload_len_out = 0;
|
||||||
*payload_offset = 0;
|
*payload_offset = 0;
|
||||||
*frame_length = 1;
|
*frame_length = 1;
|
||||||
debug("(wmbus) received E5 single byte frame.\n");
|
if (!only_test)
|
||||||
|
{
|
||||||
|
debug("(mbus) received E5 single byte frame.\n");
|
||||||
|
}
|
||||||
return FullFrame;
|
return FullFrame;
|
||||||
}
|
}
|
||||||
if (data.size() < 6)
|
if (data.size() < 6)
|
||||||
{
|
{
|
||||||
// 4 byte start, 1 checksum, 1 stop
|
// 4 byte start, 1 checksum, 1 stop
|
||||||
debug("(wmbus) less than 6 bytes, partial frame\n");
|
if (!only_test)
|
||||||
|
{
|
||||||
|
debug("(mbus) less than 6 bytes, partial frame\n");
|
||||||
|
}
|
||||||
return PartialFrame;
|
return PartialFrame;
|
||||||
}
|
}
|
||||||
if (data[0] != 0x68 && data[3] != 0x68)
|
if (data[0] != 0x68 && data[3] != 0x68)
|
||||||
{
|
{
|
||||||
verbose("(wmbus) no 0x68 byte found, clearing buffer.\n");
|
if (!only_test)
|
||||||
|
{
|
||||||
|
verbose("(mbus) no 0x68 byte found, clearing buffer.\n");
|
||||||
data.clear();
|
data.clear();
|
||||||
|
}
|
||||||
return ErrorInFrame;
|
return ErrorInFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data[1] != data[2])
|
if (data[1] != data[2])
|
||||||
{
|
{
|
||||||
verbose("(wmbus) lengths not matching, clearing buffer.\n");
|
if (!only_test)
|
||||||
|
{
|
||||||
|
verbose("(mbus) lengths not matching, clearing buffer.\n");
|
||||||
data.clear();
|
data.clear();
|
||||||
|
}
|
||||||
return ErrorInFrame;
|
return ErrorInFrame;
|
||||||
}
|
}
|
||||||
int payload_len = data[1];
|
int payload_len = data[1];
|
||||||
*frame_length = payload_len+4+1+1; // start(4)+cs(1)+stop(1)
|
*frame_length = payload_len+4+1+1; // start(4)+cs(1)+stop(1)
|
||||||
if (data.size() < *frame_length)
|
if (data.size() < *frame_length)
|
||||||
{
|
{
|
||||||
debug("(wmbus) not enough bytes, partial frame %d %d\n", data.size(), *frame_length);
|
if (!only_test)
|
||||||
|
{
|
||||||
|
debug("(mbus) not enough bytes, partial frame %d %d\n", data.size(), *frame_length);
|
||||||
|
}
|
||||||
return PartialFrame;
|
return PartialFrame;
|
||||||
}
|
}
|
||||||
uchar stop = data[*frame_length-1];
|
uchar stop = data[*frame_length-1];
|
||||||
if (stop != 0x16)
|
if (stop != 0x16)
|
||||||
{
|
{
|
||||||
verbose("(wmbus) stop byte (0x%02x) at pos %d is not 0x16, clearing buffer.\n", stop, *frame_length-1);
|
if (!only_test)
|
||||||
|
{
|
||||||
|
verbose("(mbus) stop byte (0x%02x) at pos %d is not 0x16, clearing buffer.\n", stop, *frame_length-1);
|
||||||
data.clear();
|
data.clear();
|
||||||
|
}
|
||||||
return ErrorInFrame;
|
return ErrorInFrame;
|
||||||
}
|
}
|
||||||
uchar csc = 0;
|
uchar csc = 0;
|
||||||
|
@ -4520,14 +4628,20 @@ FrameStatus checkMBusFrame(vector<uchar> &data,
|
||||||
uchar cs = data[*frame_length-2];
|
uchar cs = data[*frame_length-2];
|
||||||
if (cs != csc)
|
if (cs != csc)
|
||||||
{
|
{
|
||||||
verbose("(wmbus) expected checksum 0x%02x but got 0x%02x, clearing buffer.\n", csc, cs);
|
if (!only_test)
|
||||||
|
{
|
||||||
|
verbose("(mbus) expected checksum 0x%02x but got 0x%02x, clearing buffer.\n", csc, cs);
|
||||||
data.clear();
|
data.clear();
|
||||||
|
}
|
||||||
return ErrorInFrame;
|
return ErrorInFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
*payload_len_out = *frame_length-6;
|
*payload_len_out = *frame_length-6;
|
||||||
*payload_offset = 4;
|
*payload_offset = 4;
|
||||||
debug("(wmbus) received full frame.\n");
|
if (!only_test)
|
||||||
|
{
|
||||||
|
debug("(mbus) received full frame.\n");
|
||||||
|
}
|
||||||
return FullFrame;
|
return FullFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
src/wmbus.h
12
src/wmbus.h
|
@ -402,6 +402,7 @@ struct Telegram
|
||||||
int dll_mfct {};
|
int dll_mfct {};
|
||||||
|
|
||||||
uchar mbus_primary_address; // Single byte address 0-250 for mbus devices.
|
uchar mbus_primary_address; // Single byte address 0-250 for mbus devices.
|
||||||
|
uchar mbus_ci; // MBus control information field.
|
||||||
|
|
||||||
vector<uchar> dll_a; // A field 6 bytes
|
vector<uchar> dll_a; // A field 6 bytes
|
||||||
// The 6 a field bytes are composed of 4 id bytes, version and type.
|
// The 6 a field bytes are composed of 4 id bytes, version and type.
|
||||||
|
@ -701,6 +702,8 @@ bool isCiFieldOfType(int ci_field, CI_TYPE type);
|
||||||
int ciFieldLength(int ci_field);
|
int ciFieldLength(int ci_field);
|
||||||
string ciType(int ci_field);
|
string ciType(int ci_field);
|
||||||
string cType(int c_field);
|
string cType(int c_field);
|
||||||
|
bool isValidWMBusCField(int c_field);
|
||||||
|
bool isValidMBusCField(int c_field);
|
||||||
string ccType(int cc_field);
|
string ccType(int cc_field);
|
||||||
string difType(int dif);
|
string difType(int dif);
|
||||||
double vifScale(int vif);
|
double vifScale(int vif);
|
||||||
|
@ -726,12 +729,14 @@ enum FrameStatus { PartialFrame, FullFrame, ErrorInFrame, TextAndNotFrame };
|
||||||
FrameStatus checkWMBusFrame(vector<uchar> &data,
|
FrameStatus checkWMBusFrame(vector<uchar> &data,
|
||||||
size_t *frame_length,
|
size_t *frame_length,
|
||||||
int *payload_len_out,
|
int *payload_len_out,
|
||||||
int *payload_offset);
|
int *payload_offset,
|
||||||
|
bool only_test);
|
||||||
|
|
||||||
FrameStatus checkMBusFrame(vector<uchar> &data,
|
FrameStatus checkMBusFrame(vector<uchar> &data,
|
||||||
size_t *frame_length,
|
size_t *frame_length,
|
||||||
int *payload_len_out,
|
int *payload_len_out,
|
||||||
int *payload_offset);
|
int *payload_offset,
|
||||||
|
bool only_test);
|
||||||
|
|
||||||
AccessCheck reDetectDevice(Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
AccessCheck reDetectDevice(Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
||||||
|
|
||||||
|
@ -760,6 +765,7 @@ bool warned_for_telegram_before(Telegram *t, vector<uchar> &dll_a);
|
||||||
|
|
||||||
////////////////// MBUS
|
////////////////// MBUS
|
||||||
|
|
||||||
string mbusCField(uchar c_field);
|
const char *mbusCField(uchar c_field);
|
||||||
|
const char *mbusCiField(uchar ci_field);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -423,13 +423,13 @@ FrameStatus WMBusAmber::checkAMB8465Frame(vector<uchar> &data,
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
|
|
||||||
// The data[0] must be at least 10 bytes. C MM AAAA V T Ci
|
// The data[0] must be at least 10 bytes. C MM AAAA V T Ci
|
||||||
// And C must be 0x44.
|
// And C must be a valid wmbus c field.
|
||||||
while ((payload_len = data[offset]) < 10 || data[offset+1] != 0x44)
|
while ((payload_len = data[offset]) < 10 || !isValidWMBusCField(data[offset+1]))
|
||||||
{
|
{
|
||||||
offset++;
|
offset++;
|
||||||
if (offset + 2 >= data.size()) {
|
if (offset + 2 >= data.size()) {
|
||||||
// No sensible telegram in the buffer. Flush it!
|
// No sensible telegram in the buffer. Flush it!
|
||||||
// But not the last char, because the next char could be a 0x44
|
// But not the last char, because the next char could be a valid c field.
|
||||||
verbose("(amb8465) no sensible telegram found, clearing buffer.\n");
|
verbose("(amb8465) no sensible telegram found, clearing buffer.\n");
|
||||||
uchar last = data[data.size()-1];
|
uchar last = data[data.size()-1];
|
||||||
data.clear();
|
data.clear();
|
||||||
|
|
|
@ -196,7 +196,7 @@ void WMBusRawTTY::processSerialData()
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
FrameStatus status = checkWMBusFrame(data_buffer_, &frame_length, &payload_len, &payload_offset);
|
FrameStatus status = checkWMBusFrame(data_buffer_, &frame_length, &payload_len, &payload_offset, false);
|
||||||
|
|
||||||
if (status == PartialFrame)
|
if (status == PartialFrame)
|
||||||
{
|
{
|
||||||
|
|
|
@ -306,7 +306,7 @@ void WMBusRC1180::processSerialData()
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
FrameStatus status = checkWMBusFrame(read_buffer_, &frame_length, &payload_len, &payload_offset);
|
FrameStatus status = checkWMBusFrame(read_buffer_, &frame_length, &payload_len, &payload_offset, false);
|
||||||
|
|
||||||
if (status == PartialFrame)
|
if (status == PartialFrame)
|
||||||
{
|
{
|
||||||
|
|
|
@ -174,6 +174,32 @@ void WMBusSimulator::simulate()
|
||||||
{
|
{
|
||||||
error("Not a valid string of hex bytes! \"%s\"\n", l.c_str());
|
error("Not a valid string of hex bytes! \"%s\"\n", l.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t frame_length;
|
||||||
|
int payload_len, payload_offset;
|
||||||
|
bool is_mbus = FullFrame == checkMBusFrame(payload, &frame_length, &payload_len, &payload_offset, true);
|
||||||
|
bool is_wmbus = FullFrame == checkWMBusFrame(payload, &frame_length, &payload_len, &payload_offset, true);
|
||||||
|
|
||||||
|
debug("(simulator) is_mbus=%s is_wmbus=%s\n",
|
||||||
|
is_mbus?"true":"false",
|
||||||
|
is_wmbus?"true":"false");
|
||||||
|
|
||||||
|
if (is_mbus && is_wmbus)
|
||||||
|
{
|
||||||
|
warning("(mbus) telegram matches both mbus and wmbus! Assuming it is wmbus only.\n");
|
||||||
|
is_mbus = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_mbus)
|
||||||
|
{
|
||||||
|
debug("(simulator) is mbus telegram.\n");
|
||||||
|
AboutTelegram about("", 0, FrameType::MBUS);
|
||||||
|
handleTelegram(about, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_wmbus)
|
||||||
|
{
|
||||||
|
debug("(simulator) is wmbus telegram.\n");
|
||||||
AboutTelegram about("", 0, FrameType::WMBUS);
|
AboutTelegram about("", 0, FrameType::WMBUS);
|
||||||
// Since this is a simulation, try to remove any frame format A or B
|
// Since this is a simulation, try to remove any frame format A or B
|
||||||
// data link layer crcs. These might remain if we have received the telegram
|
// data link layer crcs. These might remain if we have received the telegram
|
||||||
|
@ -184,5 +210,6 @@ void WMBusSimulator::simulate()
|
||||||
|
|
||||||
handleTelegram(about, payload);
|
handleTelegram(about, payload);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
manager_->stop();
|
manager_->stop();
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue