...
What we deduced from looking at the signal:
Pulse | Delay |
---|---|
On Pulse | 0.5 ms |
0 value | 2 ms off between On Pulse |
1 value | 4 ms off between On Pulse |
Stop Pulse | 0.5 ms |
9 ms delay between repeats repeat the whole thing a total of 7 times. |
If we look at just one of the pulses, we see that it contains 32 bits or 4 bytes:
...
Rolling Code(2), Status(1), Temperature (signed binary), Hash Code
Data being sent:
Nible | Purpose | Our Value | Description |
---|---|---|---|
1-2 | Rolling Code | E6 | The rolling code randomly generated when the transmitter powers up. After the receiver receives it's first rolling code, it will not accept messages with a different code unless rebooted. |
3 | Status | 8 | A status of 8 signifies that the batter is ok. The status nibble's MSB is a "battery okay" flag which is normally one. It goes to zero when the battery drops below about 2.6 volts or so. |
4-6 | Temperature | 136 | The temperature with 1 decimal place. A temperature of 31.0C = 31.0*10 = 310 dec = 136 hex |
7-8 | Hash | 13 | Hash computed using |
Checksum/Hash
This sensor does not use a simple checksum or even a more advanced CRC. Instead data integrity is verified by a hash code, generated by multiplying the message bits with the byte sequence generated by a linear feedback shift register (LFSR). This algorithm has been referred to as "an LFSR-based Toeplitz hash" in some of the literature.
...
• The register value after these two operations is the sequence value to be stored. Perform these steps once for each bit in the message. If the message contains 40 bits for example (as with the F007TH message) then you will need to generate a sequence of 40 bytes. Because this sequence does not depend on the data message contents and can be pre-computed once and stored to save time.
Start Value | Shift Right | XOR with 0x18 if MSB =1 (flip bits 3 and 4) | Xor | Value | |
---|---|---|---|---|---|
1 | 0111 1100 (0x7C) | → 0011 1110 | NO | - | 0011 1110 (0x3e) |
2 | 0011 1110 (0x3e) | → 0001 1111 | NO | - | 0001 1111 (0x1f) |
3 | 0001 1111 (0x1f) | → 1000 1111 | YES | xor 0x18 | 1001 0111 (0x97) |
4 | 1001 0111 (0x97) | → 1100 1011 | YES | xor 0x18 | 1101 0011 (0xd3) |
5 | 1101 0011 (0xd3) | → 1110 1001 | YES | xor 0x18 | 1111 0001 (0xf1) |
... | |||||
32 | 1000 0110 (0x86) | → 0100 0011 | NO | - | 0100 0011 (0x43) |
Values
2. Combines the LSFR sequence with message bits to form the final hash value
...
From MSB to LSB for message 1110 0110 1000 0001 0011 0110 (E6 81 36 hex)
Register Value | Index | Value | Value=1? | Calculation | New Register Value (xor with LSFR Sequence starting at the 5th (0xF1) |
---|---|---|---|---|---|
00 | 23 -MSB | 1 | Yes | 00 xor f1 | f1 |
f1 | 22 | 1 | Yes | f1 xor e0 | 11 |
11 | 21 | 1 | Yes | 11 xor 70 | 61 |
... | |||||
13 | 0 | 0 | No | - | 13 |
Hash Code
Code Block |
---|
#define MESSAGE_SIZE 32 #define OFFSET 4 uint8_t LSFR_sequence[MESSAGE_SIZE] = {0}; void calculateLSFR() { int i; uint8_t reg = 0x7C; uint8_t temp_reg = 0; for (i = 0; i < MESSAGE_SIZE; i++) { temp_reg = reg & 0x01; reg >>= 1; reg |= (temp_reg << 7); if (temp_reg) { reg ^= 0x18; } LSFR_sequence[i] = reg; //printf("%02x\n", LSFR_sequence[i]); } } uint8_t combineLSFR(uint8_t len, uint8_t *data) { uint8_t hash_reg = 0; // not 0x64 int byte_idx, bit_idx; uint8_t byte, bit; //printf("***COMBINE\n"); for (byte_idx = 0; byte_idx < len; byte_idx++) { for (bit_idx = 7; bit_idx >= 0; bit_idx--) { bit = (data[byte_idx] & (1 << bit_idx)) >> bit_idx; if (bit) { hash_reg ^= LSFR_sequence[byte_idx * 8 + (7 - bit_idx) + OFFSET]; //printf("[%d]: %02x\n", byte_idx * 8 + (7 - bit_idx), hash_reg); } bit = 0; } } return hash_reg; } uint8_t Checksum(int length, uint8_t *buff) { calculateLSFR(); return combineLSFR(length, buff); } |
Sending Temperatures to the Receiver
Code
Code Block |
---|
References
Reference | URL |
---|---|
FCC Info | https://fccid.io/RNE606TXA1 |
RF Protocol | http://www.osengr.org/WxShield/Downloads/Weather-Sensor-RF-Protocols.pdf |
On Off Keying | https://www.youtube.com/watch?v=w6V9NyXwohI |
...