/* -*- mode: c -*- */ //////////////////////////////////////////////////////////////////////////////////////////////////// // IR REMOTE CONTROL DECODER FOR XBOX (DVDKit) // 2007 Javier Valcarce García, javier.valcarce@gmail.com // $Id$ //////////////////////////////////////////////////////////////////////////////////////////////////// #include #include // This is the INT0 Pin of the ATMega8 #define PIN_IRRX 2 // Xbox IR remote control codes #define IRCODE_DISPLAY 0x52AAD5 #define IRCODE_REVERSE 0x51DAE2 #define IRCODE_PLAY 0x515AEA #define IRCODE_FORWARD 0x51CAE3 #define IRCODE_SKIPSUB 0x522ADD #define IRCODE_STOP 0x51FAE0 #define IRCODE_PAUSE 0x519AE6 #define IRCODE_SKIPADD 0x520ADF #define IRCODE_TITLE 0x51AAE5 #define IRCODE_INFO 0x53CAC3 #define IRCODE_MENU 0x508AF7 #define IRCODE_BACK 0x527AD8 #define IRCODE_UP 0x559AA6 #define IRCODE_DOWN 0x558AA7 #define IRCODE_LEFT 0x556AA9 #define IRCODE_RIGHT 0x557AA8 #define IRCODE_SELECT 0x5F4A0B #define IRCODE_1 0x531ACE #define IRCODE_2 0x532ACD #define IRCODE_3 0x533ACC #define IRCODE_4 0x534ACB #define IRCODE_5 0x535ACA #define IRCODE_6 0x536AC9 #define IRCODE_7 0x537AC8 #define IRCODE_8 0x538AC7 #define IRCODE_9 0x539AC6 #define IRCODE_0 0x530ACF //////////////////////////////////////////////////////////////////////////////////////////////////// volatile unsigned int usec; volatile int ir_bit; volatile unsigned long ir_tmp; volatile unsigned long ir_cmd; volatile boolean ir_cmd_new; // Decoder state (variable "ir_bit") -1, 0, 1, 2, 3... 24 and (25) #define WAIT -1 // Waiting for an IR signal #define HEAD 0 // Receiving AGC pulse //... #define PERR 250 // Maximun absolute error permited inÇ vcxxz ZXC #define TIME_HEAD 4500 // AGC pulse lenght (in us) #define TIME_BIT0 1500 // Bit 0 lenght (in us) #define TIME_BIT1 2500 // Bit 1 lenght (in us) // Aruino runs at 16 Mhz, // Raise interrupt every 1 / ((16000000 / 1) / 256) = 1 / 62500 = 16us //////////////////////////////////////////////////////////////////////////////////////////////////// ISR(TIMER2_OVF_vect) { usec += 16; if (usec == 6400) // 6400 % 16 == 0 { // Time over! Reset receiver's state machine usec = 0; ir_bit = WAIT; } }; //////////////////////////////////////////////////////////////////////////////////////////////////// #define VALID_TIME(v, a, b) ( ((v) > (a)-PERR) && ((v) < (b)+PERR) ) // INT0, arduino pin2 ISR(INT0_vect) { switch (ir_bit) { case WAIT: // Waiting for an incoming signal if (!ir_cmd_new) ir_bit++; break; case HEAD: // Initial AGC pulse if ( VALID_TIME(usec, TIME_HEAD) ) { ir_tmp = 0; ir_bit++; } else { ir_bit = WAIT; } break; default: // Data bits 01, 02, 03, ... 24 if ( VALID_TIME(usec, TIME_BIT0) ) { ir_tmp = ir_tmp << 1; ir_bit++; } else if ( VALID_TIME(usec, TIME_BIT1) ) { ir_tmp = (ir_tmp << 1) | 0x00000001; ir_bit++; } else { ir_bit = WAIT; } if (ir_bit == 25) { // Bit "25" means END OF TRANSMISION, new IR data is available ir_cmd = ir_tmp; ir_cmd_new = true; } break; } usec = 0; } //////////////////////////////////////////////////////////////////////////////////////////////////// void setup() { usec = 0; ir_bit = WAIT; ir_cmd_new = false; pinMode(PIN_IRRX, INPUT); // Timer Setup, valid only for ATmega8 // Normal mode TCCR2 &= ~(1 << WGM21); TCCR2 &= ~(1 << WGM20); // No Timer Prescaler TCCR2 |= (1 << CS20); TCCR2 &= ~(1 << CS22); TCCR2 &= ~(1 << CS21); // Use internal clock ASSR &= ~(1 << AS2); // TMR2 Overflow Interrupt TIMSK |= (1 << TOIE2); TIMSK &= ~(1 << OCIE2); // INT0 interrupt GICR |= (1 << INT0); MCUCR |= (1 << ISC00); // positive edge MCUCR |= (1 << ISC01); // negative edge sei(); Serial.begin(9600); // prints title with ending line break Serial.println(""); Serial.println("Xbox IR remote control"); Serial.println("Waiting..."); // wait for the long strings to be sent to serial port delay(100); } //////////////////////////////////////////////////////////////////////////////////////////////////// void loop() { if (ir_cmd_new) { Serial.print("code - "); Serial.println(ir_cmd, HEX); ir_cmd_new = false; delay(40); } } ////////////////////////////////////////////////////////////////////////////////////////////////////