Last time, we looked at the data the door contact was sending out over the airwaves. We arrived at a simple encoding system where 0 = 100 and 1 = 110. This might not be entirely correct, but we are finding 48 bit long packets containing the same data each time.
Now we need to try and work out what these bits represent.
As we worked out in part 4, all of the automated packet control in the CC1150 has been bypassed. This means that the microprocessor must deal with everything. What is everything? What does a normal packet look like in a simple RF system?
There can be a number of components sent. In approximate order, from start to finish:
- Pre-amble – generally a series of 10101010. The purpose of this is to make the receiver aware that a transmission is happening, adjust the gain as required, and synchronise clocks. The average value of this signal is partway between 1 and 0, which will mean the gain is appropriately set to receive both 1s and 0s.
- Sync-word – sometimes a sync word is sent immediately after the pre-amble. This is similar to an address or ID, but often it is system wide.
- Packet length – if the packet length is variable, then the receiving system needs to know how long the packet should be. Even if packet length appears fixed, the protocol may accommodate for variable length packets.
- ID – each device must be uniquely identifiable. We already know this is 20 bits long i.e. just over 1 million unique IDs. Sometimes other data is encoded in the ID, such as sensor type or manufacturer. This effectively reduces the keyspace, and makes guessing IDs easier.
- Data – this is the data such as triggered/not-triggered, sensor type, battery state, tamper state and so on.
- Checksum – often a checksum is calculated on the other other bits, so that the receiver can detect errors (and sometimes even correct them). On simple uni-directional RF systems used for safety that retransmit huge numbers of times, checksums become less useful.
Working out which piece of the data is which involves careful prodding of multiple components and observation of changes. Let’s get going!
It’s quite time consuming running a logic trace, exporting the data, running it through my parser, and interpreting the results. I should really learn to write analyser plugins for the Saleae Logic software, but my last attempt never quite worked right.
First thing I notice – there is no variation from packet to packet. There is no rolling code used here.
Door contact 1
The contact only transmits RF when the button is released (tamper) or the magnet removed (door open). There is therefore no indication to the rest of the system that a fault condition has been removed or a door closed. There appears to be no low-battery signal sent either.
These are the two transmissions
001100001100100011000000010100000000000000010000 - DC1 t 001100001100100011000000010100000000000000100000 - DC1 a
Notice only a couple of bits vary (shown in red)
Door contact 2
001100001101000000010000010100000000000000010001 - DC2 t 001100001101000000010000010100000000000000100001 - DC2 a
Again, only a couple of bits vary – the same bits as with door contact 1.
Let’s compare door contact 1 and 2:
001100001100100011000000010100000000000000010000 - DC1 t 001100001101000000010000010100000000000000010001 - DC2 t
The first 4 bits are the same between the two sensors. Is this the pre-amble and sync?
We then have a few bits that differ. This could be part of the ID.
The last bit also differs (green). Notice how 10 bits are high in the first packet, and only 9 in the second. This could mean that the last bit is a parity bit, a very simple checksum.
001100011101111101100000010000000000000000010000 - PIR1 t 001100011101111101100000010000000000000000100000 - PIR1 a
14 bits are high in the PIR packet, supporting the last bit being a parity bit.
Let’s compare this with the door contacts
001100001100100011000000010100000000000000010000 - DC1 t 001100001101000000010000010100000000000000010001 - DC2 t 001100011101111101100000010000000000000000010000 - PIR1 t 001100011101111101100000010000000000000000100000 - PIR1 a
It now looks like the pre-amble is shorter and the ID a bit more certain.
001100011101111100110000010000000000000000010000 - PIR2 t 001100011101111100110000010000000000000000100000 - PIR2 a
Let’s compare this to the other PIR
001100011101111101100000010000000000000000010000 - PIR1 t 001100011101111100110000010000000000000000010000 - PIR2 t
Wow – only a couple of bits differ. They are almost sequential!
This component is much more complex, so let’s just look at the simplest trigger – the tamper switch.
000010000001000000000000011100000000001000000000 - KP t
Notice how 6 bits are high, and the last bit is 0. It really does look like parity.
Let’s compare with the others:
001100001100100011000000010100000000000000010000 - DC1 t 001100001101000000010000010100000000000000010001 - DC2 t 001100011101111101100000010000000000000000010000 - PIR1 t 001100011101111100110000010000000000000000010000 - PIR2 t 000010000001000000000000011100000000001000000000 - KP t
Now we have a lot more information. The pre-amble has got shorter. Somewhere in the middle it looks like we have data indicating the sensor type.
A typical packet:
We have :
- Packet start (not shown). The encoded bits 111000 are sent. This is on the short side for a pre-amble.
- Yellow – this could be a continuation of the pre-amble, which would now be 111000100100 – still really quite short!
- Red – 18 bits of ID. Not sure which end the other two bits are at. Or are they using the 2 bits of sensor type to make it up to 20 bits?
- Blue – likely sensor type; 00 – PIR, 01 – door contact, 11 – panel.
- Purple – status of various switches and alarms.
- Green – a simple odd-parity checksum bit
I’ve now run out of components to test. We’ve gleaned a fair bit of information about the format of the packet, most importantly that no rolling code is in use.
Where next? I know the format of genuine packets, so I should be able to build a system to transmit these sniffed packets. We’ll test to see if the receiver can pick these packets up. Then we can start modifying the packets bit-by-bit to see how the receiver responds.