Dangerous Prototypes

Dangerous Prototypes => USB Infrared Toy => Topic started by: liyin on August 11, 2010, 12:47:48 am

Title: Getting RC5 Address:Command from Hex Code
Post by: liyin on August 11, 2010, 12:47:48 am
I was trying to decipher how the IR Toy RC5 routine comes up with the hex numbers below, I believe the pause key in my remote is RC5 command number 41 (obtained from LIRC's hex code output):

{05}{69}{00}{00}{00}{00} {05}{69}{00}{00}{00}{00}

05 = VCR
69 = Pause?

Code: [Select]
void ProcessIR(void){   
static unsigned char i;
//static unsigned char rc5x, toggle, addr, cmd;
if((decoderState==SEND) && (USBUSARTIsTxTrfReady())){
//process IR data (decode RC5)
//rc5x=irToy.s[0]; //0 second start bit, use below
//toggle=irToy.s[1]; //1 toggle bit, discard
                            ...
//irToy.usbOut[0]=addr;       <===  addr
//irToy.usbOut[1]=cmd;       <===  cmd
irToy.usbOut[2]=0x00;//four extra bytes for 6 byte IRMAN format
irToy.usbOut[3]=0x00;
irToy.usbOut[4]=0x00;
irToy.usbOut[5]=0x00;
putUSBUSART(irToy.usbOut,6);
                            ...
}
}
Title: Re: Getting RC5 Address:Command from Hex Code
Post by: rsdio on August 11, 2010, 03:37:19 am
If you look online at the various descriptions of RC-5, you'll note that the protocol has a 5-bit address and 6-bit command.  There's no reason to assume that the bits will line up conveniently in 8-bit bytes.

Looking at your example, 0x41 fits into the lowest 6 bits of 0x69.  If you take the next 5 bits you get an address of 0x15, which is supposedly Phono.

But I haven't actually tried to decipher the IR decoder mode since I use IRIO mode.  I can't even remember why it is 5 bytes long instead of only 2 or 3.

You could try looking at the USB IR Toy firmware source code!
Title: Re: Getting RC5 Address:Command from Hex Code
Post by: liyin on August 11, 2010, 05:02:57 am
The code above is from the RC5 decoder in the firmware. I see the general idea, but not the detail. Is easy to spot the trailing 00's in the array, but not where the 05h and the 69h come from (RC5 VCR Pause).


RC5 Protocol  (VCR Pause = 41 = 101001;  TV 1 = 1 = 000001):

Start / Field / Toggle / Address (x5) / Command (x6) Bits

1 1 0|1 00101 101001  =  VCR Pause
1 1 0|1 00000 000001  =  TV 1


LIRC (with toggle bit):

[VCR Pause]
1169h 00h       I expected something like this:    1169h
1169h 01h                                                           1969h

10 00101 101001 = 1169h (toggle bit 0)
11 00101 101001 = 1969h (toggle bit 1)

[TV 1]
1001h 00h       I expected something like this:    1001h
1001h 01h                                                           1801h

10 00000 000001 = 1001h (toggle bit 0)
11 00000 000001 = 1801h (toggle bit 1)


IR Toy:

{05}{69}{00}{00}{00}{00} {05}{69}{00}{00}{00}{00}

05h           69h
00000101 01101001

05h = VCR
69h = 01 101001?

For TV "1" the output is:

{00}{41}{00}{00}{00}{00} {00}{41}{00}{00}{00}{00}

00000000 01000001

00h = TV
41h = 01 000001?

IR Toy seems to append a leading 01b to the 6-bits RC5 command, which I realize now must be the RC5x bit, but it doesn't agree with the comment in the source, it is either bit 2 or bit 7 (of 8), and for RC5 seems to be "1":

Quote
// Sends a 6 byte packet:
// RC5 address byte (0)
// RC5 command byte (1) *bit 6 is RC5x bit
// Bytes 2-5 are 0 padding
Title: Re: Getting RC5 Address:Command from Hex Code
Post by: ian on August 11, 2010, 09:39:08 am
The short answers, I think:
Quote
it is either bit 2 or bit 7 (of 8)
You seem to count bits from 1, they are usually counted from 0.

Quote
IR Toy seems to append a leading 01b to the 6-bits RC5 command
I'm not sure, but do you expect 11bits stuffed into two bytes MSB first: 11111111-111xxxxx (where 1 are the data bits and x are don't care)? The data is actually fully decoded and sent with the 5bit address in the first byte and 6bit command in the second byte.

