0

Attempting to reverse-engineer a checksum for a serial timing device that updates a display. Protocol is partly understood, however the checksum calculation specified does not produce the expected value.

I would like to understand what is happening in this protocol, as I would like to write to the display with my own software and not just sniff the data.

Known parameters:

  • RS-485 half duplex
  • 8n1
  • DATA0...n transmitted unchanged, low nibbles are BCD (0-9)
  • (EDIT) this is likely not the case, as the spec I have does not seem to be the correct one. Disregard the following point. ADDR byte and CSUM byte split into two bytes each, hi and lo nibbles might be split between the two bytes, however I'm confused as to why it appears that the ADDR byte is a start flag byte.
  • sub_ADDR matches the protocol specification, used to identify the data in the packet to a specific part of the display, and possibly to different displays
  • One-way communication (EDIT) one-to-many master-slave likely
  • FEC appears to be "repeat the message" as all packets are immediately duplicated in the recorded stream, i.e. 1,1,2,2,3,3..etc.
  • Receiver likely "pretends it never happened" if packets are mangled as past data is irrelevant
  • (EDIT) All packets are of known length and the lengths do not change in the data set
  • (EDIT: CRITICAL INFO) Low nibbles of bytes labeled A3-A6 and B3-B6 represent digits 0-9 as BCD. A value of 0x0f would blank the digit on the display.[1] Therefore:

    0a 0c 02 00 60 00 80 0b -> "20:00"
    28 0c 02 00 60 00 80    -> "20:00"
    0a 0c 01 09 65 09 d8 0b -> "19:59"
    0a 0c 0f 09 65 09 80 0b -> " 9:59"
    
  • (EDIT) High nibbles of A3-A6 contain flag bits. Known flag bits include bit 6 in DATA2 (A5,B5) which indicates state == running, and bit 5 in DATA2 (A5,B5) which indicates colon == on.

First question: If the FEC is indeed "repeat", does it follow that the designer would incorporate a CSUM? Perhaps the packets that appear to be CSUM are something else not documented?


Packet format:

as described in protocol spec, possibly incorrect or outdated. (EDIT: the protocol spec does appear to be incorrect for my device. Corruption of the data is unlikely)

"X" denotes a nibble that takes a value. "?" denotes a nibble that is used for flag bits.

| lo_ADDR | hi_ADDR | sub_ADDR | DATA_0 | DATA_1 | DATA_2 | DATA_3 | lo_CSUM | hi_CSUM |
|   0x8X  |   0x9X  |   0x0c   |  0x?X  |  0x?X  |  0x?X  |  0x?X  |  0xAX   |   0xBX  |

Some of the fields seem to match; others don't. As seen below, lo and hi ADDR and lo and hi CSUM don't seem to match the description.

Most packets in the stream appear to start with 0x0a and end with 0x0b, although some packets observed don't follow that pattern. Are they flag bytes?

An example of two packets of interest, bytes that work as specified marked ok, ones that don't with !k

A1 A2 A3 A4 A5 A6 A7 A8     B1 B2 B3 B4 B5 B6 B7
------------------------------------------------
!k ok ok ok ok ok !k !k     !k ok ok ok ok ok !k
0a 0c 02 00 60 00 80 0b     28 0c 02 00 60 00 80

Straight from Pyserial, appears as follows:

b'\n\x0c\x02\x00`\x00\x80\x0b(\x0c\x02\x00 \x00\x80'

Ten lines of packets, two neighboring packets shown, repeats removed: (edit: added more lines, formatting for clarity)

A1 A2 A3 A4 A5 A6 A7 A8          B1 B2 B3 B4 B5 B6 B7
--------------------- state == running --------------
----------------------(A3, B3 <= 0x09)---------------

