Skip to content

Commit

Permalink
Decode and test lircd.conf raw_codes
Browse files Browse the repository at this point in the history
Signed-off-by: Sean Young <[email protected]>
  • Loading branch information
seanyoung committed Mar 25, 2024
1 parent e7998dc commit e0d9ef6
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 24 deletions.
60 changes: 60 additions & 0 deletions irp/src/build_nfa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,66 @@ impl NFA {
pub fn dotgraphviz(&self, path: &str) {
crate::graphviz::graphviz(&self.verts, "NFA", &[], path);
}

/// Add nfa states for parsing raw IR
pub fn add_raw(&mut self, raw: &[u32], event: Event, code: i64) {
assert_ne!(raw.len(), 0);
assert_eq!(raw.len() % 2, 1);

if self.verts.is_empty() {
self.verts.push(Vertex::default());
}

let mut pos = 0;
let mut flash = true;

for raw in raw {
let length = Rc::new(Expression::Number((*raw).into()));
let actions = vec![if flash {
Action::Flash {
length,
complete: true,
}
} else {
Action::Gap {
length,
complete: true,
}
}];

if let Some(next) = self.verts[pos].edges.iter().find_map(|edge| {
if edge.actions == actions && self.verts[edge.dest].entry.is_empty() {
Some(edge.dest)
} else {
None
}
}) {
pos = next;
} else {
let next = self.verts.len();

self.verts.push(Vertex::default());

self.verts[pos].edges.push(Edge {
actions,
dest: next,
});

pos = next;
}

flash = !flash;
}

self.verts[pos].entry.push(Action::Set {
var: "CODE".into(),
expr: Rc::new(Expression::Number(code)),
});

self.verts[pos]
.entry
.push(Action::Done(event, vec!["CODE".into()]));
}
}

pub(crate) fn gen_mask(v: i64) -> i64 {
Expand Down
4 changes: 2 additions & 2 deletions src/bin/commands/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,8 @@ fn decode_lircd(matches: &clap::ArgMatches) {
let mut feed_decoder = |raw: &[InfraredData]| {
for (index, ir) in raw.iter().enumerate() {
for decoder in &mut decoders {
decoder.input(*ir, |code| {
println!("decoded: remote:{} code:{}", decoder.remote.name, code.name);
decoder.input(*ir, |name, _| {
println!("decoded: remote:{} code:{}", decoder.remote.name, name);
});

if graphviz_step {
Expand Down
54 changes: 35 additions & 19 deletions src/lircd_conf/decode.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{Code, Remote};
use super::Remote;
use irp::{Decoder, InfraredData, Irp, NFA};
use log::debug;

Expand All @@ -16,13 +16,23 @@ impl Remote {
rel_tolerance: Option<u32>,
max_gap: u32,
) -> LircDecoder {
let irp = self.decode_irp();
let nfa = if self.raw_codes.is_empty() {
let irp = self.decode_irp();

debug!("decoding irp {irp} for remote {}", self.name);
debug!("decoding irp {irp} for remote {}", self.name);

let irp = Irp::parse(&irp).unwrap();
let irp = Irp::parse(&irp).unwrap();

let nfa = irp.build_nfa().unwrap();
irp.build_nfa().unwrap()
} else {
let mut nfa = NFA::default();

for (i, raw) in self.raw_codes.iter().enumerate() {
nfa.add_raw(&raw.rawir, irp::Event::Down, u32::MAX as i64 + i as i64);
}

nfa
};

let decoder = Decoder::new(
abs_tolerance.unwrap_or(self.aeps as u32),
Expand All @@ -41,25 +51,31 @@ impl Remote {
impl<'a> LircDecoder<'a> {
pub fn input<F>(&mut self, ir: InfraredData, mut callback: F)
where
F: FnMut(&'a Code),
F: FnMut(&'a str, u64),
{
self.decoder.nfa_input(ir, &self.nfa, |_, vars| {
if let Some(decoded) = vars.get("CODE") {
// TODO: ignore mask, toggle_bit_mask with many bits set
let mask = if self.remote.toggle_bit_mask.count_ones() == 1 {
!self.remote.toggle_bit_mask
} else {
!0
};
if self.remote.raw_codes.is_empty() {
// TODO: ignore mask, toggle_bit_mask with many bits set
let mask = if self.remote.toggle_bit_mask.count_ones() == 1 {
!self.remote.toggle_bit_mask
} else {
!0
};

let decoded = *decoded as u64;
if let Some(key_code) = self.remote.codes.iter().find(|code| {
let code = code.code[0] & mask;
let decoded_masked = decoded & mask;

let decoded = *decoded as u64;
if let Some(key_code) = self.remote.codes.iter().find(|code| {
let code = code.code[0] & mask;
let decoded = decoded & mask;
code == decoded_masked || code == (decoded_masked ^ self.remote.repeat_mask)
}) {
callback(&key_code.name, decoded);
}
} else {
let decoded: usize = *decoded as usize - u32::MAX as usize;

code == decoded || code == (decoded ^ self.remote.repeat_mask)
}) {
callback(key_code);
callback(&self.remote.raw_codes[decoded].name, decoded as u64);
}
}
})
Expand Down
19 changes: 16 additions & 3 deletions tests/lircd_conf_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ fn lircd_encode_decode(path: &Path) {

let our_remote = our_conf.next().unwrap();

let mut decoder = our_remote.decoder(Some(10), Some(1), 200000);

if lircd_remote.is_raw() {
for (our_code, lircd_code) in our_remote.raw_codes.iter().zip(lircd_remote.codes_iter())
{
Expand Down Expand Up @@ -85,13 +87,24 @@ fn lircd_encode_decode(path: &Path) {
println!("cir {}", message.print_rawir());
panic!("RAW CODE: {}", our_code.name);
}

let mut decoded = Vec::new();

decoder.reset();

for ir in InfraredData::from_u32_slice(&message.raw) {
decoder.input(ir, |name, _| {
decoded.push(name);
});
}

assert!(decoded.contains(&our_code.name.as_str()));
}
}

if !our_remote.codes.is_empty() {
let irp = our_remote.encode_irp();
println!("remote {} irp:{}", our_remote.name, irp);
let mut decoder = our_remote.decoder(Some(10), Some(1), 200000);

for (our_code, lircd_code) in our_remote.codes.iter().zip(lircd_remote.codes_iter()) {
if our_code.dup {
Expand Down Expand Up @@ -205,8 +218,8 @@ fn lircd_encode_decode(path: &Path) {
.expect("encode should succeed");

for ir in InfraredData::from_u32_slice(&message.raw) {
decoder.input(ir, |code| {
decoded.push(code.code[0] & !lircd_remote.toggle_bit_mask());
decoder.input(ir, |_, code| {
decoded.push(code & !lircd_remote.toggle_bit_mask());
});
}

Expand Down

0 comments on commit e0d9ef6

Please sign in to comment.