kopia lustrzana https://github.com/weetmuts/wmbusmeters
Improve difvif parser and other fixes.
rodzic
ebf9440102
commit
843038a4f9
25
README.md
25
README.md
|
@ -1,7 +1,8 @@
|
|||
# wmbusmeters
|
||||
The program receives and decodes C1 or T1 telegrams
|
||||
(using the wireless mbus protocol) to acquire
|
||||
utility meter readings.
|
||||
utility meter readings. The readings can then be published using
|
||||
MQTT, inserted into a database or stored in a log file.
|
||||
|
||||
| OS/Compiler | Status |
|
||||
| ------------- |:-------------:|
|
||||
|
@ -33,28 +34,6 @@ The meter types: multical21,flowiq3100,supercom587,iperl (water meters) are supp
|
|||
The meter types: multical302 (heat), omnipower (electricity) are work in progress.
|
||||
```
|
||||
|
||||
Currently the meters are hardcoded for the European default setting
|
||||
that specifies what extra data is sent in the telegrams. If someone
|
||||
has a non-default meter that sends other extra data, then this will
|
||||
show up as a warning when a long telegram is received (but not in the
|
||||
short telegrams, where wrong values might be printed instead!). If
|
||||
this happens to someone, then we need to implement a way to pass the
|
||||
meter configuration as a parameter.
|
||||
|
||||
Actually, the mbus (and consequently the wmbus) protocol is a standard
|
||||
that is self-describing. Thus in reality it should not be necessary
|
||||
to supply exactly which kind of meter we expect for a given id. This
|
||||
should be possible to figure out when we receive the first telegram.
|
||||
|
||||
Thus, strictly speaking, it should not be necessary to specify the
|
||||
exact meter type. A more generic meter type might be just "water",
|
||||
"heat" or electricity. But for the moment, the separation of meter
|
||||
types will remain in the code. Thus even though the meter type right
|
||||
now is named multical302, the other heat meters (multical-402 and
|
||||
multical-602) might be compatible as well. The same is true for the
|
||||
omnipower meter type, which might include the electricity meters
|
||||
Kamstrup-162 Kamstrup-382, Kamstrup-351 etc).
|
||||
|
||||
No meter quadruplets means listen for telegram traffic and print any id heard,
|
||||
but you have to specify if you want to listen using radio mode C1 or T1. E.g.
|
||||
|
||||
|
|
37
dvparser.cc
37
dvparser.cc
|
@ -70,27 +70,25 @@ bool parseDV(Telegram *t,
|
|||
|
||||
format_bytes.clear();
|
||||
for (;;) {
|
||||
DEBUG_PARSER("Remaining format data %ju\n", std::distance(*format,format_end));
|
||||
DEBUG_PARSER("(dvparser debug) Remaining format data %ju\n", std::distance(*format,format_end));
|
||||
if (*format == format_end) break;
|
||||
uchar dif = **format;
|
||||
|
||||
int datalen = difLenBytes(dif);
|
||||
DEBUG_PARSER("dif=%02x datalen=%d \"%s\"\n", dif, datalen, difType(dif).c_str());
|
||||
DEBUG_PARSER("(dvparser debug) dif=%02x datalen=%d \"%s\"\n", dif, datalen, difType(dif).c_str());
|
||||
if (datalen == -2) {
|
||||
warning("(dvparser) cannot handle dif %02X ignoring rest of telegram.\n", dif);
|
||||
return false;
|
||||
}
|
||||
if (dif == 0x2f) {
|
||||
t->addExplanation(*format, 1, "%02X skip", dif);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (datalen == -1) {
|
||||
variable_length = true;
|
||||
warning("(dvparser) variable length dif %02X.\n", dif);
|
||||
} else {
|
||||
variable_length = false;
|
||||
}
|
||||
if (datalen == -2) {
|
||||
warning("(dvparser) cannot handle dif %02X ignoring rest of telegram.\n", dif);
|
||||
return false;
|
||||
}
|
||||
if (full_header) {
|
||||
format_bytes.push_back(dif);
|
||||
t->addExplanation(*format, 1, "%02X dif (%s)", dif, difType(dif).c_str());
|
||||
|
@ -101,7 +99,7 @@ bool parseDV(Telegram *t,
|
|||
if (*format == format_end) { warning("(dvparser) warning: unexpected end of data (vif expected)"); break; }
|
||||
|
||||
uchar vif = **format;
|
||||
DEBUG_PARSER("vif=%02x \"%s\"\n", vif, vifType(vif).c_str());
|
||||
DEBUG_PARSER("(dvparser debug) vif=%02x \"%s\"\n", vif, vifType(vif).c_str());
|
||||
if (full_header) {
|
||||
format_bytes.push_back(vif);
|
||||
t->addExplanation(*format, 1, "%02X vif (%s)", vif, vifType(vif).c_str());
|
||||
|
@ -114,7 +112,7 @@ bool parseDV(Telegram *t,
|
|||
// vif extension
|
||||
if (*format == format_end) { warning("(dvparser) warning: unexpected end of data (vife expected)"); break; }
|
||||
uchar vife = **format;
|
||||
DEBUG_PARSER("vife=%02x\n", vife);
|
||||
DEBUG_PARSER("(dvparser debug) vife=%02x\n", vife);
|
||||
if (full_header) {
|
||||
format_bytes.push_back(vife);
|
||||
t->addExplanation(*format, 1, "%02X vife (%s)", vife, vifeType(vif, vife).c_str());
|
||||
|
@ -127,7 +125,7 @@ bool parseDV(Telegram *t,
|
|||
if (overrideDifLen) {
|
||||
int new_len = overrideDifLen(dif, vif, datalen);
|
||||
if (new_len != datalen) {
|
||||
DEBUG_PARSER("changing len %d to %d for dif=%02x vif=%02x\n", datalen, new_len, dif, vif);
|
||||
DEBUG_PARSER("(dvparser debug) changing len %d to %d for dif=%02x vif=%02x\n", datalen, new_len, dif, vif);
|
||||
datalen = new_len;
|
||||
}
|
||||
}
|
||||
|
@ -138,13 +136,18 @@ bool parseDV(Telegram *t,
|
|||
} else {
|
||||
strprintf(key, "%s", dv.c_str());
|
||||
}
|
||||
DEBUG_PARSER("DifVif key is %s\n", key.c_str());
|
||||
DEBUG_PARSER("(dvparser debug) DifVif key is %s\n", key.c_str());
|
||||
|
||||
int remaining = std::distance(data, data_end);
|
||||
if (variable_length) {
|
||||
datalen = remaining;
|
||||
debug("(dvparser) varlen %02x\n", *(data+0));
|
||||
if (remaining > 2) {
|
||||
datalen = *(data);
|
||||
} else {
|
||||
datalen = remaining;
|
||||
}
|
||||
}
|
||||
DEBUG_PARSER("remaining data %d len=%d\n", remaining, datalen);
|
||||
DEBUG_PARSER("(dvparser debug) remaining data %d len=%d\n", remaining, datalen);
|
||||
if (remaining < datalen) {
|
||||
warning("(dvparser) warning: unexpected end of data\n");
|
||||
datalen = remaining;
|
||||
|
@ -153,7 +156,13 @@ bool parseDV(Telegram *t,
|
|||
string value = bin2hex(data, datalen);
|
||||
(*values)[key] = { start_parse_here+data-data_start, value };
|
||||
if (value.length() > 0) {
|
||||
// Skip the length byte in the variable length data.
|
||||
if (variable_length) {
|
||||
data++;
|
||||
}
|
||||
// This call increments data with datalen.
|
||||
t->addExplanation(data, datalen, "%s", value.c_str());
|
||||
DEBUG_PARSER("(dvparser debug) data \"%s\"\n", value.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
13
main.cc
13
main.cc
|
@ -129,30 +129,31 @@ int main(int argc, char **argv)
|
|||
|
||||
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);
|
||||
verbose("(multical21) configured \"%s\" \"multical21\" \"%s\" \"%s\"\n", m.name, m.id, m.key);
|
||||
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);
|
||||
verbose("(flowiq3100) configured \"%s\" \"flowiq3100\" \"%s\" \"%s\"\n", m.name, m.id, m.key);
|
||||
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);
|
||||
verbose("(multical302) configured \"%s\" \"multical302\" \"%s\" \"%s\"\n", 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);
|
||||
verbose("(omnipower) configured \"%s\" \"omnipower\" \"%s\" \"%s\"\n", 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);
|
||||
verbose("(supercom587) configured \"%s\" \"supercom587\" \"%s\" \"%s\"\n", 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);
|
||||
verbose("(iperl) configured \"%s\" \"iperl\" \"%s\" \"%s\"\n", m.name, m.id, m.key);
|
||||
verbose("(iperl) configured \"%s\" \"iperl\" \"%s\" %s\n", m.name, m.id, keymsg);
|
||||
break;
|
||||
case UNKNOWN_METER:
|
||||
error("No such meter type \"%s\"\n", m.type);
|
||||
|
|
|
@ -111,8 +111,7 @@ void MeterIperl::handleTelegram(Telegram *t)
|
|||
|
||||
if (useAes()) {
|
||||
vector<uchar> aeskey = key();
|
||||
decryptMode5_AES_CBC(t, aeskey, "iperl");
|
||||
verbose("$\n");
|
||||
decryptMode5_AES_CBC(t, aeskey);
|
||||
} else {
|
||||
t->content = t->payload;
|
||||
}
|
||||
|
|
|
@ -174,7 +174,7 @@ void MeterMultical21::handleTelegram(Telegram *t)
|
|||
|
||||
if (useAes()) {
|
||||
vector<uchar> aeskey = key();
|
||||
decryptMode1_AES_CTR(t, aeskey, meter_name_);
|
||||
decryptMode1_AES_CTR(t, aeskey);
|
||||
} else {
|
||||
t->content = t->payload;
|
||||
}
|
||||
|
@ -231,13 +231,13 @@ void MeterMultical21::processContent(Telegram *t)
|
|||
t->addExplanation(bytes, 2, "%02x%02x format signature", ecrc0, ecrc1);
|
||||
uint16_t format_signature = ecrc0<<8 | ecrc1;
|
||||
|
||||
// The format signature is used to find the proper format string.
|
||||
// But since the crc calculation is not yet functional. This functionality
|
||||
// has to wait a bit. So we hardcode the format string here.
|
||||
vector<uchar> format_bytes;
|
||||
hex2bin("02FF2004134413", &format_bytes); // Yes, the hash of this string should equal the format signature above.
|
||||
uint16_t format_hash = crc16_EN13757(&format_bytes[0], 7);
|
||||
debug("(multical21) format signature %4X format hash %4X\n", format_signature, format_hash);
|
||||
bool ok = loadFormatBytesFromSignature(format_signature, &format_bytes);
|
||||
if (!ok) {
|
||||
warning("(%s) warning: Unknown format signature hash 0x%02x! Cannot decode telegram.\n",
|
||||
meter_name_, format_signature);
|
||||
return;
|
||||
}
|
||||
vector<uchar>::iterator format = format_bytes.begin();
|
||||
|
||||
// 2,3 = crc for payload = hash over both DRH and data bytes. Or is it only over the data bytes?
|
||||
|
|
|
@ -96,7 +96,7 @@ void MeterMultical302::handleTelegram(Telegram *t) {
|
|||
|
||||
if (useAes()) {
|
||||
vector<uchar> aeskey = key();
|
||||
decryptMode1_AES_CTR(t, aeskey, "multical302");
|
||||
decryptMode1_AES_CTR(t, aeskey);
|
||||
} else {
|
||||
t->content = t->payload;
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ void MeterOmnipower::handleTelegram(Telegram *t) {
|
|||
|
||||
if (useAes()) {
|
||||
vector<uchar> aeskey = key();
|
||||
decryptMode5_AES_CBC(t, aeskey, "omnipower");
|
||||
decryptMode5_AES_CBC(t, aeskey);
|
||||
} else {
|
||||
t->content = t->payload;
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ void MeterSupercom587::handleTelegram(Telegram *t)
|
|||
|
||||
if (useAes()) {
|
||||
vector<uchar> aeskey = key();
|
||||
decryptMode1_AES_CTR(t, aeskey, "supercom587");
|
||||
decryptMode1_AES_CTR(t, aeskey);
|
||||
} else {
|
||||
t->content = t->payload;
|
||||
}
|
||||
|
|
31
wmbus.cc
31
wmbus.cc
|
@ -435,16 +435,19 @@ int difLenBytes(int dif)
|
|||
case 0x5: return 4; // 32 Bit Real
|
||||
case 0x6: return 6; // 48 Bit Integer/Binary
|
||||
case 0x7: return 8; // 64 Bit Integer/Binary
|
||||
case 0x8: return -1; // Selection for Readout (I do not know what this is)
|
||||
case 0x8: return 0; // Selection for Readout
|
||||
case 0x9: return 1; // 2 digit BCD
|
||||
case 0xA: return 2; // 4 digit BCD
|
||||
case 0xB: return 3; // 6 digit BCD
|
||||
case 0xC: return 4; // 8 digit BCD
|
||||
case 0xD: return -1; // variable length
|
||||
case 0xE: return 6; // 12 digit BCD
|
||||
case 0xF: return -2; // Special Functions
|
||||
case 0xF: // Special Functions
|
||||
if (dif == 0x2f) return 1; // The skip code 0x2f, used for padding.
|
||||
return -2;
|
||||
}
|
||||
return -1;
|
||||
// Bad!
|
||||
return -2;
|
||||
}
|
||||
|
||||
string difType(int dif)
|
||||
|
@ -471,22 +474,26 @@ string difType(int dif)
|
|||
default: s+= "?"; break;
|
||||
}
|
||||
|
||||
t = dif & 0x30;
|
||||
if (t != 0xf)
|
||||
{
|
||||
// Only print these suffixes when we have actual values.
|
||||
t = dif & 0x30;
|
||||
|
||||
switch (t) {
|
||||
case 0x00: s += " Instantaneous value"; break;
|
||||
case 0x10: s += " Maximum value"; break;
|
||||
case 0x20: s += " Minimum value"; break;
|
||||
case 0x30: s+= " Value during error state"; break;
|
||||
default: s += "?"; break;
|
||||
switch (t) {
|
||||
case 0x00: s += " Instantaneous value"; break;
|
||||
case 0x10: s += " Maximum value"; break;
|
||||
case 0x20: s += " Minimum value"; break;
|
||||
case 0x30: s+= " Value during error state"; break;
|
||||
default: s += "?"; break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (dif & 0x40) {
|
||||
// Kamstrup uses this bit in the Multical21 to signal that for the
|
||||
// full 32 bits of data, the lower 16 bits are from this difvif record,
|
||||
// and the high 16 bits are from a different record.
|
||||
s += " VendorSpecific";
|
||||
}
|
||||
}*/
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
|
@ -153,16 +153,15 @@ void WMBusSimulator::simulate()
|
|||
if (l[i] == '+') {
|
||||
found_time = i;
|
||||
rel_time = atoi(&l[i+1]);
|
||||
printf("Found time %ld -%s-\n", rel_time, &l[i+1]);
|
||||
break;
|
||||
}
|
||||
hex += l[i];
|
||||
}
|
||||
if (found_time) {
|
||||
verbose("(simulator) from file \"%s\" to trigger at relative time %ld\n", hex.c_str(), rel_time);
|
||||
debug("(simulator) from file \"%s\" to trigger at relative time %ld\n", hex.c_str(), rel_time);
|
||||
time_t curr = time(NULL);
|
||||
if (curr < start_time+rel_time) {
|
||||
verbose("(simulator) waiting %d seconds before simulating telegram.\n", (start_time+rel_time)-curr);
|
||||
debug("(simulator) waiting %d seconds before simulating telegram.\n", (start_time+rel_time)-curr);
|
||||
for (;;) {
|
||||
curr = time(NULL);
|
||||
if (curr > start_time + rel_time) break;
|
||||
|
@ -170,7 +169,7 @@ void WMBusSimulator::simulate()
|
|||
}
|
||||
}
|
||||
} else {
|
||||
verbose("(simulator) from file \"%s\"\n", hex.c_str());
|
||||
debug("(simulator) from file \"%s\"\n", hex.c_str());
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
|
|
|
@ -15,16 +15,17 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef WMBUS_UTILS_H
|
||||
#define WMBUS_UTILS_H
|
||||
|
||||
#include"aes.h"
|
||||
#include"util.h"
|
||||
#include"wmbus.h"
|
||||
|
||||
void decryptMode1_AES_CTR(Telegram *t, vector<uchar> &aeskey, const char *meter_name)
|
||||
void decryptMode1_AES_CTR(Telegram *t, vector<uchar> &aeskey)
|
||||
{
|
||||
vector<uchar> content;
|
||||
content.insert(content.end(), t->payload.begin(), t->payload.end());
|
||||
debugPayload("(Mode1) decrypting", content);
|
||||
|
||||
size_t remaining = content.size();
|
||||
if (remaining > 16) remaining = 16;
|
||||
|
||||
|
@ -45,7 +46,7 @@ void decryptMode1_AES_CTR(Telegram *t, vector<uchar> &aeskey, const char *meter_
|
|||
|
||||
vector<uchar> ivv(iv, iv+16);
|
||||
string s = bin2hex(ivv);
|
||||
debug("(%s) IV %s\n", meter_name, s.c_str());
|
||||
debug("(Mode1) IV %s\n", s.c_str());
|
||||
|
||||
uchar xordata[16];
|
||||
AES_ECB_encrypt(iv, &aeskey[0], xordata, 16);
|
||||
|
@ -54,11 +55,11 @@ void decryptMode1_AES_CTR(Telegram *t, vector<uchar> &aeskey, const char *meter_
|
|||
xorit(xordata, &content[0], decrypt, remaining);
|
||||
|
||||
vector<uchar> dec(decrypt, decrypt+remaining);
|
||||
debugPayload("(C1) decrypted", dec);
|
||||
debugPayload("(Mode1) decrypted first block", dec);
|
||||
|
||||
if (content.size() > 22) {
|
||||
warning("(%s) warning: C1 decryption received too many bytes of content! "
|
||||
"Got %zu bytes, expected at most 22.\n", meter_name, content.size());
|
||||
warning("(Mode1) warning: decryption received too many bytes of content! "
|
||||
"Got %zu bytes, expected at most 22.\n", content.size());
|
||||
}
|
||||
if (content.size() > 16) {
|
||||
// Yay! Lets decrypt a second block. Full frame content is 22 bytes.
|
||||
|
@ -69,20 +70,21 @@ void decryptMode1_AES_CTR(Telegram *t, vector<uchar> &aeskey, const char *meter_
|
|||
incrementIV(iv, sizeof(iv));
|
||||
vector<uchar> ivv2(iv, iv+16);
|
||||
string s2 = bin2hex(ivv2);
|
||||
debug("(%s) IV+1 %s\n", meter_name, s2.c_str());
|
||||
debug("(Mode1) IV+1 %s\n", s2.c_str());
|
||||
|
||||
AES_ECB_encrypt(iv, &aeskey[0], xordata, 16);
|
||||
|
||||
xorit(xordata, &content[16], decrypt, remaining);
|
||||
|
||||
vector<uchar> dec2(decrypt, decrypt+remaining);
|
||||
debugPayload("(C1) decrypted", dec2);
|
||||
debugPayload("(Mode1) decrypted second block", dec2);
|
||||
|
||||
// Append the second decrypted block to the first.
|
||||
dec.insert(dec.end(), dec2.begin(), dec2.end());
|
||||
}
|
||||
t->content.clear();
|
||||
t->content.insert(t->content.end(), dec.begin(), dec.end());
|
||||
debugPayload("(Mode1) decrypted", t->content);
|
||||
}
|
||||
|
||||
string frameTypeKamstrupC1(int ft) {
|
||||
|
@ -91,16 +93,18 @@ string frameTypeKamstrupC1(int ft) {
|
|||
return "?";
|
||||
}
|
||||
|
||||
void decryptMode5_AES_CBC(Telegram *t, vector<uchar> &aeskey, const char *meter_name)
|
||||
void decryptMode5_AES_CBC(Telegram *t, vector<uchar> &aeskey)
|
||||
{
|
||||
vector<uchar> content;
|
||||
content.insert(content.end(), t->payload.begin(), t->payload.end());
|
||||
debugPayload("(Mode5) decrypting", content);
|
||||
|
||||
// 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! "
|
||||
warning("(Mode5) warning: 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);
|
||||
content.size(), content.size() - content.size() % 16);
|
||||
while (content.size() % 16 != 0)
|
||||
{
|
||||
content.pop_back();
|
||||
|
@ -114,29 +118,38 @@ void decryptMode5_AES_CBC(Telegram *t, vector<uchar> &aeskey, const char *meter_
|
|||
// 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;
|
||||
for (int j=0; j<8; ++j) { iv[i++] = t->acc; }
|
||||
|
||||
vector<uchar> ivv(iv, iv+16);
|
||||
string s = bin2hex(ivv);
|
||||
verbose("(%s) IV %s\n", meter_name, s.c_str());
|
||||
debug("(Mode5) IV %s\n", 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);
|
||||
uchar decrypted_data[content.size()];
|
||||
AES_CBC_decrypt_buffer(decrypted_data, &content[0], content.size(), &aeskey[0], iv);
|
||||
vector<uchar> decrypted(decrypted_data, decrypted_data+content.size());
|
||||
|
||||
if (decrypted_data[0] != 0x2F || decrypted_data[1] != 0x2F) {
|
||||
verbose("(%s) decrypt failed!\n", meter_name);
|
||||
verbose("(Mode5) decrypt failed!\n");
|
||||
}
|
||||
|
||||
t->content.clear();
|
||||
t->content.insert(t->content.end(), decrypted.begin(), decrypted.end());
|
||||
debugPayload("(T1) decrypted", t->content);
|
||||
debugPayload("(Mode5) decrypted", t->content);
|
||||
}
|
||||
|
||||
#endif
|
||||
bool loadFormatBytesFromSignature(uint16_t format_signature, vector<uchar> *format_bytes)
|
||||
{
|
||||
// The format signature is used to find the proper format string.
|
||||
// But since the crc calculation is not yet functional. This functionality
|
||||
// has to wait a bit. So we hardcode the format string here.
|
||||
if (format_signature == 0xeda8)
|
||||
{
|
||||
hex2bin("02FF2004134413", format_bytes);
|
||||
// The hash of this string should equal the format signature above.
|
||||
uint16_t format_hash = crc16_EN13757(&(*format_bytes)[0], 7);
|
||||
debug("(utils) format signature %4X format hash %4X\n", format_signature, format_hash);
|
||||
return true;
|
||||
}
|
||||
// Unknown format signature.
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -18,8 +18,9 @@
|
|||
#ifndef WMBUS_UTILS_H
|
||||
#define WMBUS_UTILS_H
|
||||
|
||||
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);
|
||||
void decryptMode1_AES_CTR(Telegram *t, vector<uchar> &aeskey);
|
||||
void decryptMode5_AES_CBC(Telegram *t, vector<uchar> &aeskey);
|
||||
string frameTypeKamstrupC1(int ft);
|
||||
bool loadFormatBytesFromSignature(uint16_t format_signature, vector<uchar> *format_bytes);
|
||||
|
||||
#endif
|
||||
|
|
Ładowanie…
Reference in New Issue