1 /* $Id: ircontrol.c,v 1.4 2010/06/27 23:05:55 simimeie Exp $
2 * Functions for the infrared receiver
4 * The infrared receiver is connected to PB0 / PCINT0.
8 #include <avr/interrupt.h>
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
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. */
20 /* For RC5, one bit length is 1778 us, when it toggles we see half
22 * that equals around 7100 cpu cycles at 8 MHz. */
23 #define RC5HALFLENINCYCLES ((CPUFREQ * 889UL) / 1000000UL)
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
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)
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
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;
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)
60 struct timestamp curirqts;
61 uint32_t ts1diff; /* distance from last 1 */
62 uint32_t ts0diff; /* distance from last 0 */
65 if (v == lastpin) { /* No change visible - spurious interrupt */
68 curirqts = gettimestamp_noirq();
69 ts1diff = ((uint32_t)curirqts.ticks << 16) + curirqts.partticks;
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))) {
77 /* console_printpgm_P(PSTR("!NSB!")); */
78 curcodebit = 0xfe; /* Wait for second part of start sequence */
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))) {
88 if (curcodebit == 32) {
89 if (codebytes[2] != (codebytes[3] ^ 0xff)) {
90 console_printpgm_P(PSTR("!CRC!"));
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]);
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) {
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));
118 } else if ((ts0diff >= (( 8 * NECSTARTLEN2) / 10))
119 && (ts0diff <= ((12 * NECSTARTLEN2) / 10))) {
120 if (curcodebit == 0xfe) { /* voila, correct start sequence */
122 codebytes[0] = codebytes[1] = codebytes[2] = codebytes[3] = 0;
124 } else if ((ts0diff >= (( 8 * NECREPEATLEN) / 10))
125 && (ts0diff <= ((12 * NECREPEATLEN) / 10))) {
126 if (curcodebit == 0xfe) {
127 console_printpgm_P(PSTR(".REP."));
130 last1irqts = curirqts;
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("!"));
141 if (tsdiff > ((24 * HALFRC5LENINCYCLES) / 10)) {
142 /* Start of new transmission */
143 console_printpgm_P(PSTR("!1["));
144 console_printhex8(v);
146 } else if (tsdiff > ((15 * HALFRC5LENINCYCLES) / 10)) {
147 /* Different bit than last time */
150 console_printpgm_P(PSTR("1"));
152 console_printpgm_P(PSTR("0"));
154 } else if ((tsdiff < ((15 * HALFRC5LENINCYCLES) / 10))
155 && (tsdiff > (( 5 * HALFRC5LENINCYCLES) / 10))) {
156 /* Same bit as last time */
158 console_printpgm_P(PSTR("1"));
160 console_printpgm_P(PSTR("0"));
167 void ircontrol_init(void)
169 /* Activate pullup */
173 /* Enable pin change interrupt 0 (=PB0) in pcint0 */
174 PCMSK0 |= _BV(PCINT0);