kopia lustrzana https://github.com/weetmuts/wmbusmeters
Added iPerl water meter.
rodzic
5616a51792
commit
ebf9440102
4
CHANGES
4
CHANGES
|
@ -1,4 +1,8 @@
|
|||
|
||||
Version 0.7: 2018-11-23
|
||||
|
||||
David Mallon contributed the iPerl water meter! Thanks David!
|
||||
|
||||
Version 0.6: 2018-11-02
|
||||
|
||||
Added --shell command to invoke for example: mosquitto to send an MQTT message
|
||||
|
|
3
Makefile
3
Makefile
|
@ -27,7 +27,7 @@ endif
|
|||
|
||||
$(shell mkdir -p $(BUILD))
|
||||
|
||||
CXXFLAGS := $(DEBUG_FLAGS) -fPIC -fmessage-length=0 -std=c++11 -Wall -Wno-maybe-uninitialized -Wno-unused-function "-DWMBUSMETERS_VERSION=\"0.6\""
|
||||
CXXFLAGS := $(DEBUG_FLAGS) -fPIC -fmessage-length=0 -std=c++11 -Wall -Wno-maybe-uninitialized -Wno-unused-function "-DWMBUSMETERS_VERSION=\"0.7\""
|
||||
|
||||
$(BUILD)/%.o: %.cc $(wildcard %.h)
|
||||
$(CXX) $(CXXFLAGS) $< -c -o $@
|
||||
|
@ -41,6 +41,7 @@ METERS_OBJS:=\
|
|||
$(BUILD)/meter_multical302.o \
|
||||
$(BUILD)/meter_omnipower.o \
|
||||
$(BUILD)/meter_supercom587.o \
|
||||
$(BUILD)/meter_iperl.o \
|
||||
$(BUILD)/printer.o \
|
||||
$(BUILD)/serial.o \
|
||||
$(BUILD)/shell.o \
|
||||
|
|
|
@ -8,7 +8,7 @@ utility meter readings.
|
|||
|Linux G++| [![Build Status](https://travis-ci.org/weetmuts/wmbusmeters.svg?branch=master)](https://travis-ci.org/weetmuts/wmbusmeters) |
|
||||
|
||||
```
|
||||
wmbusmeters version: 0.6
|
||||
wmbusmeters version: 0.7
|
||||
Usage: wmbusmeters {options} (auto | /dev/ttyUSBx)] { [meter_name] [meter_type] [meter_id] [meter_key] }*
|
||||
|
||||
Add more meter quadruplets to listen to more meters.
|
||||
|
@ -29,9 +29,8 @@ Add --verbose for detailed debug information.
|
|||
Specifying auto as the device will automatically look for usb
|
||||
wmbus dongles on /dev/im871a and /dev/amb8465.
|
||||
|
||||
The meter types: multical21,flowiq3100 (water meters) are supported.
|
||||
The meter types: multical302 (heat), omnipower (electricity) and supercom587 (water)
|
||||
are work in progress.
|
||||
The meter types: multical21,flowiq3100,supercom587,iperl (water meters) are supported.
|
||||
The meter types: multical302 (heat), omnipower (electricity) are work in progress.
|
||||
```
|
||||
|
||||
Currently the meters are hardcoded for the European default setting
|
||||
|
|
6
main.cc
6
main.cc
|
@ -50,7 +50,7 @@ int main(int argc, char **argv)
|
|||
" or 10m for ten minutes or 5s for five seconds.\n\n");
|
||||
printf("Specifying auto as the device will automatically look for usb\n");
|
||||
printf("wmbus dongles on /dev/im871a and /dev/amb8465\n\n");
|
||||
printf("The meter types: multical21,flowiq3100,supercom587 (water meters) are supported.\n"
|
||||
printf("The meter types: multical21,flowiq3100,supercom587,iperl (water meters) are supported.\n"
|
||||
"The meter types: multical302 (heat) and omnipower (electricity)\n"
|
||||
"are work in progress.\n\n");
|
||||
exit(0);
|
||||
|
@ -150,6 +150,10 @@ int main(int argc, char **argv)
|
|||
m.meter = createSupercom587(wmbus, m.name, m.id, m.key);
|
||||
verbose("(supercom587) configured \"%s\" \"supercom587\" \"%s\" \"%s\"\n", m.name, m.id, m.key);
|
||||
break;
|
||||
case IPERL_METER:
|
||||
m.meter = createIperl(wmbus, m.name, m.id, m.key);
|
||||
verbose("(iperl) configured \"%s\" \"iperl\" \"%s\" \"%s\"\n", m.name, m.id, m.key);
|
||||
break;
|
||||
case UNKNOWN_METER:
|
||||
error("No such meter type \"%s\"\n", m.type);
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
Copyright (C) 2017-2018 Fredrik Öhrström
|
||||
Copyright (C) 2018 David Mallon
|
||||
|
||||
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"
|
||||
|
||||
#include<assert.h>
|
||||
#include<map>
|
||||
#include<memory.h>
|
||||
#include<stdio.h>
|
||||
#include<string>
|
||||
#include<time.h>
|
||||
#include<vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct MeterIperl : public virtual WaterMeter, public virtual MeterCommonImplementation {
|
||||
MeterIperl(WMBus *bus, const char *name, const char *id, const char *key);
|
||||
|
||||
// Total water counted through the meter
|
||||
double totalWaterConsumption();
|
||||
bool hasTotalWaterConsumption();
|
||||
double targetWaterConsumption();
|
||||
bool hasTargetWaterConsumption();
|
||||
double maxFlow();
|
||||
bool hasMaxFlow();
|
||||
|
||||
string statusHumanReadable();
|
||||
string status();
|
||||
string timeDry();
|
||||
string timeReversed();
|
||||
string timeLeaking();
|
||||
string timeBursting();
|
||||
|
||||
void printMeter(string *human_readable,
|
||||
string *fields, char separator,
|
||||
string *json,
|
||||
vector<string> *envs);
|
||||
|
||||
private:
|
||||
void handleTelegram(Telegram *t);
|
||||
void processContent(Telegram *t);
|
||||
string decodeTime(int time);
|
||||
|
||||
double total_water_consumption_ {};
|
||||
};
|
||||
|
||||
MeterIperl::MeterIperl(WMBus *bus, const char *name, const char *id, const char *key) :
|
||||
MeterCommonImplementation(bus, name, id, key, IPERL_METER, MANUFACTURER_SEN, 0x16, LinkModeT1)
|
||||
{
|
||||
MeterCommonImplementation::bus()->onTelegram(calll(this,handleTelegram,Telegram*));
|
||||
}
|
||||
|
||||
|
||||
double MeterIperl::totalWaterConsumption()
|
||||
{
|
||||
return total_water_consumption_;
|
||||
}
|
||||
|
||||
WaterMeter *createIperl(WMBus *bus, const char *name, const char *id, const char *key)
|
||||
{
|
||||
return new MeterIperl(bus,name,id,key);
|
||||
}
|
||||
|
||||
void MeterIperl::handleTelegram(Telegram *t)
|
||||
{
|
||||
if (!isTelegramForMe(t)) {
|
||||
// This telegram is not intended for this meter.
|
||||
return;
|
||||
}
|
||||
|
||||
verbose("(%s) telegram for %s %02x%02x%02x%02x\n", "iperl",
|
||||
name().c_str(),
|
||||
t->a_field_address[0], t->a_field_address[1], t->a_field_address[2],
|
||||
t->a_field_address[3]);
|
||||
|
||||
if (t->a_field_device_type != 0x07 && t->a_field_device_type != 0x06) {
|
||||
warning("(%s) expected telegram for cold or warm water media, but got \"%s\"!\n", "iperl",
|
||||
mediaType(t->m_field, t->a_field_device_type).c_str());
|
||||
}
|
||||
|
||||
updateMedia(t->a_field_device_type);
|
||||
|
||||
if (t->m_field != manufacturer() ||
|
||||
t->a_field_version != 0x68) {
|
||||
warning("(%s) expected telegram from SEN meter with version 0x%02x, "
|
||||
"but got \"%s\" meter with version 0x%02x !\n", "iperl",
|
||||
0x68,
|
||||
manufacturerFlag(t->m_field).c_str(),
|
||||
t->a_field_version);
|
||||
}
|
||||
|
||||
if (useAes()) {
|
||||
vector<uchar> aeskey = key();
|
||||
decryptMode5_AES_CBC(t, aeskey, "iperl");
|
||||
verbose("$\n");
|
||||
} else {
|
||||
t->content = t->payload;
|
||||
}
|
||||
char log_prefix[256];
|
||||
snprintf(log_prefix, 255, "(%s) log", "iperl");
|
||||
logTelegram(log_prefix, t->parsed, t->content);
|
||||
int content_start = t->parsed.size();
|
||||
processContent(t);
|
||||
if (isDebugEnabled()) {
|
||||
snprintf(log_prefix, 255, "(%s)", "iperl");
|
||||
t->explainParse(log_prefix, content_start);
|
||||
}
|
||||
triggerUpdate(t);
|
||||
}
|
||||
|
||||
void MeterIperl::processContent(Telegram *t)
|
||||
{
|
||||
vector<uchar>::iterator bytes = t->content.begin();
|
||||
|
||||
|
||||
map<string,pair<int,string>> values;
|
||||
parseDV(t, t->content.begin(), t->content.size(), &values);
|
||||
|
||||
int offset;
|
||||
|
||||
extractDVdouble(&values, "0413", &offset, &total_water_consumption_);
|
||||
t->addMoreExplanation(offset, " total consumption (%f m3)", total_water_consumption_);
|
||||
}
|
||||
|
||||
void MeterIperl::printMeter(string *human_readable,
|
||||
string *fields, char separator,
|
||||
string *json,
|
||||
vector<string> *envs)
|
||||
{
|
||||
char buf[65536];
|
||||
buf[65535] = 0;
|
||||
|
||||
snprintf(buf, sizeof(buf)-1,
|
||||
"%s\t"
|
||||
"%s\t"
|
||||
"% 3.3f m3\t"
|
||||
"%s",
|
||||
name().c_str(),
|
||||
id().c_str(),
|
||||
totalWaterConsumption(),
|
||||
datetimeOfUpdateHumanReadable().c_str());
|
||||
|
||||
*human_readable = buf;
|
||||
|
||||
snprintf(buf, sizeof(buf)-1,
|
||||
"%s%c"
|
||||
"%s%c"
|
||||
"%f%c"
|
||||
"%s",
|
||||
name().c_str(), separator,
|
||||
id().c_str(), separator,
|
||||
totalWaterConsumption(), separator,
|
||||
datetimeOfUpdateRobot().c_str());
|
||||
|
||||
*fields = buf;
|
||||
|
||||
#define Q(x,y) "\""#x"\":"#y","
|
||||
#define QS(x,y) "\""#x"\":\""#y"\","
|
||||
#define QSE(x,y) "\""#x"\":\""#y"\""
|
||||
|
||||
snprintf(buf, sizeof(buf)-1, "{"
|
||||
QS(media,%s)
|
||||
QS(meter,iperl)
|
||||
QS(name,%s)
|
||||
QS(id,%s)
|
||||
Q(total_m3,%f)
|
||||
QSE(timestamp,%s)
|
||||
"}",
|
||||
mediaType(manufacturer(), media()).c_str(),
|
||||
name().c_str(),
|
||||
id().c_str(),
|
||||
totalWaterConsumption(),
|
||||
datetimeOfUpdateRobot().c_str());
|
||||
|
||||
*json = buf;
|
||||
|
||||
envs->push_back(string("METER_JSON=")+*json);
|
||||
envs->push_back(string("METER_TYPE=iperl"));
|
||||
envs->push_back(string("METER_ID=")+id());
|
||||
envs->push_back(string("METER_TOTAL_M3=")+to_string(totalWaterConsumption()));
|
||||
envs->push_back(string("METER_TIMESTAMP=")+datetimeOfUpdateRobot());
|
||||
}
|
||||
|
||||
bool MeterIperl::hasTotalWaterConsumption()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
double MeterIperl::targetWaterConsumption()
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
bool MeterIperl::hasTargetWaterConsumption()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
double MeterIperl::maxFlow()
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
bool MeterIperl::hasMaxFlow()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string MeterIperl::statusHumanReadable()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
string MeterIperl::status()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
string MeterIperl::timeDry()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
string MeterIperl::timeReversed()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
string MeterIperl::timeLeaking()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
string MeterIperl::timeBursting()
|
||||
{
|
||||
return "";
|
||||
}
|
|
@ -174,7 +174,7 @@ void MeterMultical21::handleTelegram(Telegram *t)
|
|||
|
||||
if (useAes()) {
|
||||
vector<uchar> aeskey = key();
|
||||
decryptKamstrupC1(t, aeskey);
|
||||
decryptMode1_AES_CTR(t, aeskey, meter_name_);
|
||||
} else {
|
||||
t->content = t->payload;
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ void MeterMultical302::handleTelegram(Telegram *t) {
|
|||
|
||||
if (useAes()) {
|
||||
vector<uchar> aeskey = key();
|
||||
decryptKamstrupC1(t, aeskey);
|
||||
decryptMode1_AES_CTR(t, aeskey, "multical302");
|
||||
} else {
|
||||
t->content = t->payload;
|
||||
}
|
||||
|
|
|
@ -89,8 +89,7 @@ void MeterOmnipower::handleTelegram(Telegram *t) {
|
|||
|
||||
if (useAes()) {
|
||||
vector<uchar> aeskey = key();
|
||||
// Proper decryption not yet implemented!
|
||||
decryptKamstrupC1(t, aeskey);
|
||||
decryptMode5_AES_CBC(t, aeskey, "omnipower");
|
||||
} else {
|
||||
t->content = t->payload;
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ void MeterSupercom587::handleTelegram(Telegram *t)
|
|||
|
||||
if (useAes()) {
|
||||
vector<uchar> aeskey = key();
|
||||
decryptKamstrupC1(t, aeskey);
|
||||
decryptMode1_AES_CTR(t, aeskey, "supercom587");
|
||||
} else {
|
||||
t->content = t->payload;
|
||||
}
|
||||
|
|
|
@ -104,6 +104,7 @@ MeterType toMeterType(const char *type)
|
|||
if (!strcmp(type, "multical302")) return MULTICAL302_METER;
|
||||
if (!strcmp(type, "omnipower")) return OMNIPOWER_METER;
|
||||
if (!strcmp(type, "supercom587")) return SUPERCOM587_METER;
|
||||
if (!strcmp(type, "iperl")) return IPERL_METER;
|
||||
return UNKNOWN_METER;
|
||||
}
|
||||
|
||||
|
@ -114,6 +115,7 @@ LinkMode toMeterLinkMode(const char *type)
|
|||
if (!strcmp(type, "multical302")) return LinkModeC1;
|
||||
if (!strcmp(type, "omnipower")) return LinkModeC1;
|
||||
if (!strcmp(type, "supercom587")) return LinkModeT1;
|
||||
if (!strcmp(type, "iperl")) return LinkModeT1;
|
||||
|
||||
return UNKNOWN_LINKMODE;
|
||||
}
|
||||
|
|
3
meters.h
3
meters.h
|
@ -24,7 +24,7 @@
|
|||
#include<string>
|
||||
#include<vector>
|
||||
|
||||
#define LIST_OF_METERS X(MULTICAL21_METER)X(FLOWIQ3100_METER)X(MULTICAL302_METER)X(OMNIPOWER_METER)X(SUPERCOM587_METER)X(UNKNOWN_METER)
|
||||
#define LIST_OF_METERS X(MULTICAL21_METER)X(FLOWIQ3100_METER)X(MULTICAL302_METER)X(OMNIPOWER_METER)X(SUPERCOM587_METER)X(IPERL_METER)X(UNKNOWN_METER)
|
||||
|
||||
enum MeterType {
|
||||
#define X(name) name,
|
||||
|
@ -102,6 +102,7 @@ WaterMeter *createMultical21(WMBus *bus, const char *name, const char *id, const
|
|||
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);
|
||||
GenericMeter *createGeneric(WMBus *bus, const char *name, const char *id, const char *key);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,3 +5,9 @@ telegram=|A244EE4D785634123C067A73000000|0C1334190000426CE1F14C130000000082046C2
|
|||
|
||||
telegram=|A244EE4D111111113C077A72000000|0C1374140000426CE1F14C130000000082046C21298C0413010000008D04931E3A3CFE0100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000001600000031130000046D0113412B03FD6CDF120082206C5C290BFD0F0200018C4079629885238310FD3100000082106C01018110FD610002FD66020002|
|
||||
{"media":"water","meter":"supercom587","name":"MyColdWater","id":"11111111","total_m3":1.474000,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
|
||||
# Test iPerl T1 telegram
|
||||
|
||||
# 12345678 "1234567890ABCDEF1234567890ABCDEF"
|
||||
telegram=|1E44AE4C7856341268077AB5000000|53cb05c02cf40b38e4cfe6a9f6565ec27261ae620df9257179197ef2dc6512f2|
|
||||
{"media":"water","meter":"iperl","name":"MoreWater","id":"12345678","total_m3":3.699000,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
|
|
1
test.sh
1
test.sh
|
@ -24,6 +24,7 @@ cat simulation_t1.txt | grep '^{' > test_expected.txt
|
|||
$PROG --robot=json simulation_t1.txt \
|
||||
MyWarmWater supercom587 12345678 "" \
|
||||
MyColdWater supercom587 11111111 "" \
|
||||
MoreWater iperl 12345678 "1234567890ABCDEF1234567890ABCDEF" \
|
||||
> test_output.txt
|
||||
if [ "$?" == "0" ]
|
||||
then
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include"aes.h"
|
||||
#include"wmbus.h"
|
||||
|
||||
void decryptKamstrupC1(Telegram *t, vector<uchar> &aeskey)
|
||||
void decryptMode1_AES_CTR(Telegram *t, vector<uchar> &aeskey, const char *meter_name)
|
||||
{
|
||||
vector<uchar> content;
|
||||
content.insert(content.end(), t->payload.begin(), t->payload.end());
|
||||
|
@ -45,7 +45,7 @@ void decryptKamstrupC1(Telegram *t, vector<uchar> &aeskey)
|
|||
|
||||
vector<uchar> ivv(iv, iv+16);
|
||||
string s = bin2hex(ivv);
|
||||
debug("(multical21) IV %s\n", s.c_str());
|
||||
debug("(%s) IV %s\n", meter_name, s.c_str());
|
||||
|
||||
uchar xordata[16];
|
||||
AES_ECB_encrypt(iv, &aeskey[0], xordata, 16);
|
||||
|
@ -54,11 +54,11 @@ void decryptKamstrupC1(Telegram *t, vector<uchar> &aeskey)
|
|||
xorit(xordata, &content[0], decrypt, remaining);
|
||||
|
||||
vector<uchar> dec(decrypt, decrypt+remaining);
|
||||
debugPayload("(multical21) decrypted", dec);
|
||||
debugPayload("(C1) decrypted", dec);
|
||||
|
||||
if (content.size() > 22) {
|
||||
warning("(multical21) warning: Received too many bytes of content! "
|
||||
"Got %zu bytes, expected at most 22.\n", content.size());
|
||||
warning("(%s) warning: C1 decryption received too many bytes of content! "
|
||||
"Got %zu bytes, expected at most 22.\n", meter_name, content.size());
|
||||
}
|
||||
if (content.size() > 16) {
|
||||
// Yay! Lets decrypt a second block. Full frame content is 22 bytes.
|
||||
|
@ -69,14 +69,14 @@ void decryptKamstrupC1(Telegram *t, vector<uchar> &aeskey)
|
|||
incrementIV(iv, sizeof(iv));
|
||||
vector<uchar> ivv2(iv, iv+16);
|
||||
string s2 = bin2hex(ivv2);
|
||||
debug("(multical21) IV+1 %s\n", s2.c_str());
|
||||
debug("(%s) IV+1 %s\n", meter_name, s2.c_str());
|
||||
|
||||
AES_ECB_encrypt(iv, &aeskey[0], xordata, 16);
|
||||
|
||||
xorit(xordata, &content[16], decrypt, remaining);
|
||||
|
||||
vector<uchar> dec2(decrypt, decrypt+remaining);
|
||||
debugPayload("(multical21) decrypted", dec2);
|
||||
debugPayload("(C1) decrypted", dec2);
|
||||
|
||||
// Append the second decrypted block to the first.
|
||||
dec.insert(dec.end(), dec2.begin(), dec2.end());
|
||||
|
@ -91,4 +91,52 @@ string frameTypeKamstrupC1(int ft) {
|
|||
return "?";
|
||||
}
|
||||
|
||||
void decryptMode5_AES_CBC(Telegram *t, vector<uchar> &aeskey, const char *meter_name)
|
||||
{
|
||||
vector<uchar> content;
|
||||
content.insert(content.end(), t->payload.begin(), t->payload.end());
|
||||
// The content should be a multiple of 16 since we are using AES CBC mode.
|
||||
if (content.size() % 16 != 0)
|
||||
{
|
||||
warning("(%s) warning: T1 decryption received non-multiple of 16 bytes! "
|
||||
"Got %zu bytes shrinking message to %zu bytes.\n",
|
||||
meter_name, content.size(), content.size() - content.size() % 16);
|
||||
while (content.size() % 16 != 0)
|
||||
{
|
||||
content.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
uchar iv[16];
|
||||
int i=0;
|
||||
// M-field
|
||||
iv[i++] = t->m_field&255; iv[i++] = t->m_field>>8;
|
||||
// A-field
|
||||
for (int j=0; j<6; ++j) { iv[i++] = t->a_field[j]; }
|
||||
// ACC
|
||||
iv[i++] = t->acc;
|
||||
// SN-field
|
||||
for (int j=0; j<4; ++j) { iv[i++] = t->acc; }
|
||||
// FN
|
||||
iv[i++] = t->acc; iv[i++] = t->acc;
|
||||
// BC
|
||||
iv[i++] = t->acc;
|
||||
|
||||
vector<uchar> ivv(iv, iv+16);
|
||||
string s = bin2hex(ivv);
|
||||
verbose("(%s) IV %s\n", meter_name, s.c_str());
|
||||
|
||||
uchar decrypted_data[16];
|
||||
AES_CBC_decrypt_buffer(decrypted_data, &content[0], 16, &aeskey[0], iv);
|
||||
vector<uchar> decrypted(decrypted_data, decrypted_data+16);
|
||||
|
||||
if (decrypted_data[0] != 0x2F || decrypted_data[1] != 0x2F) {
|
||||
verbose("(%s) decrypt failed!\n", meter_name);
|
||||
}
|
||||
|
||||
t->content.clear();
|
||||
t->content.insert(t->content.end(), decrypted.begin(), decrypted.end());
|
||||
debugPayload("(T1) decrypted", t->content);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
#ifndef WMBUS_UTILS_H
|
||||
#define WMBUS_UTILS_H
|
||||
|
||||
void decryptKamstrupC1(Telegram *t, vector<uchar> &aeskey);
|
||||
void decryptMode1_AES_CTR(Telegram *t, vector<uchar> &aeskey, const char *meter_name);
|
||||
void decryptMode5_AES_CBC(Telegram *t, vector<uchar> &aeskey, const char *meter_name);
|
||||
string frameTypeKamstrupC1(int ft);
|
||||
|
||||
#endif
|
||||
|
|
Ładowanie…
Reference in New Issue