Page 1 of 1

Help needed to find checksum method

Posted: 07 Apr 2012 00:59
by ai_pic_oz
Hello Fellow MikroC users

I have been working on a project to control my 1/16 scale Heng Long RC tank from the PC using
either a joystick or keyboard by tapping into the PCM signal path of the RC transmitter by using
a PIC to receive rs232 data and then encoding the 4 bytes to manchester format for the heng long
transmitter.

This part works fine except I do not have proportional speed control and or using other functions at
the same time, ex moving forward and rotating the turret, unless I can set particular bits and then
calculate a 4 bit checksum.

I have written a time based manchester decoder to decode the tx PCM signals and getting
4 x 4byte codes, for example the ignition code for the tank is 0xFE3C10B0 and the idle signal
is 0xFE3C0F00 which is continually sent, I have also recorded other 4 byte codes to do other functions
such as rotate turret, fire machine gun etc

Below is the programme I wrote, it's not entirely accurate as the PCM bit times vary a bit
I recorded the 4 byte codes as I pressed the transmitter keys and moved the transmitter pots etc.

my encoding programme to send the 4byte codes works fine no problems.

//pic 16f1827 manchester encoding programme

unsigned char data_bit, bitcnt, data_rdy, first_bit;
unsigned char decode, encode, gtime;
unsigned int led_cnt, gcnt;
unsigned long data_in, temp;
unsigned int TMR1 absolute 0x16;

void interrupt()
{
if ((INTCON.INTF == 1) && (INTCON.INTE == 1) && (OPTION_REG.INTEDG == 1)) // RB0 interrupt on rising edge should be start
{
INTCON.INTF = 0; // clear RB0 interrupt flag

if (first_bit == 1)
{
INTCON.INTE = 0; // disable RB0 interrupt
TMR1 = 64943; // set timer1 for 150us interrupt
decode = 0;
PIE1.TMR1IE = 1; // enable timer1 interrupt
T1CON.TMR1ON = 1; // start TMR1 timer
PIR1.TMR1IF = 0; // clear timer1 interrupt flag
}

if (first_bit == 0) first_bit = 1; // wait for actual first data bit

}

if ((PIR1.TMR1IF == 1) && (PIE1.TMR1IE == 1)) // TMR1IF and TMR1IE should both be set
{
PIR1.TMR1IF = 0; // clear TMR1IF
if (decode == 1)
{
if (PORTB.B0 == 1) data_bit = 1; else data_bit = 0;
data_in = data_in << 1;
data_in = data_in + data_bit;
bitcnt++;
if (bitcnt < 16) TMR1 = 63223; else TMR1 = 63233; // set timer1 for 580us & 585us interrupts
}

if (decode == 0)
{
TMR1 = 63223;
decode = 1;
}
}
}

void main(void)
{
OSCCON = 0x7A; // use 0x7A if using internal osc 16mhz
PORTA = 0; // use 0x70 for 8mhz
ANSELA = 0; // PORTA all digital i/o
TRISA = 0xFF; // set PORTA to inputs

PORTB = 0;
ANSELB = 0; // PORTB all digital i/o
TRISB = 0xCD; // b11001101
INTCON = 0; // clear all interrupts
OPTION_REG = 194; // TMR0 prescaler set 1:8
OPTION_REG.INTEDG = 1; // RB0 interrupt set on rising edge

APFCON0.CCP1SEL = 0; // select RB3 as CCP1
APFCON0.RXDTSEL = 0; // select RB1 as RX
APFCON1.TXCKSEL = 0; // select RB2 as TX

T1CON.T1CKPS1 = 0; // set timer1 prescaler to 1/1
T1CON.T1CKPS0 = 0; // set timer1 prescaler to 1/1
T1CON.TMR1CS1 = 0; // TMRCS1
T1CON.TMR1ON = 0; // set timer1 off

data_bit = 0;
data_in = 0; // preload data_in with the first three ones
bitcnt = 0;
decode = 0;
encode = 0;
first_bit = 0;

INTCON.GIE = 1; // enable GIE, PEIE , disable TMR0IE, INTE interrupts
INTCON.PEIE = 1;
INTCON.TMR0IE = 0; // disable TMR0 interrupt
INTCON.INTE = 0; // disbale RB0 interrupt
PIE1.TMR1IE = 0; // disable timer1 interrupt
PIR1.TMR1IF = 0; // clear TMR1IF
INTCON.INTF = 0; // clear RB0 interrupt flag

UART1_Init(19200);

while(1)
{
mloop: // looking for the guard time about 4ms

gcnt = 0;
while (PORTB.B0 == 1);
while (PORTB.B0 == 0)
{
gcnt++;
delay_us(10);
}
if (gcnt < 120) goto mloop;

txloop:

INTCON.INTE = 1; // found guard time enable RB0 interrupt on rising edge

while (bitcnt < 32);

INTCON.INTE = 0; // disbale RB0 interrupt
INTCON.INTF = 0; // clear RB0 interrupt flag
PIE1.TMR1IE = 0; // disable timer1 interrupt
PIR1.TMR1IF = 0; // clear TMR1IF
T1CON.TMR1ON = 0; // turn TMR1 timer off


if ((Highest(data_in) == 0xFE))
{
UART1_Write(Highest(data_in));
UART1_Write(Higher(data_in));
UART1_Write(Hi(data_in));
UART1_Write(Lo(data_in));
UART1_Write(10);
}

bitcnt = 0;
data_bit = 0;
decode = 0;
data_in = 0;
first_bit = 0;

goto mloop;
}
}


