Utilities and support functions¶
CRC16 for wm-bus¶
CRC16 for wm-bus¶
- synopsis
CRC16 calculator for EN 13757
- author
Janus Bo Andersen
- date
October 2020
Overview:¶
This function performs the CRC16 algorithm.
The result can be used to confirm data integrity of received payload in a wm-bus message.
Wm-bus follows the CRC16 standard outlined in EN 13757.
A CrcCheckException class is also implemented, which is used to raise exceptions if a CRC check fails.
The IM871-A transceiver removes the outer CRC16 (last two bytes of a message) and replaces it with its own, which follows another standard, CRC16-CCITT. So the outer CRC16 can not be checked with the function in this module.
CRC16 EN 13757:¶
CRC16 uses a generator polynomial, g(x), described in EN 13757-4.
See p. 42 for data-link layer CRC, and an example with a C1 telegram on p. 84.
See p. 58 for transport layer CRC polynomial.
g(x) = x^16 + x^13 + x^12 + x^11 + x^10 + x^8 + x^6 + x^5 + x^2 + 1
In binary (excluding x^16 as it is shifted out anyway), this g(x) is represented as
Byte 1 |
Byte 2 |
Hex value |
|---|---|---|
0011 1101 |
0110 0101 |
0x3D65 |
MSbit = x^15 |
LSbit = x^0 = 1 |
See EN 13757-4, table 43, p. 50 for expected structure of ELL for a CI=0x8D telegram. PayloadCRC is included in the encrypted part of telegram.
Algorithm rules:¶
Treats data most-significant bit first
Final CRC shall be complemented
Multi-byte data is transmitted LSB first
CRC is transmitted MSB first
Math background:¶
CRC uses a finite field F=[0, 1], so we do subtraction using XOR.
CRC is the final remainder from repeated long division of message by polynomial,when no further division is possible.
The output CRC is complemented by XOR with 0xFFFF.
Algorithm implementation comments:¶
The implemented algorithm uses Python’s ability for ‘infinite’ width of integers. That is slightly inefficient, and can’t be ported to C code on an embedded device. But it is significantly easier to debug and understand than byte-wise algorithms or lookup tables.
CRC16 for IM871-A¶
Implementation of CRC16 for IM871-A (CCITT)¶
- synopsis
CRC16 CCITT implementation based on Steffen’s C implementation.
- authors
Steffen and Janus.
- date
29 Oct 2020.
See IMST’s WMBUS_HCL_Spec_V1.6.pdf.
CRC computation starts from the Control Field and ends with the last octet of the Payload Field.
IM871A uses CRC16-CCITT Polynomial G(x) = 1 + x^5 + x^12 + x^16.
CRC16 function¶
-
utils.crc16_im871a.crc16_im871a_check(m: bytes) → bool[source]¶ Confirm CRC16 integrity of a full bytestring received from IM871-A. Argument must be the entire message from IM871-A. Function returns TRUE when the check sum matches the expected CRC16 value.
-
utils.crc16_im871a.crc16_im871a_calc(m: bytes) → bytes[source]¶ Compute CRC16 (CCITT) for a message received serially from IM871-A. Argument must:
NOT contain the first field, e.g. 0xA5.
Start and contain the control field, e.g. 0x8203.
Contain full payload, e.g. 0x2744…2637.
NOT contain the trailing 2 bytes of expected CRC16 value, e.g. 0xC1AB.
Full message example: a5 8203 27442d2c5768663230028d20cd12340720519df247ff65e751662a300bc4e5c67da86477f0182637 c1ab.
Timezone handling¶
Zulu timezone handling¶
- synopsis
Stamp measurements with Zulu time (UTC), and easy future-proof management of timestamps as required by ReMoni.
- author
Janus Bo Andersen.
- date
October 2020.
- description
Output dates in ISO 8601 format, i.e. output 2020-10-25T10:08:00Z for 25th October 2020 at 10:08:00 (HH:MM:SS) in UTC time.
Note that ISO 8601 allows using +00:00 instead of Z. ReMoni prefers Z for this implementation.
UTC class implementation based on: https://docs.python.org/3.5/library/datetime.html
Zulu time definition based on: https://en.wikipedia.org/wiki/ISO_8601
ZuluTime class¶
Print datetime object with ISO 8601 format¶
-
utils.timezone.zulu_time_str(timestamp: datetime.datetime) → str[source]¶ Print a timestamp with ISO format like 2020-10-25T10:08:00Z
Logging to syslog¶
Automatic search for IM871-A dongle device¶
Experimental: Search for IMST IM871a WMbus dongle. Looking at udev rules in Linux: Default OS placed in /lib/udev/rules.d - These cannot be changed. If user want to create custom udev rules this should be placed in /etc/udev/rules.d
Rules placed in /etc have priority over /lib.
Specific for serial communication rules OS uses 60-serial.rules where one line define location and name for the link to tty PORT used for specific device.
- ENV{.ID_PORT}==”?*”, SYMLINK+=”serial/by-id/$env{ID_BUS}-$env{ID_SERIAL}
-if$env{ID_USB_INTERFACE_NUM}-port$env{.ID_PORT}”
Looking at the line its clear that the link is placed in /dev/serial/by-id. Furthermore the name of the link is given by the ID_BUS, ID_SERIAL ,ID_USB_INTERFACE_NUM, ID_PORT. At the moment it’s believed but not confirmed that ID_USB_INTERFACE_NUM and ID_PORT is subject to change if different port is assigned.
This method first confirms the directory /dev/serial/by-id exist, afterwards looks for iM871a in any link name. If any the method will return the absolute path. If Several links contains “iM871a” the method will return path to first encountered link.