From 8a1c848baac3ce2a94961382de8755408891746f Mon Sep 17 00:00:00 2001 From: simimeie Date: Sun, 27 Jun 2010 22:20:39 +0000 Subject: [PATCH] \o/ working decoder for nec infrared control code. --- ircontrol.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 146 insertions(+), 6 deletions(-) diff --git a/ircontrol.c b/ircontrol.c index cf7e494..7ae665a 100644 --- a/ircontrol.c +++ b/ircontrol.c @@ -1,4 +1,4 @@ -/* $Id: ircontrol.c,v 1.1 2010/06/26 19:08:18 simimeie Exp $ +/* $Id: ircontrol.c,v 1.2 2010/06/27 22:20:39 simimeie Exp $ * Functions for the infrared receiver * * The infrared receiver is connected to PB0 / PCINT0. @@ -7,15 +7,155 @@ #include #include #include "ircontrol.h" +#include "timers.h" #include "console.h" +/* NOTE1: Note that the signal we get from the sensor is inverted. If we + * read a zero, it means there was infrared on, if we read a one, infrared + * is off. + * NOTE2: Only NEC is implemented here right now, because MY remote uses + * that protocol. However, there may be references to RC5 because I had + * already thought about that and just left them for possible future use. */ + +/* For RC5, one bit length is 1778 us, when it toggles we see half + * of it, i.e. 889 us. + * that equals around 7100 cpu cycles at 8 MHz. */ +#define RC5HALFLENINCYCLES ((CPUFREQ * 889UL) / 1000000UL) + +/* For NEC, we start with a 9000 us pulse, then 4500 us silence. + * Then the bits follow: + * a 0 is a 560 us pulse followed by 1690 us of silence. + * a 1 is a 560 us pulse followed by 560 us of silence. + * These values equal the following cpu cycle counts: + * 9000 us = 72000 cc, 4500 us = 36000 cc, 560 us = 4480, 1690 us = 13520 cc + */ +#define NECSTARTLEN1 ((CPUFREQ * 9UL) / 1000UL) +#define NECSTARTLEN2 ((CPUFREQ * 45UL) / 10000UL) +#define NECPULSELEN ((CPUFREQ * 56UL) / 100000UL) +#define NECONELEN ((CPUFREQ * 112UL) / 100000UL) +#define NECZEROLEN ((CPUFREQ * 225UL) / 100000UL) + +/* the NEC code contains 4 bytes, sent with LSB first: + * 0+1 are either the "extended address" or "address and inverted address". + * 2 is the command code + * 3 is the inverted command code + */ + +static struct timestamp last0irqts; +static struct timestamp last1irqts; +static uint8_t lastpin = 0; +static uint8_t codebytes[4]; +static uint8_t curcodebit = 0xff; + +/* some example codes +root@moodlight# !NSB! 11111111 00001000 11011111 00100000 (r) +root@moodlight# !NSB! 11111111 00001000 01011111 10100000 (g) +root@moodlight# !NSB! 11111111 00001000 10011111 01100000 (b) +root@moodlight# !NSB! 11111111 00001000 00011111 11100000 (w) +*/ + ISR(PCINT0_vect) { - uint8_t v = PINB & _BV(PB0); - if (v) { - console_printpgm_P(PSTR("!1!")); - } else { - console_printpgm_P(PSTR("!0!")); + uint8_t v; + struct timestamp curirqts; + uint32_t ts1diff; /* distance from last 1 */ + uint32_t ts0diff; /* distance from last 0 */ + + v = PINB & _BV(PB0); + if (v == lastpin) { /* No change visible - spurious interrupt */ + return; + } + curirqts = gettimestamp_noirq(); + ts1diff = ((uint32_t)curirqts.ticks << 16) + curirqts.partticks; + ts0diff = ts1diff; + ts1diff -= ((uint32_t)last1irqts.ticks << 16) + last1irqts.partticks; + ts0diff -= ((uint32_t)last0irqts.ticks << 16) + last0irqts.partticks; + if (v) { /* Infrared just went away! */ + if ((ts1diff >= (( 8 * NECSTARTLEN1) / 10)) + && (ts1diff <= ((12 * NECSTARTLEN1) / 10))) { + /* NEC start bit */ + /* console_printpgm_P(PSTR("!NSB!")); */ + curcodebit = 0xfe; /* Wait for second part of start sequence */ + } else { + if (curcodebit <= 32) { /* We're in a decoding attempt, so */ + /* Check pulse length */ + if ((ts1diff < (( 8 * NECPULSELEN) / 10)) + || (ts1diff > ((12 * NECPULSELEN) / 10))) { + /* WRONG */ + curcodebit = 0xff; + } + } + if (curcodebit == 32) { + if (codebytes[2] != (codebytes[3] ^ 0xff)) { + console_printpgm_P(PSTR("!CRC!")); + } else { + /* Successful decode! */ + console_printpgm_P(PSTR(" DEC>")); + console_printhex8(codebytes[0]); + console_printhex8(codebytes[1]); + console_printhex8(codebytes[2]); + console_printhex8(codebytes[3]); + } + } + } + last0irqts = curirqts; + } else { /* Infrared went on */ + if ((ts1diff >= (( 8 * NECZEROLEN) / 10)) + && (ts1diff <= ((12 * NECZEROLEN) / 10))) { + /* console_printpgm_P(PSTR("0")); */ + if (curcodebit < 32) { + curcodebit++; + } + } else if ((ts1diff >= (( 8 * NECONELEN) / 10)) + && (ts1diff <= ((12 * NECONELEN) / 10))) { + /* console_printpgm_P(PSTR("1")); */ + if (curcodebit < 32) { + codebytes[curcodebit >> 3] |= (1 << (curcodebit & 0x07)); + curcodebit++; + } else { + curcodebit = 0xff; + } + } else if ((ts0diff >= (( 8 * NECSTARTLEN2) / 10)) + && (ts0diff <= ((12 * NECSTARTLEN2) / 10))) { + if (curcodebit == 0xfe) { /* voila, correct start sequence */ + curcodebit = 0; + codebytes[0] = codebytes[1] = codebytes[2] = codebytes[3] = 0; + } + } + last1irqts = curirqts; + } +#if 0 + console_printpgm_P(PSTR("!")); + console_printhex8(tsdiff >> 24); + console_printhex8(tsdiff >> 16); + console_printhex8(tsdiff >> 8); + console_printhex8(tsdiff >> 0); + console_printpgm_P(PSTR("!")); +#endif +#if 0 + if (tsdiff > ((24 * HALFRC5LENINCYCLES) / 10)) { + /* Start of new transmission */ + console_printpgm_P(PSTR("!1[")); + console_printhex8(v); + lastbit = 1; + } else if (tsdiff > ((15 * HALFRC5LENINCYCLES) / 10)) { + /* Different bit than last time */ + lastbit = !lastbit; + if (lastbit) { + console_printpgm_P(PSTR("1")); + } else { + console_printpgm_P(PSTR("0")); + } + } else if ((tsdiff < ((15 * HALFRC5LENINCYCLES) / 10)) + && (tsdiff > (( 5 * HALFRC5LENINCYCLES) / 10))) { + /* Same bit as last time */ + if (lastbit) { + console_printpgm_P(PSTR("1")); + } else { + console_printpgm_P(PSTR("0")); + } } +#endif + lastpin = v; } void ircontrol_init(void) -- 2.25.1