keytable: add support for keymap with raw literals
PATCH v2 1/1 keytable: add support for keymap with raw literals
These rc keymaps look like:
[[protocols]] name = 'Beon_Colour_TV' protocol = 'raw' [[protocols.raw]] keycode = 'KEY_POWER' raw = [ 1324, 842, 6697, 26400, 1324, 842, 6697 ] [[protocols.raw]] keycode = 'KEY_MUTE' raw = [ 1305, 865, 2357, 931, 3411, 26400, 1305, 865, 2357, 931, 3411 ]
So the incoming IR will be literally compared against the IR given, and only if the entire array matches with no leading or trailing IR will the keycode be reported.
This is analogous to lircd raw_codes support, so lircd2toml.py can also convert raw_codes lircd.conf files. This means that the vast majority of lircd files can now be converted.
This feature requires loops in BPF programs so this is only supported in kernel 5.3 onwards.
Signed-off-by Sean Young <[email protected]>
--- contrib/lircd2toml.py | 76 ++++++++---- utils/keytable/bpf_load.c | 108 +++++++++++++++- utils/keytable/bpf_load.h | 9 +- utils/keytable/bpf_protocols/Makefile.am | 2 +- utils/keytable/bpf_protocols/bitmap.h | 36 ++++++ utils/keytable/bpf_protocols/raw.c | 149 +++++++++++++++++++++++ utils/keytable/keytable.c | 139 ++++++++++++++++++++- utils/keytable/rc_keymap.5.in | 18 ++- 8 files changed, 505 insertions(+), 32 deletions(-) create mode 100644 utils/keytable/bpf_protocols/bitmap.h create mode 100644 utils/keytable/bpf_protocols/raw.c
contrib/lircd2toml.py +52 -24
@@ -146,14 +146,14 @@ class LircdParser: a = line.split() if a[0] == 'name': if len(codes) > 0: - raw_codes.append({ 'name': name, 'codes': codes }) + raw_codes.append({ 'keycode': name, 'raw': codes }) name = line.split(maxsplit=2)[1] if not name.startswith('KEY_'): name = 'KEY_' + name.upper() codes = [] elif a[0] == 'end': if len(codes) > 0: - raw_codes.append({ 'name': name, 'codes': codes }) + raw_codes.append({ 'keycode': name, 'raw': codes }) return raw_codes else: for v in a:
@@ -224,6 +224,8 @@ class Converter: return self.convert_rcmm() elif 'space_enc' in flags: return self.convert_space_enc() + elif 'raw_codes' in flags: + return self.convert_raw_codes() else: self.error('Cannot convert remote with flags: {}'.format('|'.join(flags)))
@@ -237,7 +239,7 @@ class Converter: res = { 'protocol': 'pulse_distance', 'params': {}, - 'map': {} + 'scancodes': {} } res['name'] = self.remote['name']
@@ -338,7 +340,7 @@ class Converter: elif v != variant: variant = "" - res['map'][n] = self.remote['codes'][s] + res['scancodes'][n] = self.remote['codes'][s] if variant: res['params']['variant'] = "'" + variant + "'"
@@ -374,14 +376,14 @@ class Converter: elif v != variant: variant = "" - res['map'][n] = self.remote['codes'][s] + res['scancodes'][n] = self.remote['codes'][s] if variant: res['params']['variant'] = "'" + variant + "'" else: for s in self.remote['codes']: p = (s<<post_data_bits)|pre_data - res['map'][p] = self.remote['codes'][s] + res['scancodes'][p] = self.remote['codes'][s] return res
@@ -389,7 +391,7 @@ class Converter: res = { 'protocol': 'rc-mm', 'params': {}, - 'map': {} + 'scancodes': {} } res['name'] = self.remote['name']
@@ -415,9 +417,9 @@ class Converter: pre_data = int(self.remote['pre_data'][0]) << bits bits += pre_data_bits for s in self.remote['codes']: - res['map'][s|pre_data] = self.remote['codes'][s] + res['scancodes'][s|pre_data] = self.remote['codes'][s] else: - res['map'] = self.remote['codes'] + res['scancodes'] = self.remote['codes'] res['params']['bits'] = bits res['params']['variant'] = "'rc-mm-" + str(bits) + "'"
@@ -431,7 +433,7 @@ class Converter: res = { 'protocol': 'rc-6', 'params': { }, - 'map': { } + 'scancodes': { } } res['name'] = self.remote['name']
@@ -471,7 +473,7 @@ class Converter: d = ~(s|pre_data)&mask if bits == 32: vendor = d >> 16 - res['map'][d] = self.remote['codes'][s] + res['scancodes'][d] = self.remote['codes'][s] if bits == 16: res['params']['variant'] = "'rc-6-0'"
@@ -494,7 +496,7 @@ class Converter: res = { 'protocol': 'manchester', 'params': { }, - 'map': { } + 'scancodes': { } } res['name'] = self.remote['name']
@@ -560,10 +562,20 @@ class Converter: n = s|pre_data n = (n & 0x3f) | ((n << 2) & 0x1f00) newcodes[n] = self.remote['codes'][s] - res['map'] = newcodes + res['scancodes'] = newcodes else: for s in self.remote['codes']: - res['map'][s|pre_data] = self.remote['codes'][s] + res['scancodes'][s|pre_data] = self.remote['codes'][s] + + return res + + def convert_raw_codes(self): + res = { + 'protocol': 'raw', + 'params': {}, + 'raw': self.remote['raw_codes'], + 'name': self.remote['name'] + } return res
@@ -576,16 +588,32 @@ def writeTOMLFile(fh, remote): print('protocol = {}'.format(escapeString(remote['protocol'])), file=fh) for p in remote['params']: print('{} = {}'.format(p, remote['params'][p]), file=fh) - print('[protocols.scancodes]', file=fh) - # find the largest scancode - length=1 - for c in remote['map']: - length=max(length, c.bit_length()) - - # width seems to include '0x', hence the + 2 - width = math.ceil(length/4) + 2 - for c in remote['map']: - print('{:#0{width}x} = {}'.format(c, escapeString(remote['map'][c]), width=width), file=fh) + + if 'scancodes' in remote: + print('[protocols.scancodes]', file=fh) + # find the largest scancode + length=1 + for c in remote['scancodes']: + length=max(length, c.bit_length()) + + # width seems to include '0x', hence the + 2 + width = math.ceil(length/4) + 2 + for c in remote['scancodes']: + print('{:#0{width}x} = {}'.format(c, escapeString(remote['scancodes'][c]), width=width), file=fh) + + elif 'raw' in remote: + for raw in remote['raw']: + print('[[protocols.raw]]', file=fh) + print('keycode = {}\nraw = ['.format(escapeString(raw['keycode'])), file=fh, end='') + first = True + for v in raw['raw']: + if first: + print(' {}'.format(v), file=fh, end='') + else: + print(', {}'.format(v), file=fh, end='') + first = False + + print(' ]', file=fh) return True
utils/keytable/bpf_load.c +104 -4
156 lines not on this page · raw message
utils/keytable/bpf_load.h +8 -1
@@ -24,6 +24,13 @@ struct bpf_map_data {struct bpf_load_map_def def; }; +struct raw_entry { +struct raw_entry *next; +u_int32_t scancode; +u_int32_t raw_length; +u_int32_t raw[1 ]; +}; +/* parses elf file compiled by llvm .c->.o * . parses 'maps' section and creates maps via BPF syscall * . parses 'license' section and passes it to syscall
@@ -36,7 +43,7 @@ struct bpf_map_data {* * returns zero on success */ -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 toml_table_t *toml,struct raw_entry *raw);int bpf_param (const char *name,int *val);
utils/keytable/bpf_protocols/Makefile.am +1 -1
@@ -10,7 +10,7 @@ CLANG_SYS_INCLUDES := $(shell $(CLANG) -v -E - </dev/null 2>&1 \ %.o: %.c bpf_helpers.h $(CLANG) $(CLANG_SYS_INCLUDES) -D__linux__ -I$(top_srcdir)/include -target bpf -O2 -c $< -PROTOCOLS = grundig.o pulse_distance.o pulse_length.o rc_mm.o manchester.o xbox-dvd.o imon_rsc.o +PROTOCOLS = grundig.o pulse_distance.o pulse_length.o rc_mm.o manchester.o xbox-dvd.o imon_rsc.o raw.o all: $(PROTOCOLS)
utils/keytable/bpf_protocols/bitmap.h new file +36 -0
@@ -0,0 +1,36 @@ + +#ifndef __BITMAP_H__ +#define __BITMAP_H__ + +#include "string.h" + +#define BITS_PER_LONG 64 +#define BITS_TO_LONG (n) \ + (((n) + BITS_PER_LONG - 1) / BITS_PER_LONG) + + +#define DECLARE_BITMAP (name, bits) \ + unsigned long name[BITS_TO_LONG(bits)] + +static void inline bitmap_zero (unsigned long *bitmap,int bits) +{ +for (int i =0 ; i <BITS_TO_LONG (bits); i++) + bitmap[i] =0 ; +} + +static void inline bitmap_fill (unsigned long *bitmap,int bits) +{ +for (int i =0 ; i <BITS_TO_LONG (bits); i++) + bitmap[i] = ~0 ; +} + +#define bitmap_set (b, n) \ + b[n / BITS_PER_LONG] |= 1 << (n % BITS_PER_LONG) + +#define bitmap_clear (b, n) \ + b[n / BITS_PER_LONG] &= ~(1 << (n % BITS_PER_LONG)) + +#define bitmap_test (b, n) \ + (b[n / BITS_PER_LONG] & (1 << (n % BITS_PER_LONG))) != 0 + +#endif
utils/keytable/bpf_protocols/raw.c new file +149 -0
149 lines not on this page · raw message
utils/keytable/keytable.c +138 -1
175 lines not on this page · raw message
utils/keytable/rc_keymap.5.in +17 -1
@@ -52,7 +52,8 @@ Protocol \fBrc\-mm\fR has variants \fBrc-mm-12\fR, \fBrc-mm-24\fR, and \fBrc-mm-32\fR. .SS Scancodes field The \fBscancodes\fR table list the scancodes and the mapping to linux input -key events. Multiple scancodes can map to the same key event. +key events. Multiple scancodes can map to the same key event. This field +is not present for \fBraw\fR protocols. .PP If the scancode start with 0x, it is interpreted as a hexadecimal number. If it starts with a 0, it is interpreted as an octal number.
@@ -60,6 +61,16 @@ it starts with a 0, it is interpreted as an octal number. The key events are listed in the \fBinput-event-codes.h\fR header file. Examples are \fBKEY_ENTER\fR, \fBKEY_ESC\fR or \fBBTN_LEFT\fR for the left mouse button. +.SS Raw field +If the protocol is \fBraw\fR, the \fBraw\fR field is an array of keycode +to raw mapping. For each entry, there is a \fBkeycode\fR field and \fBraw\fR +field. The \fBkeycode\fR is a linux input event, as explained the scancodes +section. +.PP +The \fBraw\fR field is an array of integers. These are the pulse and space +values of the IR message. The first is a pulse value in microseconds, and +the second a space, third pulse, etc. There should be an odd number of fields +so that the last entry is a pulse. .SS Remaining fields (BPF parameters) If the protocol is a BPF based decoder, it may have any number of numeric parameters. These parameters are used to support protocols with non-standard
@@ -74,6 +85,11 @@ Kernel based non-BPF protocol decoders do not have any parameters. Some of the BPF protocol decoders are generic and will need parameters to work. Other are for specific remotes and should work without any parameters. The timing parameters are all in microseconds (µs). +.SS raw +This decoder must be used when the keymap is raw; for each key, there is an +entry in raw array with the pulse and space values for that key. No decoding +is done, the incoming IR is simply matched against the different pulse and +space values. .SS imon_rsc This decoder is specifically for the iMON RSC remote, which was packaged with the iMON Station (amongst others). The decoder is for the directional stick in
Signature · 1 line
2.21.0