]>
git.zerfleddert.de Git - fnordlicht-mini/blob - firmware/fnordlicht-controller/ir.c
2 * ox - infrared to usb keyboard/mouse adapter
4 * by Alexander Neumann <alexander@lochraster.org>
6 * inspired by InfraHID by Alex Badea,
7 * see http://vamposdecampos.googlepages.com/infrahid.html
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.
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.
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.
22 * For more information on the GPL, please go to:
23 * http://www.gnu.org/copyleft/gpl.html
27 #include <avr/interrupt.h>
28 #include <avr/pgmspace.h>
30 #include <util/crc16.h>
33 #include "../common/common.h"
36 #include "ir-cluster.h"
40 #define IR_DDR _DDRPORT(IR_PORTNAME)
41 #define IR_PORT _OUTPORT(IR_PORTNAME)
45 # define IR_VECT PCINT0_vect
48 # define IR_VECT PCINT1_vect
51 # define IR_VECT PCINT2_vect
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)
59 /* 8 should be enough for everybody! */
60 #define MAX_CLUSTERS 8
62 /* internal state machine */
69 volatile struct ir_global_t ir_global
;
73 /* initialize input pin (with pullup) */
74 IR_DDR
&= ~_BV(IR_PIN
);
75 IR_PORT
|= _BV(IR_PIN
);
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 */
83 void ir_set_mode(enum ir_mode_t mode
)
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
);
90 /* clear interrupt flags */
92 } else if (ir_global
.mode
== IR_DISABLED
&& mode
!= IR_DISABLED
) {
93 /* clear interrupt flags */
100 /* enable pin change interrupt */
101 IR_PCMSK
|= _BV(IR_INT
);
102 PCICR
|= _BV(IR_PCIE
);
105 ir_global
.mode
= mode
;
107 if (mode
== IR_DECODE
|| mode
== IR_RAW
)
111 ISR(IR_VECT
, ISR_NOBLOCK
)
114 uint16_t value
= TCNT1
;
117 /* do not store the first 'off' timing value */
120 else if (state
== LISTEN
) {
121 ir_global
.time
[ir_global
.pos
++] = value
;
123 /* check if we reached the end of the array */
124 if (ir_global
.pos
== MAX_CODE_LENGTH
)
131 if (ir_global
.mode
== IR_DISABLED
)
134 /* check for timeout */
135 if (TIFR1
& _BV(OCF1A
)) {
136 /* clear interrupt flag */
139 /* if ir has been detected, process code, else return to listening */
140 if (ir_global
.pos
> 1) {
143 /* set last timing to zero */
144 if (ir_global
.pos
% 2 == 0)
145 ir_global
.time
[ir_global
.pos
-1] = 0;
147 ir_global
.time
[ir_global
.pos
++] = 0;
152 /* if code is complete, process! */
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
];
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
);
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
);
166 ir_global
.time
[i
] = data_on
| (data_off
<< 8);
172 if (ir_global
.mode
== IR_RECEIVE
) {
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
]));
179 /* remember code and length */
180 ir_global
.last
= crc
;
181 ir_global
.length
= ir_global
.pos
/2;
184 * insert code evaluation here...
193 ir_set_mode(IR_DISABLED
);