keytable: move keymap parsing into its own file
PATCH 1/2 keytable: move keymap parsing into its own file
We would like to reuse keymap parsing for transmitting IR based on keymap in ir-ctl.
This also reduces the size of our huge keytable.c, and keeps knowledge toml localised to the keymap parser.
--- utils/keytable/Makefile.am | 2 +- utils/keytable/bpf_load.c | 21 +- utils/keytable/bpf_load.h | 4 +- utils/keytable/keymap.c | 459 ++++++++++++++++++++++++++++ utils/keytable/keymap.h | 26 ++ utils/keytable/keytable.c | 541 +++++++--------------------------- utils/keytable/rc_keymap.5.in | 4 +- 7 files changed, 607 insertions(+), 450 deletions(-) create mode 100644 utils/keytable/keymap.c
utils/keytable/Makefile.am +1 -1
@@ -4,7 +4,7 @@ sysconf_DATA = rc_maps.cfg keytablesystem_DATA = $(srcdir)/rc_keymaps/* udevrules_DATA = 70-infrared.rules -ir_keytable_SOURCES = keytable.c parse.h ir-encode.c ir-encode.h toml.c toml.h keymap.h +ir_keytable_SOURCES = keytable.c parse.h ir-encode.c ir-encode.h toml.c toml.h keymap.c keymap.h if WITH_BPF ir_keytable_SOURCES += bpf.c bpf_load.c bpf.h bpf_load.h
utils/keytable/bpf_load.c +4 -17
@@ -13,7 +13,6 @@#include <stdlib.h> #include <linux/bpf.h> #include <assert.h> -#include "toml.h" #include "keymap.h" #include "bpf.h" #include "bpf_load.h"
@@ -55,7 +54,7 @@ struct bpf_file {Elf_Data *data;int strtabidx;Elf_Data *symbols; -struct toml_table_t *toml; +struct protocol_param *param; };static int load_and_attach (int lirc_fd,struct bpf_file *bpf_file,const char *name,struct bpf_insn *prog,int size)
@@ -271,23 +270,11 @@ static int parse_relo_and_apply(struct bpf_file *bpf_file, GElf_Shdr *shdr,const char *raw =NULL ;int value =0 ; -if (!bpf_param (sym_name, &value)) { -// done - }else if (bpf_file->toml && - (raw =toml_raw_in (bpf_file->toml, sym_name)) !=NULL ) { -int64_t val64; - -if (toml_rtoi (raw, &val64)) { -printf (_ ("variable %s not a integer: %s\n" ), sym_name, raw); -return 1 ; - } - +if (!bpf_param (bpf_file->param, sym_name, &value)) {if (value <INT_MIN && value >UINT_MAX ) {printf (_ ("variable %s out of range: %s\n" ), sym_name, raw);return 1 ; } - - value = val64; }else if (sym.st_shndx == bpf_file->dataidx) {// Value is not overridden on command line // or toml file. For the raw decoder, the
@@ -436,10 +423,10 @@ static int load_elf_maps_section(struct bpf_file *bpf_file)return nr_maps; } -int load_bpf_file (const char *path,int lirc_fd,struct toml_table_t *toml, +int load_bpf_file (const char *path,int lirc_fd,struct protocol_param *param,struct raw_entry *raw) { -struct bpf_file bpf_file = { .toml = toml }; +struct bpf_file bpf_file = { .param = param };int fd, i, ret;Elf *elf;GElf_Ehdr ehdr;
utils/keytable/bpf_load.h +2 -2
@@ -36,8 +36,8 @@ struct bpf_map_data {* * returns zero on success */ -int load_bpf_file (const char *path,int lirc_fd,struct toml_table_t *toml,struct raw_entry *raw); +int load_bpf_file (const char *path,int lirc_fd,struct protocol_param *param,struct raw_entry *raw); -int bpf_param (const char *name,int *val); +int bpf_param (struct protocol_param *param,const char *name,int *val);#endif
utils/keytable/keymap.c new file +459 -0
459 lines not on this page · raw message
utils/keytable/keymap.h +26 -0
@@ -2,11 +2,37 @@#ifndef __KEYMAP_H#define __KEYMAP_H +struct keymap { +struct keymap *next; +char *name; +char *protocol; +char *variant; +struct protocol_param *param; +struct scancode_entry *scancode; +struct raw_entry *raw; +}; + +struct protocol_param { +struct protocol_param *next; +char *name; +long int value; +}; + +struct scancode_entry { +struct scancode_entry *next; +u_int32_t scancode; +char *keycode; +}; +struct raw_entry {struct raw_entry *next;u_int32_t scancode;u_int32_t raw_length; +char *keycode;u_int32_t raw[1 ]; }; +void free_keymap (struct keymap *map); +error_t parse_keyfile (char *fname,struct keymap **keymap,bool verbose); +#endif
utils/keytable/keytable.c +113 -428
717 lines not on this page · raw message
utils/keytable/rc_keymap.5.in +2 -2
@@ -4,7 +4,7 @@ rc_keymap \- toml file describing remote control keymap .SH DESCRIPTION An rc_keymap describes a remote control. It list the protocols used, and the mapping from decoded IR to linux input events. This file is used by -ir\-keytable(1). +ir\-keytable(1) for IR decoding, and by ir-ctl(1) for sending IR. .PP The file format is toml. Since a remote control can use multiple protocols, the top level is an array of protocols. The vast majority of remotes only use
@@ -308,7 +308,7 @@ License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. .SH SEE ALSO -ir\-keytable(1). +ir\-keytable(1) and ir\-ctl(1) .PP https://lwn.net/Articles/759188/ .PP
Signature · 1 line
2.21.0
PATCH 2/2 ir-ctl: send keys based on keymap
ir-ctl can now send keys based on rc keymaps. The keymap file must be specified and the keys to be sent:
ir-ctl -k /lib/udev/rc_keymaps/hauppauge.toml -K KEY_VOLUMEUP
--- utils/common/keymap.c | 471 ++++++++++ utils/common/keymap.h | 39 + utils/common/toml.c | 1903 +++++++++++++++++++++++++++++++++++++ utils/common/toml.h | 110 +++ utils/ir-ctl/Makefile.am | 2 +- utils/ir-ctl/ir-ctl.1.in | 26 +- utils/ir-ctl/ir-ctl.c | 126 ++- utils/ir-ctl/keymap.c | 1 + utils/ir-ctl/keymap.h | 1 + utils/ir-ctl/toml.c | 1 + utils/ir-ctl/toml.h | 1 + utils/keytable/keymap.c | 460 +-------- utils/keytable/keymap.h | 39 +- utils/keytable/toml.c | 1904 +------------------------------------- utils/keytable/toml.h | 111 +-- 15 files changed, 2679 insertions(+), 2516 deletions(-) create mode 100644 utils/common/keymap.c create mode 100644 utils/common/keymap.h create mode 100644 utils/common/toml.c create mode 100644 utils/common/toml.h create mode 120000 utils/ir-ctl/keymap.c create mode 120000 utils/ir-ctl/keymap.h create mode 120000 utils/ir-ctl/toml.c create mode 120000 utils/ir-ctl/toml.h mode change 100644 => 120000 utils/keytable/keymap.c mode change 100644 => 120000 utils/keytable/keymap.h mode change 100644 => 120000 utils/keytable/toml.c mode change 100644 => 120000 utils/keytable/toml.h
utils/common/keymap.c new file +471 -0
@@ -0,0 +1,471 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +// Read a toml keymap or plain text keymap (ir-keytable 1.14 or earlier +// format). + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <limits.h> +#include <stdbool.h> + +#include "keymap.h" +#include "toml.h" + +#ifdef ENABLE_NLS +# define _ (string) gettext(string) +# include "gettext.h" +# include <locale.h> +# include <langinfo.h> +# include <iconv.h> +#else +# define _ (string) string +#endif + +void free_keymap (struct keymap *map) +{ +struct scancode_entry *se; +struct raw_entry *re; +struct protocol_param *param; +struct keymap *next; + +while (map) { + re = map->raw; + +while (re) { +struct raw_entry *next = re->next; +free (re->keycode); +free (re); + re = next; + } + + + se = map->scancode; + +while (se) { +struct scancode_entry *next = se->next; +free (se->keycode); +free (se); + se = next; + } + + param = map->param; + +while (param) { +struct protocol_param *next = param->next; +free (param->name); +free (param); + param = next; + } + + next = map->next; + +free (map->name); +free (map->protocol); +free (map->variant); +free (map); + + map = next; + } +} + +static error_t parse_plain_keyfile (char *fname,struct keymap **keymap,bool verbose) +{ +FILE *fin; +int line =0 ; +char *scancode, *keycode, s[2048 ]; +struct scancode_entry *se; +struct keymap *map; + + map =calloc (1 ,sizeof (*map)); +if (!map) { +perror ("parse_keyfile" ); +return ENOMEM ; + } + +if (verbose) +fprintf (stderr,_ ("Parsing %s keycode file as plain text\n" ), fname); + + fin =fopen (fname,"r" ); +if (!fin) { +return errno; + } + +while (fgets (s,sizeof (s), fin)) { +char *p = s; + + line++; +while (*p ==' ' || *p =='\t' ) + p++; +if (line==1 && p[0 ] =='#' ) { + p++; + p =strtok (p,"\n\t =:" ); +do { +if (!p) + goto err_einval; +if (!strcmp (p,"table" )) { + p =strtok (NULL ,"\n, " ); +if (!p) + goto err_einval; + map->name =strdup (p); + }else if (!strcmp (p,"type" )) { + p =strtok (NULL ," ,\n" ); +if (!p) + goto err_einval; + +while (p) { +if (!map->protocol) { + map->protocol =strdup (p); + }else { +struct keymap *k; + + k =calloc (1 ,sizeof (*k)); + k->protocol =strdup (p); + k->next = map->next; + map->next = k; + } + + p =strtok (NULL ," ,\n" ); + } + }else { + goto err_einval; + } + p =strtok (NULL ,"\n\t =:" ); + }while (p); +continue ; + } + +if (*p =='\n' || *p =='#' ) +continue ; + + scancode =strtok (p,"\n\t =:" ); +if (!scancode) + goto err_einval; +if (!strcasecmp (scancode,"scancode" )) { + scancode =strtok (NULL ,"\n\t =:" ); +if (!scancode) + goto err_einval; + } + + keycode =strtok (NULL ,"\n\t =:(" ); +if (!keycode) + goto err_einval; + + se =calloc (1 ,sizeof (*se)); +if (!se) { +free_keymap (map); +perror ("parse_keyfile" ); +fclose (fin); +return ENOMEM ; + } + + se->scancode =strtoul (scancode,NULL ,0 ); + se->keycode =strdup (keycode); + se->next = map->scancode; + map->scancode = se; + } +fclose (fin); + + *keymap = map; + +return 0 ; + +err_einval: +free_keymap (map); +fprintf (stderr,_ ("Invalid parameter on line %d of %s\n" ), + line, fname); +return EINVAL ; +} + +static error_t parse_toml_raw_part (const char *fname,struct toml_array_t *raw,struct keymap *map) +{ +struct toml_table_t *t; +struct toml_array_t *rawarray; +struct raw_entry *re; +const char *rkeycode; +int ind =0 , length; +char *keycode; + +while ((t =toml_table_at (raw, ind++)) !=NULL ) { + rkeycode =toml_raw_in (t,"keycode" ); +if (!rkeycode) { +fprintf (stderr,_ ("%s: invalid keycode for raw entry %d\n" ), + fname, ind); +return EINVAL ; + } + +if (toml_rtos (rkeycode, &keycode)) { +fprintf (stderr,_ ("%s: bad value `%s' for keycode\n" ), + fname, rkeycode); +return EINVAL ; + } + + rawarray =toml_array_in (t,"raw" ); +if (!rawarray) { +fprintf (stderr,_ ("%s: missing raw array for entry %d\n" ), + fname, ind); +return EINVAL ; + } + +// determine length of array + length =0 ; +while (toml_raw_at (rawarray, length) !=NULL ) + length++; + +if (!(length %2 )) { +fprintf (stderr,_ ("%s: raw array must have odd length rather than %d\n" ), + fname, length); +return EINVAL ; + } + + re =calloc (1 ,sizeof (*re) +sizeof (re->raw[0 ]) * length); +if (!re) { +fprintf (stderr,_ ("Failed to allocate memory" )); +return EINVAL ; + } + +for (int i=0 ; i<length; i++) { +const char *s =toml_raw_at (rawarray, i); +int64_t v; + +if (toml_rtoi (s, &v) || v ==0 ) { +fprintf (stderr,_ ("%s: incorrect raw value `%s'" ), + fname, s); +return EINVAL ; + } + +if (v <=0 || v >USHRT_MAX ) { +fprintf (stderr,_ ("%s: raw value %ld out of range" ), + fname, v); +return EINVAL ; + } + + re->raw[i] = v; + } + + re->raw_length = length; + re->keycode = keycode; + re->next = map->raw; + map->raw = re; + } + +return 0 ; +} + + +static error_t parse_toml_protocol (const char *fname,struct toml_table_t *proot,struct keymap **keymap,bool verbose) +{ +struct toml_table_t *scancodes; +struct toml_array_t *rawarray; +const char *raw, *key; +bool have_raw_protocol = false; +struct keymap *map; +char *p; +int i =0 ; + + map =calloc (1 ,sizeof (*map)); +if (!map) { +perror ("parse_toml_protocol" ); +return ENOMEM ; + } + *keymap = map; + + raw =toml_raw_in (proot,"protocol" ); +if (!raw) { +fprintf (stderr,_ ("%s: protocol missing\n" ), fname); +return EINVAL ; + } + +if (toml_rtos (raw, &p)) { +fprintf (stderr,_ ("%s: bad value `%s' for protocol\n" ), fname, raw); +return EINVAL ; + } + + map->protocol =strdup (p); +if (!strcmp (p,"raw" )) + have_raw_protocol = true; + + raw =toml_raw_in (proot,"variant" ); +if (raw) { +if (toml_rtos (raw, &p)) { +fprintf (stderr,_ ("%s: bad value `%s' for variant\n" ), fname, raw); +return EINVAL ; + } + + map->variant =strdup (p); + } + + raw =toml_raw_in (proot,"name" ); +if (raw) { +if (toml_rtos (raw, &p)) { +fprintf (stderr,_ ("%s: bad value `%s' for name\n" ), fname, raw); +return EINVAL ; + } + + map->name =strdup (p); + } + + rawarray =toml_array_in (proot,"raw" ); +if (rawarray) { +if (toml_raw_in (proot,"scancodes" )) { +fprintf (stderr,_ ("Cannot have both [raw] and [scancode] sections" )); +return EINVAL ; + } +if (!have_raw_protocol) { +fprintf (stderr,_ ("Keymap with raw entries must have raw protocol" )); +return EINVAL ; + } +error_t err =parse_toml_raw_part (fname, rawarray, map); +if (err !=0 ) +return err; + + }else if (have_raw_protocol) { +fprintf (stderr,_ ("Keymap with raw protocol must have raw entries" )); +return EINVAL ; + } + + scancodes =toml_table_in (proot,"scancodes" ); +if (!scancodes) { +if (verbose) +fprintf (stderr,_ ("%s: no [protocols.scancodes] section\n" ), fname); +return 0 ; + } + +for (i =0 ; (key =toml_key_in (proot, i)) !=NULL ; i++) { +long int value; + + raw =toml_raw_in (proot, key); +if (!toml_rtoi (raw, &value)) { +struct protocol_param *param; + + param =malloc (sizeof (*param)); + param->name =strdup (key); + param->value = value; + param->next = map->param; + map->param = param; +if (verbose) +fprintf (stderr,_ ("%s: protocol parameter %s=%ld\n" ), fname, param->name, param->value); + } + } + +for (;;) { +struct scancode_entry *se; +const char *scancode; +char *keycode; + + scancode =toml_key_in (scancodes, i++); +if (!scancode) +break ; + + raw =toml_raw_in (scancodes, scancode); +if (!raw) { +fprintf (stderr,_ ("%s: invalid value `%s'\n" ), fname, scancode); +return EINVAL ; + } + +if (toml_rtos (raw, &keycode)) { +fprintf (stderr,_ ("%s: bad value `%s' for keycode\n" ), + fname, keycode); +return EINVAL ; + } + + se =calloc (1 ,sizeof (*se)); +if (!se) { +perror ("parse_keyfile" ); +return ENOMEM ; + } + + se->scancode =strtoul (scancode,NULL ,0 ); + se->keycode = keycode; + se->next = map->scancode; + map->scancode = se; + } + +return 0 ; +} + +static error_t parse_toml_keyfile (char *fname,struct keymap **keymap,bool verbose) +{ +struct toml_table_t *root, *proot; +struct toml_array_t *arr; +int ret, i =0 ; +char buf[200 ]; +FILE *fin; + +if (verbose) +fprintf (stderr,_ ("Parsing %s keycode file as toml\n" ), fname); + + fin =fopen (fname,"r" ); +if (!fin) +return errno; + + root =toml_parse_file (fin, buf,sizeof (buf)); +fclose (fin); +if (!root) { +fprintf (stderr,_ ("%s: failed to parse toml: %s\n" ), fname, buf); +return EINVAL ; + } + + arr =toml_array_in (root,"protocols" ); +if (!arr) { +fprintf (stderr,_ ("%s: missing [protocols] section\n" ), fname); +return EINVAL ; + } + +struct keymap *map =NULL ; + +for (;;) { +struct keymap *cur_map; + + proot =toml_table_at (arr, i); +if (!proot) +break ; + + ret =parse_toml_protocol (fname, proot, &cur_map, verbose); +if (ret) + goto out; + +if (!map) { + map = cur_map; + }else { + cur_map->next = map->next; + map->next = cur_map; + } + i++; + } + +if (i ==0 ) { +fprintf (stderr,_ ("%s: no protocols found\n" ), fname); + goto out; + } + +toml_free (root); + *keymap = map; +return 0 ; +out: +toml_free (root); +return EINVAL ; +} + +error_t parse_keyfile (char *fname,struct keymap **keymap,bool verbose) +{ +size_t len =strlen (fname); + +if (len >=5 &&strcasecmp (fname + len -5 ,".toml" ) ==0 ) +return parse_toml_keyfile (fname, keymap, verbose); +else +return parse_plain_keyfile (fname, keymap, verbose); +} + +int keymap_param (struct keymap *map,const char *name,int fallback) +{ +struct protocol_param *param; + +for (param = map->param; param; param = param->next) { +if (!strcmp (param->name, name)) +return param->value; + } + +return fallback; +}
utils/common/keymap.h new file +39 -0
@@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __KEYMAP_H +#define __KEYMAP_H + +struct keymap { +struct keymap *next; +char *name; +char *protocol; +char *variant; +struct protocol_param *param; +struct scancode_entry *scancode; +struct raw_entry *raw; +}; + +struct protocol_param { +struct protocol_param *next; +char *name; +long int value; +}; + +struct scancode_entry { +struct scancode_entry *next; +u_int32_t scancode; +char *keycode; +}; + +struct raw_entry { +struct raw_entry *next; +u_int32_t scancode; +u_int32_t raw_length; +char *keycode; +u_int32_t raw[1 ]; +}; + +void free_keymap (struct keymap *map); +error_t parse_keyfile (char *fname,struct keymap **keymap,bool verbose); +int keymap_param (struct keymap *map,const char *name,int fallback); + +#endif
utils/common/toml.c new file +1903 -0
1,903 lines not on this page · raw message
utils/common/toml.h new file +110 -0
110 lines not on this page · raw message
utils/ir-ctl/Makefile.am +1 -1
@@ -1,6 +1,6 @@ bin_PROGRAMS = ir-ctl man_MANS = ir-ctl.1 -ir_ctl_SOURCES = ir-ctl.c ir-encode.c ir-encode.h +ir_ctl_SOURCES = ir-ctl.c ir-encode.c ir-encode.h toml.c toml.h keymap.c keymap.h ir_ctl_LDADD = @LIBINTL@ ir_ctl_LDFLAGS = $(ARGP_LIBS)
utils/ir-ctl/ir-ctl.1.in +24 -2
@@ -15,10 +15,16 @@ ir\-ctl \- a swiss\-knife tool to handle raw IR and to set lirc options [\fIOPTION\fR]... \fI\-\-scancode\fR [\fIprotocol and scancode to send\fR] .br .B ir\-ctl +[\fIOPTION\fR]... \fI\-\-keycode\fR [\fIkeycode to send\fR] +.br +.B ir\-ctl [\fIOPTION\fR]... \fI\-\-receive\fR [\fIsave to file\fR] .SH DESCRIPTION ir\-ctl is a tool that allows one to list the features of a lirc device, -set its options, receive raw IR, send raw IR or send complete IR scancodes. +set its options, receive raw IR, and send IR. +.PP +IR can be sent as the keycode of a keymap, or using a scancode, or using +raw IR. .PP Note: You need to have read or write permissions on the /dev/lirc device for options to work.
@@ -45,6 +51,16 @@ protocols listed below, followed by a colon and the scancode number. If this option is specified multiple times, send all scancodes in\-order with a 125ms gap between them. The gap length can be modified with \fB\-\-gap\fR. .TP +\fB-K\fR, \fB\-\-keycode\fR=\fIKEYCODE\fR +Send the \fBKEYCODE\fR from the keymap which must be specified with +\fB--keymap\fR. If this option is specified multiple times, send all keycodes +in\-order with a 125ms gap between them. The gap length can be modified +with \fB\-\-gap\fR. +.TP +\fB-k\fR, \fB\-\-keymap\fR=\fIKEYMAP\fR +The rc keymap in toml format. The format is described in the rc_keymap(5) +man page. +.TP \fB\-1\fR, \fB\-\-oneshot\fR When receiving, stop receiving after the first message, i.e. after a space or timeout of more than 19ms is received.
@@ -224,7 +240,11 @@ To send the pulse and space file \fBplay\fR on emitter 3: .PP To send the rc-5 hauppauge '1' scancode: .br - \fBir\-ctl \-S rc5:0x1e01 + \fBir\-ctl \-S rc5:0x1e01\fR +.PP +To send the rc-5 hauppauage '1' key from the hauppauge keymap: +.br + \fBir\-ctl -k hauppauge.toml -K KEY_NUMERIC_0\fR .SH BUGS Report bugs to \fBLinux Media Mailing List <[email protected]>\fR .SH COPYRIGHT
@@ -237,3 +257,5 @@ There is NO WARRANTY, to the extent permitted by law. .SH SEE ALSO To display decoded IR, or set IR decoding options, see ir\-keytable(1). + +The keymap format is described in rc_keymap(5).
utils/ir-ctl/ir-ctl.c +123 -3
216 lines not on this page · raw message
utils/ir-ctl/keymap.c new file +1 -0
@@ -0,0 +1 @@ +../common/keymap.c
utils/ir-ctl/keymap.h new file +1 -0
@@ -0,0 +1 @@ +../common/keymap.h
utils/ir-ctl/toml.c new file +1 -0
@@ -0,0 +1 @@ +../common/toml.c
utils/ir-ctl/toml.h new file +1 -0
@@ -0,0 +1 @@ +../common/toml.h
utils/keytable/keymap.c deleted +0 -459
196 lines not on this page · raw message
utils/keytable/toml.c deleted +0 -1903
1,903 lines not on this page · raw message
utils/keytable/toml.h deleted +0 -110
110 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.21.0
Part of the diff is not shown here. View the raw message.