Added address sanitizer to debug build and fixed memory errors.

pull/22/head
weetmuts 2018-12-28 18:35:32 +01:00
rodzic 281105325b
commit 24bd281d9f
22 zmienionych plików z 195 dodań i 117 usunięć

Wyświetl plik

@ -17,9 +17,10 @@ else
endif
ifeq "$(DEBUG)" "true"
DEBUG_FLAGS=-O0 -g
DEBUG_FLAGS=-O0 -ggdb -fsanitize=address -fno-omit-frame-pointer
STRIP_BINARY=
BUILD:=$(BUILD)_debug
DEBUG_LDFLAGS=-lasan
else
DEBUG_FLAGS=-Os
STRIP_BINARY=$(STRIP) $(BUILD)/wmbusmeters
@ -56,10 +57,11 @@ all: $(BUILD)/wmbusmeters $(BUILD)/testinternals
$(STRIP_BINARY)
$(BUILD)/wmbusmeters: $(METERS_OBJS) $(BUILD)/main.o
$(CXX) -o $(BUILD)/wmbusmeters $(METERS_OBJS) $(BUILD)/main.o -lpthread
$(CXX) -o $(BUILD)/wmbusmeters $(METERS_OBJS) $(BUILD)/main.o $(DEBUG_LDFLAGS) -lpthread
$(BUILD)/testinternals: $(METERS_OBJS) $(BUILD)/testinternals.o
$(CXX) -o $(BUILD)/testinternals $(METERS_OBJS) $(BUILD)/testinternals.o -lpthread
$(CXX) -o $(BUILD)/testinternals $(METERS_OBJS) $(BUILD)/testinternals.o $(DEBUG_LDFLAGS) -lpthread
clean:
rm -f build/* build_arm/* build_debug/* build_arm_debug/* *~

Wyświetl plik

@ -21,19 +21,19 @@
using namespace std;
CommandLine *parseCommandLine(int argc, char **argv) {
unique_ptr<CommandLine> parseCommandLine(int argc, char **argv) {
CommandLine * c = new CommandLine;
int i=1;
if (argc < 2) {
c->need_help = true;
return c;
return unique_ptr<CommandLine>(c);
}
while (argv[i] && argv[i][0] == '-') {
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help") || !strcmp(argv[i], "--help")) {
c->need_help = true;
return c;
return unique_ptr<CommandLine>(c);
}
if (!strcmp(argv[i], "--silence")) {
c->silence = true;
@ -180,5 +180,5 @@ CommandLine *parseCommandLine(int argc, char **argv) {
c->meters.push_back(MeterInfo(name,type,id,key));
}
return c;
return unique_ptr<CommandLine>(c);
}

Wyświetl plik

@ -19,6 +19,7 @@
#define CMDLINE_H
#include"meters.h"
#include<memory>
#include<string.h>
#include<vector>
@ -29,7 +30,6 @@ struct MeterInfo {
char *type;
char *id;
char *key;
Meter *meter;
MeterInfo(char *n, char *t, char *i, char *k) {
name = n;
@ -59,8 +59,10 @@ struct CommandLine {
bool link_mode_set {};
bool no_init {};
vector<MeterInfo> meters;
~CommandLine() = default;
};
CommandLine *parseCommandLine(int argc, char **argv);
unique_ptr<CommandLine> parseCommandLine(int argc, char **argv);
#endif

Wyświetl plik

@ -18,6 +18,8 @@
#include"dvparser.h"
#include"util.h"
#include<assert.h>
// 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...
@ -27,6 +29,7 @@
using namespace std;
bool parseDV(Telegram *t,
vector<uchar> &databytes,
vector<uchar>::iterator data,
size_t data_len,
map<string,pair<int,string>> *values,
@ -140,7 +143,7 @@ bool parseDV(Telegram *t,
int remaining = std::distance(data, data_end);
if (variable_length) {
debug("(dvparser debug) varlen %02x\n", *(data+0));
DEBUG_PARSER("(dvparser debug) varlen %02x\n", *(data+0));
if (remaining > 2) {
datalen = *(data);
} else {
@ -159,7 +162,11 @@ bool parseDV(Telegram *t,
// Skip the length byte in the variable length data.
if (variable_length) {
data++;
datalen--;
}
assert(data != databytes.end());
assert(data+datalen <= databytes.end());
// This call increments data with datalen.
t->addExplanation(data, datalen, "%s", value.c_str());
DEBUG_PARSER("(dvparser debug) data \"%s\"\n", value.c_str());

Wyświetl plik

@ -29,6 +29,7 @@
// DV stands for DIF VIF
bool parseDV(Telegram *t,
std::vector<uchar> &databytes,
std::vector<uchar>::iterator data,
size_t data_len,
std::map<std::string,std::pair<int,std::string>> *values,

54
main.cc
Wyświetl plik

@ -26,11 +26,11 @@
using namespace std;
void oneshotCheck(CommandLine *cmdline, SerialCommunicationManager *manager, Meter *meter);
void oneshotCheck(CommandLine *cmdline, SerialCommunicationManager *manager, Meter *meter, vector<unique_ptr<Meter>> &meters);
int main(int argc, char **argv)
{
CommandLine *cmdline = parseCommandLine(argc, argv);
auto cmdline = parseCommandLine(argc, argv);
if (cmdline->need_help) {
printf("wmbusmeters version: " WMBUSMETERS_VERSION "\n");
@ -76,24 +76,24 @@ int main(int argc, char **argv)
auto manager = createSerialCommunicationManager(cmdline->exitafter);
onExit(call(manager,stop));
onExit(call(manager.get(),stop));
WMBus *wmbus = NULL;
unique_ptr<WMBus> wmbus;
auto type_and_device = detectMBusDevice(cmdline->usb_device, manager);
auto type_and_device = detectMBusDevice(cmdline->usb_device, manager.get());
switch (type_and_device.first) {
case DEVICE_IM871A:
verbose("(im871a) detected on %s\n", type_and_device.second.c_str());
wmbus = openIM871A(type_and_device.second, manager);
wmbus = openIM871A(type_and_device.second, manager.get());
break;
case DEVICE_AMB8465:
verbose("(amb8465) detected on %s\n", type_and_device.second.c_str());
wmbus = openAMB8465(type_and_device.second, manager);
wmbus = openAMB8465(type_and_device.second, manager.get());
break;
case DEVICE_SIMULATOR:
verbose("(simulator) found %s\n", type_and_device.second.c_str());
wmbus = openSimulator(type_and_device.second, manager);
wmbus = openSimulator(type_and_device.second, manager.get());
break;
case DEVICE_UNKNOWN:
error("No wmbus device found!\n");
@ -123,36 +123,38 @@ int main(int argc, char **argv)
verbose("(cmdline) using link mode: %s\n", using_link_mode.c_str());
Printer *output = new Printer(cmdline->json, cmdline->fields,
cmdline->separator, cmdline->meterfiles, cmdline->meterfiles_dir,
cmdline->shells);
auto output = unique_ptr<Printer>(new Printer(cmdline->json, cmdline->fields,
cmdline->separator, cmdline->meterfiles, cmdline->meterfiles_dir,
cmdline->shells));
vector<unique_ptr<Meter>> meters;
if (cmdline->meters.size() > 0) {
for (auto &m : cmdline->meters) {
const char *keymsg = (m.key[0] == 0) ? "not-encrypted" : "encrypted";
switch (toMeterType(m.type)) {
case MULTICAL21_METER:
m.meter = createMultical21(wmbus, m.name, m.id, m.key, MULTICAL21_METER);
meters.push_back(createMultical21(wmbus.get(), m.name, m.id, m.key, MULTICAL21_METER));
verbose("(multical21) configured \"%s\" \"multical21\" \"%s\" %s\n", m.name, m.id, keymsg);
break;
case FLOWIQ3100_METER:
m.meter = createMultical21(wmbus, m.name, m.id, m.key, FLOWIQ3100_METER);
meters.push_back(createMultical21(wmbus.get(), m.name, m.id, m.key, FLOWIQ3100_METER));
verbose("(flowiq3100) configured \"%s\" \"flowiq3100\" \"%s\" %s\n", m.name, m.id, keymsg);
break;
case MULTICAL302_METER:
m.meter = createMultical302(wmbus, m.name, m.id, m.key);
meters.push_back(createMultical302(wmbus.get(), m.name, m.id, m.key));
verbose("(multical302) configured \"%s\" \"multical302\" \"%s\" %s\n", m.name, m.id, keymsg);
break;
case OMNIPOWER_METER:
m.meter = createOmnipower(wmbus, m.name, m.id, m.key);
meters.push_back(createOmnipower(wmbus.get(), m.name, m.id, m.key));
verbose("(omnipower) configured \"%s\" \"omnipower\" \"%s\" %s\n", m.name, m.id, keymsg);
break;
case SUPERCOM587_METER:
m.meter = createSupercom587(wmbus, m.name, m.id, m.key);
meters.push_back(createSupercom587(wmbus.get(), m.name, m.id, m.key));
verbose("(supercom587) configured \"%s\" \"supercom587\" \"%s\" %s\n", m.name, m.id, keymsg);
break;
case IPERL_METER:
m.meter = createIperl(wmbus, m.name, m.id, m.key);
meters.push_back(createIperl(wmbus.get(), m.name, m.id, m.key));
verbose("(iperl) configured \"%s\" \"iperl\" \"%s\" %s\n", m.name, m.id, keymsg);
break;
case UNKNOWN_METER:
@ -162,10 +164,10 @@ int main(int argc, char **argv)
if (cmdline->list_shell_envs) {
string ignore1, ignore2, ignore3;
vector<string> envs;
m.meter->printMeter(&ignore1,
&ignore2, cmdline->separator,
&ignore3,
&envs);
meters.back()->printMeter(&ignore1,
&ignore2, cmdline->separator,
&ignore3,
&envs);
printf("Environment variables provided to shell for meter %s:\n", m.type);
for (auto &e : envs) {
int p = e.find('=');
@ -174,8 +176,8 @@ int main(int argc, char **argv)
}
exit(0);
}
m.meter->onUpdate(calll(output,print,Meter*));
m.meter->onUpdate([cmdline,manager](Meter*meter) { oneshotCheck(cmdline,manager,meter); });
meters.back()->onUpdate(calll(output.get(),print,Meter*));
meters.back()->onUpdate([&](Meter*meter) { oneshotCheck(cmdline.get(), manager.get(), meter, meters); });
}
} else {
printf("No meters configured. Printing id:s of all telegrams heard!\n\n");
@ -190,12 +192,12 @@ int main(int argc, char **argv)
manager->waitForStop();
}
void oneshotCheck(CommandLine *cmdline, SerialCommunicationManager *manager, Meter *meter)
void oneshotCheck(CommandLine *cmdline, SerialCommunicationManager *manager, Meter *meter, vector<unique_ptr<Meter>> &meters)
{
if (!cmdline->oneshot) return;
for (auto &m : cmdline->meters) {
if (m.meter->numUpdates() == 0) return;
for (auto &m : meters) {
if (m->numUpdates() == 0) return;
}
// All meters have received at least one update! Stop!
manager->stop();

Wyświetl plik

@ -80,9 +80,9 @@ double MeterIperl::totalWaterConsumption()
return total_water_consumption_;
}
WaterMeter *createIperl(WMBus *bus, const char *name, const char *id, const char *key)
unique_ptr<WaterMeter> createIperl(WMBus *bus, const char *name, const char *id, const char *key)
{
return new MeterIperl(bus,name,id,key);
return unique_ptr<WaterMeter>(new MeterIperl(bus,name,id,key));
}
void MeterIperl::handleTelegram(Telegram *t)
@ -137,7 +137,7 @@ void MeterIperl::processContent(Telegram *t)
map<string,pair<int,string>> values;
parseDV(t, t->content.begin(), t->content.size(), &values);
parseDV(t, t->content, t->content.begin(), t->content.size(), &values);
int offset;

Wyświetl plik

@ -168,12 +168,12 @@ bool MeterMultical21::hasExternalTemperature()
return has_external_temperature_;
}
WaterMeter *createMultical21(WMBus *bus, const char *name, const char *id, const char *key, MeterType mt)
unique_ptr<WaterMeter> createMultical21(WMBus *bus, const char *name, const char *id, const char *key, MeterType mt)
{
if (mt != MULTICAL21_METER && mt != FLOWIQ3100_METER) {
error("Internal error! Not a proper meter type when creating a multical21 style meter.\n");
}
return new MeterMultical21(bus,name,id,key,mt);
return unique_ptr<WaterMeter>(new MeterMultical21(bus,name,id,key,mt));
}
void MeterMultical21::handleTelegram(Telegram *t)
@ -269,7 +269,7 @@ void MeterMultical21::processContent(Telegram *t)
t->addExplanation(bytes, 2, "%02x%02x data crc", ecrc2, ecrc3);
map<string,pair<int,string>> values;
parseDV(t, t->content.begin()+7, t->content.size()-7, &values, &format, format_bytes.size(),
parseDV(t, t->content, t->content.begin()+7, t->content.size()-7, &values, &format, format_bytes.size(),
NULL,
[](int dif, int vif, int len) {
// Override len for 4413 to len 2 for compact frame!
@ -287,14 +287,14 @@ void MeterMultical21::processContent(Telegram *t)
t->addMoreExplanation(offset, " total consumption (%f m3)", total_water_consumption_);
extractDVdoubleCombined(&values, "0413", "4413", &offset, &target_volume_);
has_target_volume_ = true;
has_target_volume_ = true;
t->addMoreExplanation(offset, " target consumption (%f m3)", target_volume_);
}
else
if (frame_type == 0x78)
{
map<string,pair<int,string>> values;
parseDV(t, t->content.begin()+3, t->content.size()-3, &values);
parseDV(t, t->content, t->content.begin()+3, t->content.size()-3, &values);
int offset;
@ -309,13 +309,15 @@ void MeterMultical21::processContent(Telegram *t)
has_target_volume_ = true;
t->addMoreExplanation(offset, " target consumption (%f m3)", target_volume_);
extractDVdouble(&values, "615B", &offset, &flow_temperature_);
has_flow_temperature_ = true;
t->addMoreExplanation(offset, " flow temperature (%f °C)", flow_temperature_);
has_flow_temperature_ = extractDVdouble(&values, "615B", &offset, &flow_temperature_);
if (has_flow_temperature_) {
t->addMoreExplanation(offset, " flow temperature (%f °C)", flow_temperature_);
}
extractDVdouble(&values, "6167", &offset, &external_temperature_);
has_external_temperature_ = true;
t->addMoreExplanation(offset, " external temperature (%f °C)", external_temperature_);
has_external_temperature_ = extractDVdouble(&values, "6167", &offset, &external_temperature_);
if (has_external_temperature_) {
t->addMoreExplanation(offset, " external temperature (%f °C)", external_temperature_);
}
}
else
{
@ -453,13 +455,31 @@ void MeterMultical21::printMeter(string *human_readable,
char buf[65536];
buf[65535] = 0;
snprintf(buf, sizeof(buf)-1, "%s\t%s\t% 3.3f m3\t% 3.3f m3\t% 2.0f°C\t% 2.0f°C\t%s\t%s",
char ft[10], et[10];
ft[9] = 0;
et[9] = 0;
if (hasFlowTemperature()) {
snprintf(ft, sizeof(ft)-1, "% 2.0f", flowTemperature());
} else {
ft[0] = '-';
ft[1] = 0;
}
if (hasExternalTemperature()) {
snprintf(et, sizeof(et)-1, "% 2.0f", externalTemperature());
} else {
et[0] = '-';
et[1] = 0;
}
snprintf(buf, sizeof(buf)-1, "%s\t%s\t% 3.3f m3\t% 3.3f m3\t%s°C\t%s°C\t%s\t%s",
name().c_str(),
id().c_str(),
totalWaterConsumption(),
targetWaterConsumption(),
flowTemperature(),
externalTemperature(),
ft,
et,
statusHumanReadable().c_str(),
datetimeOfUpdateHumanReadable().c_str());

Wyświetl plik

@ -178,8 +178,8 @@ void MeterMultical302::processContent(Telegram *t) {
}
}
HeatMeter *createMultical302(WMBus *bus, const char *name, const char *id, const char *key) {
return new MeterMultical302(bus,name,id,key);
unique_ptr<HeatMeter> createMultical302(WMBus *bus, const char *name, const char *id, const char *key) {
return unique_ptr<HeatMeter>(new MeterMultical302(bus,name,id,key));
}
void MeterMultical302::printMeter(string *human_readable,

Wyświetl plik

@ -111,16 +111,16 @@ void MeterOmnipower::processContent(Telegram *t)
// xx xx xx xx (total energy)
map<string,pair<int,string>> values;
parseDV(t, t->content.begin(), t->content.size(), &values);
parseDV(t, t->content, t->content.begin(), t->content.size(), &values);
int offset;
extractDVdouble(&values, "04833B", &offset, &total_energy_);
t->addMoreExplanation(offset, " total power (%f kwh)", total_energy_);
}
ElectricityMeter *createOmnipower(WMBus *bus, const char *name, const char *id, const char *key)
unique_ptr<ElectricityMeter> createOmnipower(WMBus *bus, const char *name, const char *id, const char *key)
{
return new MeterOmnipower(bus,name,id,key);
return unique_ptr<ElectricityMeter>(new MeterOmnipower(bus,name,id,key));
}
void MeterOmnipower::printMeter(string *human_readable,

Wyświetl plik

@ -79,9 +79,9 @@ double MeterSupercom587::totalWaterConsumption()
return total_water_consumption_;
}
WaterMeter *createSupercom587(WMBus *bus, const char *name, const char *id, const char *key)
unique_ptr<WaterMeter> createSupercom587(WMBus *bus, const char *name, const char *id, const char *key)
{
return new MeterSupercom587(bus,name,id,key);
return unique_ptr<WaterMeter>(new MeterSupercom587(bus,name,id,key));
}
void MeterSupercom587::handleTelegram(Telegram *t)
@ -135,7 +135,7 @@ void MeterSupercom587::processContent(Telegram *t)
// Meter record:
map<string,pair<int,string>> values;
parseDV(t, t->content.begin(), t->content.size(), &values);
parseDV(t, t->content, t->content.begin(), t->content.size(), &values);
int offset;

Wyświetl plik

@ -64,6 +64,8 @@ struct Meter {
virtual std::vector<std::string> getRecords() = 0;
virtual double getRecordAsDouble(std::string record) = 0;
virtual uint16_t getRecordAsUInt16(std::string record) = 0;
virtual ~Meter() = default;
};
struct WaterMeter : public virtual Meter {
@ -102,11 +104,11 @@ struct GenericMeter : public virtual Meter {
MeterType toMeterType(const char *type);
LinkMode toMeterLinkMode(const char *type);
WaterMeter *createMultical21(WMBus *bus, const char *name, const char *id, const char *key, MeterType mt);
HeatMeter *createMultical302(WMBus *bus, const char *name, const char *id, const char *key);
ElectricityMeter *createOmnipower(WMBus *bus, const char *name, const char *id, const char *key);
WaterMeter *createSupercom587(WMBus *bus, const char *name, const char *id, const char *key);
WaterMeter *createIperl(WMBus *bus, const char *name, const char *id, const char *key);
unique_ptr<WaterMeter> createMultical21(WMBus *bus, const char *name, const char *id, const char *key, MeterType mt);
unique_ptr<HeatMeter> createMultical302(WMBus *bus, const char *name, const char *id, const char *key);
unique_ptr<ElectricityMeter> createOmnipower(WMBus *bus, const char *name, const char *id, const char *key);
unique_ptr<WaterMeter> createSupercom587(WMBus *bus, const char *name, const char *id, const char *key);
unique_ptr<WaterMeter> createIperl(WMBus *bus, const char *name, const char *id, const char *key);
GenericMeter *createGeneric(WMBus *bus, const char *name, const char *id, const char *key);
#endif

Wyświetl plik

@ -22,7 +22,8 @@
#include<map>
struct MeterCommonImplementation : public virtual Meter {
struct MeterCommonImplementation : public virtual Meter
{
string id();
string name();
MeterType type();
@ -49,6 +50,8 @@ struct MeterCommonImplementation : public virtual Meter {
MeterType type, int manufacturer, int media,
LinkMode required_link_mode);
~MeterCommonImplementation() = default;
protected:
void triggerUpdate(Telegram *t);

Wyświetl plik

@ -36,7 +36,9 @@ struct SerialDeviceTTY;
struct SerialCommunicationManagerImp : public SerialCommunicationManager {
SerialCommunicationManagerImp(time_t exit_after_seconds);
SerialDevice *createSerialDeviceTTY(string dev, int baud_rate);
~SerialCommunicationManagerImp() { }
unique_ptr<SerialDevice> createSerialDeviceTTY(string dev, int baud_rate);
void listenTo(SerialDevice *sd, function<void()> cb);
void stop();
void waitForStop();
@ -66,6 +68,7 @@ struct SerialDeviceImp : public SerialDevice {
struct SerialDeviceTTY : public SerialDeviceImp {
SerialDeviceTTY(string device, int baud_rate, SerialCommunicationManagerImp *manager);
~SerialDeviceTTY();
bool open(bool fail_if_not_ok);
void close();
@ -91,6 +94,11 @@ SerialDeviceTTY::SerialDeviceTTY(string device, int baud_rate,
manager_ = manager;
}
SerialDeviceTTY::~SerialDeviceTTY()
{
close();
}
bool SerialDeviceTTY::open(bool fail_if_not_ok)
{
bool ok = checkCharacterDeviceExists(device_.c_str(), fail_if_not_ok);
@ -194,9 +202,8 @@ void *SerialCommunicationManagerImp::startLoop(void *a) {
return t->eventLoop();
}
SerialDevice *SerialCommunicationManagerImp::createSerialDeviceTTY(string device, int baud_rate) {
SerialDevice *sd = new SerialDeviceTTY(device, baud_rate, this);
return sd;
unique_ptr<SerialDevice> SerialCommunicationManagerImp::createSerialDeviceTTY(string device, int baud_rate) {
return unique_ptr<SerialDevice>(new SerialDeviceTTY(device, baud_rate, this));
}
void SerialCommunicationManagerImp::listenTo(SerialDevice *sd, function<void()> cb) {
@ -283,9 +290,9 @@ void *SerialCommunicationManagerImp::eventLoop() {
return NULL;
}
SerialCommunicationManager *createSerialCommunicationManager(time_t exit_after_seconds)
unique_ptr<SerialCommunicationManager> createSerialCommunicationManager(time_t exit_after_seconds)
{
return new SerialCommunicationManagerImp(exit_after_seconds);
return unique_ptr<SerialCommunicationManager>(new SerialCommunicationManagerImp(exit_after_seconds));
}
static int openSerialTTY(const char *tty, int baud_rate)
@ -349,3 +356,7 @@ err:
if (fd != -1) close(fd);
return -1;
}
SerialCommunicationManager::~SerialCommunicationManager()
{
}

Wyświetl plik

@ -21,6 +21,7 @@
#include"util.h"
#include<functional>
#include<memory>
#include<string>
#include<vector>
@ -38,13 +39,14 @@ struct SerialDevice {
};
struct SerialCommunicationManager {
virtual SerialDevice *createSerialDeviceTTY(string dev, int baud_rate) = 0;
virtual unique_ptr<SerialDevice> createSerialDeviceTTY(string dev, int baud_rate) = 0;
virtual void listenTo(SerialDevice *sd, function<void()> cb) = 0;
virtual void stop() = 0;
virtual void waitForStop() = 0;
virtual bool isRunning() = 0;
virtual ~SerialCommunicationManager();
};
SerialCommunicationManager *createSerialCommunicationManager(time_t exit_after_seconds);
unique_ptr<SerialCommunicationManager> createSerialCommunicationManager(time_t exit_after_seconds);
#endif

4
util.h
Wyświetl plik

@ -27,8 +27,8 @@ void onExit(std::function<void()> cb);
typedef unsigned char uchar;
#define call(A,B) ([A](){A->B();})
#define calll(A,B,T) ([A](T t){A->B(t);})
#define call(A,B) ([&](){A->B();})
#define calll(A,B,T) ([&](T t){A->B(t);})
bool hex2bin(const char* src, std::vector<uchar> *target);
bool hex2bin(std::string &src, std::vector<uchar> *target);

Wyświetl plik

@ -1274,3 +1274,6 @@ string linkModeName(LinkMode link_mode)
}
return "UnknownLinkMode";
}
WMBus::~WMBus() {
}

Wyświetl plik

@ -103,6 +103,7 @@ struct WMBus {
virtual void onTelegram(function<void(Telegram*)> cb) = 0;
virtual SerialDevice *serial() = 0;
virtual void simulate() = 0;
virtual ~WMBus() = 0;
};
#define LIST_OF_MBUS_DEVICES X(DEVICE_IM871A)X(DEVICE_AMB8465)X(DEVICE_SIMULATOR)X(DEVICE_UNKNOWN)
@ -117,10 +118,10 @@ LIST_OF_MBUS_DEVICES
// Returned is the type and the found device string.
pair<MBusDeviceType,string> detectMBusDevice(string device, SerialCommunicationManager *manager);
WMBus *openIM871A(string device, SerialCommunicationManager *manager);
WMBus *openAMB8465(string device, SerialCommunicationManager *manager);
unique_ptr<WMBus> openIM871A(string device, SerialCommunicationManager *manager);
unique_ptr<WMBus> openAMB8465(string device, SerialCommunicationManager *manager);
struct WMBusSimulator;
WMBus *openSimulator(string file, SerialCommunicationManager *manager);
unique_ptr<WMBus> openSimulator(string file, SerialCommunicationManager *manager);
string manufacturer(int m_field);
string manufacturerFlag(int m_field);

Wyświetl plik

@ -37,12 +37,14 @@ struct WMBusAmber : public WMBus {
void processSerialData();
void getConfiguration();
SerialDevice *serial() { return serial_; }
SerialDevice *serial() { return serial_.get(); }
void simulate() { }
WMBusAmber(SerialDevice *serial, SerialCommunicationManager *manager);
WMBusAmber(unique_ptr<SerialDevice> serial, SerialCommunicationManager *manager);
~WMBusAmber() { }
private:
SerialDevice *serial_;
unique_ptr<SerialDevice> serial_;
SerialCommunicationManager *manager_;
vector<uchar> read_buffer_;
pthread_mutex_t command_lock_ = PTHREAD_MUTEX_INITIALIZER;
@ -52,30 +54,36 @@ private:
LinkMode link_mode_ = UNKNOWN_LINKMODE;
vector<uchar> received_payload_;
vector<function<void(Telegram*)>> telegram_listeners_;
bool rssi_expected_;
void waitForResponse();
FrameStatus checkAMB8465Frame(vector<uchar> &data,
size_t *frame_length, int *msgid_out, int *payload_len_out, int *payload_offset);
size_t *frame_length,
int *msgid_out,
int *payload_len_out,
int *payload_offset,
uchar *rssi);
void handleMessage(int msgid, vector<uchar> &frame);
};
WMBus *openAMB8465(string device, SerialCommunicationManager *manager)
unique_ptr<WMBus> openAMB8465(string device, SerialCommunicationManager *manager)
{
SerialDevice *serial = manager->createSerialDeviceTTY(device.c_str(), 9600);
WMBusAmber *imp = new WMBusAmber(serial, manager);
return imp;
auto serial = manager->createSerialDeviceTTY(device.c_str(), 9600);
WMBusAmber *imp = new WMBusAmber(std::move(serial), manager);
return unique_ptr<WMBus>(imp);
}
WMBusAmber::WMBusAmber(SerialDevice *serial, SerialCommunicationManager *manager) :
serial_(serial), manager_(manager)
WMBusAmber::WMBusAmber(unique_ptr<SerialDevice> serial, SerialCommunicationManager *manager) :
serial_(std::move(serial)), manager_(manager)
{
sem_init(&command_wait_, 0, 0);
manager_->listenTo(serial_,call(this,processSerialData));
manager_->listenTo(serial_.get(),call(this,processSerialData));
serial_->open(true);
rssi_expected_ = true;
}
uchar xorChecksum(vector<uchar> msg, int len) {
uchar xorChecksum(vector<uchar> msg, int len)
{
uchar c = 0;
for (int i=0; i<len; ++i) {
c ^= msg[i];
@ -83,7 +91,8 @@ uchar xorChecksum(vector<uchar> msg, int len) {
return c;
}
bool WMBusAmber::ping() {
bool WMBusAmber::ping()
{
pthread_mutex_lock(&command_lock_);
/*
@ -102,7 +111,8 @@ bool WMBusAmber::ping() {
return true;
}
uint32_t WMBusAmber::getDeviceId() {
uint32_t WMBusAmber::getDeviceId()
{
pthread_mutex_lock(&command_lock_);
vector<uchar> msg(4);
@ -172,7 +182,11 @@ void WMBusAmber::getConfiguration()
// These are just some random config settings store in non-volatile memory.
verbose("(amb8465) config: uart %02x\n", received_payload_[2]);
verbose("(amb8465) config: radio Channel %02x\n", received_payload_[60+2]);
verbose("(amb8465) config: rssi enabled %02x\n", received_payload_[69+2]);
uchar re = received_payload_[69+2];
verbose("(amb8465) config: rssi enabled %02x\n", re);
if (re != 0) {
rssi_expected_ = true;
}
verbose("(amb8465) config: mode Preselect %02x\n", received_payload_[70+2]);
}
@ -225,21 +239,25 @@ FrameStatus WMBusAmber::checkAMB8465Frame(vector<uchar> &data,
size_t *frame_length,
int *msgid_out,
int *payload_len_out,
int *payload_offset)
int *payload_offset,
uchar *rssi)
{
// telegram=|2A442D2C998734761B168D2021D0871921|58387802FF2071000413F81800004413F8180000615B|+96
if (data.size() == 0) return PartialFrame;
int payload_len = 0;
if (data[0] == 0xff) {
if (data.size() < 3) return PartialFrame;
// A command response begins with 0xff
*msgid_out = data[1];
payload_len = data[2];
*payload_len_out = payload_len;
*payload_offset = 3;
*frame_length = 3+payload_len+1; // expect device to have checksumbyte at end enabled.
// Check checksum here!
*frame_length = 3+payload_len + (int)rssi_expected_;
if (data.size() < *frame_length) return PartialFrame;
if (rssi_expected_) {
*rssi = data[*frame_length-1];
}
return FullFrame;
}
// If it is not a 0xff we assume it is a message beginning with a length.
@ -267,8 +285,9 @@ void WMBusAmber::processSerialData()
size_t frame_length;
int msgid;
int payload_len, payload_offset;
uchar rssi;
FrameStatus status = checkAMB8465Frame(read_buffer_, &frame_length, &msgid, &payload_len, &payload_offset);
FrameStatus status = checkAMB8465Frame(read_buffer_, &frame_length, &msgid, &payload_len, &payload_offset, &rssi);
if (status == ErrorInFrame) {
verbose("(amb8465) protocol error in message received!\n");
@ -287,6 +306,9 @@ void WMBusAmber::processSerialData()
read_buffer_.erase(read_buffer_.begin(), read_buffer_.begin()+frame_length);
if (rssi_expected_) {
verbose("(amb8465) rssi %d\n", rssi);
}
handleMessage(msgid, payload);
}
}
@ -347,7 +369,7 @@ void WMBusAmber::handleMessage(int msgid, vector<uchar> &frame)
bool detectAMB8465(string device, SerialCommunicationManager *manager)
{
// Talk to the device and expect a very specific answer.
SerialDevice *serial = manager->createSerialDeviceTTY(device.c_str(), 9600);
auto serial = manager->createSerialDeviceTTY(device.c_str(), 9600);
bool ok = serial->open(false);
if (!ok) return false;

Wyświetl plik

@ -36,12 +36,14 @@ struct WMBusIM871A : public WMBus {
void onTelegram(function<void(Telegram*)> cb);
void processSerialData();
SerialDevice *serial() { return serial_; }
SerialDevice *serial() { return serial_.get(); }
void simulate() { }
WMBusIM871A(SerialDevice *serial, SerialCommunicationManager *manager);
WMBusIM871A(unique_ptr<SerialDevice> serial, SerialCommunicationManager *manager);
~WMBusIM871A() { }
private:
SerialDevice *serial_;
unique_ptr<SerialDevice> serial_;
SerialCommunicationManager *manager_;
vector<uchar> read_buffer_;
pthread_mutex_t command_lock_ = PTHREAD_MUTEX_INITIALIZER;
@ -62,18 +64,18 @@ private:
void handleHWTest(int msgid, vector<uchar> &payload);
};
WMBus *openIM871A(string device, SerialCommunicationManager *manager)
unique_ptr<WMBus> openIM871A(string device, SerialCommunicationManager *manager)
{
SerialDevice *serial = manager->createSerialDeviceTTY(device.c_str(), 57600);
WMBusIM871A *imp = new WMBusIM871A(serial, manager);
return imp;
auto serial = manager->createSerialDeviceTTY(device.c_str(), 57600);
WMBusIM871A *imp = new WMBusIM871A(std::move(serial), manager);
return unique_ptr<WMBus>(imp);
}
WMBusIM871A::WMBusIM871A(SerialDevice *serial, SerialCommunicationManager *manager) :
serial_(serial), manager_(manager)
WMBusIM871A::WMBusIM871A(unique_ptr<SerialDevice> serial, SerialCommunicationManager *manager) :
serial_(std::move(serial)), manager_(manager)
{
sem_init(&command_wait_, 0, 0);
manager_->listenTo(serial_,call(this,processSerialData));
manager_->listenTo(serial_.get(),call(this,processSerialData));
serial_->open(true);
}
@ -335,7 +337,7 @@ FrameStatus WMBusIM871A::checkFrame(vector<uchar> &data,
}
if (has_rssi) {
uint32_t rssi = data[i];
debug("(im871a) rssi %02x\n", rssi);
verbose("(im871a) rssi %02x\n", rssi);
i++;
}
if (has_crc16) {
@ -481,7 +483,7 @@ void WMBusIM871A::handleHWTest(int msgid, vector<uchar> &payload)
bool detectIM871A(string device, SerialCommunicationManager *manager)
{
// Talk to the device and expect a very specific answer.
SerialDevice *serial = manager->createSerialDeviceTTY(device.c_str(), 57600);
auto serial = manager->createSerialDeviceTTY(device.c_str(), 57600);
bool ok = serial->open(false);
if (!ok) return false;

Wyświetl plik

@ -52,10 +52,10 @@ private:
int loadFile(string file, vector<string> *lines);
WMBus *openSimulator(string device, SerialCommunicationManager *manager)
unique_ptr<WMBus> openSimulator(string device, SerialCommunicationManager *manager)
{
WMBusSimulator *imp = new WMBusSimulator(device, manager);
return imp;
return unique_ptr<WMBus>(imp);
}
WMBusSimulator::WMBusSimulator(string file, SerialCommunicationManager *manager)

Wyświetl plik

@ -58,8 +58,6 @@ void decryptMode1_AES_CTR(Telegram *t, vector<uchar> &aeskey)
debugPayload("(Mode1) decrypted first block", dec);
if (content.size() > 16) {
// Yay! Lets decrypt a second block. Full frame content is 22 bytes.
// So a second block should enough for everyone!
remaining = content.size()-16;
if (remaining > 16) remaining = 16; // Should not happen.