4

I'm trying to build a simple Arduino-based IR remote control for a cheap toy IR-controlled helicopter (same as this one - it's called "Diamond Gyro" or "Diamond Force"). I've decoded the IR protocol except for the last few bits. These last bits seem to be a check or CRC, but I haven't been able to "crack" it.

It's easy enough to simply repeat a recorded packet, but I want to fully control the helicopter. That means reverse-engineering the check bits.

(I should add that I do software by day, but electronics is a sometimes-hobby, so maybe I'm just missing something very basic.)

The details of the protocol are in the question and answer, but here are the basics:

  • 32 bit packet spanning multiple individual values/commands of varying length (plus 1 start bit/preamble, which doesn't count as data)
  • The values are little endian (MSB first)
  • I'm positive I've got the first 22 bits mapped...
  • ... but the following 4 bits are a little mysterious, although I know the purpose of at least 2 of them.
  • The last 6 bits do seem to be a check or CRC of some kind

Here's a diagram

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2
--+---------------------------+-----------+---+---+-+-+-----------
 P|    Yaw    |   Throttle    |   Pitch   | T | C |X|X|  CRC?

P: Preamble (always 1), T: Trim, C: Channel,
X: Either part of the channel data or the checksum.

First of all, I'm not sure whether the X bits are part of the channel value, part of the check, or something else. They always follow the channel value though, so it's likely the channel value is 3-4 bits wide, although 2 bits would be sufficient for the 3 possible channel values.

Second, there are the last 6 bits (marked CRC? above) which are clearly some kind of check (and indeed, the helicopter doesn't respond if I change any of those bits).

So basically, there's a packet of 24-26 data bits, followed by 6-8 check bits. And I'd really like to figure those check bits out so I can compose packets myself.

Below are a bunch of samples of the binary data I'm getting. The preamble "1" is always present, and I don't believe it counts as part of the data, but I've included it anyway, just in case it's the key to everything.

Again, I don't know if the X bits are part of the data or the check. Depending on the way the check's calculated, it might be that the first 1-2 bits of the check just happen to follow the channel value. But it's also quite possible that the channel value is 4 bits long, incorporating the X bits. Or it's in between with one X bit being part of the channel, and the other being part of the check. I don't know.

If anyone knows what that check is, or how I could go about finding out, I'd love to know. I imagine I can brute-force it, but even if that's the only option, I'd love to hear some hints for how to best do that.

The helicopter is dirt cheap, so I doubt there's anything really fancy going on.

Channel A                                                       
P  Yaw     Throttle  Pitch   Tr  Ch  XX  Check     Description
--------------------------------------------------------------
1  000100  10000100  000000  00  01  01  000101    Left Mid + throttle 
1  000000  10000110  010001  00  01  01  010010    Left Max + throttle 
1  100001  10000110  000000  00  01  01  100010    Right Mid + throttle 
1  100100  10000100  010001  00  01  01  110100    Right Max + throttle
1  010001  00000000  001011  00  01  01  011111    Forward Min 
1  010001  00000000  000000  00  01  01  010100    Forward Max 
1  010001  00000000  011000  00  01  01  001100    Back Min 
1  010001  00000000  100101  00  01  01  110001    Back Max
1  010001  00000000  010001  01  01  01  010101    Left Trim 
1  010001  00000000  010001  10  01  01  100101    Right Trim 
1  010001  00000011  010001  00  01  01  000110    Throttle 01 (min)
1  010001  00010110  010001  00  01  01  010011    Throttle 02
1  010001  00011111  010001  00  01  01  011010    Throttle 03
1  010001  00101111  010001  00  01  01  101010    Throttle 04
1  010001  00111110  010001  00  01  01  111011    Throttle 05
1  010001  01010101  010001  00  01  01  010000    Throttle 06
1  010001  01011111  010001  00  01  01  011010    Throttle 07
1  010001  01101100  010001  00  01  01  101001    Throttle 08
1  010001  01111010  010001  00  01  01  111111    Throttle 09
1  010001  10000101  010001  00  01  01  000000    Throttle 10 (max)

Channel B
P  Yaw     Throttle  Pitch   Tr  Ch  XX  Check     Description
--------------------------------------------------------------
1  000000  10000110  010001  00  00  10  010101    Left Max + throttle 
1  100100  10000110  010001  00  00  10  110001    Right Max + throttle 
1  010001  00000000  001001  00  00  10  011010    Forward Min 
1  010001  00000000  000000  00  00  10  010011    Forward Max 
1  010001  00000000  010111  00  00  10  000100    Back Min 
1  010001  00000000  100110  00  00  10  110101    Back Max
1  010001  00000000  010001  01  00  10  010010    Left Trim 
1  010001  00000000  010001  10  00  10  100010    Right Trim 
1  010001  00000001  010001  00  00  10  000011    Throttle Min 
1  010001  00110100  010001  00  00  10  110110    Throttle Mid 
1  010001  01100111  010001  00  00  10  100101    Throttle High 
1  010001  10001111  010001  00  00  10  001101    Throttle Max 

Channel C
P  Yaw     Throttle  Pitch   Tr  Ch  XX  Check     Description
--------------------------------------------------------------
1  000000  10000101  010001  00  10  00  011100    Left Max + throttle
1  100100  10000101  010001  00  10  00  111000    Right Max + throttle 
1  010001  00000000  001010  00  10  00  010011    Forward Min 
1  010001  00000000  000000  00  10  00  011001    Forward Max 
1  010001  00000000  010111  00  10  00  001110    Back Min 
1  010001  00000000  100110  00  10  00  111111    Back Max
1  010001  00000000  010001  01  10  00  011000    Left Trim 
1  010001  00000000  010001  10  10  00  101000    Right Trim 
1  010001  00000001  010001  00  10  00  001001    Throttle Min 
1  010001  00110100  010001  00  10  00  111100    Throttle Mid 
1  010001  01100110  010001  00  10  00  101110    Throttle High 
1  010001  10000101  010001  00  10  00  001101    Throttle Max
Flambino
  • 293
  • 1
  • 11

3 Answers3

7

First of all, it's pretty clear that the "XX" bits are part of the channel designation, since that's the only thing they depend on. The "XX" bits may simply be a check on the "Ch" bits.

The check bits are a simple bitwise XOR of 24 of the 26 data bits: If you take the 6 Yaw bits, the 6 LSBs of the Throttle, the 6 Pitch bits, and the next 6 bits, and XOR these quantities together, you get the 6 check bits. It appears that the upper 2 bits of the Throttle do not affect the check bits at all.

The following Perl script verifies this.

#!/usr/bin/perl

# crc.pl - verify decoding of check bits

# On the lines starting with '1', just keep the '0's and '1's in an array. 
while (<>) {
    my @letters = split '', $_;
    next unless $letters[0] eq '1';
    @letters = grep /[01]/, @letters;
    @letters = @letters[1..32];
    $a = string2bin (@letters[0..5]);
    $b = string2bin (@letters[8..13]);
    $c = string2bin (@letters[14..19]);
    $d = string2bin (@letters[20..25]);
    $e = string2bin (@letters[26..31]);
    $f = $a ^ $b ^ $c ^ $d;
    printf "%02X %02X %02X %02X %02X %02X %s\n", $a, $b, $c, $d, $e, $f,
        $e == $f ? '-' : '###';
}

sub string2bin {
    my $temp = 0;
    for (@_) {
        $temp = ($temp << 1) + ($_ eq '1' ? 1 : 0);
    }
    $temp;
}
Dave Tweed
  • 168,369
  • 17
  • 228
  • 393
  • Perfect! And: The helicopter agrees! I suppose I should've seen the XOR scheme myself, but, like with the protocol decoding, I think I tricked myself into thinking it was more complicated than it actually was. Thank you! That was the last piece of the puzzle, I believe – Flambino Dec 28 '13 at 22:34
  • Just to follow up on @Olin's comments -- scripting languages like Perl make it easy to manipulate the data and test hypotheses in the algorithmic way he's suggesting. That's why I included my script here, as a demonstration. I've been using Perl since the late 1980s, so that's what I turn to, but all of the modern scripting languages are about equally capable for this sort of thing. It just so happened that the first thing I tried was correct. I had previously scanned through the data by eye and found a few lines that were different in only a few bits. – Dave Tweed Dec 28 '13 at 23:40
  • Personally, I turn to Ruby (never been into Perl much, but I've got no trouble understanding your script). I used Ruby to do the software demodulation/envelope detection of the IR signal from raw timing data (as I was reading directly from the controller's IC, not a receiver), working out the protocol specifics, and even generating some graphics for my earlier question. I also tried some things to crack the check bits myself, but I was working from the wrong assumptions (i.e. CRC). Needed fresh eyes - yours, in this case - on the data itself. – Flambino Dec 29 '13 at 00:59
3

I don't see a immediately obvious pattern, so I would attack this more algorithmically. You apparently have the ability to capture a large number of packets, then use some automated way to get them into a computer. I would capture a large number while slowly varying the controls.

After you have a pile of packets in a file, write some code to crack the code. Think of it as a cryptography problem. One of the first things I'd do is to look for pairs of packets that only vary in one bit. That should tell you right away if you have a simple checksum or something more complicated like a CRC. If a basic checksum, then the checksum of such packet pairs should only vary by having a power of 2 added to it. If a whole bunch of bits vary in a unpredictable way, then you probably have a CRC.

If it's a basic sum, then after you get a few single-bit changes you should be able to figure out how each field is added into the checksum. If it looks like a CRC, then I'd probably do a exhaustive search next. It's only a 6 bit checksum, so there are only 64 possible polynomials. There could be up to 64 different start values, but usually you start a CRC with the high bit set and the other bits 0. New bits could be shifted from either end. Probably, at least if whoever designed the CRC knew what they were doing, then if you run the whole packet thru the CRC the result should be 0. The number of combinations is small enough that a exhaustive search by machine should find the answer instantly in human time if it really is a usual CRC.

Added:

I just saw Dave Tweed's answer where he has shown this is even simpler than a sum, just XOR of the fields. There are a lot of lazy engineers out there. I would have done this with a CRC, which is really very easy to compute.

I'll leave my answer here as a description of how to attack something like this when you don't see a pattern by inspection. If you had used this method, you would have seen that single bit changes in the data would have resulted in single bit changes in the checksum, which would have immediately pointed to a XOR scheme.

Olin Lathrop
  • 310,974
  • 36
  • 428
  • 915
  • Thanks again! Before Dave Tweed found the simpler answer, this is the sort of answer I was hoping for. I had been looking into brute-forcing CRC checks, but found few practical guides (instead I mostly found complications, like whether to reverse the input/output, and of course I wasn't sure about those `X` bits at the time). As for changing a single bit and looking at the check, I would've liked to try that, but it would've required some work with this cheap-o controller. Would've had to mod it a bit to get that kind of resolution. – Flambino Dec 28 '13 at 22:46
  • As for lazy engineers: That's sort of why I thought it'd be a CRC. Easy to implement, as you say. Oh, well – Flambino Dec 28 '13 at 22:47
2

About the XX: like Dave points out, they seem to be part of the channel information, since they are always the same for a given channel. They're not really required; like you said you can encode 3 channels with just 2 bits, but the given 4 bits allow a Hamming distance of 2. This means that the codes for the channels are always at least 2 bit changes apart; changing a single bit doesn't result in a valid channel code. Together with the checksum this increases reliability.

flup
  • 902
  • 7
  • 14