]> git.zerfleddert.de Git - fnordlicht-mini/blob - firmware/fnordlicht-controller/ir.c
reference firmware
[fnordlicht-mini] / firmware / fnordlicht-controller / ir.c
1 /*
2 * ox - infrared to usb keyboard/mouse adapter
3 *
4 * by Alexander Neumann <alexander@lochraster.org>
5 *
6 * inspired by InfraHID by Alex Badea,
7 * see http://vamposdecampos.googlepages.com/infrahid.html
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * For more information on the GPL, please go to:
23 * http://www.gnu.org/copyleft/gpl.html
24 */
25
26 #include <avr/io.h>
27 #include <avr/interrupt.h>
28 #include <avr/pgmspace.h>
29 #include <stdbool.h>
30 #include <util/crc16.h>
31 #include "config.h"
32 #include "globals.h"
33 #include "../common/common.h"
34 #include "usb.h"
35 #include "ir.h"
36 #include "ir-cluster.h"
37 #include "ui.h"
38
39 /* macro magic */
40 #define IR_DDR _DDRPORT(IR_PORTNAME)
41 #define IR_PORT _OUTPORT(IR_PORTNAME)
42
43 #if IR_INTNUM < 8
44 # define IR_BANK 0
45 # define IR_VECT PCINT0_vect
46 #elif IR_INTNUM < 16
47 # define IR_BANK 1
48 # define IR_VECT PCINT1_vect
49 #else
50 # define IR_BANK 2
51 # define IR_VECT PCINT2_vect
52 #endif
53
54 #define IR_INT (IR_INTNUM - IR_BANK * 8)
55 #define IR_PCIE _PCIE(IR_BANK)
56 #define IR_PCIF _PCIF(IR_BANK)
57 #define IR_PCMSK _PCMSK(IR_BANK)
58
59 /* 8 should be enough for everybody! */
60 #define MAX_CLUSTERS 8
61
62 /* internal state machine */
63 static enum {
64 READY = 0,
65 LISTEN = 1,
66 DONE = 2,
67 } state;
68
69 volatile struct ir_global_t ir_global;
70
71 void ir_init(void)
72 {
73 /* initialize input pin (with pullup) */
74 IR_DDR &= ~_BV(IR_PIN);
75 IR_PORT |= _BV(IR_PIN);
76
77 /* configure timer1 with prescaler 64 and CTC for measuring ir timings */
78 TCCR1B = _BV(CS11) | _BV(CS10) | _BV(WGM12);
79 /* configure timer action after 20ms: 20mhz/64/50 */
80 OCR1A = F_CPU/50/64;
81 }
82
83 void ir_set_mode(enum ir_mode_t mode)
84 {
85 if (ir_global.mode != IR_DISABLED && mode == IR_DISABLED) {
86 /* disable pin change interrupt */
87 IR_PCMSK &= ~_BV(IR_INT);
88 PCICR &= ~_BV(IR_PCIE);
89
90 /* clear interrupt flags */
91 TIFR1 = TIFR1;
92 } else if (ir_global.mode == IR_DISABLED && mode != IR_DISABLED) {
93 /* clear interrupt flags */
94 TIFR1 = TIFR1;
95
96 /* reset variables */
97 ir_global.pos = 0;
98 state = READY;
99
100 /* enable pin change interrupt */
101 IR_PCMSK |= _BV(IR_INT);
102 PCICR |= _BV(IR_PCIE);
103 }
104
105 ir_global.mode = mode;
106
107 if (mode == IR_DECODE || mode == IR_RAW)
108 ui_blink(0, 0x5);
109 }
110
111 ISR(IR_VECT, ISR_NOBLOCK)
112 {
113 /* store code */
114 uint16_t value = TCNT1;
115 TCNT1 = 0;
116
117 /* do not store the first 'off' timing value */
118 if (state == READY)
119 state = LISTEN;
120 else if (state == LISTEN) {
121 ir_global.time[ir_global.pos++] = value;
122
123 /* check if we reached the end of the array */
124 if (ir_global.pos == MAX_CODE_LENGTH)
125 state = DONE;
126 }
127 }
128
129 void ir_poll(void)
130 {
131 if (ir_global.mode == IR_DISABLED)
132 return;
133
134 /* check for timeout */
135 if (TIFR1 & _BV(OCF1A)) {
136 /* clear interrupt flag */
137 TIFR1 = _BV(OCF1A);
138
139 /* if ir has been detected, process code, else return to listening */
140 if (ir_global.pos > 1) {
141 state = DONE;
142
143 /* set last timing to zero */
144 if (ir_global.pos % 2 == 0)
145 ir_global.time[ir_global.pos-1] = 0;
146 else
147 ir_global.time[ir_global.pos++] = 0;
148 } else
149 state = READY;
150 }
151
152 /* if code is complete, process! */
153 if (state == DONE) {
154 /* compute clusters */
155 if (ir_global.mode == IR_RECEIVE || ir_global.mode == IR_DECODE) {
156 uint16_t cluster_on[MAX_CLUSTERS];
157 uint16_t cluster_off[MAX_CLUSTERS];
158
159 uint8_t con = ir_cluster(&ir_global.time[0], ir_global.pos/2, &cluster_on[0], MAX_CLUSTERS);
160 uint8_t coff = ir_cluster(&ir_global.time[1], ir_global.pos/2-1, &cluster_off[0], MAX_CLUSTERS);
161
162 for (uint8_t i = 0; i < ir_global.pos/2; i++) {
163 uint8_t data_on = ir_min_cluster(ir_global.time[2*i], cluster_on, con);
164 uint8_t data_off = ir_min_cluster(ir_global.time[2*i+1], cluster_off, coff);
165
166 ir_global.time[i] = data_on | (data_off << 8);
167 }
168
169 ir_global.pos /= 2;
170 }
171
172 if (ir_global.mode == IR_RECEIVE) {
173 uint16_t crc = 0;
174 for (uint8_t i = 0; i < ir_global.pos; i++) {
175 crc = _crc16_update(crc, LO8(ir_global.time[i]));
176 crc = _crc16_update(crc, HI8(ir_global.time[i]));
177 }
178
179 /* remember code and length */
180 ir_global.last = crc;
181 ir_global.length = ir_global.pos/2;
182
183 /*
184 * insert code evaluation here...
185 */
186
187 ui_blink(0x1, 0);
188
189 ir_global.pos = 0;
190 state = READY;
191 } else {
192 ui_blink(0, 0x1);
193 ir_set_mode(IR_DISABLED);
194 }
195 }
196 }
Impressum, Datenschutz