LIRC libraries
Linux Infrared Remote Control
config_file.c
Go to the documentation of this file.
1 /****************************************************************************
2 ** config_file.c ***********************************************************
3 ****************************************************************************
4 *
5 *
6 * Copyright (C) 1998 Pablo d'Angelo <pablo@ag-trek.allgaeu.org>
7 *
8 */
9 
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 
21 #include <dirent.h>
22 #include <errno.h>
23 #include <glob.h>
24 #include <limits.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <libgen.h>
31 #include <sys/socket.h>
32 #include <sys/un.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <fcntl.h>
36 #include <ctype.h>
37 
38 #ifdef HAVE_KERNEL_LIRC_H
39 #include <linux/lirc.h>
40 #else
41 #include "media/lirc.h"
42 #endif
43 
44 #include "lirc/lirc_log.h"
45 #include "lirc/lirc_options.h"
46 #include "lirc/ir_remote.h"
47 #include "lirc/config_file.h"
48 #include "lirc/transmit.h"
49 #include "lirc/config_flags.h"
50 
51 
52 static const logchannel_t logchannel = LOG_LIB;
53 
54 enum directive { ID_none, ID_remote, ID_codes, ID_raw_codes, ID_raw_name };
55 
56 struct ptr_array {
57  void** ptr;
58  size_t nr_items;
59  size_t chunk_size;
60 };
61 
62 struct void_array {
63  void* ptr;
64  size_t item_size;
65  size_t nr_items;
66  size_t chunk_size;
67 };
68 
69 
71 typedef void* (*array_guest_func)(void* item, void* arg);
72 
73 
74 #define LINE_LEN 1024
75 #define MAX_INCLUDES 10
76 
77 const char* whitespace = " \t";
78 
79 static int line;
80 static int parse_error;
81 
82 static struct ir_remote* read_config_recursive(FILE* f, const char* name, int depth);
83 static void calculate_signal_lengths(struct ir_remote* remote);
84 
85 void** init_void_array(struct void_array* ar, size_t chunk_size, size_t item_size)
86 {
87  ar->chunk_size = chunk_size;
88  ar->item_size = item_size;
89  ar->nr_items = 0;
90  ar->ptr = calloc(chunk_size, ar->item_size);
91  if (!ar->ptr) {
92  log_error("out of memory");
93  parse_error = 1;
94  return NULL;
95  }
96  return ar->ptr;
97 }
98 
99 const struct flaglist all_flags[] = {
100  { "RAW_CODES", RAW_CODES },
101  { "RC5", RC5 },
102  { "SHIFT_ENC", SHIFT_ENC }, /* obsolete */
103  { "RC6", RC6 },
104  { "RCMM", RCMM },
105  { "SPACE_ENC", SPACE_ENC },
106  { "SPACE_FIRST", SPACE_FIRST },
107  { "GRUNDIG", GRUNDIG },
108  { "BO", BO },
109  { "SERIAL", SERIAL },
110  { "XMP", XMP },
111 
112  { "REVERSE", REVERSE },
113  { "NO_HEAD_REP", NO_HEAD_REP },
114  { "NO_FOOT_REP", NO_FOOT_REP },
115  { "CONST_LENGTH", CONST_LENGTH }, /* remember to adapt warning
116  * message when changing this */
117  { "REPEAT_HEADER", REPEAT_HEADER },
118  { NULL, 0 },
119 };
120 
121 
123 int add_void_array(struct void_array* ar, void* dataptr)
124 {
125  void* ptr;
126 
127  if ((ar->nr_items % ar->chunk_size) == (ar->chunk_size) - 1) {
128  /* I hope this works with the right alignment,
129  * if not we're screwed */
130  ptr = realloc(ar->ptr,
131  ar->item_size *
132  (ar->nr_items + ar->chunk_size + 1));
133  if (!ptr) {
134  log_error("out of memory");
135  parse_error = 1;
136  return 0;
137  }
138  ar->ptr = ptr;
139  }
140  memcpy((ar->ptr) + (ar->item_size * ar->nr_items), dataptr, ar->item_size);
141  ar->nr_items = (ar->nr_items) + 1;
142  memset((ar->ptr) + (ar->item_size * ar->nr_items), 0, ar->item_size);
143  return 1;
144 }
145 
146 
148 void* get_void_array(struct void_array* ar)
149 {
150  return ar->ptr;
151 }
152 
153 
158 static void*
159 foreach_void_array(struct void_array* ar, array_guest_func func, void* arg)
160 {
161  void* r;
162  int i;
163 
164  for (i = 0; i < ar->nr_items; i += 1) {
165  r = func(ar->ptr + (i * ar->item_size), arg);
166  if (r != NULL)
167  return r;
168  }
169  return NULL;
170 }
171 
172 
173 static int
174 ir_code_node_equals(struct ir_code_node* node1, struct ir_code_node* node2)
175 {
176  if (node1 == NULL || node2 == NULL)
177  return node1 == node2;
178  return node1->code == node2->code;
179 }
180 
181 
186 static void* array_guest_code_equals(void* arg1, void* arg2)
187 {
188 
189  struct ir_ncode* code1 = (struct ir_ncode*) arg1;
190  struct ir_ncode* code2 = (struct ir_ncode*) arg2;
191  struct ir_code_node* next1;
192  struct ir_code_node* next2;
193 
194  if (code1 == NULL || code2 == NULL)
195  return NULL;
196  if (code1->code != code2->code)
197  return NULL;
198  next1 = code1->next;
199  next2 = code2->next;
200  while (next1 != NULL) {
201  if (!ir_code_node_equals(next1, next2))
202  return NULL;
203  next1 = next1->next;
204  next2 = next2->next;
205  }
206  return next2 == NULL ? arg1 : NULL;
207 }
208 
209 
214 static void* array_guest_ncode_cmp(void* item, void* arg)
215 {
216 
217  struct ir_ncode* code1 = (struct ir_ncode*) item;
218  struct ir_ncode* code2 = (struct ir_ncode*) arg;
219 
220  if (strcmp(code1->name, code2->name) == 0)
221  return item;
222  return NULL;
223 }
224 
225 
226 void* s_malloc(size_t size)
227 {
228  void* ptr;
229 
230  ptr = malloc(size);
231  if (ptr == NULL) {
232  log_error("out of memory");
233  parse_error = 1;
234  return NULL;
235  }
236  memset(ptr, 0, size);
237  return ptr;
238 }
239 
240 char* s_strdup(char* string)
241 {
242  char* ptr;
243 
244  ptr = strdup(string);
245  if (!ptr) {
246  log_error("out of memory");
247  parse_error = 1;
248  return NULL;
249  }
250  return ptr;
251 }
252 
253 ir_code s_strtocode(const char* val)
254 {
255  ir_code code = 0;
256  char* endptr;
257 
258  errno = 0;
259  code = strtoull(val, &endptr, 0);
260  if ((code == (uint64_t) -1 && errno == ERANGE) || strlen(endptr) != 0 || strlen(val) == 0) {
261  log_error("error in configfile line %d:", line);
262  log_error("\"%s\": must be a valid (uint64_t) number", val);
263  parse_error = 1;
264  return 0;
265  }
266  return code;
267 }
268 
269 uint32_t s_strtou32(char* val)
270 {
271  uint32_t n;
272  char* endptr;
273 
274  n = strtoul(val, &endptr, 0);
275  if (!*val || *endptr) {
276  log_error("error in configfile line %d:", line);
277  log_error("\"%s\": must be a valid (uint32_t) number", val);
278  parse_error = 1;
279  return 0;
280  }
281  return n;
282 }
283 
284 int s_strtoi(char* val)
285 {
286  char* endptr;
287  long n;
288  int h;
289 
290  n = strtol(val, &endptr, 0);
291  h = (int)n;
292  if (!*val || *endptr || n != ((long)h)) {
293  log_error("error in configfile line %d:", line);
294  log_error("\"%s\": must be a valid (int) number", val);
295  parse_error = 1;
296  return 0;
297  }
298  return h;
299 }
300 
301 unsigned int s_strtoui(char* val)
302 {
303  char* endptr;
304  uint32_t n;
305  unsigned int h;
306 
307  n = strtoul(val, &endptr, 0);
308  h = (unsigned int)n;
309  if (!*val || *endptr || n != ((uint32_t)h)) {
310  log_error("error in configfile line %d:", line);
311  log_error("\"%s\": must be a valid (unsigned int) number", val);
312  parse_error = 1;
313  return 0;
314  }
315  return h;
316 }
317 
318 lirc_t s_strtolirc_t(char* val)
319 {
320  uint32_t n;
321  lirc_t h;
322  char* endptr;
323 
324  n = strtoul(val, &endptr, 0);
325  h = (lirc_t)n;
326  if (!*val || *endptr || n != ((uint32_t)h)) {
327  log_error("error in configfile line %d:", line);
328  log_error("\"%s\": must be a valid (lirc_t) number", val);
329  parse_error = 1;
330  return 0;
331  }
332  if (h < 0) {
333  log_warn("error in configfile line %d:", line);
334  log_warn("\"%s\" is out of range", val);
335  }
336  return h;
337 }
338 
339 int checkMode(int is_mode, int c_mode, char* error)
340 {
341  if (is_mode != c_mode) {
342  log_error("fatal error in configfile line %d:", line);
343  log_error("\"%s\" isn't valid at this position", error);
344  parse_error = 1;
345  return 0;
346  }
347  return 1;
348 }
349 
350 int addSignal(struct void_array* signals, char* val)
351 {
352  unsigned int t;
353 
354  t = s_strtoui(val);
355  if (parse_error)
356  return 0;
357  if (!add_void_array(signals, &t))
358  return 0;
359 
360  return 1;
361 }
362 
363 struct ir_ncode* defineCode(char* key, char* val, struct ir_ncode* code)
364 {
365  memset(code, 0, sizeof(*code));
366  code->name = s_strdup(key);
367  code->code = s_strtocode(val);
368  log_trace2(" %-20s 0x%016llX", code->name, code->code);
369  return code;
370 }
371 
372 struct ir_code_node* defineNode(struct ir_ncode* code, const char* val)
373 {
374  struct ir_code_node* node;
375 
376  node = s_malloc(sizeof(*node));
377  if (node == NULL)
378  return NULL;
379 
380  node->code = s_strtocode(val);
381  node->next = NULL;
382 
383  log_trace2(" 0x%016llX", node->code);
384 
385  if (code->current == NULL) {
386  code->next = node;
387  code->current = node;
388  } else {
389  code->current->next = node;
390  code->current = node;
391  }
392  return node;
393 }
394 
395 int parseFlags(char* val)
396 {
397  const struct flaglist* flaglptr;
398  int flags = 0;
399  char* flag;
400  char* help;
401 
402  flag = help = val;
403  while (flag != NULL) {
404  while (*help != '|' && *help != 0)
405  help++;
406  if (*help == '|') {
407  *help = 0;
408  help++;
409  } else {
410  help = NULL;
411  }
412 
413  flaglptr = all_flags;
414  while (flaglptr->name != NULL) {
415  if (strcasecmp(flaglptr->name, flag) == 0) {
416  if (flaglptr->flag & IR_PROTOCOL_MASK && flags & IR_PROTOCOL_MASK) {
417  log_error("error in configfile line %d:", line);
418  log_error("multiple protocols given in flags: \"%s\"", flag);
419  parse_error = 1;
420  return 0;
421  }
422  flags = flags | flaglptr->flag;
423  log_trace2("flag %s recognized", flaglptr->name);
424  break;
425  }
426  flaglptr++;
427  }
428  if (flaglptr->name == NULL) {
429  log_error("error in configfile line %d:", line);
430  log_error("unknown flag: \"%s\"", flag);
431  parse_error = 1;
432  return 0;
433  }
434  flag = help;
435  }
436  log_trace1("flags value: %d", flags);
437 
438  return flags;
439 }
440 
441 int defineRemote(char* key, char* val, char* val2, struct ir_remote* rem)
442 {
443  if ((strcasecmp("name", key)) == 0) {
444  if (rem->name != NULL)
445  free((void*)(rem->name));
446  rem->name = s_strdup(val);
447  log_info("Using remote: %s.", val);
448  return 1;
449  }
450  if (options_getboolean("lircd:dynamic-codes")) {
451  if ((strcasecmp("dyncodes_name", key)) == 0) {
452  if (rem->dyncodes_name != NULL)
453  free(rem->dyncodes_name);
454  rem->dyncodes_name = s_strdup(val);
455  return 1;
456  }
457  } else if (strcasecmp("driver", key) == 0) {
458  if (rem->driver != NULL)
459  free((void*)(rem->driver));
460  rem->driver = s_strdup(val);
461  return 1;
462  } else if ((strcasecmp("bits", key)) == 0) {
463  rem->bits = s_strtoi(val);
464  return 1;
465  } else if (strcasecmp("flags", key) == 0) {
466  rem->flags |= parseFlags(val);
467  return 1;
468  } else if (strcasecmp("eps", key) == 0) {
469  rem->eps = s_strtoi(val);
470  return 1;
471  } else if (strcasecmp("aeps", key) == 0) {
472  rem->aeps = s_strtoi(val);
473  return 1;
474  } else if (strcasecmp("plead", key) == 0) {
475  rem->plead = s_strtolirc_t(val);
476  return 1;
477  } else if (strcasecmp("ptrail", key) == 0) {
478  rem->ptrail = s_strtolirc_t(val);
479  return 1;
480  } else if (strcasecmp("pre_data_bits", key) == 0) {
481  rem->pre_data_bits = s_strtoi(val);
482  return 1;
483  } else if (strcasecmp("pre_data", key) == 0) {
484  rem->pre_data = s_strtocode(val);
485  return 1;
486  } else if (strcasecmp("post_data_bits", key) == 0) {
487  rem->post_data_bits = s_strtoi(val);
488  return 1;
489  } else if (strcasecmp("post_data", key) == 0) {
490  rem->post_data = s_strtocode(val);
491  return 1;
492  } else if (strcasecmp("gap", key) == 0) {
493  if (val2 != NULL)
494  rem->gap2 = s_strtou32(val2);
495  rem->gap = s_strtou32(val);
496  return val2 != NULL ? 2 : 1;
497  } else if (strcasecmp("repeat_gap", key) == 0) {
498  rem->repeat_gap = s_strtou32(val);
499  return 1;
500  } else if (strcasecmp("repeat_mask", key) == 0) {
501  rem->repeat_mask = s_strtocode(val);
502  return 1;
503  }
504  /* obsolete: use toggle_bit_mask instead */
505  else if (strcasecmp("toggle_bit", key) == 0) {
506  rem->toggle_bit = s_strtoi(val);
507  return 1;
508  } else if (strcasecmp("toggle_bit_mask", key) == 0) {
509  rem->toggle_bit_mask = s_strtocode(val);
510  return 1;
511  } else if (strcasecmp("toggle_mask", key) == 0) {
512  rem->toggle_mask = s_strtocode(val);
513  return 1;
514  } else if (strcasecmp("rc6_mask", key) == 0) {
515  rem->rc6_mask = s_strtocode(val);
516  return 1;
517  } else if (strcasecmp("ignore_mask", key) == 0) {
518  rem->ignore_mask = s_strtocode(val);
519  return 1;
520  } else if (strcasecmp("manual_sort", key) == 0) {
521  rem->manual_sort = s_strtoi(val);
522  return 1;
523  }
524  /* obsolete name */
525  else if (strcasecmp("repeat_bit", key) == 0) {
526  rem->toggle_bit = s_strtoi(val);
527  return 1;
528  } else if (strcasecmp("suppress_repeat", key) == 0) {
529  rem->suppress_repeat = s_strtoi(val);
530  return 1;
531  } else if (strcasecmp("min_repeat", key) == 0) {
532  rem->min_repeat = s_strtoi(val);
533  return 1;
534  } else if (strcasecmp("min_code_repeat", key) == 0) {
535  rem->min_code_repeat = s_strtoi(val);
536  return 1;
537  } else if (strcasecmp("frequency", key) == 0) {
538  rem->freq = s_strtoui(val);
539  return 1;
540  } else if (strcasecmp("duty_cycle", key) == 0) {
541  rem->duty_cycle = s_strtoui(val);
542  return 1;
543  } else if (strcasecmp("baud", key) == 0) {
544  rem->baud = s_strtoui(val);
545  return 1;
546  } else if (strcasecmp("serial_mode", key) == 0) {
547  if (val[0] < '5' || val[0] > '9') {
548  log_error("error in configfile line %d:", line);
549  log_error("bad bit count");
550  parse_error = 1;
551  return 0;
552  }
553  rem->bits_in_byte = val[0] - '0';
554  switch (toupper(val[1])) {
555  case 'N':
556  rem->parity = IR_PARITY_NONE;
557  break;
558  case 'E':
559  rem->parity = IR_PARITY_EVEN;
560  break;
561  case 'O':
562  rem->parity = IR_PARITY_ODD;
563  break;
564  default:
565  log_error("error in configfile line %d:", line);
566  log_error("unsupported parity mode");
567  parse_error = 1;
568  return 0;
569  }
570  if (strcmp(val + 2, "1.5") == 0)
571  rem->stop_bits = 3;
572  else
573  rem->stop_bits = s_strtoui(val + 2) * 2;
574  return 1;
575  } else if (val2 != NULL) {
576  if (strcasecmp("header", key) == 0) {
577  rem->phead = s_strtolirc_t(val);
578  rem->shead = s_strtolirc_t(val2);
579  return 2;
580  } else if (strcasecmp("three", key) == 0) {
581  rem->pthree = s_strtolirc_t(val);
582  rem->sthree = s_strtolirc_t(val2);
583  return 2;
584  } else if (strcasecmp("two", key) == 0) {
585  rem->ptwo = s_strtolirc_t(val);
586  rem->stwo = s_strtolirc_t(val2);
587  return 2;
588  } else if (strcasecmp("one", key) == 0) {
589  rem->pone = s_strtolirc_t(val);
590  rem->sone = s_strtolirc_t(val2);
591  return 2;
592  } else if (strcasecmp("zero", key) == 0) {
593  rem->pzero = s_strtolirc_t(val);
594  rem->szero = s_strtolirc_t(val2);
595  return 2;
596  } else if (strcasecmp("foot", key) == 0) {
597  rem->pfoot = s_strtolirc_t(val);
598  rem->sfoot = s_strtolirc_t(val2);
599  return 2;
600  } else if (strcasecmp("repeat", key) == 0) {
601  rem->prepeat = s_strtolirc_t(val);
602  rem->srepeat = s_strtolirc_t(val2);
603  return 2;
604  } else if (strcasecmp("pre", key) == 0) {
605  rem->pre_p = s_strtolirc_t(val);
606  rem->pre_s = s_strtolirc_t(val2);
607  return 2;
608  } else if (strcasecmp("post", key) == 0) {
609  rem->post_p = s_strtolirc_t(val);
610  rem->post_s = s_strtolirc_t(val2);
611  return 2;
612  }
613  }
614  if (val2) {
615  log_error("error in configfile line %d:", line);
616  log_error("unknown definiton: \"%s %s %s\"", key, val, val2);
617  } else {
618  log_error("error in configfile line %d:", line);
619  log_error("unknown definiton or too few arguments: \"%s %s\"", key, val);
620  }
621  parse_error = 1;
622  return 0;
623 }
624 
625 static int sanityChecks(struct ir_remote* rem, const char* path)
626 {
627  struct ir_ncode* codes;
628  struct ir_code_node* node;
629 
630  path = path != NULL ? path : "unknown file";
631 
632  if (!rem->name) {
633  log_error("%s: Missing remote name", path);
634  return 0;
635  }
636  if (rem->gap == 0) {
637  log_warn("%s: %s: Gap value missing or invalid",
638  path, rem->name);
639  }
640  if (has_repeat_gap(rem) && is_const(rem)) {
641  log_warn("%s: %s: Repeat_gap ignored (CONST_LENGTH is set)",
642  path, rem->name);
643  }
644 
645  if (is_raw(rem))
646  return 1;
647 
648  if ((rem->pre_data & gen_mask(rem->pre_data_bits)) != rem->pre_data) {
649  log_warn(
650  "%s: %s: Invalid pre_data", path, rem->name);
651  rem->pre_data &= gen_mask(rem->pre_data_bits);
652  }
653  if ((rem->post_data & gen_mask(rem->post_data_bits)) != rem->post_data) {
654  log_warn("%s: %s: Invalid post_data",
655  path, rem->name);
656  rem->post_data &= gen_mask(rem->post_data_bits);
657  }
658  if (!rem->codes) {
659  log_error("%s: %s: No codes", path, rem->name);
660  return 0;
661  }
662  for (codes = rem->codes; codes->name != NULL; codes++) {
663  if ((codes->code & gen_mask(rem->bits)) != codes->code) {
664  log_warn("%s: %s: Invalid code : %s",
665  path, rem->name, codes->name);
666  codes->code &= gen_mask(rem->bits);
667  }
668  for (node = codes->next; node != NULL; node = node->next) {
669  if ((node->code & gen_mask(rem->bits)) != node->code) {
670  log_warn("%s: %s: Invalid code %s: %s",
671  path, rem->name, codes->name);
672  node->code &= gen_mask(rem->bits);
673  }
674  }
675  }
676  return 1;
677 }
678 
685 static int remote_bits_cmp(struct ir_remote* r1, struct ir_remote* r2)
686 {
687  int r1_size;
688  int r2_size;
689  struct ir_ncode* c;
690 
691  int r1_is_raw = is_raw(r1);
692  int r2_is_raw = is_raw(r2);
693 
694  if (!r1_is_raw && r2_is_raw)
695  return -1;
696  if (r1_is_raw && !r2_is_raw)
697  return 1;
698 
699  if (r1_is_raw && r2_is_raw) {
700  for (c = r1->codes, r1_size = 0; c->name != NULL; c++)
701  r1_size += 1;
702  for (c = r2->codes, r2_size = 0; c->name != NULL; c++)
703  r2_size += 1;
704  } else {
705  r1_size = bit_count(r1);
706  r2_size = bit_count(r2);
707  }
708  if (r1_size == r2_size)
709  return 0;
710  return r1_size < r2_size ? -1 : 1;
711 }
712 
713 
718 static struct ir_remote* sort_by_bit_count(struct ir_remote* remotes)
719 {
720  struct ir_remote* top;
721  struct ir_remote* rem;
722  struct ir_remote* next;
723  struct ir_remote* prev;
724  struct ir_remote* scan;
725  struct ir_remote* r;
726 
727  for (r = remotes; r != NULL && r != (void*)-1; r = r->next)
728  if (r->manual_sort)
729  return remotes;
730  rem = remotes;
731  top = NULL;
732  while (rem != NULL && rem != (void*)-1) {
733  next = rem->next;
734 
735  scan = top;
736  prev = NULL;
737  while (scan && remote_bits_cmp(scan, rem) <= 0) {
738  prev = scan;
739  scan = scan->next;
740  }
741  if (prev)
742  prev->next = rem;
743  else
744  top = rem;
745  if (scan)
746  rem->next = scan;
747  else
748  rem->next = NULL;
749 
750  rem = next;
751  }
752 
753  return top;
754 }
755 
756 static const char* lirc_parse_include(char* s)
757 {
758  char* last;
759  size_t len;
760 
761  len = strlen(s);
762  if (len < 2)
763  return NULL;
764  last = s + len - 1;
765  while (last > s && strchr(whitespace, *last) != NULL)
766  last--;
767  if (last <= s)
768  return NULL;
769  if (*s != '"' && *s != '<')
770  return NULL;
771  if (*s == '"' && *last != '"')
772  return NULL;
773  else if (*s == '<' && *last != '>')
774  return NULL;
775  *last = 0;
776  memmove(s, s + 1, len - 2 + 1); /* terminating 0 is copied, and
777  * maybe more, but we don't care */
778  return s;
779 }
780 
781 
783 static const char* lirc_parse_relative(char* dst,
784  size_t dst_size,
785  const char* child,
786  const char* current)
787 {
788  char* dir;
789  size_t dirlen;
790 
791  if (!current)
792  return child;
793 
794  /* Already an absolute path */
795  if (*child == '/') {
796  snprintf(dst, dst_size, "%s", child);
797  return dst;
798  }
799  if (strlen(current) >= dst_size)
800  return NULL;
801  strcpy(dst, current);
802  dir = dirname(dst);
803  dirlen = strlen(dir);
804  if (dir != dst)
805  memmove(dst, dir, dirlen + 1);
806 
807  if (dirlen + 1 + strlen(child) + 1 > dst_size)
808  return NULL;
809  strcat(dst, "/");
810  strcat(dst, child);
811 
812  return dst;
813 }
814 
815 
817 static struct ir_remote*
818 ir_remotes_append(struct ir_remote* root, struct ir_remote* what)
819 {
820  struct ir_remote* r;
821 
822  if (root == (struct ir_remote*)-1)
823  root = NULL;
824  if (what == (struct ir_remote*)-1)
825  what = NULL;
826  if (root == NULL && what != NULL)
827  return what;
828  if (what == NULL)
829  return root;
830  for (r = root; r->next != NULL; r = r->next)
831  ;
832  r->next = what;
833  return root;
834 }
835 
836 
837 struct ir_remote* read_config(FILE* f, const char* name)
838 {
839  struct ir_remote* head;
840 
841  head = read_config_recursive(f, name, 0);
842  head = sort_by_bit_count(head);
843  return head;
844 }
845 
846 
857 static struct ir_remote*
858 read_included(const char* name, int depth, char* val, struct ir_remote* top_rem)
859 {
860  FILE* childFile;
861  const char* childName;
862  struct ir_remote* rem = NULL;
863 
864  if (depth > MAX_INCLUDES) {
865  log_error("error opening child file defined at %s:%d", name, line);
866  log_error("too many files included");
867  return top_rem;
868  }
869  childName = lirc_parse_include(val);
870  if (!childName) {
871  log_error("error parsing child file value defined at line %d:", line);
872  log_error("invalid quoting");
873  return top_rem;
874  }
875  childFile = fopen(childName, "r");
876  if (childFile == NULL) {
877  log_error("error opening child file '%s' defined at line %d:",
878  childName, line);
879  log_error("ignoring this child file for now.");
880  return NULL;
881  }
882  rem = read_config_recursive(childFile, childName, depth + 1);
883  top_rem = ir_remotes_append(top_rem, rem);
884  fclose(childFile);
885  return top_rem;
886 }
887 
888 
899 static struct ir_remote* read_all_included(const char* name,
900  int depth,
901  char* val,
902  struct ir_remote* top_rem)
903 {
904  int i;
905  glob_t globbuf;
906  char buff[256] = { '\0' };
907 
908  memset(&globbuf, 0, sizeof(globbuf));
909  val = val + 1; // Strip quotes
910  val[strlen(val) - 1] = '\0';
911  lirc_parse_relative(buff, sizeof(buff), val, name);
912  glob(buff, 0, NULL, &globbuf);
913  for (i = 0; i < globbuf.gl_pathc; i += 1) {
914  snprintf(buff, sizeof(buff), "\"%s\"", globbuf.gl_pathv[i]);
915  top_rem = read_included(name, depth, buff, top_rem);
916  }
917  globfree(&globbuf);
918  return top_rem;
919 }
920 
921 
922 static void check_ncode_dups(const char* path,
923  const char* name,
924  struct void_array* ar,
925  struct ir_ncode* code)
926 {
927  if (foreach_void_array(ar, array_guest_ncode_cmp, code) != NULL) {
928  log_notice("%s: %s: Multiple definitions of: %s",
929  path, name, code->name);
930  }
931  if (foreach_void_array(ar, array_guest_code_equals, code) != NULL) {
932  log_notice("%s: %s: Multiple values for same code: %s",
933  path, name, code->name);
934  }
935 }
936 
937 
938 static struct ir_remote*
939 read_config_recursive(FILE* f, const char* name, int depth)
940 {
941  char buf[LINE_LEN + 1];
942  char* key;
943  char* val;
944  char* val2;
945  int len, argc;
946  struct ir_remote* top_rem = NULL;
947  struct ir_remote* rem = NULL;
948  struct void_array codes_list, raw_codes, signals;
949  struct ir_ncode raw_code = { NULL, 0, 0, NULL };
950  struct ir_ncode name_code = { NULL, 0, 0, NULL };
951  struct ir_ncode* code;
952  int mode = ID_none;
953 
954  line = 0;
955  parse_error = 0;
956  log_trace1("parsing '%s'", name);
957 
958  while (fgets(buf, LINE_LEN, f) != NULL) {
959  line++;
960  len = strlen(buf);
961  if (len == LINE_LEN && buf[len - 1] != '\n') {
962  log_error("line %d too long in config file", line);
963  parse_error = 1;
964  break;
965  }
966 
967  if (len > 0) {
968  len--;
969  if (buf[len] == '\n')
970  buf[len] = 0;
971  }
972  if (len > 0) {
973  len--;
974  if (buf[len] == '\r')
975  buf[len] = 0;
976  }
977  /* ignore comments */
978  if (buf[0] == '#')
979  continue;
980  key = strtok(buf, whitespace);
981  /* ignore empty lines */
982  if (key == NULL)
983  continue;
984  val = strtok(NULL, whitespace);
985  if (val != NULL) {
986  val2 = strtok(NULL, whitespace);
987  log_trace2("Tokens: \"%s\" \"%s\" \"%s\"", key, val, (val2 == NULL ? "(null)" : val));
988  if (strcasecmp("include", key) == 0) {
989  int save_line = line;
990 
991  top_rem = read_all_included(name,
992  depth,
993  val,
994  top_rem);
995  line = save_line;
996  } else if (strcasecmp("begin", key) == 0) {
997  if (strcasecmp("codes", val) == 0) {
998  /* init codes mode */
999  log_trace1(" begin codes");
1000  if (!checkMode(mode, ID_remote, "begin codes"))
1001  break;
1002  if (rem->codes) {
1003  log_error("error in configfile line %d:", line);
1004  log_error("codes are already defined");
1005  parse_error = 1;
1006  break;
1007  }
1008 
1009  init_void_array(&codes_list, 30, sizeof(struct ir_ncode));
1010  mode = ID_codes;
1011  } else if (strcasecmp("raw_codes", val) == 0) {
1012  /* init raw_codes mode */
1013  log_trace1(" begin raw_codes");
1014  if (!checkMode(mode, ID_remote, "begin raw_codes"))
1015  break;
1016  if (rem->codes) {
1017  log_error("error in configfile line %d:", line);
1018  log_error("codes are already defined");
1019  parse_error = 1;
1020  break;
1021  }
1022  set_protocol(rem, RAW_CODES);
1023  raw_code.code = 0;
1024  init_void_array(&raw_codes, 30, sizeof(struct ir_ncode));
1025  mode = ID_raw_codes;
1026  } else if (strcasecmp("remote", val) == 0) {
1027  /* create new remote */
1028  log_trace("parsing remote");
1029  if (!checkMode(mode, ID_none, "begin remote"))
1030  break;
1031  mode = ID_remote;
1032  if (!top_rem) {
1033  /* create first remote */
1034  log_trace1("creating first remote");
1035  rem = top_rem = s_malloc(sizeof(struct ir_remote));
1036  rem->freq = DEFAULT_FREQ;
1037  } else {
1038  /* create new remote */
1039  log_trace1("creating next remote");
1040  rem = s_malloc(sizeof(struct ir_remote));
1041  rem->freq = DEFAULT_FREQ;
1042  ir_remotes_append(top_rem, rem);
1043  }
1044  } else if (mode == ID_codes) {
1045  code = defineCode(key, val, &name_code);
1046  while (!parse_error && val2 != NULL) {
1047  if (val2[0] == '#')
1048  break; /* comment */
1049  defineNode(code, val2);
1050  val2 = strtok(NULL, whitespace);
1051  }
1052  code->current = NULL;
1053  check_ncode_dups(name, rem->name, &codes_list, code);
1054  add_void_array(&codes_list, code);
1055  } else {
1056  log_error("error in configfile line %d:", line);
1057  log_error("unknown section \"%s\"", val);
1058  parse_error = 1;
1059  }
1060  if (!parse_error && val2 != NULL) {
1061  log_warn("%s: garbage after '%s' token "
1062  "in line %d ignored",
1063  rem->name, val, line);
1064  }
1065  } else if (strcasecmp("end", key) == 0) {
1066  if (strcasecmp("codes", val) == 0) {
1067  /* end Codes mode */
1068  log_trace1(" end codes");
1069  if (!checkMode(mode, ID_codes, "end codes"))
1070  break;
1071  rem->codes = get_void_array(&codes_list);
1072  mode = ID_remote; /* switch back */
1073  } else if (strcasecmp("raw_codes", val) == 0) {
1074  /* end raw codes mode */
1075  log_trace1(" end raw_codes");
1076 
1077  if (mode == ID_raw_name) {
1078  raw_code.signals = get_void_array(&signals);
1079  raw_code.length = signals.nr_items;
1080  if (raw_code.length % 2 == 0) {
1081  log_error("error in configfile line %d:", line);
1082  log_error("bad signal length");
1083  parse_error = 1;
1084  }
1085  if (!add_void_array(&raw_codes, &raw_code))
1086  break;
1087  mode = ID_raw_codes;
1088  }
1089  if (!checkMode(mode, ID_raw_codes, "end raw_codes"))
1090  break;
1091  rem->codes = get_void_array(&raw_codes);
1092  mode = ID_remote; /* switch back */
1093  } else if (strcasecmp("remote", val) == 0) {
1094  /* end remote mode */
1095  log_trace1("end remote");
1096  /* print_remote(rem); */
1097  if (!checkMode(mode, ID_remote, "end remote"))
1098  break;
1099  if (!sanityChecks(rem, name)) {
1100  parse_error = 1;
1101  break;
1102  }
1103  if (options_getboolean("lircd:dynamic-codes")) {
1104  if (rem->dyncodes_name == NULL)
1105  rem->dyncodes_name = s_strdup("unknown");
1106  rem->dyncodes[0].name = rem->dyncodes_name;
1107  rem->dyncodes[1].name = rem->dyncodes_name;
1108  }
1109  /* not really necessary because we
1110  * clear the alloced memory */
1111  rem->next = NULL;
1112  rem->last_code = NULL;
1113  mode = ID_none; /* switch back */
1114  } else if (mode == ID_codes) {
1115  code = defineCode(key, val, &name_code);
1116  while (!parse_error && val2 != NULL) {
1117  if (val2[0] == '#')
1118  break; /* comment */
1119  defineNode(code, val2);
1120  val2 = strtok(NULL, whitespace);
1121  }
1122  code->current = NULL;
1123  add_void_array(&codes_list, code);
1124  } else {
1125  log_error("error in configfile line %d:", line);
1126  log_error("unknown section %s", val);
1127  parse_error = 1;
1128  }
1129  if (!parse_error && val2 != NULL) {
1130  log_warn(
1131  "%s: garbage after '%s'"
1132  " token in line %d ignored",
1133  rem->name, val, line);
1134  }
1135  } else {
1136  switch (mode) {
1137  case ID_remote:
1138  argc = defineRemote(key, val, val2, rem);
1139  if (!parse_error
1140  && ((argc == 1 && val2 != NULL)
1141  || (argc == 2 && val2 != NULL && strtok(NULL, whitespace) != NULL))) {
1142  log_warn("%s: garbage after '%s'"
1143  " token in line %d ignored",
1144  rem->name, key, line);
1145  }
1146  break;
1147  case ID_codes:
1148  code = defineCode(key, val, &name_code);
1149  while (!parse_error && val2 != NULL) {
1150  if (val2[0] == '#')
1151  break; /* comment */
1152  defineNode(code, val2);
1153  val2 = strtok(NULL, whitespace);
1154  }
1155  code->current = NULL;
1156  check_ncode_dups(name,
1157  rem->name,
1158  &codes_list,
1159  code);
1160  add_void_array(&codes_list, code);
1161  break;
1162  case ID_raw_codes:
1163  case ID_raw_name:
1164  if (strcasecmp("name", key) == 0) {
1165  log_trace2("Button: \"%s\"", val);
1166  if (mode == ID_raw_name) {
1167  raw_code.signals = get_void_array(&signals);
1168  raw_code.length = signals.nr_items;
1169  if (raw_code.length % 2 == 0) {
1170  log_error("error in configfile line %d:",
1171  line);
1172  log_error("bad signal length");
1173  parse_error = 1;
1174  }
1175  if (!add_void_array(&raw_codes, &raw_code))
1176  break;
1177  }
1178  raw_code.name = s_strdup(val);
1179  if (!raw_code.name)
1180  break;
1181  raw_code.code++;
1182  init_void_array(&signals, 50, sizeof(lirc_t));
1183  mode = ID_raw_name;
1184  if (!parse_error && val2 != NULL) {
1185  log_warn("%s: garbage after '%s'"
1186  " token in line %d ignored",
1187  rem->name, key, line);
1188  }
1189  } else {
1190  if (mode == ID_raw_codes) {
1191  log_error("no name for signal defined at line %d",
1192  line);
1193  parse_error = 1;
1194  break;
1195  }
1196  if (!addSignal(&signals, key))
1197  break;
1198  if (!addSignal(&signals, val))
1199  break;
1200  if (val2)
1201  if (!addSignal(&signals, val2))
1202  break;
1203  while ((val = strtok(NULL, whitespace)))
1204  if (!addSignal(&signals, val))
1205  break;
1206  }
1207  break;
1208  }
1209  }
1210  } else if (mode == ID_raw_name) {
1211  if (!addSignal(&signals, key))
1212  break;
1213  } else {
1214  log_error("error in configfile line %d", line);
1215  parse_error = 1;
1216  break;
1217  }
1218  if (parse_error)
1219  break;
1220  }
1221  if (mode != ID_none) {
1222  switch (mode) {
1223  case ID_raw_name:
1224  if (raw_code.name != NULL) {
1225  free(raw_code.name);
1226  if (get_void_array(&signals) != NULL)
1227  free(get_void_array(&signals));
1228  }
1229  case ID_raw_codes:
1230  rem->codes = get_void_array(&raw_codes);
1231  break;
1232  case ID_codes:
1233  rem->codes = get_void_array(&codes_list);
1234  break;
1235  }
1236  if (!parse_error) {
1237  log_error("unexpected end of file");
1238  parse_error = 1;
1239  }
1240  }
1241  if (parse_error) {
1242  static int print_error = 1;
1243 
1244  if (print_error) {
1245  log_error("reading of file '%s' failed", name);
1246  print_error = 0;
1247  }
1248  free_config(top_rem);
1249  if (depth == 0)
1250  print_error = 1;
1251  return (void*)-1;
1252  }
1253  /* kick reverse flag */
1254  /* handle RC6 flag to be backwards compatible: previous RC-6
1255  * config files did not set rc6_mask */
1256  rem = top_rem;
1257  while (rem != NULL) {
1258  if ((!is_raw(rem)) && rem->flags & REVERSE) {
1259  struct ir_ncode* codes;
1260 
1261  if (has_pre(rem))
1262  rem->pre_data = reverse(rem->pre_data, rem->pre_data_bits);
1263  if (has_post(rem))
1264  rem->post_data = reverse(rem->post_data, rem->post_data_bits);
1265  codes = rem->codes;
1266  while (codes->name != NULL) {
1267  codes->code = reverse(codes->code, rem->bits);
1268  codes++;
1269  }
1270  rem->flags = rem->flags & (~REVERSE);
1271  rem->flags = rem->flags | COMPAT_REVERSE;
1272  /* don't delete the flag because we still need
1273  * it to remain compatible with older versions
1274  */
1275  }
1276  if (rem->flags & RC6 && rem->rc6_mask == 0 && rem->toggle_bit > 0) {
1277  int all_bits = bit_count(rem);
1278 
1279  rem->rc6_mask = ((ir_code)1) << (all_bits - rem->toggle_bit);
1280  }
1281  if (rem->toggle_bit > 0) {
1282  int all_bits = bit_count(rem);
1283 
1284  if (has_toggle_bit_mask(rem)) {
1285  log_warn("%s uses both toggle_bit and toggle_bit_mask", rem->name);
1286  } else {
1287  rem->toggle_bit_mask = ((ir_code)1) << (all_bits - rem->toggle_bit);
1288  }
1289  rem->toggle_bit = 0;
1290  }
1291  if (has_toggle_bit_mask(rem)) {
1292  if (!is_raw(rem) && rem->codes) {
1293  rem->toggle_bit_mask_state = (rem->codes->code & rem->toggle_bit_mask);
1294  if (rem->toggle_bit_mask_state)
1295  /* start with state set to 0 for backwards compatibility */
1296  rem->toggle_bit_mask_state ^= rem->toggle_bit_mask;
1297  }
1298  }
1299  if (is_serial(rem)) {
1300  lirc_t base;
1301 
1302  if (rem->baud > 0) {
1303  base = 1000000 / rem->baud;
1304  if (rem->pzero == 0 && rem->szero == 0)
1305  rem->pzero = base;
1306  if (rem->pone == 0 && rem->sone == 0)
1307  rem->sone = base;
1308  }
1309  if (rem->bits_in_byte == 0)
1310  rem->bits_in_byte = 8;
1311  }
1312  if (rem->min_code_repeat > 0) {
1313  if (!has_repeat(rem) || rem->min_code_repeat > rem->min_repeat) {
1314  log_warn("invalid min_code_repeat value");
1315  rem->min_code_repeat = 0;
1316  }
1317  }
1318  calculate_signal_lengths(rem);
1319  rem = rem->next;
1320  }
1321 
1322  return top_rem;
1323 }
1324 
1325 void calculate_signal_lengths(struct ir_remote* remote)
1326 {
1327  if (is_const(remote)) {
1328  remote->min_total_signal_length = min_gap(remote);
1329  remote->max_total_signal_length = max_gap(remote);
1330  } else {
1331  remote->min_gap_length = min_gap(remote);
1332  remote->max_gap_length = max_gap(remote);
1333  }
1334 
1335  lirc_t min_signal_length = 0, max_signal_length = 0;
1336  lirc_t max_pulse = 0, max_space = 0;
1337  int first_sum = 1;
1338  struct ir_ncode* c = remote->codes;
1339  int i;
1340 
1341  while (c->name) {
1342  struct ir_ncode code = *c;
1343  struct ir_code_node* next = code.next;
1344  int first = 1;
1345  int repeat = 0;
1346 
1347  do {
1348  if (first) {
1349  first = 0;
1350  } else {
1351  code.code = next->code;
1352  next = next->next;
1353  }
1354  for (repeat = 0; repeat < 2; repeat++) {
1355  if (init_sim(remote, &code, repeat)) {
1356  lirc_t sum = send_buffer_sum();
1357 
1358  if (sum) {
1359  if (first_sum || sum < min_signal_length)
1360  min_signal_length = sum;
1361  if (first_sum || sum > max_signal_length)
1362  max_signal_length = sum;
1363  first_sum = 0;
1364  }
1365  for (i = 0; i < send_buffer_length(); i++) {
1366  if (i & 1) { /* space */
1367  if (send_buffer_data()[i] > max_space)
1368  max_space = send_buffer_data()[i];
1369  } else { /* pulse */
1370  if (send_buffer_data()[i] > max_pulse)
1371  max_pulse = send_buffer_data()[i];
1372  }
1373  }
1374  }
1375  }
1376  } while (next);
1377  c++;
1378  }
1379  if (first_sum) {
1380  /* no timing data, so assume gap is the actual total
1381  * length */
1382  remote->min_total_signal_length = min_gap(remote);
1383  remote->max_total_signal_length = max_gap(remote);
1384  remote->min_gap_length = min_gap(remote);
1385  remote->max_gap_length = max_gap(remote);
1386  } else if (is_const(remote)) {
1387  if (remote->min_total_signal_length > max_signal_length) {
1388  remote->min_gap_length = remote->min_total_signal_length - max_signal_length;
1389  } else {
1390  log_warn("min_gap_length is 0 for '%s' remote",
1391  remote->name);
1392  remote->min_gap_length = 0;
1393  }
1394  if (remote->max_total_signal_length > min_signal_length) {
1395  remote->max_gap_length = remote->max_total_signal_length - min_signal_length;
1396  } else {
1397  log_warn("max_gap_length is 0 for '%s' remote", remote->name);
1398  remote->max_gap_length = 0;
1399  }
1400  } else {
1401  remote->min_total_signal_length = min_signal_length + remote->min_gap_length;
1402  remote->max_total_signal_length = max_signal_length + remote->max_gap_length;
1403  }
1404  log_trace("lengths: %lu %lu %lu %lu", remote->min_total_signal_length, remote->max_total_signal_length,
1405  remote->min_gap_length, remote->max_gap_length);
1406 }
1407 
1408 void free_config(struct ir_remote* remotes)
1409 {
1410  struct ir_remote* next;
1411  struct ir_ncode* codes;
1412 
1413  while (remotes != NULL) {
1414  next = remotes->next;
1415 
1416  if (remotes->dyncodes_name != NULL)
1417  free(remotes->dyncodes_name);
1418  if (remotes->name != NULL)
1419  free((void*)(remotes->name));
1420  if (remotes->codes != NULL) {
1421  codes = remotes->codes;
1422  while (codes->name != NULL) {
1423  struct ir_code_node* node;
1424  struct ir_code_node* next_node;
1425 
1426  free(codes->name);
1427  if (codes->signals != NULL)
1428  free(codes->signals);
1429  node = codes->next;
1430  while (node) {
1431  next_node = node->next;
1432  free(node);
1433  node = next_node;
1434  }
1435  codes++;
1436  }
1437  free(remotes->codes);
1438  }
1439  free(remotes);
1440  remotes = next;
1441  }
1442 }
void *(* array_guest_func)(void *item, void *arg)
foreach_void_array argument.
Definition: config_file.c:71
void * get_void_array(struct void_array *ar)
Return the array dataptr, an array[nr_items] of item_size elements.
Definition: config_file.c:148
int add_void_array(struct void_array *ar, void *dataptr)
Add *dataptr to end of ar, re-allocating as necessary.
Definition: config_file.c:123
const struct flaglist all_flags[]
All flags i config file: Their name and mask.
Definition: config_file.c:99
const lirc_t * send_buffer_data(void)
Definition: transmit.c:379
lirc_t send_buffer_sum(void)
Definition: transmit.c:384
int send_buffer_length(void)
Do not document this function.
Definition: transmit.c:373
void free_config(struct ir_remote *remotes)
Free() an ir_remote instance obtained using read_config().
Definition: config_file.c:1408
struct ir_remote * read_config(FILE *f, const char *name)
Parse a lircd.conf config file.
Definition: config_file.c:837
#define SHIFT_ENC
IR data is shift encoded (name obsolete)
#define RAW_CODES
for internal use only
#define XMP
XMP protocol.
#define RC6
IR data follows RC6 protocol.
#define REPEAT_HEADER
header is also sent before repeat code
#define GRUNDIG
encoding found on Grundig remote
#define BO
encoding found on Bang & Olufsen remote
uint64_t ir_code
Denotes an internal coded representation for an IR transmission.
#define COMPAT_REVERSE
compatibility mode for REVERSE flag
#define SPACE_FIRST
bits are encoded as space+pulse
#define SPACE_ENC
IR data is space encoded.
#define RC5
IR data follows RC5 protocol.
#define NO_FOOT_REP
no foot for key repeats
#define SERIAL
serial protocol
#define NO_HEAD_REP
no header for key repeats
#define CONST_LENGTH
signal length+gap is always constant
#define RCMM
IR data follows RC-MM protocol.
#define log_trace(fmt,...)
Log a trace message.
Definition: lirc_log.h:129
#define log_notice(fmt,...)
Log a notice message.
Definition: lirc_log.h:119
#define log_info(fmt,...)
Log an info message.
Definition: lirc_log.h:114
#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
#define log_trace1(fmt,...)
Log a trace1 message.
Definition: lirc_log.h:134
logchannel_t
Log channels used to filter messages.
Definition: lirc_log.h:53
#define log_warn(fmt,...)
Log a warning message.
Definition: lirc_log.h:109
Description of flag to print.
Definition: config_flags.h:16
char * name
Name of flag.
Definition: config_flags.h:17
int flag
Flag bitmask.
Definition: config_flags.h:18
An ir_code for entering into (singly) linked lists, i.e.
IR Command, corresponding to one (command defining) line of the configuration file.
struct ir_code_node * next
Linked list of the subsequent ir_code's, after the first one.
ir_code code
The first code of the command.
int length
(private)
lirc_t * signals
(private)
char * name
Name of command.
One remote as represented in the configuration file.
const char * driver
Name of driver for LIRCCODE cases.
uint32_t repeat_gap
time between two repeat codes if different from gap
lirc_t stwo
2 (only used for RC-MM)
unsigned int freq
modulation frequency
int suppress_repeat
suppress unwanted repeats
unsigned int aeps
detecting very short pulses is difficult with relative tolerance for some remotes,...
uint32_t gap2
time between signals in usecs
lirc_t min_total_signal_length
how long is the shortest signal including gap
unsigned int stop_bits
mapping: 1->2 1.5->3 2->4
unsigned int bits_in_byte
default: 8
struct ir_ncode dyncodes[2]
helper structs for unknown buttons
lirc_t sfoot
foot
ir_code rc6_mask
RC-6 doubles signal length of some bits.
lirc_t ptrail
trailing pulse
unsigned int duty_cycle
0<duty cycle<=100 default: 50
lirc_t min_gap_length
how long is the shortest gap
ir_code repeat_mask
mask defines which bits are inverted for repeats
lirc_t srepeat
indicate repeating
ir_code pre_data
data which the remote sends before actual keycode
int bits
bits (length of code)
int post_data_bits
length of post_data
ir_code ignore_mask
mask defines which bits can be ignored when matching a code
lirc_t plead
leading pulse
lirc_t sthree
3 (only used for RC-MM)
lirc_t shead
header
lirc_t szero
0
ir_code post_data
data which the remote sends after actual keycode
ir_code toggle_mask
Sharp (?) error detection scheme.
int flags
flags
unsigned int baud
can be overridden by [p|s]zero, [p|s]one
int min_repeat
code is repeated at least x times code sent once -> min_repeat=0
int manual_sort
If set in any remote, disables automatic sorting.
lirc_t post_s
signal between keycode and post_code
lirc_t pre_s
signal between pre_data and keycode
uint32_t gap
time between signals in usecs
int eps
eps (relative tolerance)
char * dyncodes_name
name for unknown buttons
struct ir_ncode * last_code
code received or sent last
unsigned int min_code_repeat
meaningful only if remote sends a repeat code: in this case this value indicates how often the real c...
lirc_t sone
1
const char * name
name of remote control
ir_code toggle_bit_mask
previously only one bit called toggle_bit
unsigned int parity
currently unsupported
int pre_data_bits
length of pre_data
lirc_t max_gap_length
how long is the longest gap
lirc_t max_total_signal_length
how long is the longest signal including gap
int toggle_bit
obsolete