Skip to content

Commit b284293

Browse files
committed
Add encoder for same bpf protocols that ir-ctl can encode
Create IRPs for old v4l-utils bpf protocols. Signed-off-by: Sean Young <[email protected]>
1 parent 5e43ca6 commit b284293

File tree

7 files changed

+452
-9
lines changed

7 files changed

+452
-9
lines changed

Diff for: libirctl/src/bpf_encoder.c

+15-7
Original file line numberDiff line numberDiff line change
@@ -61,24 +61,24 @@ static void encode_pulse_length(struct keymap *map, uint32_t scancode, int *buf,
6161
if (keymap_param(map, "reverse", 0)) {
6262
for (i = 0; i < bits; i++) {
6363
if (scancode & (1 << i))
64-
buf[len++] = keymap_param(map, "bit_1_space", 1625);
64+
buf[len++] = keymap_param(map, "bit_1_pulse", 1625);
6565
else
66-
buf[len++] = keymap_param(map, "bit_0_space", 375);
66+
buf[len++] = keymap_param(map, "bit_0_pulse", 375);
6767

68-
buf[len++] = keymap_param(map, "bit_pulse", 625);
68+
buf[len++] = keymap_param(map, "bit_space", 625);
6969
}
7070
} else {
7171
for (i = bits - 1; i >= 0; i--) {
7272
if (scancode & (1 << i))
73-
buf[len++] = keymap_param(map, "bit_1_space", 1625);
73+
buf[len++] = keymap_param(map, "bit_1_pulse", 1625);
7474
else
75-
buf[len++] = keymap_param(map, "bit_0_space", 375);
75+
buf[len++] = keymap_param(map, "bit_0_pulse", 375);
7676

77-
buf[len++] = keymap_param(map, "bit_pulse", 625);
77+
buf[len++] = keymap_param(map, "bit_space", 625);
7878
}
7979
}
8080

81-
*length = len;
81+
*length = len - 1;
8282
}
8383