After the analysis below, I think the comments at the top of the code are correct:
Quote
// IRman compatible RC decoder for RC5, RC5x
// Sends a 6 byte packet:
// RC5 address byte (0)
// RC5 command byte (1) *bit 6 is RC5x bit
// Bytes 2-5 are 0 padding

but to clarify, I added this:

Code: [Select]
		//final USB packet is:
//byte 1 bits 7-5 (don't care)
//byte 1 bits 4-0 (5 address bits)
//byte 2 bit 7 (don't care)
//byte 2 bit 6 (RC5x/start bit 2, not inversed)
//byte 2 bits 5-0 (RC5 6 bit command)
//byte 3-6 (unused)

Also, the USB IR Toy implementation does not inverse the 6th data bit for RC5x as it should, giving the leading 1 (or as you say 01).

---------------
Hey liyin - The comments could very well be wrong, this code has been through a lot of revisions and development.

I'm having a really hard time understanding your last post though, what do you mean by expected? What is the source of the LIRC data? Why does your RC5 example seem to have 3 start bits?

Code: [Select]
IR Toy seems to append a leading 01b to the 6-bits RC5 command

Are you expecting everything crammed into the least number of bits? The address and command are each placed into a 8bit byte variable, the bits are not aligned in a big long string.

Let's take a look at the code for any bugs.

The bits are put into an array, one per byte, in the interrupt routine:
Code: [Select]
                        case BIT_PERIOD_0:
                                RC5.bp0=IRX;
                                decoderState=BIT_PERIOD_1;
                                break;
                        case BIT_PERIOD_1:
                                RC5.bp1=IRX;

                                if(RC5.bp0==1 && RC5.bp1==0){
                                        irToy.s[RC5.bcnt]=1;
                                }else if (RC5.bp0==0 && RC5.bp1==1){
                                        irToy.s[RC5.bcnt]=0;
                                }else{//error                  
                                        decoderState=IDLE; //reset
                                        T2ON=0; //timer off
                                        IRRX_IE=1;      //IR interrupts back on
                                        break;
                                }

                                decoderState=BIT_PERIOD_0;

                                RC5.bcnt++;                    
                                if(RC5.bcnt==13){//done sampling
                                        decoderState=SEND; //process and send in service loop
                                        T2ON=0;//turn off the timer
                                }
                                break; 
 

A timer fires and it alternates between storing a sample of each bit period in RC5.bp0/1. This decodes the RC5 manchester encoding. 10=1; 01=0; else error. The resulting data bits are put into irToy.s[] array, one bit per byte.

At this point you have:
irToy.s[0]=S2 (RC5x bit)
1=toggle bit
2-6 = 5bit address
7-12 = 6bit command

The magic actually happens in the loops you removed (...) from the processIR function. Let's take a look at that now:

Code: [Select]
void ProcessIR(void){   
        static unsigned char i;
        //static unsigned char rc5x, toggle, addr, cmd;

        if((decoderState==SEND) && (USBUSARTIsTxTrfReady())){
       
                //process IR data (decode RC5)
                //rc5x=irToy.s[0]; //0 second start bit, use below
                //toggle=irToy.s[1]; //1 toggle bit, discard

                irToy.usbOut[0]=0; //addr=0; //address is first byte of 6 byte packet
                for(i=2;i<7;i++){ //loop through and assemble 8 address bits into byte
                        irToy.usbOut[0]<<=1;
                        irToy.usbOut[0]|=irToy.s[i];                                   
                }

                irToy.usbOut[1]=irToy.s[0]; //command is second byte
                                                                                          // optional rc5x bit is bit 6
                for(i=7;i<13;i++){ //assemble 6 command bits into byte
                        irToy.usbOut[1]<<=1;
                        irToy.usbOut[1]|=irToy.s[i];
                }


                //irToy.usbOut[0]=addr;
                //irToy.usbOut[1]=cmd; 

                irToy.usbOut[2]=0x00;//four extra bytes for 6 byte IRMAN format
                irToy.usbOut[3]=0x00;
                irToy.usbOut[4]=0x00;
                irToy.usbOut[5]=0x00;  

                putUSBUSART(irToy.usbOut,6);

                decoderState=IDLE;//wait for more RC commands....
                IRRX_IE=1;//interrupts back on 

        }

}      

This is the entire function. The two loops are the most important part.

