Electronic – Reverse Engineer Serial Signal

reverse-engineeringsaleae-logic-analyzerserialserial-bus

This is a long post as I want to take you through all the work I've done. The TL;DR version is I've got an unknown controller for a mechanical heat pump and I'm trying to reverse engineer the signal and data….so if you think you can help, then please read on.

First off, I'm not an electrical engineer. I'm a software engineer who is a bit out of his depth.

I have an ITS heatpump and it has a controller I want to reverse engineer in order to read data from the sensors and set some parameters in software. I've looked for technical specifications and asked the manufacturer, but they told me to GTFO. In the end, reverse engineering seemed the only way to get what I wanted.

Between the unit and the control panel is a 3 wire connection. From what I've been able to deduce it is GND, +12V (to power panel) and a signal wire.

I then got myself a Saleae protocol analyser to see what I could see. I've confirmed that the single data wire is used for both RX/TX. I thought the easiest point to tackle is the control panel and disconnected the signal wire so that I could read only what the panel is transmitting. A sample can be found at http://tinyurl.com/ppuemv7 . I am using the 1.1.24 beta version for decoding. It seems to decode nicely using Async Serial 8N1 autobaud. I've tried a bunch of other decoders and parameters but all of them get framing or other errors.

I then started systematically changing the values on the controller to see how the byte stream changes. I changed parameter 1 using values [51-55] and this was the result (spaced intentionally for ease of spotting differences) of the byte streams.

Format <Param>-<value>:<decoded byte string in hex>
01-51:8055DD555555555555555555555555555575577557F58075757757 DD 757577577755DD55555D7777775577755D 55 5D 77 FD
01-52:8055DD555555555555555555555555555575577557F58075757757 D5 DD7577577755DD55555D7777775577755D 55 77 77 F5
01-53:8055DD555555555555555555555555555575577557F58075757757 5D DD7577577755DD55555D7777775577755D 55 75 77 FD
01-54:8055DD555555555555555555555555555575577557F58075757757 75 DD7577577755DD55555D7777775577755D 55 D7 77 F5
01-55:8055DD555555555555555555555555555575577557F58075757757 DD D757DD5D7755D757555D75DD7755DDD575 57 D5 77 57

From that the pattern wasn't obvious so I decided to change another parameter (param:0 changed to 16 from 15) keeping parameter 01 at 52 and this is what I got.

Format <Param>-<value>:<decoded byte string in hex>
00-15:8055DD555555555555555555555555555575577557F5807575 7757 D5 DD7577577755DD55555D7777775577755D 55 77 77 F5 
00-16:8055DD555555555555555555555555555575577557F5807575 5555 D7 57DD5D7755D757555D75DD7755DDD57557 55 77 F5 

Those of you quick on the draw will notice that the 00-16 capture is 1-byte shorter. My only conclusion is that either I'm using the wrong decoding or the panel is doing some compression.

I need advice on what to attempt next as I feel pretty stuck.

Best Answer

My first thought (based on the async decoded data only) was this could be Manchester encoded signal, instead of async serial. Now I think the data is encoded by supressing alternate clock pulses.

Here's why:

With the exception of the 0x80 (which may be a "start byte"), the async serial 8N1 claims that the messages are composed of only 10 distinct symbol bytes:

0x55 01010101 (139 occurrence) 
0x57 01010111 (32 occurrence) 
0x5d 01011101 (16 occurrence) 
0x75 01110101 (45 occurrence) 
0x77 01110111 (49 occurrence) 
0xd5 11010101 (5 occurrence) 
0xd7 11010111 (5 occurrence) 
0xdd 11011101 (24 occurrence) 
0xf5 11110101 (11 occurrence, only at end of message) 
0xfd 11111101 (2 occurrence, only at end of message) 

Looking at the binary it looks like the message bitstream is composed of long and short pulses, and may not be correctly synced up with the start and stop bits of the async serial. The only bit patterns that have more than three 1's in a row are 0xFD and 0xF5, but that occurs only at the end of a message -- and remember, async serial is LSB-first. So those longer sequences of 1's in the MSB may be after the end of the underlying Manchester encoded signal. Similarly the 0x80 at the start of each message may precede the underlying signal.

Atmel's primer on Manchester Coding Basics gives a good overview of encoding and decoding: http://www.atmel.com/images/atmel-9164-manchester-coding-basics_application-note.pdf

waveform capture picture

Now that I see the waveform, it's definitely not Manchester coding... Looks like idle-high, with a long pulse as a header, followed by a very long string of clock pulses -- with occasional missing clock pulses. At this point I'd guess the pulses alternate between Clock pulses and Data pulses. So a 0 is encoded as two clock pulses, and a 1 is encoded as one clock pulse and one "missing" pulse. I'm not sure what this is called but I think I've seen it before, a long time ago...