LIRC libraries
Linux Infrared Remote Control
Loading...
Searching...
No Matches
transmit.c
Go to the documentation of this file.
1/******************************************************************
2** transmit.c **************************************************************
3****************************************************************************
4*
5* functions that prepare IR codes for transmitting
6*
7* Copyright (C) 1999-2004 Christoph Bartelmus <lirc@bartelmus.de>
8*
9*/
10
16
17#ifdef HAVE_CONFIG_H
18# include <config.h>
19#endif
20
21/* if the gap is lower than this value, we will concatenate the
22 * signals and send the signal chain at a single blow */
23#define LIRCD_EXACT_GAP_THRESHOLD 10000
24
25#include "media/lirc.h"
26
27#include "lirc/lirc_log.h"
28#include "lirc/transmit.h"
29
30static const logchannel_t logchannel = LOG_LIB;
31
35static struct sbuf {
36 lirc_t* data;
37
38 lirc_t _data[WBUF_SIZE];
39 int wptr;
40 int too_long;
41 int is_biphase;
42 lirc_t pendingp;
43 lirc_t pendings;
44 lirc_t sum;
45} send_buffer;
46
47
48static void send_signals(lirc_t* signals, int n);
49static int init_send_or_sim(struct ir_remote* remote, struct ir_ncode* code, int sim, int repeat_preset);
50
51/*
52 * sending stuff
53 */
54
59{
60 memset(&send_buffer, 0, sizeof(send_buffer));
61}
62
63static void clear_send_buffer(void)
64{
65 log_trace2("clearing transmit buffer");
66 send_buffer.wptr = 0;
67 send_buffer.too_long = 0;
68 send_buffer.is_biphase = 0;
69 send_buffer.pendingp = 0;
70 send_buffer.pendings = 0;
71 send_buffer.sum = 0;
72}
73
74static void add_send_buffer(lirc_t data)
75{
76 if (send_buffer.wptr < WBUF_SIZE) {
77 log_trace2("adding to transmit buffer: %u", data);
78 send_buffer.sum += data;
79 send_buffer._data[send_buffer.wptr] = data;
80 send_buffer.wptr++;
81 } else {
82 send_buffer.too_long = 1;
83 }
84}
85
86static void send_pulse(lirc_t data)
87{
88 if (send_buffer.pendingp > 0) {
89 send_buffer.pendingp += data;
90 } else {
91 if (send_buffer.pendings > 0) {
92 add_send_buffer(send_buffer.pendings);
93 send_buffer.pendings = 0;
94 }
95 send_buffer.pendingp = data;
96 }
97}
98
99static void send_space(lirc_t data)
100{
101 if (send_buffer.wptr == 0 && send_buffer.pendingp == 0) {
102 log_trace("first signal is a space!");
103 return;
104 }
105 if (send_buffer.pendings > 0) {
106 send_buffer.pendings += data;
107 } else {
108 if (send_buffer.pendingp > 0) {
109 add_send_buffer(send_buffer.pendingp);
110 send_buffer.pendingp = 0;
111 }
112 send_buffer.pendings = data;
113 }
114}
115
116static int bad_send_buffer(void)
117{
118 if (send_buffer.too_long != 0)
119 return 1;
120 if (send_buffer.wptr == WBUF_SIZE && send_buffer.pendingp > 0)
121 return 1;
122 return 0;
123}
124
125static int check_send_buffer(void)
126{
127 int i;
128
129 if (send_buffer.wptr == 0) {
130 log_trace("nothing to send");
131 return 0;
132 }
133 for (i = 0; i < send_buffer.wptr; i++) {
134 if (send_buffer.data[i] == 0) {
135 if (i % 2) {
136 log_trace("invalid space: %d", i);
137 } else {
138 log_trace("invalid pulse: %d", i);
139 }
140 return 0;
141 }
142 }
143
144 return 1;
145}
146
147static void flush_send_buffer(void)
148{
149 if (send_buffer.pendingp > 0) {
150 add_send_buffer(send_buffer.pendingp);
151 send_buffer.pendingp = 0;
152 }
153 if (send_buffer.pendings > 0) {
154 add_send_buffer(send_buffer.pendings);
155 send_buffer.pendings = 0;
156 }
157}
158
159static void sync_send_buffer(void)
160{
161 if (send_buffer.pendingp > 0) {
162 add_send_buffer(send_buffer.pendingp);
163 send_buffer.pendingp = 0;
164 }
165 if (send_buffer.wptr > 0 && send_buffer.wptr % 2 == 0)
166 send_buffer.wptr--;
167}
168
169static void send_header(struct ir_remote* remote)
170{
171 if (has_header(remote)) {
172 send_pulse(remote->phead);
173 send_space(remote->shead);
174 }
175}
176
177static void send_foot(struct ir_remote* remote)
178{
179 if (has_foot(remote)) {
180 send_space(remote->sfoot);
181 send_pulse(remote->pfoot);
182 }
183}
184
185static void send_lead(struct ir_remote* remote)
186{
187 if (remote->plead != 0)
188 send_pulse(remote->plead);
189}
190
191static void send_trail(struct ir_remote* remote)
192{
193 if (remote->ptrail != 0)
194 send_pulse(remote->ptrail);
195}
196
197static void send_data(struct ir_remote* remote, ir_code data, int bits, int done)
198{
199 int i;
200 int all_bits = bit_count(remote);
201 int toggle_bit_mask_bits = bits_set(remote->toggle_bit_mask);
202 ir_code mask;
203
204 data = reverse(data, bits);
205 if (is_rcmm(remote)) {
206 mask = 1 << (all_bits - 1 - done);
207 if (bits % 2 || done % 2) {
208 log_error("invalid bit number.");
209 return;
210 }
211 for (i = 0; i < bits; i += 2, mask >>= 2) {
212 switch (data & 3) {
213 case 0:
214 send_pulse(remote->pzero);
215 send_space(remote->szero);
216 break;
217 /* 2 and 1 swapped due to reverse() */
218 case 2:
219 send_pulse(remote->pone);
220 send_space(remote->sone);
221 break;
222 case 1:
223 send_pulse(remote->ptwo);
224 send_space(remote->stwo);
225 break;
226 case 3:
227 send_pulse(remote->pthree);
228 send_space(remote->sthree);
229 break;
230 }
231 data = data >> 2;
232 }
233 return;
234 } else if (is_xmp(remote)) {
235 if (bits % 4 || done % 4) {
236 log_error("invalid bit number.");
237 return;
238 }
239 for (i = 0; i < bits; i += 4) {
240 ir_code nibble;
241
242 nibble = reverse(data & 0xf, 4);
243 send_pulse(remote->pzero);
244 send_space(remote->szero + nibble * remote->sone);
245 data >>= 4;
246 }
247 return;
248 }
249
250 mask = ((ir_code)1) << (all_bits - 1 - done);
251 for (i = 0; i < bits; i++, mask >>= 1) {
252 if (has_toggle_bit_mask(remote) && mask & remote->toggle_bit_mask) {
253 if (toggle_bit_mask_bits == 1) {
254 /* backwards compatibility */
255 data &= ~((ir_code)1);
256 if (remote->toggle_bit_mask_state & mask)
257 data |= (ir_code)1;
258 } else {
259 if (remote->toggle_bit_mask_state & mask)
260 data ^= (ir_code)1;
261 }
262 }
263 if (has_toggle_mask(remote) && mask & remote->toggle_mask && remote->toggle_mask_state % 2)
264 data ^= 1;
265 if (data & 1) {
266 if (is_biphase(remote)) {
267 if (mask & remote->rc6_mask) {
268 send_space(2 * remote->sone);
269 send_pulse(2 * remote->pone);
270 } else {
271 send_space(remote->sone);
272 send_pulse(remote->pone);
273 }
274 } else if (is_space_first(remote)) {
275 send_space(remote->sone);
276 send_pulse(remote->pone);
277 } else {
278 send_pulse(remote->pone);
279 send_space(remote->sone);
280 }
281 } else {
282 if (mask & remote->rc6_mask) {
283 send_pulse(2 * remote->pzero);
284 send_space(2 * remote->szero);
285 } else if (is_space_first(remote)) {
286 send_space(remote->szero);
287 send_pulse(remote->pzero);
288 } else {
289 send_pulse(remote->pzero);
290 send_space(remote->szero);
291 }
292 }
293 data = data >> 1;
294 }
295}
296
297static void send_pre(struct ir_remote* remote)
298{
299 if (has_pre(remote)) {
300 send_data(remote, remote->pre_data, remote->pre_data_bits, 0);
301 if (remote->pre_p > 0 && remote->pre_s > 0) {
302 send_pulse(remote->pre_p);
303 send_space(remote->pre_s);
304 }
305 }
306}
307
308static void send_post(struct ir_remote* remote)
309{
310 if (has_post(remote)) {
311 if (remote->post_p > 0 && remote->post_s > 0) {
312 send_pulse(remote->post_p);
313 send_space(remote->post_s);
314 }
315 send_data(remote, remote->post_data, remote->post_data_bits, remote->pre_data_bits + remote->bits);
316 }
317}
318
319static void send_repeat(struct ir_remote* remote)
320{
321 send_lead(remote);
322 send_pulse(remote->prepeat);
323 send_space(remote->srepeat);
324 send_trail(remote);
325}
326
327static void send_code(struct ir_remote* remote, ir_code code, int repeat)
328{
329 if (!repeat || !(remote->flags & NO_HEAD_REP))
330 send_header(remote);
331 send_lead(remote);
332 send_pre(remote);
333 send_data(remote, code, remote->bits, remote->pre_data_bits);
334 send_post(remote);
335 send_trail(remote);
336 if (!repeat || !(remote->flags & NO_FOOT_REP))
337 send_foot(remote);
338
339 if (!repeat && remote->flags & NO_HEAD_REP && remote->flags & CONST_LENGTH)
340 send_buffer.sum -= remote->phead + remote->shead;
341}
342
343static void send_signals(lirc_t* signals, int n)
344{
345 int i;
346
347 for (i = 0; i < n; i++)
348 add_send_buffer(signals[i]);
349}
350
351int send_buffer_put(struct ir_remote* remote, struct ir_ncode* code)
352{
353 return init_send_or_sim(remote, code, 0, 0);
354}
355
360int init_sim(struct ir_remote* remote, struct ir_ncode* code, int repeat_preset)
361{
362 return init_send_or_sim(remote, code, 1, repeat_preset);
363}
367
368
370{
371 return send_buffer.wptr;
372}
373
374
375const lirc_t* send_buffer_data(void)
376{
377 return send_buffer.data;
378}
379
380lirc_t send_buffer_sum(void)
381{
382 return send_buffer.sum;
383}
384
385static int init_send_or_sim(struct ir_remote* remote, struct ir_ncode* code, int sim, int repeat_preset)
386{
387 int i, repeat = repeat_preset;
388
389 if (is_grundig(remote) || is_serial(remote) || is_bo(remote)) {
390 if (!sim)
391 log_error("sorry, can't send this protocol yet");
392 return 0;
393 }
394 clear_send_buffer();
395 if (strcmp(remote->name, "lirc") == 0) {
396 send_buffer.data[send_buffer.wptr] = LIRC_EOF | 1;
397 send_buffer.wptr += 1;
398 goto final_check;
399 }
400
401 if (is_biphase(remote))
402 send_buffer.is_biphase = 1;
403 if (!sim) {
404 if (repeat_remote == NULL)
405 remote->repeat_countdown = remote->min_repeat;
406 else
407 repeat = 1;
408 }
409
410init_send_loop:
411 if (repeat && has_repeat(remote)) {
412 if (remote->flags & REPEAT_HEADER && has_header(remote))
413 send_header(remote);
414 send_repeat(remote);
415 } else {
416 if (!is_raw(remote)) {
417 ir_code next_code;
418
419 if (sim || code->transmit_state == NULL)
420 next_code = code->code;
421 else
422 next_code = code->transmit_state->code;
423
424 if (repeat && has_repeat_mask(remote))
425 next_code ^= remote->repeat_mask;
426
427 send_code(remote, next_code, repeat);
428 if (!sim && has_toggle_mask(remote)) {
429 remote->toggle_mask_state++;
430 if (remote->toggle_mask_state == 4)
431 remote->toggle_mask_state = 2;
432 }
433 send_buffer.data = send_buffer._data;
434 } else {
435 if (code->signals == NULL) {
436 if (!sim)
437 log_error("no signals for raw send");
438 return 0;
439 }
440 if (send_buffer.wptr > 0) {
441 send_signals(code->signals, code->length);
442 } else {
443 send_buffer.data = code->signals;
444 send_buffer.wptr = code->length;
445 for (i = 0; i < code->length; i++)
446 send_buffer.sum += code->signals[i];
447 }
448 }
449 }
450 sync_send_buffer();
451 if (bad_send_buffer()) {
452 if (!sim)
453 log_error("buffer too small");
454 return 0;
455 }
456 if (sim)
457 goto final_check;
458
459 if (has_repeat_gap(remote) && repeat && has_repeat(remote)) {
460 remote->min_remaining_gap = remote->repeat_gap;
461 remote->max_remaining_gap = remote->repeat_gap;
462 } else if (is_const(remote)) {
463 if (min_gap(remote) > send_buffer.sum) {
464 remote->min_remaining_gap = min_gap(remote) - send_buffer.sum;
465 remote->max_remaining_gap = max_gap(remote) - send_buffer.sum;
466 } else {
467 log_error("too short gap: %u", remote->gap);
468 remote->min_remaining_gap = min_gap(remote);
469 remote->max_remaining_gap = max_gap(remote);
470 return 0;
471 }
472 } else {
473 remote->min_remaining_gap = min_gap(remote);
474 remote->max_remaining_gap = max_gap(remote);
475 }
476 /* update transmit state */
477 if (code->next != NULL) {
478 if (code->transmit_state == NULL) {
479 code->transmit_state = code->next;
480 } else {
481 code->transmit_state = code->transmit_state->next;
482 if (is_xmp(remote) && code->transmit_state == NULL)
483 code->transmit_state = code->next;
484 }
485 }
486 if ((remote->repeat_countdown > 0 || code->transmit_state != NULL)
487 && remote->min_remaining_gap < LIRCD_EXACT_GAP_THRESHOLD) {
488 if (send_buffer.data != send_buffer._data) {
489 lirc_t* signals;
490 int n;
491
492 log_trace("unrolling raw signal optimisation");
493 signals = send_buffer.data;
494 n = send_buffer.wptr;
495 send_buffer.data = send_buffer._data;
496 send_buffer.wptr = 0;
497
498 send_signals(signals, n);
499 }
500 log_trace("concatenating low gap signals");
501 if (code->next == NULL || code->transmit_state == NULL)
502 remote->repeat_countdown--;
503 send_space(remote->min_remaining_gap);
504 flush_send_buffer();
505 send_buffer.sum = 0;
506
507 repeat = 1;
508 goto init_send_loop;
509 }
510 log_trace2("transmit buffer ready");
511
512final_check:
513 if (!check_send_buffer()) {
514 if (!sim) {
515 log_error("invalid send buffer");
516 log_error("this remote configuration cannot be used to transmit");
517 }
518 return 0;
519 }
520 return 1;
521}
int send_buffer_put(struct ir_remote *remote, struct ir_ncode *code)
Initializes the global send buffer for transmitting the code in the second argument,...
Definition transmit.c:351
lirc_t send_buffer_sum(void)
Definition transmit.c:380
struct ir_remote * repeat_remote
Global pointer to the remote that contains the code currently repeating.
Definition ir_remote.c:57
void send_buffer_init(void)
Initializes the global sending buffer.
Definition transmit.c:58
const lirc_t * send_buffer_data(void)
Definition transmit.c:375
int send_buffer_length(void)
Do not document this function.
Definition transmit.c:369
#define REPEAT_HEADER
header is also sent before repeat code
uint64_t ir_code
Denotes an internal coded representation for an IR transmission.
#define NO_FOOT_REP
no foot for key repeats
#define NO_HEAD_REP
no header for key repeats
#define CONST_LENGTH
signal length+gap is always constant
#define LIRC_EOF
Bit manipulator in lirc_t, see lirc.h .
Definition lirc_config.h:90
#define log_trace(fmt,...)
Log a trace message.
Definition lirc_log.h:129
#define log_trace2(fmt,...)
Log a trace2 message.
Definition lirc_log.h:139
#define log_error(fmt,...)
Log an error message.
Definition lirc_log.h:104
logchannel_t
Log channels used to filter messages.
Definition lirc_log.h:53
IR Command, corresponding to one (command defining) line of the configuration file.
One remote as represented in the configuration file.