\o/ working decoder for nec infrared control code.
authorsimimeie <simimeie>
Sun, 27 Jun 2010 22:20:39 +0000 (22:20 +0000)
committersimimeie <simimeie>
Sun, 27 Jun 2010 22:20:39 +0000 (22:20 +0000)
ircontrol.c

index cf7e49444833e585dbd8065cab398246ee91853d..7ae665a41b439f89f296d4fc0508ae1363554a38 100644 (file)
@@ -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.
 #include <avr/io.h>
 #include <avr/interrupt.h>
 #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)
This page took 0.057367 seconds and 4 git commands to generate.