I would like some help with figuring out the crc byte of a RS485 communication of an Endress+Hauser pH probe
I have here init bytes of 4 different probes, the first byte i'm not so sure if it is included, its more like an start of frame that pulls the line low for 1120us.
The sixth byte (0x1F) is xor of the first bytes, 9th byte is also xor of 7th and 8th byte
0x00 0x01 0x1A 0x04 0x00 0x1F 0x22 0x04 0x26 0x80
0x00 0x01 0x1A 0x04 0x00 0x1F 0x29 0xE9 0xC0 0x77
0x00 0x01 0x1A 0x04 0x00 0x1F 0x52 0xA8 0xFA 0x18
0x00 0x01 0x1A 0x04 0x00 0x1F 0x6B 0x5F 0x34 0x13
Only the last byte puzzles me. Can't find how that gets calculated
EDIT: The system is an Endress+Hauser pH measuring device. The meter is LIQUISYS-H and the probes are CPS11D-7FA21. The system uses digital communication between the probe and instrument and inductive couping to prevent corrosion. I went so far to successfuly read the probe (mV and temperature) but my system works as long as I don't change the probe with a new one. What you are seeing here is a part of a lenghty initialization of the probe at start (calibatrion data is read and probe identified), but the snippet I pasted is some kind of init code that "wakes up" the probe for reading. In other words if you power up the probe you need to send one of these bytes to it one time and then just poll the probe with
0x00 0x01 0x01 0x01 0x00 0x01
over and over to get the mV and temperature responses. Every probe has different init codes that I have yet not identified but first I need to get all of these checksums or crc figured out. Thank you
I would like some help with figuring out the crc byte of a RS485 communication of an Endress+Hauser pH probe
I have here init bytes of 4 different probes, the first byte i'm not so sure if it is included, its more like an start of frame that pulls the line low for 1120us.
The sixth byte (0x1F) is xor of the first bytes, 9th byte is also xor of 7th and 8th byte
0x00 0x01 0x1A 0x04 0x00 0x1F 0x22 0x04 0x26 0x80
0x00 0x01 0x1A 0x04 0x00 0x1F 0x29 0xE9 0xC0 0x77
0x00 0x01 0x1A 0x04 0x00 0x1F 0x52 0xA8 0xFA 0x18
0x00 0x01 0x1A 0x04 0x00 0x1F 0x6B 0x5F 0x34 0x13
Only the last byte puzzles me. Can't find how that gets calculated
EDIT: The system is an Endress+Hauser pH measuring device. The meter is LIQUISYS-H and the probes are CPS11D-7FA21. The system uses digital communication between the probe and instrument and inductive couping to prevent corrosion. I went so far to successfuly read the probe (mV and temperature) but my system works as long as I don't change the probe with a new one. What you are seeing here is a part of a lenghty initialization of the probe at start (calibatrion data is read and probe identified), but the snippet I pasted is some kind of init code that "wakes up" the probe for reading. In other words if you power up the probe you need to send one of these bytes to it one time and then just poll the probe with
0x00 0x01 0x01 0x01 0x00 0x01
over and over to get the mV and temperature responses. Every probe has different init codes that I have yet not identified but first I need to get all of these checksums or crc figured out. Thank you
Share Improve this question edited 2 days ago TadyTheFish asked 2 days ago TadyTheFishTadyTheFish 33 bronze badges 3- It is impossible to tell what is really happening with the information you gave. Please update your post with more context. Mainly, what is the exact model of your pH meter and what those bytes exactly stand for (answer of which requests) ? – jlandercy Commented 2 days ago
- 2 Have you asked the manufacturer for details of the protocol? This does not seem like the sort of cheap consumer-grade device you would need to reverse engineer. – Sneftel Commented 2 days ago
- This question is similar to: Memosense pH probe communication CRC reverse engeneering. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. – Mark Adler Commented 2 days ago
1 Answer
Reset to default 0Your class of sensor seems to implement a CRC checksum on the complete payload but does not provide any information on the actual CRC setup.
If you believe your initialization datagrams do contain a checksum then your problem is equivalent to find out which CRC setup (polynomial, init, xorout) has been chosen to check the payload.
CRC32 is 4 bytes long which is incompatible with your setup as the first six bytes over the ten are identical (therefore they must have the same CRC32, same last four bytes).
It could be some CRC16 (which is 2 bytes long) or CRC8 (which is 1 byte long) but does not seems to be standard CRC as you can see below.
Here is some code to check out the result:
from collections.abc import Callable
import crcmod
crc8 = crcmod.mkCrcFun(0x107, rev=False, initCrc=0x00, xorOut=0x00)
crc16 = crcmod.mkCrcFun(0x18005, rev=False, initCrc=0xffff, xorOut=0x0000)
crc32 = crcmod.mkCrcFun(poly=0x104c11db7, rev=True, initCrc=0x00000000, xorOut=0xffffffff)
datagrams = [
b"\x00\x01\x1A\x04\x00\x1F\x22\x04\x26\x80",
b"\x00\x01\x1A\x04\x00\x1F\x29\xE9\xC0\x77",
b"\x00\x01\x1A\x04\x00\x1F\x52\xA8\xFA\x18",
b"\x00\x01\x1A\x04\x00\x1F\x6B\x5F\x34\x13",
]
def checksum(payload: bytes, method: Callable = crc32, size: int = 4, order: str = "big") -> bytes:
return method(payload).to_bytes(size, order)
for method, size in [(crc8, 1), (crc16, 2), (crc32, 4)]:
checksums = [checksum(datagram[:-size], method=method, size=size) for datagram in datagrams]
trials = [datagram[-size:] for datagram in datagrams]
checked = checksum == trials
print(f"{checked}: {trials} {checksums}")
# False: [b'\x80', b'w', b'\x18', b'\x13'] [b'\xb1', b'K', b'(', b'\xe8']
# False: [b'&\x80', b'\xc0w', b'\xfa\x18', b'4\x13'] [b'\x7f\xac', b'\xc7\xc1', b'\\B', b'Hs']
# False: [b'"\x04&\x80', b')\xe9\xc0w', b'R\xa8\xfa\x18', b'k_4\x13'] [b'9\x07\x9a\xc1', b'9\x07\x9a\xc1', b'9\x07\x9a\xc1', b'9\x07\x9a\xc1']
Now, if your datagram does contain the checksum, the task is about to find out which CRC setup is implemented in your system.
You may check this List of CRC values to find out the rigth setup.