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