- add eepromdata.h
[moodlight.git] / ircontrol.c
CommitLineData
c7c49995 1/* $Id: ircontrol.c,v 1.6 2010/07/10 07:36: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
c7c49995 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.
8a1c848b 28 * Then the bits follow:
32eb657a 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).
8a1c848b 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
32eb657a 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.
8a1c848b 36 */
37#define NECSTARTLEN1 ((CPUFREQ * 9UL) / 1000UL)
38#define NECSTARTLEN2 ((CPUFREQ * 45UL) / 10000UL)
39#define NECPULSELEN ((CPUFREQ * 56UL) / 100000UL)
2e7f4185 40#define NECZEROLEN ((CPUFREQ * 112UL) / 100000UL)
41#define NECONELEN ((CPUFREQ * 225UL) / 100000UL)
6dc7afb2 42#define NECREPEATLEN ((CPUFREQ * 225UL) / 100000UL)
8a1c848b 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
50static struct timestamp last0irqts;
51static struct timestamp last1irqts;
32eb657a 52static uint8_t lastpin = 0xff;
8a1c848b 53static uint8_t codebytes[4];
54static uint8_t curcodebit = 0xff;
32eb657a 55static uint8_t lastcommand = 0xff;
56static uint8_t repeatcommand = 0xff;
57static uint16_t repeatticks = 0;
58/* Repeat after this many ticks (70 = 0.5s) */
59#define REPEATAFTERTICKS 100
8a1c848b 60
61/* some example codes
62root@moodlight# !NSB! 11111111 00001000 11011111 00100000 (r)
63root@moodlight# !NSB! 11111111 00001000 01011111 10100000 (g)
64root@moodlight# !NSB! 11111111 00001000 10011111 01100000 (b)
65root@moodlight# !NSB! 11111111 00001000 00011111 11100000 (w)
66*/
67
17aea8ef 68ISR(PCINT0_vect) {
8a1c848b 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
c7c49995 74 v = PINB & _BV(0);
8a1c848b 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! */
32eb657a 103 lastcommand = codebytes[2];
104 repeatcommand = codebytes[2];
105 repeatticks = curirqts.ticks;
8a1c848b 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 }
6dc7afb2 137 } else if ((ts0diff >= (( 8 * NECREPEATLEN) / 10))
138 && (ts0diff <= ((12 * NECREPEATLEN) / 10))) {
139 if (curcodebit == 0xfe) {
140 console_printpgm_P(PSTR(".REP."));
32eb657a 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 }
6dc7afb2 147 }
8a1c848b 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 }
17aea8ef 181 }
8a1c848b 182#endif
183 lastpin = v;
17aea8ef 184}
185
186void ircontrol_init(void)
187{
188 /* Activate pullup */
c7c49995 189 PORTB |= _BV(0);
17aea8ef 190 /* enable PCINT0 */
191 PCICR |= _BV(PCIE0);
192 /* Enable pin change interrupt 0 (=PB0) in pcint0 */
193 PCMSK0 |= _BV(PCINT0);
194}
32eb657a 195
196uint8_t ircontrol_getlastcommand(void)
197{
198 uint8_t res;
199 res = lastcommand;
200 lastcommand = 0xff;
201 return res;
202}
This page took 0.072633 seconds and 4 git commands to generate.