]> cloudbase.mooo.com Git - irmp.git/blob - irsnd.c
Version 1.3.1
[irmp.git] / irsnd.c
1 /*---------------------------------------------------------------------------------------------------------------------------------------------------
2 * @file irsnd.c
3 *
4 * Copyright (c) 2010 Frank Meyer - frank(at)fli4l.de
5 *
6 * $Id: irsnd.c,v 1.9 2010/04/28 14:58:59 fm Exp $
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *---------------------------------------------------------------------------------------------------------------------------------------------------
13 */
14
15 #ifdef unix // test/debug on linux/unix
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <inttypes.h>
21
22 #define DEBUG
23 #define F_CPU 8000000L
24
25 #else // not unix:
26
27 #ifdef WIN32 // test/debug on windows
28 #include <stdio.h>
29 #define F_CPU 8000000L
30 typedef unsigned char uint8_t;
31 typedef unsigned short uint16_t;
32 #define DEBUG
33
34 #else
35
36 #ifdef CODEVISION
37 #define COM2A0 6
38 #define WGM21 1
39 #define CS20 0
40 #else
41 #include <inttypes.h>
42 #include <avr/io.h>
43 #include <util/delay.h>
44 #include <avr/pgmspace.h>
45 #endif // CODEVISION
46
47 #endif // WIN32
48 #endif // unix
49
50 #include "irmp.h"
51 #include "irsndconfig.h"
52 #include "irsnd.h"
53
54 #define SIRCS_START_BIT_PULSE_LEN (uint8_t)(F_INTERRUPTS * SIRCS_START_BIT_PULSE_TIME + 0.5)
55 #define SIRCS_START_BIT_PAUSE_LEN (uint8_t)(F_INTERRUPTS * SIRCS_START_BIT_PAUSE_TIME + 0.5)
56 #define SIRCS_1_PULSE_LEN (uint8_t)(F_INTERRUPTS * SIRCS_1_PULSE_TIME + 0.5)
57 #define SIRCS_0_PULSE_LEN (uint8_t)(F_INTERRUPTS * SIRCS_0_PULSE_TIME + 0.5)
58 #define SIRCS_PAUSE_LEN (uint8_t)(F_INTERRUPTS * SIRCS_PAUSE_TIME + 0.5)
59 #define SIRCS_REPETITION_LEN (uint16_t)(F_INTERRUPTS * SIRCS_REPETITION_TIME + 0.5) // use uint16_t!
60
61 #define NEC_START_BIT_PULSE_LEN (uint8_t)(F_INTERRUPTS * NEC_START_BIT_PULSE_TIME + 0.5)
62 #define NEC_START_BIT_PAUSE_LEN (uint8_t)(F_INTERRUPTS * NEC_START_BIT_PAUSE_TIME + 0.5)
63 #define NEC_PULSE_LEN (uint8_t)(F_INTERRUPTS * NEC_PULSE_TIME + 0.5)
64 #define NEC_1_PAUSE_LEN (uint8_t)(F_INTERRUPTS * NEC_1_PAUSE_TIME + 0.5)
65 #define NEC_0_PAUSE_LEN (uint8_t)(F_INTERRUPTS * NEC_0_PAUSE_TIME + 0.5)
66
67 #define SAMSUNG_START_BIT_PULSE_LEN (uint8_t)(F_INTERRUPTS * SAMSUNG_START_BIT_PULSE_TIME + 0.5)
68 #define SAMSUNG_START_BIT_PAUSE_LEN (uint8_t)(F_INTERRUPTS * SAMSUNG_START_BIT_PAUSE_TIME + 0.5)
69 #define SAMSUNG_PULSE_LEN (uint8_t)(F_INTERRUPTS * SAMSUNG_PULSE_TIME + 0.5)
70 #define SAMSUNG_1_PAUSE_LEN (uint8_t)(F_INTERRUPTS * SAMSUNG_1_PAUSE_TIME + 0.5)
71 #define SAMSUNG_0_PAUSE_LEN (uint8_t)(F_INTERRUPTS * SAMSUNG_0_PAUSE_TIME + 0.5)
72
73 #define MATSUSHITA_START_BIT_PULSE_LEN (uint8_t)(F_INTERRUPTS * MATSUSHITA_START_BIT_PULSE_TIME + 0.5)
74 #define MATSUSHITA_START_BIT_PAUSE_LEN (uint8_t)(F_INTERRUPTS * MATSUSHITA_START_BIT_PAUSE_TIME + 0.5)
75 #define MATSUSHITA_PULSE_LEN (uint8_t)(F_INTERRUPTS * MATSUSHITA_PULSE_TIME + 0.5)
76 #define MATSUSHITA_1_PAUSE_LEN (uint8_t)(F_INTERRUPTS * MATSUSHITA_1_PAUSE_TIME + 0.5)
77 #define MATSUSHITA_0_PAUSE_LEN (uint8_t)(F_INTERRUPTS * MATSUSHITA_0_PAUSE_TIME + 0.5)
78
79 #define RECS80_START_BIT_PULSE_LEN (uint8_t)(F_INTERRUPTS * RECS80_START_BIT_PULSE_TIME + 0.5)
80 #define RECS80_START_BIT_PAUSE_LEN (uint8_t)(F_INTERRUPTS * RECS80_START_BIT_PAUSE_TIME + 0.5)
81 #define RECS80_PULSE_LEN (uint8_t)(F_INTERRUPTS * RECS80_PULSE_TIME + 0.5)
82 #define RECS80_1_PAUSE_LEN (uint8_t)(F_INTERRUPTS * RECS80_1_PAUSE_TIME + 0.5)
83 #define RECS80_0_PAUSE_LEN (uint8_t)(F_INTERRUPTS * RECS80_0_PAUSE_TIME + 0.5)
84
85 #define RC5_START_BIT_LEN (uint8_t)(F_INTERRUPTS * RC5_BIT_TIME + 0.5)
86 #define RC5_BIT_LEN (uint8_t)(F_INTERRUPTS * RC5_BIT_TIME + 0.5)
87
88 #define RC6_START_BIT_PULSE_LEN (uint8_t)(F_INTERRUPTS * RC6_START_BIT_PULSE_TIME + 0.5)
89 #define RC6_START_BIT_PAUSE_LEN (uint8_t)(F_INTERRUPTS * RC6_START_BIT_PAUSE_TIME + 0.5)
90 #define RC6_TOGGLE_BIT_LEN (uint8_t)(F_INTERRUPTS * RC6_TOGGLE_BIT_TIME + 0.5)
91 #define RC6_BIT_LEN (uint8_t)(F_INTERRUPTS * RC6_BIT_TIME + 0.5)
92
93 #define DENON_PULSE_LEN (uint8_t)(F_INTERRUPTS * DENON_PULSE_TIME + 0.5)
94 #define DENON_1_PAUSE_LEN (uint8_t)(F_INTERRUPTS * DENON_1_PAUSE_TIME + 0.5)
95 #define DENON_0_PAUSE_LEN (uint8_t)(F_INTERRUPTS * DENON_0_PAUSE_TIME + 0.5)
96 #define DENON_REPETITION_LEN (uint16_t)(F_INTERRUPTS * DENON_REPETITION_TIME + 0.5) // use uint16_t!
97
98 #define RECS80EXT_START_BIT_PULSE_LEN (uint8_t)(F_INTERRUPTS * RECS80EXT_START_BIT_PULSE_TIME + 0.5)
99 #define RECS80EXT_START_BIT_PAUSE_LEN (uint8_t)(F_INTERRUPTS * RECS80EXT_START_BIT_PAUSE_TIME + 0.5)
100 #define RECS80EXT_PULSE_LEN (uint8_t)(F_INTERRUPTS * RECS80EXT_PULSE_TIME + 0.5)
101 #define RECS80EXT_1_PAUSE_LEN (uint8_t)(F_INTERRUPTS * RECS80EXT_1_PAUSE_TIME + 0.5)
102 #define RECS80EXT_0_PAUSE_LEN (uint8_t)(F_INTERRUPTS * RECS80EXT_0_PAUSE_TIME + 0.5)
103
104 #define NUBERT_START_BIT_PULSE_LEN (uint8_t)(F_INTERRUPTS * NUBERT_START_BIT_PULSE_TIME + 0.5)
105 #define NUBERT_START_BIT_PAUSE_LEN (uint8_t)(F_INTERRUPTS * NUBERT_START_BIT_PAUSE_TIME + 0.5)
106 #define NUBERT_1_PULSE_LEN (uint8_t)(F_INTERRUPTS * NUBERT_1_PULSE_TIME + 0.5)
107 #define NUBERT_1_PAUSE_LEN (uint8_t)(F_INTERRUPTS * NUBERT_1_PAUSE_TIME + 0.5)
108 #define NUBERT_0_PULSE_LEN (uint8_t)(F_INTERRUPTS * NUBERT_0_PULSE_TIME + 0.5)
109 #define NUBERT_0_PAUSE_LEN (uint8_t)(F_INTERRUPTS * NUBERT_0_PAUSE_TIME + 0.5)
110 #define NUBERT_REPETITION_LEN (uint16_t)(F_INTERRUPTS * NUBERT_REPETITION_TIME + 0.5) // use uint16_t!
111
112 #define BANG_OLUFSEN_START_BIT1_PULSE_LEN (uint8_t)(F_INTERRUPTS * BANG_OLUFSEN_START_BIT1_PULSE_TIME + 0.5)
113 #define BANG_OLUFSEN_START_BIT1_PAUSE_LEN (uint8_t)(F_INTERRUPTS * BANG_OLUFSEN_START_BIT1_PAUSE_TIME + 0.5)
114 #define BANG_OLUFSEN_START_BIT2_PULSE_LEN (uint8_t)(F_INTERRUPTS * BANG_OLUFSEN_START_BIT2_PULSE_TIME + 0.5)
115 #define BANG_OLUFSEN_START_BIT2_PAUSE_LEN (uint8_t)(F_INTERRUPTS * BANG_OLUFSEN_START_BIT2_PAUSE_TIME + 0.5)
116 #define BANG_OLUFSEN_START_BIT3_PULSE_LEN (uint8_t)(F_INTERRUPTS * BANG_OLUFSEN_START_BIT3_PULSE_TIME + 0.5)
117 #define BANG_OLUFSEN_START_BIT3_PAUSE_LEN (uint8_t)(F_INTERRUPTS * BANG_OLUFSEN_START_BIT3_PAUSE_TIME + 0.5)
118 #define BANG_OLUFSEN_PULSE_LEN (uint8_t)(F_INTERRUPTS * BANG_OLUFSEN_PULSE_TIME + 0.5)
119 #define BANG_OLUFSEN_1_PAUSE_LEN (uint8_t)(F_INTERRUPTS * BANG_OLUFSEN_1_PAUSE_TIME + 0.5)
120 #define BANG_OLUFSEN_0_PAUSE_LEN (uint8_t)(F_INTERRUPTS * BANG_OLUFSEN_0_PAUSE_TIME + 0.5)
121 #define BANG_OLUFSEN_R_PAUSE_LEN (uint8_t)(F_INTERRUPTS * BANG_OLUFSEN_R_PAUSE_TIME + 0.5)
122 #define BANG_OLUFSEN_TRAILER_BIT_PAUSE_LEN (uint8_t)(F_INTERRUPTS * BANG_OLUFSEN_TRAILER_BIT_PAUSE_TIME + 0.5)
123
124 #define IRSND_FREQ_32_KHZ (uint8_t) ((F_CPU / 32000 / 2) - 1)
125 #define IRSND_FREQ_36_KHZ (uint8_t) ((F_CPU / 36000 / 2) - 1)
126 #define IRSND_FREQ_38_KHZ (uint8_t) ((F_CPU / 38000 / 2) - 1)
127 #define IRSND_FREQ_40_KHZ (uint8_t) ((F_CPU / 40000 / 2) - 1)
128 #define IRSND_FREQ_56_KHZ (uint8_t) ((F_CPU / 56000 / 2) - 1)
129 #define IRSND_FREQ_455_KHZ (uint8_t) ((F_CPU / 455000 / 2) - 1)
130
131 static volatile uint8_t irsnd_busy;
132 static volatile uint8_t irsnd_protocol;
133 static volatile uint8_t irsnd_buffer[5];
134 static volatile uint8_t irsnd_is_on = FALSE;
135
136 /*---------------------------------------------------------------------------------------------------------------------------------------------------
137 * Switch PWM on
138 * @details Switches PWM on with a narrow spike on all 3 channels -> leds glowing
139 *---------------------------------------------------------------------------------------------------------------------------------------------------
140 */
141 static void
142 irsnd_on (void)
143 {
144 if (! irsnd_is_on)
145 {
146 #ifndef DEBUG
147 #if defined (__AVR_ATmega32__)
148 TCCR2 |= (1<<COM20)|(1<<WGM21); // = 0x42: toggle OC2A on compare match, clear Timer 2 at compare match OCR2A
149 #else
150 TCCR2A |= (1<<COM2A0)|(1<<WGM21); // = 0x42: toggle OC2A on compare match, clear Timer 2 at compare match OCR2A
151 #endif // __AVR...
152 #endif // DEBUG
153 irsnd_is_on = TRUE;
154 }
155 }
156
157 /*---------------------------------------------------------------------------------------------------------------------------------------------------
158 * Switch PWM off
159 * @details Switches PWM off
160 *---------------------------------------------------------------------------------------------------------------------------------------------------
161 */
162 static void
163 irsnd_off (void)
164 {
165 if (irsnd_is_on)
166 {
167 #ifndef DEBUG
168 #if defined (__AVR_ATmega32__)
169 TCCR2 &= ~(1<<COM20); // normal port operation, OC2A disconnected.
170 #else
171 TCCR2A &= ~(1<<COM2A0); // normal port operation, OC2A disconnected.
172 #endif // __AVR...
173 IRSND_PORT &= ~(1<<IRSND_BIT); // set IRSND_BIT to low
174 #endif // DEBUG
175 irsnd_is_on = FALSE;
176 }
177 }
178
179 /*---------------------------------------------------------------------------------------------------------------------------------------------------
180 * Set PWM frequency
181 * @details sets pwm frequency
182 *---------------------------------------------------------------------------------------------------------------------------------------------------
183 */
184 static void
185 irsnd_set_freq (uint8_t freq)
186 {
187 #ifndef DEBUG
188 #if defined (__AVR_ATmega32__)
189 OCR2 = freq;
190 #else
191 OCR2A = freq;
192 #endif // __AVR...
193 #endif // DEBUG
194 }
195
196 /*---------------------------------------------------------------------------------------------------------------------------------------------------
197 * Initialize the PWM
198 * @details Configures 0CR0A, 0CR0B and 0CR2B as PWM channels
199 *---------------------------------------------------------------------------------------------------------------------------------------------------
200 */
201 void
202 irsnd_init (void)
203 {
204 #ifndef DEBUG
205 IRSND_PORT &= ~(1<<IRSND_BIT); // set IRSND_BIT to low
206 IRSND_DDR |= (1<<IRSND_BIT); // set IRSND_BIT to output
207
208 #if defined (__AVR_ATmega32__)
209 TCCR2 = (1<<WGM21); // CTC mode
210 TCCR2 |= (1<<CS20); // 0x01, start Timer 2, no prescaling
211 #else
212 TCCR2A = (1<<WGM21); // CTC mode
213 TCCR2B |= (1<<CS20); // 0x01, start Timer 2, no prescaling
214 #endif // __AVR...
215
216 irsnd_set_freq (IRSND_FREQ_36_KHZ); // default frequency
217 #endif // DEBUG
218 }
219
220 uint8_t
221 irsnd_is_busy (void)
222 {
223 return irsnd_busy;
224 }
225
226 static uint16_t
227 bitsrevervse (uint16_t x, uint8_t len)
228 {
229 uint16_t xx = 0;
230
231 while(len)
232 {
233 xx <<= 1;
234 if (x & 1)
235 {
236 xx |= 1;
237 }
238 x >>= 1;
239 len--;
240 }
241 return xx;
242 }
243
244
245 uint8_t
246 irsnd_send_data (IRMP_DATA * irmp_data_p)
247 {
248 #if IRSND_SUPPORT_RECS80_PROTOCOL == 1
249 static uint8_t toggle_bit_recs80;
250 #endif
251 #if IRSND_SUPPORT_RECS80EXT_PROTOCOL == 1
252 static uint8_t toggle_bit_recs80ext;
253 #endif
254 #if IRSND_SUPPORT_RC5_PROTOCOL == 1
255 static uint8_t toggle_bit_rc5;
256 #endif
257 uint16_t address;
258 uint16_t command;
259
260 while (irsnd_busy)
261 {
262 ;
263 }
264
265 irsnd_protocol = irmp_data_p->protocol;
266
267 switch (irsnd_protocol)
268 {
269 #if IRSND_SUPPORT_SIRCS_PROTOCOL == 1
270 case IRMP_SIRCS_PROTOCOL:
271 {
272 command = bitsrevervse (irmp_data_p->command, SIRCS_MINIMUM_DATA_LEN);
273
274 irsnd_buffer[0] = (command & 0x0FF0) >> 4; // CCCCCCCC
275 irsnd_buffer[1] = (command & 0x000F) << 4; // CCCC0000
276 irsnd_busy = TRUE;
277 break;
278 }
279 #endif
280 #if IRSND_SUPPORT_NEC_PROTOCOL == 1
281 case IRMP_NEC_PROTOCOL:
282 case IRMP_APPLE_PROTOCOL:
283 {
284 address = bitsrevervse (irmp_data_p->address, NEC_ADDRESS_LEN);
285 command = bitsrevervse (irmp_data_p->command, NEC_COMMAND_LEN);
286
287 irsnd_buffer[0] = (address & 0xFF00) >> 8; // AAAAAAAA
288 irsnd_buffer[1] = (address & 0x00FF); // AAAAAAAA
289 irsnd_buffer[2] = (command & 0xFF00) >> 8; // CCCCCCCC
290
291 if (irsnd_protocol == IRMP_APPLE_PROTOCOL)
292 {
293 irsnd_protocol = IRMP_NEC_PROTOCOL; // APPLE protocol is NEC with fix bitmask instead of inverted command
294 irsnd_buffer[3] = 0x8B; // 10001011
295 }
296 else
297 {
298 irsnd_buffer[3] = ~((command & 0xFF00) >> 8); // cccccccc
299 }
300
301 irsnd_busy = TRUE;
302 break;
303 }
304 #endif
305 #if IRSND_SUPPORT_SAMSUNG_PROTOCOL == 1
306 case IRMP_SAMSUNG_PROTOCOL:
307 {
308 address = bitsrevervse (irmp_data_p->address, SAMSUNG_ADDRESS_LEN);
309 command = bitsrevervse (irmp_data_p->command, SAMSUNG_COMMAND_LEN);
310
311 irsnd_buffer[0] = (address & 0xFF00) >> 8; // AAAAAAAA
312 irsnd_buffer[1] = (address & 0x00FF); // AAAAAAAA
313 irsnd_buffer[2] = (command & 0x00F0) | ((command & 0xF000) >> 12); // IIIICCCC
314 irsnd_buffer[3] = ((command & 0x0F00) >> 4) | ((~(command & 0xF000) >> 12) & 0x0F); // CCCCcccc
315 irsnd_buffer[4] = (~(command & 0x0F00) >> 4) & 0xF0; // cccc0000
316 irsnd_busy = TRUE;
317 break;
318 }
319 case IRMP_SAMSUNG32_PROTOCOL:
320 {
321 address = bitsrevervse (irmp_data_p->address, SAMSUNG_ADDRESS_LEN);
322 command = bitsrevervse (irmp_data_p->command, SAMSUNG32_COMMAND_LEN);
323
324 irsnd_buffer[0] = (address & 0xFF00) >> 8; // AAAAAAAA
325 irsnd_buffer[1] = (address & 0x00FF); // AAAAAAAA
326 irsnd_buffer[2] = (command & 0xFF00) >> 8; // CCCCCCCC
327 irsnd_buffer[3] = (command & 0x00FF); // CCCCCCCC
328 irsnd_busy = TRUE;
329 break;
330 }
331 #endif
332 #if IRSND_SUPPORT_MATSUSHITA_PROTOCOL == 1
333 case IRMP_MATSUSHITA_PROTOCOL:
334 {
335 address = bitsrevervse (irmp_data_p->address, MATSUSHITA_ADDRESS_LEN);
336 command = bitsrevervse (irmp_data_p->command, MATSUSHITA_COMMAND_LEN);
337
338 irsnd_buffer[0] = (command & 0x0FF0) >> 4; // CCCCCCCC
339 irsnd_buffer[1] = ((command & 0x000F) << 4) | ((address & 0x0F00) >> 8); // CCCCAAAA
340 irsnd_buffer[2] = (address & 0x00FF); // AAAAAAAA
341 irsnd_busy = TRUE;
342 break;
343 }
344 #endif
345 #if IRSND_SUPPORT_RECS80_PROTOCOL == 1
346 case IRMP_RECS80_PROTOCOL:
347 {
348 toggle_bit_recs80 = toggle_bit_recs80 ? 0x00 : 0x40;
349
350 irsnd_buffer[0] = 0x80 | toggle_bit_recs80 | ((irmp_data_p->address & 0x0007) << 3) |
351 ((irmp_data_p->command & 0x0038) >> 3); // STAAACCC
352 irsnd_buffer[1] = (irmp_data_p->command & 0x07) << 5; // CCC00000
353 irsnd_busy = TRUE;
354 break;
355 }
356 #endif
357 #if IRSND_SUPPORT_RECS80EXT_PROTOCOL == 1
358 case IRMP_RECS80EXT_PROTOCOL:
359 {
360 toggle_bit_recs80ext = toggle_bit_recs80ext ? 0x00 : 0x40;
361
362 irsnd_buffer[0] = 0x80 | toggle_bit_recs80ext | ((irmp_data_p->address & 0x000F) << 2) |
363 ((irmp_data_p->command & 0x0030) >> 4); // STAAAACC
364 irsnd_buffer[1] = (irmp_data_p->command & 0x0F) << 4; // CCCC0000
365 irsnd_busy = TRUE;
366 break;
367 }
368 #endif
369 #if IRSND_SUPPORT_RC5_PROTOCOL == 1
370 case IRMP_RC5_PROTOCOL:
371 {
372 toggle_bit_rc5 = toggle_bit_rc5 ? 0x00 : 0x40;
373
374 irsnd_buffer[0] = ((irmp_data_p->command & 0x40) ? 0x00 : 0x80) | toggle_bit_rc5 |
375 ((irmp_data_p->address & 0x001F) << 1) | ((irmp_data_p->command & 0x20) >> 5); // CTAAAAAC
376 irsnd_buffer[1] = (irmp_data_p->command & 0x1F) << 3; // CCCCC000
377 irsnd_busy = TRUE;
378 break;
379 }
380 #endif
381 #if IRSND_SUPPORT_DENON_PROTOCOL == 1
382 case IRMP_DENON_PROTOCOL:
383 {
384 irsnd_buffer[0] = ((irmp_data_p->address & 0x1F) << 3) | ((irmp_data_p->command & 0x0380) >> 7); // AAAAACCC
385 irsnd_buffer[1] = (irmp_data_p->command & 0x7F) << 1; // CCCCCCC0
386 irsnd_buffer[2] = ((irmp_data_p->address & 0x1F) << 3) | (((~irmp_data_p->command) & 0x0380) >> 7); // AAAAACCC
387 irsnd_buffer[3] = (~(irmp_data_p->command) & 0x7F) << 1; // CCCCCCC0
388 irsnd_busy = TRUE;
389 break;
390 }
391 #endif
392 #if IRSND_SUPPORT_NUBERT_PROTOCOL == 1
393 case IRMP_NUBERT_PROTOCOL:
394 {
395 irsnd_buffer[0] = irmp_data_p->command >> 2; // CCCCCCCC
396 irsnd_buffer[1] = (irmp_data_p->command & 0x0003) << 6; // CC000000
397 irsnd_busy = TRUE;
398 break;
399 }
400 #endif
401 #if IRSND_SUPPORT_BANG_OLUFSEN_PROTOCOL == 1
402 case IRMP_BANG_OLUFSEN_PROTOCOL:
403 {
404 irsnd_buffer[0] = irmp_data_p->command >> 11; // SXSCCCCC
405 irsnd_buffer[1] = irmp_data_p->command >> 3; // CCCCCCCC
406 irsnd_buffer[2] = (irmp_data_p->command & 0x0007) << 5; // CCC00000
407 irsnd_busy = TRUE;
408 break;
409 }
410 #endif
411 default:
412 {
413 break;
414 }
415 }
416
417 return irsnd_busy;
418 }
419
420 /*---------------------------------------------------------------------------------------------------------------------------------------------------
421 * ISR routine
422 * @details ISR routine, called 10000 times per second
423 *---------------------------------------------------------------------------------------------------------------------------------------------------
424 */
425 uint8_t
426 irsnd_ISR (void)
427 {
428 static uint8_t current_bit = 0xFF;
429 static uint8_t pulse_counter;
430 static uint8_t pause_counter;
431 static uint8_t startbit_pulse_len;
432 static uint8_t startbit_pause_len;
433 static uint8_t pulse_1_len;
434 static uint8_t pause_1_len;
435 static uint8_t pulse_0_len;
436 static uint8_t pause_0_len;
437 static uint8_t has_stop_bit;
438 static uint8_t new_frame = TRUE;
439 static uint8_t complete_data_len;
440 static uint8_t n_frames; // number of repetitions
441 static uint8_t frame_counter; // repetition counter
442 static uint16_t repetition_pause; // pause before repetition, uint16_t!
443 static uint16_t repetition_pause_counter; // pause before repetition, uint16_t!
444 #if IRSND_SUPPORT_BANG_OLUFSEN_PROTOCOL == 1
445 static uint8_t last_bit_value;
446 #endif
447 static uint8_t pulse_len = 0xFF;
448 static uint8_t pause_len = 0xFF;
449
450 if (irsnd_busy)
451 {
452 if (current_bit == 0xFF && new_frame) // start of transmission...
453 {
454 if (frame_counter > 0)
455 {
456 repetition_pause_counter++;
457
458 if (repetition_pause_counter >= repetition_pause)
459 {
460 repetition_pause_counter = 0;
461
462 if (irsnd_protocol == IRMP_DENON_PROTOCOL)
463 {
464 current_bit = 16;
465 complete_data_len = 2 * DENON_COMPLETE_DATA_LEN + 1;
466 }
467 }
468 else
469 {
470 #ifdef DEBUG
471 if (irsnd_is_on)
472 {
473 putchar ('0');
474 }
475 else
476 {
477 putchar ('1');
478 }
479 #endif
480 return irsnd_busy;
481 }
482 }
483 else
484 {
485 pulse_counter = 0;
486 pause_counter = 0;
487
488 switch (irsnd_protocol)
489 {
490 #if IRSND_SUPPORT_SIRCS_PROTOCOL == 1
491 case IRMP_SIRCS_PROTOCOL:
492 {
493 startbit_pulse_len = SIRCS_START_BIT_PULSE_LEN;
494 startbit_pause_len = SIRCS_START_BIT_PAUSE_LEN;
495 pulse_1_len = SIRCS_1_PULSE_LEN;
496 pause_1_len = SIRCS_PAUSE_LEN;
497 pulse_0_len = SIRCS_0_PULSE_LEN;
498 pause_0_len = SIRCS_PAUSE_LEN;
499 has_stop_bit = SIRCS_STOP_BIT;
500 complete_data_len = SIRCS_MINIMUM_DATA_LEN;
501 n_frames = SIRCS_REPETITION_CNT;
502 repetition_pause = SIRCS_REPETITION_LEN; // 45 ms pause
503 irsnd_set_freq (IRSND_FREQ_40_KHZ);
504 break;
505 }
506 #endif
507 #if IRSND_SUPPORT_NEC_PROTOCOL == 1
508 case IRMP_NEC_PROTOCOL:
509 {
510 startbit_pulse_len = NEC_START_BIT_PULSE_LEN;
511 startbit_pause_len = NEC_START_BIT_PAUSE_LEN;
512 pulse_1_len = NEC_PULSE_LEN;
513 pause_1_len = NEC_1_PAUSE_LEN;
514 pulse_0_len = NEC_PULSE_LEN;
515 pause_0_len = NEC_0_PAUSE_LEN;
516 has_stop_bit = NEC_STOP_BIT;
517 complete_data_len = NEC_COMPLETE_DATA_LEN;
518 n_frames = 1;
519 irsnd_set_freq (IRSND_FREQ_38_KHZ);
520 break;
521 }
522 #endif
523 #if IRSND_SUPPORT_SAMSUNG_PROTOCOL == 1
524 case IRMP_SAMSUNG_PROTOCOL:
525 {
526 startbit_pulse_len = SAMSUNG_START_BIT_PULSE_LEN;
527 startbit_pause_len = SAMSUNG_START_BIT_PAUSE_LEN;
528 pulse_1_len = SAMSUNG_PULSE_LEN;
529 pause_1_len = SAMSUNG_1_PAUSE_LEN;
530 pulse_0_len = SAMSUNG_PULSE_LEN;
531 pause_0_len = SAMSUNG_0_PAUSE_LEN;
532 has_stop_bit = SAMSUNG_STOP_BIT;
533 complete_data_len = SAMSUNG_COMPLETE_DATA_LEN;
534 n_frames = 1;
535 irsnd_set_freq (IRSND_FREQ_38_KHZ);
536 break;
537 }
538
539 case IRMP_SAMSUNG32_PROTOCOL:
540 {
541 startbit_pulse_len = SAMSUNG_START_BIT_PULSE_LEN;
542 startbit_pause_len = SAMSUNG_START_BIT_PAUSE_LEN;
543 pulse_1_len = SAMSUNG_PULSE_LEN;
544 pause_1_len = SAMSUNG_1_PAUSE_LEN;
545 pulse_0_len = SAMSUNG_PULSE_LEN;
546 pause_0_len = SAMSUNG_0_PAUSE_LEN;
547 has_stop_bit = SAMSUNG_STOP_BIT;
548 complete_data_len = SAMSUNG32_COMPLETE_DATA_LEN;
549 n_frames = 1;
550 irsnd_set_freq (IRSND_FREQ_38_KHZ);
551 break;
552 }
553 #endif
554 #if IRSND_SUPPORT_MATSUSHITA_PROTOCOL == 1
555 case IRMP_MATSUSHITA_PROTOCOL:
556 {
557 startbit_pulse_len = MATSUSHITA_START_BIT_PULSE_LEN;
558 startbit_pause_len = MATSUSHITA_START_BIT_PAUSE_LEN;
559 pulse_1_len = MATSUSHITA_PULSE_LEN;
560 pause_1_len = MATSUSHITA_1_PAUSE_LEN;
561 pulse_0_len = MATSUSHITA_PULSE_LEN;
562 pause_0_len = MATSUSHITA_0_PAUSE_LEN;
563 has_stop_bit = MATSUSHITA_STOP_BIT;
564 complete_data_len = MATSUSHITA_COMPLETE_DATA_LEN;
565 n_frames = 1;
566 irsnd_set_freq (IRSND_FREQ_36_KHZ);
567 break;
568 }
569 #endif
570 #if IRSND_SUPPORT_RECS80_PROTOCOL == 1
571 case IRMP_RECS80_PROTOCOL:
572 {
573 startbit_pulse_len = RECS80_START_BIT_PULSE_LEN;
574 startbit_pause_len = RECS80_START_BIT_PAUSE_LEN;
575 pulse_1_len = RECS80_PULSE_LEN;
576 pause_1_len = RECS80_1_PAUSE_LEN;
577 pulse_0_len = RECS80_PULSE_LEN;
578 pause_0_len = RECS80_0_PAUSE_LEN;
579 has_stop_bit = RECS80_STOP_BIT;
580 complete_data_len = RECS80_COMPLETE_DATA_LEN;
581 n_frames = 1;
582 irsnd_set_freq (IRSND_FREQ_38_KHZ);
583 break;
584 }
585 #endif
586 #if IRSND_SUPPORT_RECS80EXT_PROTOCOL == 1
587 case IRMP_RECS80EXT_PROTOCOL:
588 {
589 startbit_pulse_len = RECS80EXT_START_BIT_PULSE_LEN;
590 startbit_pause_len = RECS80EXT_START_BIT_PAUSE_LEN;
591 pulse_1_len = RECS80EXT_PULSE_LEN;
592 pause_1_len = RECS80EXT_1_PAUSE_LEN;
593 pulse_0_len = RECS80EXT_PULSE_LEN;
594 pause_0_len = RECS80EXT_0_PAUSE_LEN;
595 has_stop_bit = RECS80EXT_STOP_BIT;
596 complete_data_len = RECS80EXT_COMPLETE_DATA_LEN;
597 n_frames = 1;
598 irsnd_set_freq (IRSND_FREQ_38_KHZ);
599 break;
600 }
601 #endif
602 #if IRSND_SUPPORT_RC5_PROTOCOL == 1
603 case IRMP_RC5_PROTOCOL:
604 {
605 startbit_pulse_len = RC5_BIT_LEN;
606 startbit_pause_len = RC5_BIT_LEN;
607 pulse_1_len = RC5_BIT_LEN;
608 pause_1_len = RC5_BIT_LEN;
609 pulse_0_len = RC5_BIT_LEN;
610 pause_0_len = RC5_BIT_LEN;
611 has_stop_bit = RC5_STOP_BIT;
612 complete_data_len = RC5_COMPLETE_DATA_LEN;
613 n_frames = 1;
614 irsnd_set_freq (IRSND_FREQ_36_KHZ);
615 break;
616 }
617 #endif
618 #if IRSND_SUPPORT_DENON_PROTOCOL == 1
619 case IRMP_DENON_PROTOCOL:
620 {
621 startbit_pulse_len = 0x00;
622 startbit_pause_len = 0x00;
623 pulse_1_len = DENON_PULSE_LEN;
624 pause_1_len = DENON_1_PAUSE_LEN;
625 pulse_0_len = DENON_PULSE_LEN;
626 pause_0_len = DENON_0_PAUSE_LEN;
627 has_stop_bit = DENON_STOP_BIT;
628 complete_data_len = DENON_COMPLETE_DATA_LEN;
629 n_frames = 2;
630 repetition_pause = DENON_REPETITION_LEN; // 65 ms pause after 1st frame (15 bits)
631 irsnd_set_freq (IRSND_FREQ_32_KHZ);
632 break;
633 }
634 #endif
635 #if IRSND_SUPPORT_NUBERT_PROTOCOL == 1
636 case IRMP_NUBERT_PROTOCOL:
637 {
638 startbit_pulse_len = NUBERT_START_BIT_PULSE_LEN;
639 startbit_pause_len = NUBERT_START_BIT_PAUSE_LEN;
640 pulse_1_len = NUBERT_1_PULSE_LEN;
641 pause_1_len = NUBERT_1_PAUSE_LEN;
642 pulse_0_len = NUBERT_0_PULSE_LEN;
643 pause_0_len = NUBERT_0_PAUSE_LEN;
644 has_stop_bit = NUBERT_STOP_BIT;
645 complete_data_len = NUBERT_COMPLETE_DATA_LEN;
646 n_frames = 2;
647 repetition_pause = NUBERT_REPETITION_LEN; // 35 ms pause
648 irsnd_set_freq (IRSND_FREQ_36_KHZ);
649 break;
650 }
651 #endif
652 #if IRSND_SUPPORT_BANG_OLUFSEN_PROTOCOL == 1
653 case IRMP_BANG_OLUFSEN_PROTOCOL:
654 {
655 startbit_pulse_len = BANG_OLUFSEN_START_BIT1_PULSE_LEN;
656 startbit_pause_len = BANG_OLUFSEN_START_BIT1_PAUSE_LEN;
657 pulse_1_len = BANG_OLUFSEN_PULSE_LEN;
658 pause_1_len = BANG_OLUFSEN_1_PAUSE_LEN;
659 pulse_0_len = BANG_OLUFSEN_PULSE_LEN;
660 pause_0_len = BANG_OLUFSEN_0_PAUSE_LEN;
661 has_stop_bit = BANG_OLUFSEN_STOP_BIT;
662 complete_data_len = BANG_OLUFSEN_COMPLETE_DATA_LEN;
663 n_frames = 1;
664 last_bit_value = 0;
665 irsnd_set_freq (IRSND_FREQ_455_KHZ);
666 break;
667 }
668 #endif
669 default:
670 {
671 irsnd_busy = FALSE;
672 break;
673 }
674 }
675 }
676 }
677
678 if (irsnd_busy)
679 {
680 new_frame = FALSE;
681 switch (irsnd_protocol)
682 {
683 #if IRSND_SUPPORT_SIRCS_PROTOCOL == 1
684 case IRMP_SIRCS_PROTOCOL:
685 #endif
686 #if IRSND_SUPPORT_NEC_PROTOCOL == 1
687 case IRMP_NEC_PROTOCOL:
688 #endif
689 #if IRSND_SUPPORT_SAMSUNG_PROTOCOL == 1
690 case IRMP_SAMSUNG_PROTOCOL:
691 case IRMP_SAMSUNG32_PROTOCOL:
692 #endif
693 #if IRSND_SUPPORT_MATSUSHITA_PROTOCOL == 1
694 case IRMP_MATSUSHITA_PROTOCOL:
695 #endif
696 #if IRSND_SUPPORT_RECS80_PROTOCOL == 1
697 case IRMP_RECS80_PROTOCOL:
698 #endif
699 #if IRSND_SUPPORT_RECS80EXT_PROTOCOL == 1
700 case IRMP_RECS80EXT_PROTOCOL:
701 #endif
702 #if IRSND_SUPPORT_DENON_PROTOCOL == 1
703 case IRMP_DENON_PROTOCOL:
704 #endif
705 #if IRSND_SUPPORT_NUBERT_PROTOCOL == 1
706 case IRMP_NUBERT_PROTOCOL:
707 #endif
708 #if IRSND_SUPPORT_BANG_OLUFSEN_PROTOCOL == 1
709 case IRMP_BANG_OLUFSEN_PROTOCOL:
710 #endif
711 {
712 if (pulse_counter == 0)
713 {
714 if (current_bit == 0xFF) // send start bit
715 {
716 pulse_len = startbit_pulse_len;
717 pause_len = startbit_pause_len;
718 }
719 else if (current_bit < complete_data_len) // send n'th bit
720 {
721 #if IRSND_SUPPORT_SAMSUNG_PROTOCOL == 1
722 if (irsnd_protocol == IRMP_SAMSUNG_PROTOCOL)
723 {
724 if (current_bit < SAMSUNG_ADDRESS_LEN) // send address bits
725 {
726 pulse_len = SAMSUNG_PULSE_LEN;
727 pause_len = (irsnd_buffer[current_bit / 8] & (1<<(7-(current_bit % 8)))) ?
728 SAMSUNG_1_PAUSE_LEN : SAMSUNG_0_PAUSE_LEN;
729 }
730 else if (current_bit == SAMSUNG_ADDRESS_LEN) // send SYNC bit (16th bit)
731 {
732 pulse_len = SAMSUNG_PULSE_LEN;
733 pause_len = SAMSUNG_START_BIT_PAUSE_LEN;
734 }
735 else if (current_bit < SAMSUNG_COMPLETE_DATA_LEN) // send n'th bit
736 {
737 uint8_t cur_bit = current_bit - 1; // sync skipped, offset = -1 !
738
739 pulse_len = SAMSUNG_PULSE_LEN;
740 pause_len = (irsnd_buffer[cur_bit / 8] & (1<<(7-(cur_bit % 8)))) ?
741 SAMSUNG_1_PAUSE_LEN : SAMSUNG_0_PAUSE_LEN;
742 }
743 }
744 else
745 #endif
746
747 #if IRSND_SUPPORT_BANG_OLUFSEN_PROTOCOL == 1
748 if (irsnd_protocol == IRMP_BANG_OLUFSEN_PROTOCOL)
749 {
750 if (current_bit == 0) // send 2nd start bit
751 {
752 pulse_len = BANG_OLUFSEN_START_BIT2_PULSE_LEN;
753 pause_len = BANG_OLUFSEN_START_BIT2_PAUSE_LEN;
754 }
755 else if (current_bit == 1) // send 3rd start bit
756 {
757 pulse_len = BANG_OLUFSEN_START_BIT3_PULSE_LEN;
758 pause_len = BANG_OLUFSEN_START_BIT3_PAUSE_LEN;
759 }
760 else if (current_bit == 2) // send 4th start bit
761 {
762 pulse_len = BANG_OLUFSEN_START_BIT2_PULSE_LEN;
763 pause_len = BANG_OLUFSEN_START_BIT2_PAUSE_LEN;
764 }
765 else if (current_bit == 19) // send trailer bit
766 {
767 pulse_len = BANG_OLUFSEN_PULSE_LEN;
768 pause_len = BANG_OLUFSEN_TRAILER_BIT_PAUSE_LEN;
769 }
770 else if (current_bit < BANG_OLUFSEN_COMPLETE_DATA_LEN) // send n'th bit
771 {
772 uint8_t cur_bit_value = (irsnd_buffer[current_bit / 8] & (1<<(7-(current_bit % 8)))) ? 1 : 0;
773 pulse_len = BANG_OLUFSEN_PULSE_LEN;
774
775 if (cur_bit_value == last_bit_value)
776 {
777 pause_len = BANG_OLUFSEN_R_PAUSE_LEN;
778 }
779 else
780 {
781 pause_len = cur_bit_value ? BANG_OLUFSEN_1_PAUSE_LEN : BANG_OLUFSEN_0_PAUSE_LEN;
782 last_bit_value = cur_bit_value;
783 }
784 }
785 }
786 else
787 #endif
788 if (irsnd_buffer[current_bit / 8] & (1<<(7-(current_bit % 8))))
789 {
790 pulse_len = pulse_1_len;
791 pause_len = pause_1_len;
792 }
793 else
794 {
795 pulse_len = pulse_0_len;
796 pause_len = pause_0_len;
797 }
798 }
799 else if (has_stop_bit) // send stop bit
800 {
801 pulse_len = pulse_0_len;
802
803 if (frame_counter < n_frames)
804 {
805 pause_len = pause_0_len;
806 }
807 else
808 {
809 pause_len = 255; // last frame: pause of 255
810 }
811 }
812 }
813
814 if (pulse_counter < pulse_len)
815 {
816 if (pulse_counter == 0)
817 {
818 irsnd_on ();
819 }
820 pulse_counter++;
821 }
822 else if (pause_counter < pause_len)
823 {
824 if (pause_counter == 0)
825 {
826 irsnd_off ();
827 }
828 pause_counter++;
829 }
830 else
831 {
832 current_bit++;
833
834 if (current_bit >= complete_data_len + has_stop_bit)
835 {
836 current_bit = 0xFF;
837 frame_counter++;
838
839 if (frame_counter == n_frames)
840 {
841 irsnd_busy = FALSE;
842 frame_counter = 0;
843 }
844 new_frame = TRUE;
845 }
846
847 pulse_counter = 0;
848 pause_counter = 0;
849 }
850 break;
851 }
852 #if IRSND_SUPPORT_RC5_PROTOCOL == 1
853 case IRMP_RC5_PROTOCOL:
854 {
855 uint8_t first_pulse;
856 uint8_t next_bit = FALSE;
857
858 if (current_bit == 0xFF) // 1 start bit
859 {
860 first_pulse = FALSE;
861 }
862 else // send n'th bit
863 {
864 first_pulse = (irsnd_buffer[current_bit / 8] & (1<<(7-(current_bit % 8)))) ? FALSE : TRUE;
865 }
866
867 if (first_pulse)
868 {
869 if (pulse_counter < RC5_BIT_LEN)
870 {
871 if (pulse_counter == 0)
872 {
873 irsnd_on ();
874 }
875 pulse_counter++;
876 }
877 else if (pause_counter < RC5_BIT_LEN)
878 {
879 if (pause_counter == 0)
880 {
881 irsnd_off ();
882 }
883 pause_counter++;
884 }
885 else
886 {
887 next_bit = TRUE;
888 }
889 }
890 else
891 {
892 if (pause_counter < RC5_BIT_LEN)
893 {
894 if (pause_counter == 0)
895 {
896 irsnd_off ();
897 }
898 pause_counter++;
899 }
900 else if (pulse_counter < RC5_BIT_LEN)
901 {
902 if (pulse_counter == 0)
903 {
904 irsnd_on ();
905 }
906 pulse_counter++;
907 }
908 else
909 {
910 next_bit = TRUE;
911 }
912 }
913
914 if (next_bit)
915 {
916 current_bit++;
917
918 if (current_bit >= RC5_COMPLETE_DATA_LEN)
919 {
920 current_bit = 0xFF;
921 irsnd_busy = FALSE;
922 new_frame = TRUE;
923 irsnd_off ();
924 }
925
926 pulse_counter = 0;
927 pause_counter = 0;
928 }
929 break;
930 }
931 #endif // IRSND_SUPPORT_RC5_PROTOCOL
932 default:
933 {
934 irsnd_busy = FALSE;
935 break;
936 }
937 }
938 }
939 }
940
941 #ifdef DEBUG
942 if (irsnd_is_on)
943 {
944 putchar ('0');
945 }
946 else
947 {
948 putchar ('1');
949 }
950 #endif
951
952 return irsnd_busy;
953 }
954
955 #ifdef DEBUG
956
957 // main function - for unix/linux + windows only!
958 // AVR: see main.c!
959 // Compile it under linux with:
960 // cc irsnd.c -o irsnd
961 //
962 // usage: ./irsnd protocol hex-address hex-command >filename
963
964 int
965 main (int argc, char ** argv)
966 {
967 int idx;
968 int cnt;
969 int protocol;
970 int address;
971 int command;
972 int repeat = 1;
973 IRMP_DATA irmp_data;
974
975 if (argc != 4)
976 {
977 fprintf (stderr, "usage: %s protocol hex-address hex-command > filename\n", argv[0]);
978 return 1;
979 }
980
981 if (sscanf (argv[1], "%d", &protocol) == 1 &&
982 sscanf (argv[2], "%x", &address) == 1 &&
983 sscanf (argv[3], "%x", &command) == 1)
984 {
985 irmp_data.protocol = protocol;
986 irmp_data.address = address;
987 irmp_data.command = command;
988
989 irsnd_init ();
990
991 for (cnt = 0; cnt < repeat; cnt++)
992 {
993 (void) irsnd_send_data (&irmp_data);
994
995 for (idx = 0; idx < 3000; idx++)
996 {
997 irsnd_ISR ();
998 }
999 }
1000
1001 putchar ('\n');
1002 }
1003 else
1004 {
1005 fprintf (stderr, "%s: wrong arguments\n", argv[0]);
1006 return 1;
1007 }
1008 return 0;
1009 }
1010
1011 #endif // DEBUG