Added :hex type for stdin, files and ttys.

pull/343/head
Fredrik Öhrström 2021-09-12 19:51:33 +02:00
rodzic 21c8ab66cf
commit 0788ad7b90
8 zmienionych plików z 159 dodań i 17 usunięć

Wyświetl plik

@ -291,6 +291,12 @@ These telegrams are expected to have the data link layer crc bytes removed alrea
`telegrams.bin`, to read raw wmbus telegrams from this file.
These telegrams are expected to have the data link layer crc bytes removed already!
`stdin:hex`, to read hex characters wbus telegrams from stdin.
These telegrams are expected to have the data link layer crc bytes removed laready!
`telegrams.txt:hex`, to read hex characters wmbus telegrams from this file.
These telegrams are expected to have the data link layer crc bytes removed already!
`stdin:rtlwmbus`, to read telegrams formatted using the rtlwmbus format from stdin. Works for rtl433 as well.
`telegrams.msg:rtlwmbus`, to read rtlwmbus formatted telegrams from this file. Works for rtl433 as well.
@ -536,9 +542,9 @@ wmbusmeters --format=json --meterfiles /dev/ttyUSB0:im871a:c1 MyTapWater multica
rtl_sdr -f 868.625M -s 1600000 - 2>/dev/null | rtl_wmbus -s | wmbusmeters --format=json stdin:rtlwmbus MyMeter auto 12345678 NOKEY | ...more processing...
```
# Decoding a telegram supplied on the command line as a hex string
# Decoding hex string telegrams
If you have a single telegram you want decoded, you do not need to create a simulation file,
If you have a single telegram as hex, which you want decoded, you do not need to create a simulation file,
you can just supply the telegram as a hex string on the command line.
```shell
@ -567,6 +573,16 @@ which will output:
{"media":"other","meter":"lansenpu","name":"MyCounter","id":"00010206","counter_a_int":4711,"counter_b_int":1234,"timestamp":"2021-09-12T08:45:52Z"}
```
You can also pipe the hex into wmbusmeters like this:
```shell
echo 234433300602010014007a8e0000002f2f0efd3a1147000000008e40fd3a341200000000 | ./build/wmbusmeters --silent --format=json stdin:hex MyCounter auto 00010206 NOKEY
```
or read hex data from a a file, `wmbusmeters myfile.txt:hex`
Any non-hex characters are ignored when using the suffix `:hex`. The hex string must be proper
with no spaces nor bad characters, when supplied on the command line.
# Additional tools

Wyświetl plik

@ -213,6 +213,10 @@ shared_ptr<WMBus> BusManager::createWmbusObject(Detected *detected, Configuratio
verbose("(rawtty) on %s\n", detected->found_file.c_str());
wmbus = openRawTTY(*detected, serial_manager_, serial_override);
break;
case DEVICE_HEXTTY:
verbose("(hextty) on %s\n", detected->found_file.c_str());
wmbus = openHexTTY(*detected, serial_manager_, serial_override);
break;
case DEVICE_RTLWMBUS:
wmbus = openRTLWMBUS(*detected, config->bin_dir, config->daemon, serial_manager_, serial_override);
break;

Wyświetl plik

@ -141,6 +141,11 @@ int char2int(char input)
return -1;
}
bool isHexChar(uchar c)
{
return char2int(c) != -1;
}
// The byte 0x13 i converted into the integer value 13.
uchar bcd2bin(uchar c)
{

Wyświetl plik

@ -39,6 +39,9 @@ typedef unsigned char uchar;
uchar bcd2bin(uchar c);
uchar revbcd2bin(uchar c);
uchar reverse(uchar c);
bool isHexChar(uchar c);
bool isHexString(const char* txt, bool *invalid);
bool isHexString(const std::string &txt, bool *invalid);
bool hex2bin(const char* src, std::vector<uchar> *target);

Wyświetl plik

@ -4187,7 +4187,7 @@ FrameStatus checkWMBusFrame(vector<uchar> &data,
// Ugly: 00615B2A442D2C998734761B168D2021D0871921|58387802FF2071000413F81800004413F8180000615B
// Here the frame is prefixed with some random data.
debugPayload("(wmbus) checkWMBUSFrame\n", data);
debugPayload("(wmbus) checkWMBUSFrame", data);
if (data.size() < 11)
{
@ -4447,6 +4447,7 @@ bool is_type_id_extras(string t, WMBusDeviceType *out_type, string *out_id, stri
// im871a im871a[12345678] im871a(foo=123)
// auto
// rtlwmbus rtlwmbus[plast123] rtlwmbus(device extras) rtlwmbus[hej](extras)
// hex
if (t == "auto")
{
*out_type = WMBusDeviceType::DEVICE_AUTO;
@ -4454,6 +4455,13 @@ bool is_type_id_extras(string t, WMBusDeviceType *out_type, string *out_id, stri
return true;
}
if (t == "hex")
{
*out_type = WMBusDeviceType::DEVICE_HEXTTY;
*out_id = "";
return true;
}
size_t bs = t.find('[');
size_t be = t.find(']');

Wyświetl plik

@ -39,6 +39,7 @@ bool trimCRCsFrameFormatB(std::vector<uchar> &payload);
X(IM871A,im871a,true,false,detectIM871AIM170A) \
X(IM170A,im170a,true,false,detectSKIP) \
X(RAWTTY,rawtty,true,false,detectRAWTTY) \
X(HEXTTY,hextty,true,false,detectSKIP) \
X(RC1180,rc1180,true,false,detectRC1180) \
X(RTL433,rtl433,false,true,detectRTL433) \
X(RTLWMBUS,rtlwmbus,false,true,detectRTLWMBUS) \
@ -632,6 +633,9 @@ shared_ptr<WMBus> openAMB8465(Detected detected,
shared_ptr<WMBus> openRawTTY(Detected detected,
shared_ptr<SerialCommunicationManager> manager,
shared_ptr<SerialDevice> serial_override);
shared_ptr<WMBus> openHexTTY(Detected detected,
shared_ptr<SerialCommunicationManager> manager,
shared_ptr<SerialDevice> serial_override);
shared_ptr<WMBus> openMBUS(Detected detected,
shared_ptr<SerialCommunicationManager> manager,
shared_ptr<SerialDevice> serial_override);

Wyświetl plik

@ -43,19 +43,24 @@ struct WMBusRawTTY : public virtual WMBusCommonImplementation
void processSerialData();
void simulate() { }
WMBusRawTTY(string bus_alias, shared_ptr<SerialDevice> serial, shared_ptr<SerialCommunicationManager> manager);
WMBusRawTTY(string bus_alias, shared_ptr<SerialDevice> serial,
shared_ptr<SerialCommunicationManager> manager, bool use_hex);
~WMBusRawTTY() { }
private:
void copy(vector<uchar> *from, vector<uchar> *to);
vector<uchar> read_buffer_;
vector<uchar> data_buffer_;
LinkModeSet link_modes_;
vector<uchar> received_payload_;
};
shared_ptr<WMBus> openRawTTY(Detected detected,
shared_ptr<SerialCommunicationManager> manager,
shared_ptr<SerialDevice> serial_override)
shared_ptr<WMBus> openRawTTYInternal(Detected detected,
shared_ptr<SerialCommunicationManager> manager,
shared_ptr<SerialDevice> serial_override,
bool use_hex)
{
string bus_alias = detected.specified_device.bus_alias;
string device = detected.found_file;
@ -65,17 +70,32 @@ shared_ptr<WMBus> openRawTTY(Detected detected,
if (serial_override)
{
WMBusRawTTY *imp = new WMBusRawTTY(bus_alias, serial_override, manager);
WMBusRawTTY *imp = new WMBusRawTTY(bus_alias, serial_override, manager, use_hex);
imp->markAsNoLongerSerial();
return shared_ptr<WMBus>(imp);
}
auto serial = manager->createSerialDeviceTTY(device.c_str(), bps, PARITY::NONE, "rawtty");
WMBusRawTTY *imp = new WMBusRawTTY(bus_alias, serial, manager);
auto serial = manager->createSerialDeviceTTY(device.c_str(), bps, PARITY::NONE, use_hex?"hextty":"rawtty");
WMBusRawTTY *imp = new WMBusRawTTY(bus_alias, serial, manager, use_hex);
return shared_ptr<WMBus>(imp);
}
WMBusRawTTY::WMBusRawTTY(string bus_alias, shared_ptr<SerialDevice> serial, shared_ptr<SerialCommunicationManager> manager) :
WMBusCommonImplementation(bus_alias, DEVICE_RAWTTY, manager, serial, true)
shared_ptr<WMBus> openRawTTY(Detected detected,
shared_ptr<SerialCommunicationManager> manager,
shared_ptr<SerialDevice> serial_override)
{
return openRawTTYInternal(detected, manager, serial_override, false);
}
shared_ptr<WMBus> openHexTTY(Detected detected,
shared_ptr<SerialCommunicationManager> manager,
shared_ptr<SerialDevice> serial_override)
{
return openRawTTYInternal(detected, manager, serial_override, true);
}
WMBusRawTTY::WMBusRawTTY(string bus_alias, shared_ptr<SerialDevice> serial,
shared_ptr<SerialCommunicationManager> manager, bool use_hex) :
WMBusCommonImplementation(bus_alias, use_hex?DEVICE_HEXTTY:DEVICE_RAWTTY, manager, serial, true)
{
reset();
}
@ -107,6 +127,59 @@ void WMBusRawTTY::deviceSetLinkModes(LinkModeSet lms)
{
}
void WMBusRawTTY::copy(vector<uchar> *from, vector<uchar> *to)
{
if (type() == WMBusDeviceType::DEVICE_RAWTTY)
{
// We expect binary bytes incoming.
to->insert(to->end(), from->begin(), from->end());
debug("copied %zu binary bytes\n", from->size());
from->clear();
return;
}
if (type() == WMBusDeviceType::DEVICE_HEXTTY)
{
// We expect hex chars incoming. Everything else is thrown away.
vector<uchar> hex;
int num_hex = 0;
int num_other = 0;
for (uchar c : *from)
{
if (isHexChar(c))
{
hex.push_back(c); // Just ignore any non-hex chars!
num_hex++;
}
else
{
num_other++;
}
}
debug("found %d hex chars and %d other bytes\n", num_hex, num_other);
from->clear();
if (hex.size() > 0)
{
if (hex.size() % 2 == 1)
{
// An odd hexadecimal char at the end!
// Save it for later!
from->push_back(hex.back());
hex.pop_back();
}
// We now have an even number of hex chars to work with!
vector<uchar> bin;
bool ok = hex2bin(hex, &bin);
assert(ok);
debug("converted %zu hex bytes into %zu binary bytes.\n", hex.size(), bin.size());
to->insert(to->end(), bin.begin(), bin.end());
}
return;
}
assert(0);
}
void WMBusRawTTY::processSerialData()
{
vector<uchar> data;
@ -116,12 +189,14 @@ void WMBusRawTTY::processSerialData()
read_buffer_.insert(read_buffer_.end(), data.begin(), data.end());
copy(&read_buffer_, &data_buffer_);
size_t frame_length;
int payload_len, payload_offset;
for (;;)
{
FrameStatus status = checkWMBusFrame(read_buffer_, &frame_length, &payload_len, &payload_offset);
FrameStatus status = checkWMBusFrame(data_buffer_, &frame_length, &payload_len, &payload_offset);
if (status == PartialFrame)
{
@ -131,9 +206,9 @@ void WMBusRawTTY::processSerialData()
if (status == ErrorInFrame)
{
verbose("(rawtty) protocol error in message received!\n");
string msg = bin2hex(read_buffer_);
string msg = bin2hex(data_buffer_);
debug("(rawtty) protocol error \"%s\"\n", msg.c_str());
read_buffer_.clear();
data_buffer_.clear();
break;
}
if (status == FullFrame)
@ -143,9 +218,9 @@ void WMBusRawTTY::processSerialData()
{
uchar l = payload_len;
payload.insert(payload.end(), &l, &l+1); // Re-insert the len byte.
payload.insert(payload.end(), read_buffer_.begin()+payload_offset, read_buffer_.begin()+payload_offset+payload_len);
payload.insert(payload.end(), data_buffer_.begin()+payload_offset, data_buffer_.begin()+payload_offset+payload_len);
}
read_buffer_.erase(read_buffer_.begin(), read_buffer_.begin()+frame_length);
data_buffer_.erase(data_buffer_.begin(), data_buffer_.begin()+frame_length);
AboutTelegram about("", 0, FrameType::WMBUS);
handleTelegram(about, payload);
}

Wyświetl plik

@ -78,3 +78,30 @@ else
echo "======================="
cat $TEST/test_stderr.txt
fi
TESTNAME="Test hex on stdin"
cat > $TEST/test_expected.txt <<EOF
{"media":"other","meter":"lansenpu","name":"MyCounter","id":"00010206","counter_a_int":4711,"counter_b_int":1234,"timestamp":"1111-11-11T11:11:11Z"}
{"media":"cold water","meter":"multical21","name":"MyWater","id":"76348799","total_m3":6.408,"target_m3":6.408,"max_flow_m3h":0,"flow_temperature_c":127,"external_temperature_c":19,"current_status":"DRY","time_dry":"22-31 days","time_reversed":"","time_leaking":"","time_bursting":"","timestamp":"1111-11-11T11:11:11Z"}
{"media":"other","meter":"lansenpu","name":"MyCounter","id":"00010206","counter_a_int":4711,"counter_b_int":1234,"timestamp":"1111-11-11T11:11:11Z"}
EOF
echo 234433300602010014007a8e0000002f2f0efd3a1147000000008e40fd3a3412000000002A442D2C998734761B168D2091D37CAC21E1D68CDAFFCD3DC452BD802913FF7B1706CA9E355D6C2701CC24234433300602010014007a8e0000002f2f0efd3a1147000000008e40fd3a341200000000999 | \
$PROG --silent --ignoreduplicates=false --format=json stdin:hex MyCounter auto 00010206 NOKEY MyWater auto 76348799 28F64A24988064A079AA2C807D6102AE > $TEST/test_output.txt 2> $TEST/test_stderr.txt
if [ "$?" = "0" ]
then
cat $TEST/test_output.txt | sed 's/"timestamp":"....-..-..T..:..:..Z"/"timestamp":"1111-11-11T11:11:11Z"/' > $TEST/test_responses.txt
diff $TEST/test_expected.txt $TEST/test_responses.txt
if [ "$?" = "0" ]
then
echo OK: $TESTNAME
TESTRESULT="OK"
fi
else
echo "wmbusmeters returned error code: $?"
cat $TEST/test_output.txt
cat $TEST/test_stderr.txt
fi