My problem is finding out what checksum method is used, if I want to simulate exactly what the
transmitter sends, for example proportional speed control and rotating turret at the same time
then I need to set the relevant bits and then calculate the checksum and send the 4 bytes.

I have tried online crc calculators using CRC4 to no avail, I have tried LRC checksum by
adding every 4bits then 2's compliment no success, even tried xoring 8bit, 5bit and 4bit codes
again no success.

In the image file attachment, the first two bits of the PCM signal which is 11 is an illegal manchester
code, so I don't know if that is included in the checksum calculation, I have tried by assuming different
values for the first two 11 bits but I get know where.
hl codes.JPG
hl codes.JPG (242.24 KiB) Viewed 1725 times
I am hoping that some checksum genius out there can steer me in the right direction or provide a
solution.

regards Andrew

Re: Help needed to find checksum method

Posted: 20 Jun 2012 03:06
by tamato
Hi Andrew!

Not sure if you are still working on this (apologies if I revived a dead thread)
but you should not give up, if only because I am pretty much in the same boat;

I have same data that looks like:

f(161) = 53
f(169) = 53
f(160) = 55
f(168) = 55
f(170) = 59
f(174) = 59
f(171) = 61

really, it is an 8 byte checksum (RHS), and these results are for just one byte (LHS, between the f() ) in an unknown # of input bytes (my estimate is 3-9) that the checksum is generated from,
but I at least know that for these examples, the input data only differed in a single byte, so I figured solving this would be simpler than solving
f(unknown size data) = 8 bytes
all at once.

I can not directly run the algorithm on input data of my choosing, although I can
somewhat control what gets fed in; the above I at least know for certain, the
input data should only differ by a single byte, because I ensure all the other potential
input bytes are the same (even if I don't know which are relevant, I know this
one byte anyway DOES influence the checksum)

anyway, the best things I've found so far:

http://www.cosc.canterbury.ac.nz/greg.e ... ering.html
http://www.tty1.net/pycrc/index_en.html
http://regregex.bbcmicro.net/#prog.reveng

the first link describes some methods and processes of attack;

the second link is a python crc checker that allows you to input the parameters
(brute force of crc or any other algorithm will always work; it is merely a minor detail
of will it find the result while you are still alive or not )

the third link is CRCRevEng, which is an update of a perl script crcbfs.pl which you might
see references to; it is by the same author, and claims to be much faster

any thing you can do to narrow down the CRC parameters (see the first link) will help.
there are also tests to be sure it is really a CRC algorithm.

in my case, all I know is the algorithm I am working with is "nonstandard"
(could be a common algorithm, just unpopular parameters) and that is the
only documentation.

anyways, good luck, and if you have/had any luck, certainly let me know which approach
worked for you :) or if you gave up, may this post spark you to continue :)