Code: [Select]
                irToy.usbOut[0]=0; //addr=0; //address is first byte of 6 byte packet
                for(i=2;i<7;i++){ //loop through and assemble 8 address bits into byte
                        irToy.usbOut[0]<<=1;
                        irToy.usbOut[0]|=irToy.s[i];                                   
                }

Here's how the device address works, from SB projects RC5 page:
http://www.sbprojects.com/knowledge/ir/rc5.htm (http://www.sbprojects.com/knowledge/ir/rc5.htm)
Quote
The next 5 bits represent the IR device address, which is sent with MSB first.

In the first loop the address byte is assembled. The USB output buffer is first set to 0, then each of the address bits (irToy.s[2]-6) is shifted into the USB output buffer MSB first.

Now we have the address byte in irToy.usbOut[0], we can build the command byte in irToy.usbOut[1]:
Quote
The address is followed by a 6 bit command, again sent with MSB first.

We also need to consider the RC5x command bit if we want to support 7bit commands too:
Quote
Bit S2 is transformed to command bit 6, providing for a total of 7 command bits. The value of S2 must be inverted to get the 7th command bit though!
Well, that's a small IR Toy bug because I don't think it inverts the RC5x bit, but since each IRman decoder is unique, it shouldn't 'break' any functionality.

Code: [Select]
                irToy.usbOut[1]=irToy.s[0]; //command is second byte
                                                                                          // optional rc5x bit is bit 6
                for(i=7;i<13;i++){ //assemble 6 command bits into byte
                        irToy.usbOut[1]<<=1;
                        irToy.usbOut[1]|=irToy.s[i];
                }

Remember that the 6bit command byte is now in irToy.s[7]-[12], and the second start bit is in irToy.s[0]. In this loop, instead of starting with 0, we load the RC5x bit into the MSB position and then add the lower 6bits from [7]-[12] in the loop.

Technically speaking, the first line should be
Code: [Select]
 irToy.usbOut[1]=(~irToy.s[0]);
to reverse this bit as per the SBprojects description.

The rest of the function just adds the trailing 0s and sends the packet to USB. The final packet is:
irToy.usbOut[0] = address bits 4...0
irToy.usbOut[1] = command bits 6...0 (bit 6, RC5x bit, is inversed)
bytes 2-5 = 0x00 (unused)

Also, from the updated code:

Code: [Select]
		//final USB packet is:
//byte 1 bits 7-5 (don't care)
//byte 1 bits 4-0 (5 address bits)
//byte 2 bit 7 (don't care)
//byte 2 bit 6 (RC5x/start bit 2, not inversed)
//byte 2 bits 5-0 (RC5 6 bit command)
//byte 3-6 (unused)

Quote
I can't even remember why it is 5 bytes long instead of only 2 or 3.

The packets are 6bytes long because that is the IRman protocol :)

I updated the RC5decoder code and comments in SVN to be a bit clearer, you can see the code here:
http://code.google.com/p/dangerous-prot ... Cdecoder.c (http://code.google.com/p/dangerous-prototypes-open-hardware/source/browse/trunk/USBIRtoy/IRtoy-firmware/RCdecoder.c)

Code: [Select]
//IR signals are first captured in the interrupt loop below
//when the capture is complete, the bits are decoded into bytes and sent to USB from this function
void ProcessIR(void){  
static unsigned char i;

if((decoderState==SEND) && (USBUSARTIsTxTrfReady())){

//process IR data (decode RC5) in irToy.s[]
//byte# | description
//0 second start bit, use as bit 6 in command byte for RC5x protocol support
//1 toggle bit, discard
//2-6 5bit address
//7-12 6bit command

//final USB packet is:
//byte 1 bits 7-5 (don't care)
//byte 1 bits 4-0 (5 address bits)
//byte 2 bit 7 (don't care)
//byte 2 bit 6 (RC5x/start bit 2, not inversed)
//byte 2 bits 5-0 (RC5 5 bit command)
//byte 3-6 (unused)

//first byte of USB data is the RC5 address (lower 5 bits of first byte)
//loop through irToy.s[] and shift the 5bit address into the USB output buffer
//5 address bits, 5-0, MSB first
irToy.usbOut[0]=0; //clear USB buffer byte to 0
for(i=2;i<7;i++){ //loop through and assemble 5 address bits into a byte, bit 4 to bit 0, MSB first
irToy.usbOut[0]<<=1; //shift last bit up
irToy.usbOut[0]|=irToy.s[i]; //set bit 0 to value of irToy.s[i]
}

//second byte of USB data is the RC5 command (lower 6 or 7 bits of second byte)
//for RC5x, the second start bit is used as the MSB of the command (bit 6)
irToy.usbOut[1]=irToy.s[0]; //start with the value of the RC5x bit (bit 6),
//irToy.usbOut[1]=(~irToy.s[0]); //technically this should be inversed, but that would ruin compatibility for exisitng remote profiles
//loop through irToy.s[] and shift the 'normal' 6 command bits, bit 5 to bit 0, into the USB output buffer
//6 command bits, 5-0, MSB first
for(i=7;i<13;i++){ //loop through and assemble 6 command bits into a byte, bit 5 to bit 0, MSB first
irToy.usbOut[1]<<=1; //shift last bit up
irToy.usbOut[1]|=irToy.s[i]; //set bit 0 to value of irToy.s[i]
}

irToy.usbOut[2]=0x00;//four extra bytes for 6 byte IRMAN format
irToy.usbOut[3]=0x00;
irToy.usbOut[4]=0x00;
irToy.usbOut[5]=0x00;

putUSBUSART(irToy.usbOut,6);

decoderState=IDLE;//wait for more RC commands....
IRRX_IE=1;//interrupts back on

}

}
Title: Re: Getting RC5 Address:Command from Hex Code
Post by: liyin on August 11, 2010, 05:59:19 pm
Yes, numbering of bits is 0-7, goig right to left (76543210).