0a 0c 01 09 65 09 d8 0b .repeat. 28 0c 01 09 65 09 e0 .repeat. ...
0a 0c 01 09 65 08 c0 0b ........ 28 0c 01 09 65 08 80 ...
0a 0c 01 09 65 07 a8 0b ........ 28 0c 01 09 65 07 a0 ...
0a 0c 01 09 65 06 90 0b ........ 28 0c 01 09 65 06 c0 ...
0a 0c 01 09 65 05 f8 0b ........ 28 0c 01 09 65 05 e0 ...
0a 0c 01 09 65 04 e0 0b ........ 28 0c 01 09 65 04 80 ...
0a 0c 01 09 65 03 c8 0b ........ 28 0c 01 09 65 03 a0 ...
0a 0c 01 09 65 02 b0 0b ........ 28 0c 01 09 65 02 c0 ...
0a 0c 01 09 65 01 98 0b ........ 28 0c 01 09 65 01 e0 ...
0a 0c 01 09 65 00 80 0b ........ 28 0c 01 09 65 00 80 ...
0a 0c 01 09 64 09 e0 0b ........ 28 0c 01 09 64 09 80 ...
0a 0c 01 09 64 08 80 0b ........ 28 0c 01 09 64 08 80 ...
0a 0c 01 09 64 07 a0 0b ........ 28 0c 01 09 64 07 80 ...
0a 0c 01 09 64 06 c0 0b ........ 28 0c 01 09 64 06 80 ...
0a 0c 01 09 64 05 e0 0b ........ 28 0c 01 09 64 05 80 ...
0a 0c 01 09 64 04 80 0b ........ 28 0c 01 09 64 04 80 ...
0a 0c 01 09 64 03 a0 0b ........ 28 0c 01 09 64 03 80 ...
0a 0c 01 09 64 02 c0 0b ........ 28 0c 01 09 64 02 80 ...
0a 0c 01 09 64 01 e0 0b ........ 28 0c 01 09 64 01 80 ...
0a 0c 01 09 64 00 80 0b ........ 28 0c 01 09 64 00 80 ...
         ...                             ...
0a 0c 01 09 64 04 a0 0b ........ 28 0c 01 09 63 04 80 ...
         ...                             ...
-------------------- state == stopped -------------------
------------(high nibble A5, B5 0b110 -> 0b10)-----------
------------(bit 6 in byte A5, B5 == flag bit)-----------

0a 0c 01 09 23 04 a0 0b ........ 28 0c 01 09 23 04 80 ...
         ...                             ...
---------------- state == running | stopped -------------
------------(if A3, B3 == 0x0f, then A7, B7 -> 80)-------
------------(A3, B3 == 0x0f == no digit displayed)-------
         ...                             ...
0a 0c 0f ** ** ** 80 0b ........ 28 0c 0f ** ** ** 80 ...
         ...                             ...

0x0a << 2 == 0x28. Is that just coincidence? Or are some bits handled improperly?

It would appear that A7 and B7 are 8 bit CSUM values. However, when the following CSUM calculation is done as specified in the documentation:

CSUM = lo_ADDR ^ hi_ADDR ^ sub_ADDR ^ DATA_0 ^ DATA_1 ^ DATA_2 ^ DATA_3
0x62 =   0xa   ^   0x0   ^   0x0c   ^  0x01  ^  0x09  ^  0x65  ^  0x09
0x62 =   0x8   ^   0x2   ^   0x0c   ^  0x01  ^  0x09  ^  0x65  ^  0x09   

The calculated value doesn't match A7 or B7. However:

"The CSUM byte is then split into 2 bytes, 0xAX (low nibble) and 0xBX (high nibble)"

I've tried https://crccalc.com as well as others, thinking that the calculation in the specification is incorrect, however I can't get any matches on any 8-bit CSUMs that I've tried.

I think I'm missing something obvious, as I'm quite an amateur. I'm really trying to understand what's happening, where I've gone wrong, and not just get my problem solved. I'm now two days into trying to figure this out, and I just can't get it.

Quesion two: Are those fields actually checksums, if they are, how are they calculated?

Question three: If they're not, what are they?

Question four: Why would some packets appear to be missing (or have a different) start and stop flag bytes? (EDIT: Most likely because the specification I have is wrong)


(EDIT) The CSUM calc in the spec does not apply to my data.

Check sum calculation spec, verbatim from documentation:

CSUM = LOW ADDR
CSUM = CSUM XOR'ed with HIGH ADDR
CSUM = CSUM XOR'ed with SUB ADDR
CSUM = CSUM XOR'ed with Data0
..
CSUM = CSUM XOR'ed with DataN (the last data-byte)
The CSUM byte is then split into 2 byte, 0xAn (low nibble) and 0xBn (high nibble)

Some interesting patterns which seem to hold throughout my data set:

  1. if A3,B3 == 0x0f then A7,B7 == 0x80
  2. High nibble A5,B5 == 0x6 | 0x2: change does not seem to affect A7,B7
  3. if A6,B6 == 0x00 then A7,B7 == 0x80

(EDIT) UPDATE: You know, the more I think about it and look around the internet, this system shares many similarities with DMX protocol. This system was made to work with many devices daisy-chained together.

  1. One-to-many connection, with termination required at the end
  2. 0x00 break on every line, similar to lo value inter-packet (line?) break, bursts of data about once a second
  3. possibly no error correction at all
  4. used to control a "lighting" device (7-segment display)
  5. others ...?

