6dc7afb2 |
1 | /* $Id: ircontrol.c,v 1.4 2010/06/27 23:05:55 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: |
2e7f4185 |
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. |
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 |
31 | */ |
32 | #define NECSTARTLEN1 ((CPUFREQ * 9UL) / 1000UL) |
33 | #define NECSTARTLEN2 ((CPUFREQ * 45UL) / 10000UL) |
34 | #define NECPULSELEN ((CPUFREQ * 56UL) / 100000UL) |
2e7f4185 |
35 | #define NECZEROLEN ((CPUFREQ * 112UL) / 100000UL) |
36 | #define NECONELEN ((CPUFREQ * 225UL) / 100000UL) |
6dc7afb2 |
37 | #define NECREPEATLEN ((CPUFREQ * 225UL) / 100000UL) |
8a1c848b |
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 | |
17aea8ef |
58 | ISR(PCINT0_vect) { |
8a1c848b |
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 | } |
6dc7afb2 |
124 | } else if ((ts0diff >= (( 8 * NECREPEATLEN) / 10)) |
125 | && (ts0diff <= ((12 * NECREPEATLEN) / 10))) { |
126 | if (curcodebit == 0xfe) { |
127 | console_printpgm_P(PSTR(".REP.")); |
128 | } |
8a1c848b |
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 | } |
17aea8ef |
162 | } |
8a1c848b |
163 | #endif |
164 | lastpin = v; |
17aea8ef |
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 | } |