e0e5317927a36c722d96a00738e68feab63242dc
[moodlight.git] / ircontrol.c
1 /* $Id: ircontrol.c,v 1.4 2010/06/27 23:05:55 simimeie Exp $
2  * Functions for the infrared receiver
3  *
4  * The infrared receiver is connected to PB0 / PCINT0.
5  */
6
7 #include <avr/io.h>
8 #include <avr/interrupt.h>
9 #include "ircontrol.h"
10 #include "timers.h"
11 #include "console.h"
12
13 /* NOTE1: Note that the signal we get from the sensor is inverted. If we
14  * read a zero, it means there was infrared on, if we read a one, infrared
15  * is off.
16  * NOTE2: Only NEC is implemented here right now, because MY remote uses
17  * that protocol. However, there may be references to RC5 because I had
18  * already thought about that and just left them for possible future use. */
19
20 /* For RC5, one bit length is 1778 us, when it toggles we see half
21  * of it, i.e. 889 us.
22  * that equals around 7100 cpu cycles at 8 MHz. */
23 #define RC5HALFLENINCYCLES ((CPUFREQ * 889UL) / 1000000UL)
24
25 /* For NEC, we start with a 9000 us pulse, then 4500 us silence.
26  * Then the bits follow:
27  * a 1 is a 560 us pulse followed by 1690 us of silence.
28  * a 0 is a 560 us pulse followed by  560 us of silence.
29  * These values equal the following cpu cycle counts:
30  *  9000 us = 72000 cc, 4500 us = 36000 cc, 560 us = 4480, 1690 us = 13520 cc
31  */
32 #define NECSTARTLEN1 ((CPUFREQ *   9UL) / 1000UL)
33 #define NECSTARTLEN2 ((CPUFREQ *  45UL) / 10000UL)
34 #define NECPULSELEN  ((CPUFREQ *  56UL) / 100000UL)
35 #define NECZEROLEN   ((CPUFREQ * 112UL) / 100000UL)
36 #define NECONELEN    ((CPUFREQ * 225UL) / 100000UL)
37 #define NECREPEATLEN ((CPUFREQ * 225UL) / 100000UL)
38
39 /* the NEC code contains 4 bytes, sent with LSB first:
40  * 0+1 are either the "extended address" or "address and inverted address".
41  * 2 is the command code
42  * 3 is the inverted command code
43  */
44
45 static struct timestamp last0irqts;
46 static struct timestamp last1irqts;
47 static uint8_t lastpin = 0;
48 static uint8_t codebytes[4];
49 static uint8_t curcodebit = 0xff;
50
51 /* some example codes
52 root@moodlight# !NSB! 11111111 00001000 11011111 00100000  (r)
53 root@moodlight# !NSB! 11111111 00001000 01011111 10100000  (g)
54 root@moodlight# !NSB! 11111111 00001000 10011111 01100000  (b)
55 root@moodlight# !NSB! 11111111 00001000 00011111 11100000  (w)
56 */
57
58 ISR(PCINT0_vect) {
59   uint8_t v;
60   struct timestamp curirqts;
61   uint32_t ts1diff; /* distance from last 1 */
62   uint32_t ts0diff; /* distance from last 0 */
63   
64   v = PINB & _BV(PB0);
65   if (v == lastpin) {  /* No change visible - spurious interrupt */
66     return;
67   }
68   curirqts = gettimestamp_noirq();
69   ts1diff = ((uint32_t)curirqts.ticks << 16) + curirqts.partticks;
70   ts0diff = ts1diff;
71   ts1diff -= ((uint32_t)last1irqts.ticks << 16) + last1irqts.partticks;
72   ts0diff -= ((uint32_t)last0irqts.ticks << 16) + last0irqts.partticks;
73   if (v) { /* Infrared just went away! */
74     if ((ts1diff >= (( 8 * NECSTARTLEN1) / 10))
75      && (ts1diff <= ((12 * NECSTARTLEN1) / 10))) {
76         /* NEC start bit */
77         /* console_printpgm_P(PSTR("!NSB!")); */
78         curcodebit = 0xfe; /* Wait for second part of start sequence */
79     } else {
80       if (curcodebit <= 32) { /* We're in a decoding attempt, so */
81                               /* Check pulse length */
82         if ((ts1diff < (( 8 * NECPULSELEN) / 10))
83          || (ts1diff > ((12 * NECPULSELEN) / 10))) {
84             /* WRONG */
85             curcodebit = 0xff;
86         }
87       }
88       if (curcodebit == 32) {
89         if (codebytes[2] != (codebytes[3] ^ 0xff)) {
90           console_printpgm_P(PSTR("!CRC!"));
91         } else {
92           /* Successful decode! */
93           console_printpgm_P(PSTR(" DEC>"));
94           console_printhex8(codebytes[0]);
95           console_printhex8(codebytes[1]);
96           console_printhex8(codebytes[2]);
97           console_printhex8(codebytes[3]);
98         }
99       }
100     }
101     last0irqts = curirqts;
102   } else { /* Infrared went on */
103     if ((ts1diff >= (( 8 * NECZEROLEN) / 10))
104      && (ts1diff <= ((12 * NECZEROLEN) / 10))) {
105         /* console_printpgm_P(PSTR("0")); */
106         if (curcodebit < 32) {
107           curcodebit++;
108         }
109     } else if ((ts1diff >= (( 8 * NECONELEN) / 10))
110             && (ts1diff <= ((12 * NECONELEN) / 10))) {
111         /* console_printpgm_P(PSTR("1")); */
112         if (curcodebit < 32) {
113           codebytes[curcodebit >> 3] |= (1 << (curcodebit & 0x07));
114           curcodebit++;
115         } else {
116           curcodebit = 0xff;
117         }
118     } else if ((ts0diff >= (( 8 * NECSTARTLEN2) / 10))
119             && (ts0diff <= ((12 * NECSTARTLEN2) / 10))) {
120         if (curcodebit == 0xfe) { /* voila, correct start sequence */
121           curcodebit = 0;
122           codebytes[0] = codebytes[1] = codebytes[2] = codebytes[3] = 0;
123         }
124     } else if ((ts0diff >= (( 8 * NECREPEATLEN) / 10))
125             && (ts0diff <= ((12 * NECREPEATLEN) / 10))) {
126         if (curcodebit == 0xfe) {
127           console_printpgm_P(PSTR(".REP."));
128         }
129     }
130     last1irqts = curirqts;
131   }
132 #if 0
133   console_printpgm_P(PSTR("!"));
134   console_printhex8(tsdiff >> 24);
135   console_printhex8(tsdiff >> 16);
136   console_printhex8(tsdiff >>  8);
137   console_printhex8(tsdiff >>  0);
138   console_printpgm_P(PSTR("!"));
139 #endif
140 #if 0
141   if (tsdiff > ((24 * HALFRC5LENINCYCLES) / 10)) {
142     /* Start of new transmission */
143     console_printpgm_P(PSTR("!1["));
144     console_printhex8(v);
145     lastbit = 1;
146   } else if (tsdiff > ((15 * HALFRC5LENINCYCLES) / 10)) {
147     /* Different bit than last time */
148     lastbit = !lastbit;
149     if (lastbit) {
150       console_printpgm_P(PSTR("1"));
151     } else {
152       console_printpgm_P(PSTR("0"));
153     }
154   } else if ((tsdiff < ((15 * HALFRC5LENINCYCLES) / 10))
155           && (tsdiff > (( 5 * HALFRC5LENINCYCLES) / 10))) {
156     /* Same bit as last time */
157     if (lastbit) {
158       console_printpgm_P(PSTR("1"));
159     } else {
160       console_printpgm_P(PSTR("0"));
161     }
162   }
163 #endif
164   lastpin = v;
165 }
166
167 void ircontrol_init(void)
168 {
169   /* Activate pullup */
170   PORTB |= _BV(PB0);
171   /* enable PCINT0 */
172   PCICR |= _BV(PCIE0);
173   /* Enable pin change interrupt 0 (=PB0) in pcint0 */
174   PCMSK0 |= _BV(PCINT0);
175 }
This page took 0.052795 seconds and 2 git commands to generate.