[1] "The Texas Instruments seven-segment display decoder chips 7446/7447/7448/7449 and 74246/74247/74248/74249 and the Siemens FLH551-7448/555-8448 chips used truncated versions of "2", "3", "4", "5" and "6" for digits A–E. Digit F (1111 binary) was blank." - wikipedia, 7-segment display

5
  • 1
    "However, when the following CSUM calculation is done as specified in the documentation:" - are you sure you interpreted it correctly? Can you show us the full specification? Commented Feb 25, 2019 at 2:27
  • 1
    The specified packet format has 9 bytes, but your packets only have 8 and 7 bytes. So where did the extra bytes go, and where are you getting hi_ADDR from? According the spec hi/low address bytes start with high nibbles 8/9 and hi/low checksum bytes start with A/B, but your data does not have this. Clearly the spec does not match your data, so either it's 'outdated' or the data is corrupt. Commented Feb 25, 2019 at 18:57
  • do you have access to the code on either sending or receiving side? might be easier to RE it than trying to guess the algorithm.
    – Igor Skochinsky
    Commented Feb 25, 2019 at 20:41
  • @BruceAbbott Yes, it would appear that the spec doesn't match. I'm pretty sure the data is not corrupt, I checked all the packets' duplicates and found no difference. The start and end bytes match on all subsequent packets, and the data inside DATA0...n matches the true values, which are known. I'll update the first post
    – r a
    Commented Feb 26, 2019 at 7:27
  • @IgorSkochinsky I'll see if I can get the code used to record this stream. The source of the stream is a hardware device, used to drive 7-segment style dumb display.
    – r a
    Commented Feb 26, 2019 at 7:27

1 Answer 1

2

The protocol spec clearly does not apply to your device, so don't bother trying to use its checksum calculation. However it may be similar enough to provide some clues to the actual protocol.

The protocol should include some method of synchronizing the serial data stream. In the (incorrect) spec this could be done using the high nibbles (8,9,A,B) that all have bit 7 set. In your data only bytes A7 and B7 have bit 7 set, which suggests that this bit is used for synchronization.

Bytes A4-A6 and B4-B6 appear to be digit and flag data. Bytes A2 and B2 match the fixed value for sub_ADDR in the spec, which suggests they perform the same function.

A1,A3,A8,B1,B3 and bits 6-0 of A7 and B7 are unaccounted for. A1,A3,B1,B3 may be the high and low address nibbles, and A8 appears to be a constant value. Bits 2-0 of A7 and bits 3-0 of B7 are always 0 in your data, which leaves bits 6-3 of A7 and bits 6-4 of B7 as potential checksum bits.

As the digits are different on each line, so the checksum should also be different (though some lines may produce the same checksum). Combining A7 bits 6-3 and B7 bits 6-4 to produce a single 7 bit Hex number,

A7   A7    B7   B7   B7+A7
   (6..3)     (6.4)  (Hex) (ID#)
d8  1011   e0  110    6B     1
c0  1000   80  000    08     2
a8  0101   a0  010    25     3
90  0010   c0  100    42     4
f8  1111   e0  110    6F     5
e0  1101   80  000    0B     6
c8  1001   a0  010    29     7
b0  1010   c0  100    4A     8
98  0011   e0  110    63     9
80  0000   80  000    00     10
e0  1100   80  000    0C     11
80  0000   80  000    00    (10)
a0  0100   80  000    04     12
c0  1000   80  000    08     (2)
e0  1100   80  000    0C    (11)
80  0000   80  000    00    (10)
a0  0100   80  000    04    (12)
c0  1000   80  000    08     (2)
e0  1100   80  000    0C    (11)
80  0000   80  000    00    (10)

The first 11 lines in your data dump all have unique 'checksums'. Looking good so far!

The next 9 lines are not so good, as they have many duplicate values. However I have not attempted to calculate checksums of address and data bytes. Depending on the algorithm used, some lines may be expected to produce the same checksum.

For a thorough analysis I would capture more data with as many different digit and flag combinations as possible, then write a program to create checksums with various algorithms until one matches the bits in A7 and B7.

2
  • Wow, thanks! I just realized that I have failed to mark in my op that the low nibbles of bytes A3-A6 are indeed simple BCD that represent clock values. So in my first example, 0a 0c 02 00 60 00 80 0b == "20:00" I can't believe I left out that critical info. I'll edit the op.
    – r a
    Commented Feb 27, 2019 at 8:59
  • I have made a pastebin which includes the data set I am working with. The format is: EPOCH [DATA] The data was captured on approximately one second intervals. pastebin.com/QuEqVns4
    – r a
    Commented Feb 27, 2019 at 9:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.