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