8484
static void manchester_advance_space(int *buf, int *len, unsigned length)
@@ -101,6 +101,14 @@ static void encode_manchester(struct keymap *map, uint32_t scancode, int *buf, i
101101
{
102102
int len = 0, bits, i;
103103

104+
int header_pulse = keymap_param(map, "header_pulse", 0);
105+
int header_space = keymap_param(map, "header_space", 0);
106+
107+
if (header_pulse > 0) {
108+
manchester_advance_pulse(buf, &len, header_pulse);
109+
manchester_advance_space(buf, &len, header_space);
110+
}
111+
104112
bits = keymap_param(map, "bits", 14);
105113

106114
for (i = bits - 1; i >= 0; i--) {

Diff for: libirctl/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub struct raw_entry {
4545
}
4646

4747
extern "C" {
48-
pub fn parse_keymap(fname: *const c_char, keymap: *const *const keymap, verbose: bool) -> i32;
48+
pub fn parse_keymap(fname: *const c_char, keymap: *mut *mut keymap, verbose: bool) -> i32;
4949
pub fn free_keymap(keymap: *const keymap);
5050
pub fn keymap_param(keymap: *const keymap, name: *const c_char, fallback: i32) -> i32;
5151
}

Diff for: src/keymap.rs

+248-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Parse linux rc keymaps
22
3-
use std::{collections::HashMap, ffi::OsStr, path::Path};
3+
use std::{collections::HashMap, ffi::OsStr, fmt::Write, path::Path};
44
use toml::{Table, Value};
55

66
#[derive(PartialEq, Eq, Debug, Default)]
@@ -9,6 +9,7 @@ pub struct Protocol {
99
pub protocol: String,
1010
pub variant: Option<String>,
1111
pub irp: Option<String>,
12+
pub rc_protocol: Option<u16>,
1213
pub raw: Option<Vec<Raw>>,
1314
pub scancodes: Option<HashMap<String, String>>,
1415
}
@@ -120,6 +121,18 @@ fn parse_toml(contents: &str, filename: &Path) -> Result<Keymap, String> {
120121
variant = Some(entry.to_owned());
121122
}
122123

124+
let mut rc_protocol = None;
125+
if let Some(Value::Integer(n)) = entry.get("rc_protocol") {
126+
if let Ok(n) = (*n).try_into() {
127+
rc_protocol = Some(n);
128+
} else {
129+
return Err(format!(
130+
"{}: rc_protocol {n} must be 16 bit value",
131+
filename.display()
132+
));
133+
}
134+
}
135+
123136
let mut irp = None;
124137
let mut raw = None;
125138
let mut scancodes = None;
@@ -184,6 +197,11 @@ fn parse_toml(contents: &str, filename: &Path) -> Result<Keymap, String> {
184197
if let Some(Value::String(entry)) = entry.get("irp") {
185198
irp = Some(entry.to_owned());
186199
}
200+
} else if entry.get("irp").is_some() {
201+
return Err("set the protocol to irp when using irp".to_string());
202+
} else if let Some(rewrite) = bpf_protocol_irp(protocol, entry.as_table().unwrap()) {
203+
log::info!("{}: protocol {protocol} has been rewritten to irp {rewrite}", filename.display());
204+
irp = Some(rewrite);
187205
}
188206

189207
if let Some(Value::Table(codes)) = entry.get("scancodes") {
@@ -206,6 +224,7 @@ fn parse_toml(contents: &str, filename: &Path) -> Result<Keymap, String> {
206224
protocol: protocol.to_owned(),
207225
variant,
208226
raw,
227+
rc_protocol,
209228
scancodes,
210229
irp,
211230
});
@@ -214,6 +233,185 @@ fn parse_toml(contents: &str, filename: &Path) -> Result<Keymap, String> {
214233
Ok(Keymap { protocols: res })
215234
}
216235

236+
fn bpf_protocol_irp(protocol: &str, entry: &Table) -> Option<String> {
237+
let param = |name: &str, default: i64| -> i64 {
238+
if let Some(Value::Integer(n)) = entry.get(name) {
239+
*n
240+
} else {
241+
default
242+
}
243+
};
244+
245+
match protocol {
246+
"pulse_distance" => {
247+
let mut irp = "{".to_owned();
248+
let bits = param("bits", 4);
249+
250+
if param("reverse", 0) == 0 {
251+
irp.push_str("msb,");
252+
}
253+
254+
if entry.contains_key("carrier") {
255+
write!(irp, "{}Hz,", param("carrier", 0)).unwrap();
256+
}
257+
258+
if irp.ends_with(',') {
259+
irp.pop();
260+
}
261+
262+
write!(
263+
irp,
264+
"}}<{},-{}|{},-{}>({},-{},CODE:{},{},-40m",
265+
param("bit_pulse", 625),
266+
param("bit_0_space", 375),
267+
param("bit_pulse", 625),
268+
param("bit_1_space", 1625),
269+
param("header_pulse", 2125),
270+
param("header_space", 1875),
271+
bits,
272+
param("trailer_pulse", 625),
273+
)
274+
.unwrap();
275+
276+
let header_optional = param("header_optional", 0);
277+
278+
if header_optional > 0 {
279+
write!(
280+
irp,
281+
",(CODE:{},{},-40m)*",
282+
bits,
283+
param("trailer_pulse", 625),
284+
)
285+
.unwrap();
286+
} else {
287+
let repeat_pulse = param("repeat_pulse", 0);
288+
if repeat_pulse > 0 {
289+
write!(
290+
irp,
291+
",({},-{},{},-40)*",
292+
repeat_pulse,
293+
param("repeat_space", 0),
294+
param("trailer_pulse", 625)
295+
)
296+
.unwrap();
297+
}
298+
}
299+
300+
write!(irp, ") [CODE:0..{}]", gen_mask(bits)).unwrap();
301+
302+
Some(irp)
303+
}
304+
"pulse_length" => {
305+
let mut irp = "{".to_owned();
306+
let bits = param("bits", 4);
307+
308+
if param("reverse", 0) == 0 {
309+
irp.push_str("msb,");
310+
}
311+
312+
if entry.contains_key("carrier") {
313+
write!(irp, "{}Hz,", param("carrier", 0)).unwrap();
314+
}
315+
316+
if irp.ends_with(',') {
317+
irp.pop();
318+
}
319+
320+
write!(
321+
irp,
322+
"}}<{},-{}|{},-{}>({},-{},CODE:{},-40m",
323+
param("bit_0_pulse", 375),
324+
param("bit_space", 625),
325+
param("bit_1_pulse", 1625),
326+
param("bit_space", 625),
327+
param("header_pulse", 2125),
328+
param("header_space", 1875),
329+
bits,
330+
)
331+
.unwrap();
332+
333+
let header_optional = param("header_optional", 0);
334+
335+
if header_optional > 0 {
336+
write!(irp, ",(CODE:{},-40m)*", bits).unwrap();
337+
} else {
338+
let repeat_pulse = param("repeat_pulse", 0);
339+
if repeat_pulse > 0 {
340+
write!(
341+
irp,
342+
",({},-{},{},-40)*",
343+
repeat_pulse,
344+
param("repeat_space", 0),
345+
param("trailer_pulse", 625)
346+
)
347+
.unwrap();
348+
}
349+
}
350+
351+
write!(irp, ") [CODE:0..{}]", gen_mask(bits)).unwrap();
352+
353+
Some(irp)
354+
}
355+
"manchester" => {
356+
let mut irp = "{msb,".to_owned();
357+
let bits = param("bits", 14);
358+
let toggle_bit = param("toggle_bit", 100);
359+
360+
if entry.contains_key("carrier") {
361+
write!(irp, "{}Hz,", param("carrier", 0)).unwrap();
362+
}
363+
364+
if irp.ends_with(',') {
365+
irp.pop();
366+
}
367+
368+
write!(
369+
irp,
370+
"}}<-{},{}|{},-{}>(",
371+
param("zero_space", 888),
372+
param("zero_pulse", 888),
373+
param("one_pulse", 888),
374+
param("one_space", 888),
375+
)
376+
.unwrap();
377+
378+
let header_pulse = param("header_pulse", 0);
379+
let header_space = param("header_space", 0);
380+
381+
if header_pulse > 0 && header_space > 0 {
382+
write!(irp, "{},-{},", header_pulse, header_space).unwrap();
383+
}
384+
385+
if toggle_bit >= bits {
386+
write!(irp, "CODE:{},-40m", bits,).unwrap();
387+
} else {
388+
let leading = bits - toggle_bit;
389+
if leading > 1 {
390+
write!(irp, "CODE:{}:{},", leading - 1, toggle_bit + 1).unwrap();
391+
}
392+
write!(irp, "T:1,").unwrap();
393+
if toggle_bit > 0 {
394+
write!(irp, "CODE:{},", toggle_bit).unwrap();
395+
}
396+
irp.pop();
397+
}
398+
399+
write!(irp, ",-40m) [CODE:0..{}]", gen_mask(bits)).unwrap();
400+
401+
Some(irp)
402+
}
403+
_ => None,
404+
}
405+
}
406+
407+
fn gen_mask(v: i64) -> u64 {
408+
if v < 64 {
409+
(1u64 << v) - 1
410+
} else {
411+
u64::MAX
412+
}
413+
}
414+
217415
#[test]
218416
fn parse_toml_test() {
219417
let s = r#"
@@ -358,3 +556,52 @@ fn parse_text_test() {
358556
}
359557
}
360558
}
559+
560+
#[test]
561+
fn parse_bpf_toml_test() {
562+
let s = r#"
563+
[[protocols]]
564+
name = "meh"
565+
protocol = "manchester"
566+
toggle_bit = 12
567+
[protocols.scancodes]
568+
0x1e3b = "KEY_SELECT"
569+
0x1e3d = "KEY_POWER2"
570+
0x1e1c = "KEY_TV"
571+
"#;
572+
573+
let k = parse(s, Path::new("x.toml")).unwrap();
574+
575+
assert_eq!(k.protocols[0].name, "meh");
576+
assert_eq!(k.protocols[0].protocol, "manchester");
577+
assert_eq!(
578+
k.protocols[0].irp,
579+
Some("{msb}<-888,888|888,-888>(CODE:1:13,T:1,CODE:12,-40m) [CODE:0..16383]".into())
580+
);
581+
582+
let s = r#"
583+
[[protocols]]
584+
name = "meh"
585+
protocol = "manchester"
586+
toggle_bit = 1
587+
carrier = 38000
588+
header_pulse = 300
589+
header_space = 350
590+
[protocols.scancodes]
591+
0x1e3b = "KEY_SELECT"
592+
0x1e3d = "KEY_POWER2"
593+
0x1e1c = "KEY_TV"
594+
"#;
595+
596+
let k = parse(s, Path::new("x.toml")).unwrap();
597+
598+
assert_eq!(k.protocols[0].name, "meh");
599+
assert_eq!(k.protocols[0].protocol, "manchester");
600+
assert_eq!(
601+
k.protocols[0].irp,
602+
Some(
603+
"{msb,38000Hz}<-888,888|888,-888>(300,-350,CODE:12:2,T:1,CODE:1,-40m) [CODE:0..16383]"
604+
.into()
605+
)
606+
);
607+
}

Diff for: testdata/rc_keymaps/RM-687C.toml

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
[[protocols]]
2+
name = 'Sony_RM-687C'
3+
protocol = 'pulse_length'
4+
header_pulse = 2369
5+
header_space = 637
6+
bits = 12
7+
bit_space = 637
8+
bit_1_pulse = 1166
9+
bit_0_pulse = 565
10+
[protocols.scancodes]
11+
0xa90 = 'KEY_STANDBY'
12+
0x290 = 'KEY_MUTE'
13+
0x5d0 = 'KEY_DISPLAY'
14+
0x010 = 'KEY_1'
15+
0x810 = 'KEY_2'
16+
0x410 = 'KEY_3'
17+
0xc10 = 'KEY_4'
18+
0x210 = 'KEY_5'
19+
0xa10 = 'KEY_6'
20+
0x610 = 'KEY_7'
21+
0xe10 = 'KEY_8'
22+
0x110 = 'KEY_9'
23+
0x310 = 'KEY_1-'
24+
0x910 = 'KEY_0'
25+
0xb10 = 'KEY_2-'
26+
0x6d0 = 'KEY_SLEEP'
27+
0x3f0 = 'KEY_SELECT'
28+
0x2f0 = 'KEY_KPPLUS'
29+
0x690 = 'KEY_NORMAL'
30+
0xaf0 = 'KEY_KPMINUS'
31+
0x490 = 'KEY_VOLUMEUP'
32+
0x090 = 'KEY_CHANNELUP'
33+
0xa50 = 'KEY_TV/VIDEO'
34+
0xc90 = 'KEY_VOLUMEDOWN'
35+
0x890 = 'KEY_CHANNELDOWN'

0 commit comments

Comments
 (0)