Still the new comment about byte 2 bit 6 says: "bit 2", which seems to refer to 1-8 numbering.

Quote
//byte 2 bit 6 (RC5x/start bit 2, not inversed)

Quote
... sent with the 5bit address in the first byte and 6bit command in the second byte.

It may well be an IRMan protocol thing, I was only noting that the "RC5x/start bit" (01b) is added/appended to the array for byte 2, is not just the RC5 command bits in byte 2, in contrast with byte 1, which doesn't have any extra bits, only the RC5 address bits. Something to be aware of when looking for the RC5 command number (decimal), as table values are unrealiable.

I take it the "RC5x/start bit" indicates RC5 when "1", RC5x when "0" (not inverted).

Why call it a start bit? Start bits make sense in the original bitstream, not in the hex code output (as in RC5 start bits used for Automatic Gain Calibration (AGC) of the receiver).

Thanks for the info Ian, I'm still reading the last part of your post.

[hr:][/hr:]

Quote
What is the source of the LIRC data? Why does your RC5 example seem to have 3 start bits?

I have a working LIRC config file for my universal remote (Phillips TV code - RC5). I also have LIRC's output in Hercules (TCP).

I'm interested in finding the actual RC5 command values (decimal) for my remote from LIRC's hex codes. I'm using the IR Toy's RC5 output to verify that my interpretation of LIRC's hex codes is correct.

Three start bits? Are you referring to the Start bit (usually discarded) + Field bit + Toggle bit?

Quote
RC5 Protocol  (VCR Pause = 41 = 101001;  TV 1 = 1 = 000001):

Start / Field / Toggle / Address (x5) / Command (x6) Bits

1 1 0|1 00101 101001  =  VCR Pause
1 1 0|1 00000 000001  =  TV 1

[hr:][/hr:]

EDIT:

Ok, dukey pointed out that the LIRC output includes a repeat count next to the LIRC hex code.
Title: Re: Getting RC5 Address:Command from Hex Code
Post by: ian on August 11, 2010, 06:58:25 pm
Quote
Still the new comment about byte 2 bit 6 says: "bit 2", which seems to refer to 1-8 numbering.

Quote
//byte 2 bit 6 (RC5x/start bit 2, not inversed)

Yes, that refers to the second start bit of the manchester encoded RC5 transmission, not the bits in a byte. It doesn't make sense to say 0th start bit. The second start bit of an RC5 transmission is used for the extra RC5x data. The first start bit is always off-on (half ignored), the second is available for data.
Title: Re: Getting RC5 Address:Command from Hex Code
Post by: ian on August 11, 2010, 07:03:14 pm
Quote
I take it the "RC5x/start bit" indicates RC5 when "1", RC5x when "0" (not inverted).

In the IR signal, the second startbit is always 1 for RC5, but can be 0 or 1 in RC5x where is becomes the bit 6 of the RC5 command. SBprojects does a much better job of explaining it:
 http://www.sbprojects.com/knowledge/ir/rc5.htm (http://www.sbprojects.com/knowledge/ir/rc5.htm)
