Obviously the last 2 quartets of a 40 bits message are a kind of checksum or CRC. Indeed their value changes according to the other quartets of the message. If the other part of the message doesn’t change they don’t change.
But they change with enough randomness that they can’t be a simple checksum.
Might that 2 last quartets be a CRC ? a 8 bits CRC ?
What’s a CRC ?
A CRC (Cyclic Redundancy Code) is an error detecting code that is calculed over a bunch of information and appended to it.
CRCs are very often used in data transmission over the air.
In such cases the information and the CRC are both transmitted. The receiver calculates the CRC over the information it has received and compares with the transmitted CRC. If both differ it means an error happens during the transmission of the message.
Refer to http://en.wikipedia.org/wiki/Cyclic_redundancy_check for more information.
For a more complete (but painless) comprehension the following website is kind of mandatory :
A painless guide to CRC by Ross Williams.
Before really trying to reverse-engineering this CRC I browsed a little and have found an interesting site :
Reverse-engineering a CRC by Gregory Ewing.
Gregory has managed to find the polynom of the CRC he tried to reverse-engineer by using specifically forged messages.
He generated a few messages composed of all bits to 0 except 1 :
message #1 : 00 80 00
message #2 : 00 40 00
message #3 : 00 20 00
message #4 : 00 01 00
He then generated the CRC for each message, then given that CRC computations involve shift and XOR operations he did the following :
- CRC2 XOR (CRC1 shifted right)
- CRC3 XOR (CRC2 shifted right)
- CRC4 XOR (CRC3 shifted right)
Since his messages are specifically forged he obtained the value of the polynom for the CRC.
It is difficult to try this method with the messages sent by the TX29 sensor because we can’t forge them. But we can be patient…
20.1°C / 20.2°C / 20.4°C / 20.8°C
In order to adapt this method to the TX29 sensor I patiently waited for the temperature to vary between the above values. I use the heat of my palms to slowly increase the sensor temperature.
Eventually I’ve got the following messages (hexa) :
9 a 6 6 0 1 6 a 6 8
9 a 6 6 0 2 6 a 4 5
9 a 6 6 0 4 6 a 1 f
9 a 6 6 0 8 6 a a b
You can notice that the 3rd byte of each messages is :
I applied Greg’s method (XOR + shift) on the CRCs of 2 consecutive messages :
45 with 68 => 4a
1f with 45 => 4a
ab with 1f => 4a
This proves that the last 8 bits of each message correspond to a CRC.
But this doesn’t give us the polynom of that CRC because all the bits of each message (except 1) are not null.
We need to push investigations further…
…but not that further :-)
In order to find the poly I have collected a set of messages that I know have been correctly received. In fact I have selected messages that I have received identically 2 or three times or more in a row.
And I developped a python script that tries every value of polynom on all the messages.
They are a total of 256 different polynoms for a CRC that is 8 bits long, so the brute force approach should not be too long.
For the record at first I had a bug in my polynom division function and I did not manage to find a polynom that matches for all my messages with an initial register value of 0.
That’s why I modified the python script so that it scans all the initial values from 0 to 255 for every polynom from 0 to 255.
But after having corrected my polynom division function I managed to find the polynom value (and the initial value which is 0).
The python script that do this is called brutef.py is available as part of the source package (please see below).
Again I recommend that you carrefully read Ross Williams’s A painless guide to CRC.
Eventually I found the polynom value : 0×31 (0×131)
The CRC polynom is thus : x8 + x5 + x4 + 1
It is simply a standard CRC-8 (width 8 bits).
The python script called raw.py available in implements this CRC in order to check the received messages.
It is very interesting to know the CRC used by the TX29 and TX29D sensors because after a few experiments it occured to me that the transmission is not very reliable.
It may be due to my soldering skills, to my test setup, or it may also be due to interferences in the 868MHz band.
I observed that the following accidents occur frequently at the reception :
- A gap after the 12th bit more or less long, which is wrongly detected as a bit to 0 (all remaining bits are interpreted as shifted)
- In some conditions and if set to 1, 2 consecutive bits between the 13th and the 16th bits are merged as 1 longer bit (in time), thus my decoding algorithm is fooled and considers only one bit to 1 (all the remaining bits are shifted)
- Plus all kinds of transmission error on any bit which is wrongly interpreted (flip)
In order to cope with those errors I’ve implemented something that is very common in modern radio transmissions.
The idea is the following : in case a message is received and that its CRC is KO, the message is not trashed.
Instead the receiver tries to “guess” what error has altered the message in order to “reconstruct” it.
Indeed if we know that there is an important probability that a 0 might be inserted between the 12th and the 13th bits during the transmission, we can try to remove the 13th bit.
Then we check the CRC again on the “reconstructed” message to see if it becomes OK.
If the CRC becomes OK it means that our guess was good, and we have succeded in reconstructing the orginal message.
The raw.py python script implements several tricks in order to reconstruct an altered message.
It is available in the sources package.
Script to brute force the CRC : crc.tgz
Sources of the programs and scripts used to do the complete decoding : tx29.1.0.tgz
Next : to the conclusion.