- add eepromdata.h
[moodlight.git] / ircontrol.c
1 /* $Id: ircontrol.c,v 1.6 2010/07/10 07:36:28 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 /* Source for most of this was the following nice page with illustrations
26  * and all that: http://www.sbprojects.com/knowledge/ir/nec.htm
27  * For NEC, we start with a 9000 us pulse, then 4500 us silence.
28  * Then the bits follow:
29  * a 1 is a 560 us pulse followed by 1690 us of silence (=2250 us total).
30  * a 0 is a 560 us pulse followed by  560 us of silence (=1120 us total).
31  * These values equal the following cpu cycle counts:
32  *  9000 us = 72000 cc, 4500 us = 36000 cc, 560 us = 4480, 1690 us = 13520 cc
33  * When the key stays pressed, it is not resubmitted, but instead a special
34  * "repeat" code is sent. That is: 9000 us pulse, 2250 us silence, 560 us
35  * pulse.
36  */
37 #define NECSTARTLEN1 ((CPUFREQ *   9UL) / 1000UL)
38 #define NECSTARTLEN2 ((CPUFREQ *  45UL) / 10000UL)
39 #define NECPULSELEN  ((CPUFREQ *  56UL) / 100000UL)
40 #define NECZEROLEN   ((CPUFREQ * 112UL) / 100000UL)
41 #define NECONELEN    ((CPUFREQ * 225UL) / 100000UL)
42 #define NECREPEATLEN ((CPUFREQ * 225UL) / 100000UL)
43
44 /* the NEC code contains 4 bytes, sent with LSB first:
45  * 0+1 are either the "extended address" or "address and inverted address".
46  * 2 is the command code
47  * 3 is the inverted command code
48  */
49
50 static struct timestamp last0irqts;
51 static struct timestamp last1irqts;
52 static uint8_t lastpin = 0xff;
53 static uint8_t codebytes[4];
54 static uint8_t curcodebit = 0xff;
55 static uint8_t lastcommand = 0xff;
56 static uint8_t repeatcommand = 0xff;
57 static uint16_t repeatticks = 0;
58 /* Repeat after this many ticks (70 = 0.5s) */
59 #define REPEATAFTERTICKS 100
60
61 /* some example codes
62 root@moodlight# !NSB! 11111111 00001000 11011111 00100000  (r)
63 root@moodlight# !NSB! 11111111 00001000 01011111 10100000  (g)
64 root@moodlight# !NSB! 11111111 00001000 10011111 01100000  (b)
65 root@moodlight# !NSB! 11111111 00001000 00011111 11100000  (w)
66 */
67
68 ISR(PCINT0_vect) {
69   uint8_t v;
70   struct timestamp curirqts;
71   uint32_t ts1diff; /* distance from last 1 */
72   uint32_t ts0diff; /* distance from last 0 */
73   
74   v = PINB & _BV(0);
75   if (v == lastpin) {  /* No change visible - spurious interrupt */
76     return;
77   }
78   curirqts = gettimestamp_noirq();
79   ts1diff = ((uint32_t)curirqts.ticks << 16) + curirqts.partticks;
80   ts0diff = ts1diff;
81   ts1diff -= ((uint32_t)last1irqts.ticks << 16) + last1irqts.partticks;
82   ts0diff -= ((uint32_t)last0irqts.ticks << 16) + last0irqts.partticks;
83   if (v) { /* Infrared just went away! */
84     if ((ts1diff >= (( 8 * NECSTARTLEN1) / 10))
85      && (ts1diff <= ((12 * NECSTARTLEN1) / 10))) {
86         /* NEC start bit */
87         /* console_printpgm_P(PSTR("!NSB!")); */
88         curcodebit = 0xfe; /* Wait for second part of start sequence */
89     } else {
90       if (curcodebit <= 32) { /* We're in a decoding attempt, so */
91                               /* Check pulse length */
92         if ((ts1diff < (( 8 * NECPULSELEN) / 10))
93          || (ts1diff > ((12 * NECPULSELEN) / 10))) {
94             /* WRONG */
95             curcodebit = 0xff;
96         }
97       }
98       if (curcodebit == 32) {
99         if (codebytes[2] != (codebytes[3] ^ 0xff)) {
100           console_printpgm_P(PSTR("!CRC!"));
101         } else {
102           /* Successful decode! */
103           lastcommand = codebytes[2];
104           repeatcommand = codebytes[2];
105           repeatticks = curirqts.ticks;
106           console_printpgm_P(PSTR(" DEC>"));
107           console_printhex8(codebytes[0]);
108           console_printhex8(codebytes[1]);
109           console_printhex8(codebytes[2]);
110           console_printhex8(codebytes[3]);
111         }
112       }
113     }
114     last0irqts = curirqts;
115   } else { /* Infrared went on */
116     if ((ts1diff >= (( 8 * NECZEROLEN) / 10))
117      && (ts1diff <= ((12 * NECZEROLEN) / 10))) {
118         /* console_printpgm_P(PSTR("0")); */
119         if (curcodebit < 32) {
120           curcodebit++;
121         }
122     } else if ((ts1diff >= (( 8 * NECONELEN) / 10))
123             && (ts1diff <= ((12 * NECONELEN) / 10))) {
124         /* console_printpgm_P(PSTR("1")); */
125         if (curcodebit < 32) {
126           codebytes[curcodebit >> 3] |= (1 << (curcodebit & 0x07));
127           curcodebit++;
128         } else {
129           curcodebit = 0xff;
130         }
131     } else if ((ts0diff >= (( 8 * NECSTARTLEN2) / 10))
132             && (ts0diff <= ((12 * NECSTARTLEN2) / 10))) {
133         if (curcodebit == 0xfe) { /* voila, correct start sequence */
134           curcodebit = 0;
135           codebytes[0] = codebytes[1] = codebytes[2] = codebytes[3] = 0;
136         }
137     } else if ((ts0diff >= (( 8 * NECREPEATLEN) / 10))
138             && (ts0diff <= ((12 * NECREPEATLEN) / 10))) {
139         if (curcodebit == 0xfe) {
140           console_printpgm_P(PSTR(".REP."));
141           if ((curirqts.ticks - repeatticks) > REPEATAFTERTICKS) {
142             if ((repeatcommand == 0x00) || (repeatcommand == 0x01)) {
143               /* Only the up/down arrows are allowed to be repeated */
144               lastcommand = repeatcommand;
145             }
146           }
147         }
148     }
149     last1irqts = curirqts;
150   }
151 #if 0
152   console_printpgm_P(PSTR("!"));
153   console_printhex8(tsdiff >> 24);
154   console_printhex8(tsdiff >> 16);
155   console_printhex8(tsdiff >>  8);
156   console_printhex8(tsdiff >>  0);
157   console_printpgm_P(PSTR("!"));
158 #endif
159 #if 0
160   if (tsdiff > ((24 * HALFRC5LENINCYCLES) / 10)) {
161     /* Start of new transmission */
162     console_printpgm_P(PSTR("!1["));
163     console_printhex8(v);
164     lastbit = 1;
165   } else if (tsdiff > ((15 * HALFRC5LENINCYCLES) / 10)) {
166     /* Different bit than last time */
167     lastbit = !lastbit;
168     if (lastbit) {
169       console_printpgm_P(PSTR("1"));
170     } else {
171       console_printpgm_P(PSTR("0"));
172     }
173   } else if ((tsdiff < ((15 * HALFRC5LENINCYCLES) / 10))
174           && (tsdiff > (( 5 * HALFRC5LENINCYCLES) / 10))) {
175     /* Same bit as last time */
176     if (lastbit) {
177       console_printpgm_P(PSTR("1"));
178     } else {
179       console_printpgm_P(PSTR("0"));
180     }
181   }
182 #endif
183   lastpin = v;
184 }
185
186 void ircontrol_init(void)
187 {
188   /* Activate pullup */
189   PORTB |= _BV(0);
190   /* enable PCINT0 */
191   PCICR |= _BV(PCIE0);
192   /* Enable pin change interrupt 0 (=PB0) in pcint0 */
193   PCMSK0 |= _BV(PCINT0);
194 }
195
196 uint8_t ircontrol_getlastcommand(void)
197 {
198   uint8_t res;
199   res = lastcommand;
200   lastcommand = 0xff;
201   return res;
202 }
This page took 0.048795 seconds and 3 git commands to generate.