Quote
Why call it a start bit? Start bits make sense in the original bitstream, not in the hex code output (as in RC5 start bits used for Automatic Gain Calibration (AGC) of the receiver).

In RC5 it is just the value of the IR signal startbit, not data. In RC5x the RC5 second startbit is used as part of the command byte.
Title: Re: Getting RC5 Address:Command from Hex Code
Post by: liyin on August 11, 2010, 07:09:52 pm
Quote
Yes, that refers to the second start bit of the manchester encoded RC5 transmission, not the bits in a byte.

Ok, it is the Field bit (Start 2).

In RC5 is always "1", and denotes the lower field commands (0-63), when "0" it denotes the upper field commands in RC5x (64-127).
 

EDIT: You posted before I did. Yes, the field bit is used to extend the number of available commands in Extended RC5, and is not used as a start bit.
 
I knew about the Field bit and the extra commands, but wasn't aware of the name Extended RC5 (RC5x), only RC5 & RC6.
Title: Re: Getting RC5 Address:Command from Hex Code
Post by: rsdio on August 11, 2010, 07:12:18 pm
[quote author="liyin"]In RC5 is always "1", and denotes the lower field commands (0-63), when "0" it denotes the upper field commands in RC5x (64-127).[/quote]In other words, if you invert that bit, it becomes the most significant command bit.
Title: Re: Getting RC5 Address:Command from Hex Code
Post by: ian on August 12, 2010, 08:51:22 am
I will add updated irman code that is posted in the forum somewhere once I track it down. I will fixed the incorrectly inverted bit when I make that swap.
Title: Re: Getting RC5 Address:Command from Hex Code
Post by: liyin on August 12, 2010, 06:52:48 pm
When you say incorrectly inverted you mean IRMan specifies a "0" for RC5's lower field commands (0-64), and a "1" for RC5x's upper field commands (65-127)?

Because all texts about RC5 specify the field/start2 bit the way the IR Toy is using it now, "1" for RC5, "0" for RC5x.
Title: Re: Getting RC5 Address:Command from Hex Code
Post by: dukey on August 12, 2010, 06:55:43 pm
The real irman hardware didn't decode any protocols at all. If you get caught up with protocol X or protocol Y you'll find you'll only support a few remotes. This streamzap remote on my desk, it is RC5 but like a lot of remotes they've changed the protocol very slightly to suit their own needs, and as a result it doesn't work in IRMan mode with the IRToy.
Title: Re: Getting RC5 Address:Command from Hex Code
Post by: ian on August 12, 2010, 07:14:15 pm
I'm just going by the sbproject link.
Title: Re: Getting RC5 Address:Command from Hex Code
Post by: liyin on August 12, 2010, 08:05:13 pm
Quote
SB-Projects:

The first two pulses are the start pulses, and are both logical "1". Please note that half a bit time is elapsed before the receiver will notice the real start of the message.

Extended RC-5 uses only one start bit. Bit S2 is transformed to command bit 6, providing for a total of 7 command bits. The value of S2 must be inverted to get the 7th command bit though!

I see, but is that something for the PC software to do, or the IR Toy?

Lower field (logic 1 = 0 to 63 decimal)
Upper field (logic 0 = 64 to 127 decimal)

The idea of inverting is to have a nice 0 for 0-63, and 1 for 64-127 commands, from RC5's second start bit of 1 and 0-63 commands. Can be done either way.
Title: Re: Getting RC5 Address:Command from Hex Code
Post by: ian on August 12, 2010, 08:12:10 pm
Well, the IR Toy does not do it now, but it could...

There is no way to differentiate if the RC5x bit is not 0. IR products usually work with a specified remote control, so this is a generic receiver only issue.

( ! ) Fatal error: Uncaught exception 'Elk_Exception' with message 'Please try again. If you come back to this error screen, report the error to an administrator.' in /var/www/dangerousprototypes/forum/sources/database/Db-mysql.class.php on line 696
( ! ) Elk_Exception: Please try again. If you come back to this error screen, report the error to an administrator. in /var/www/dangerousprototypes/forum/sources/database/Db-mysql.class.php on line 696
Call Stack
#TimeMemoryFunctionLocation
10.01392151120session_write_close ( )...(null):0
20.01432282696ElkArte\sources\subs\SessionHandler\DatabaseHandler->write( )...(null):0
30.01432283472Database_MySQL->query( ).../DatabaseHandler.php:119
40.06062422192Database_MySQL->error( ).../Db-mysql.class.php:273