-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Investigate how to make tolerances configurable #37
Comments
FYI: I was looking for a workaround to the inability to control this very thing (tolerances) and came up with this: // The infrared module is a bit too picky about timing so we fudge it a bit to make the IR
// receiver *much* more reliable (at least with NEC remotes):
if elapsed_us < 850 { // No idea how close these values are to their theoretical exact timings
elapsed_us = 550;
} else if elapsed_us > 1400 && elapsed_us < 2000 {
elapsed_us = 1600;
} ...and it works surprisingly well! Like, flawlessly. Basically, I've got the IR pin tied to IO_IRQ_BANK0 and triggering on High and Low (just like in the RP2040 example I wrote a while back). The value that gets passed to Basically, when I first started this code the IR remote worked OK-ish... Had to re-press a button about 25% of the time. However, as time went on and the project grew the IR events became more and more unreliable to the point where they would only work like 10% of the time. I knew why: I had too much simultaneous crap going on! haha. This was messing with the very precise timing required by Here's the full function code in case you need more context: // NOTE: This needs to be bound to the IO_IRQ_BANK0 interrupt
#[inline(never)]
#[link_section = ".data.ram_func"]
pub(crate) fn handle_ir_event(mut c: crate::app::handle_ir_event::Context) {
// static mut LAST: Option<Instant<u64, 1, 1000000>> = None;
let ir_edge = c.local.ir_edge;
let ir_recv = c.local.ir_recv;
let now = monotonics::now();
let elapsed = now.checked_duration_since(*ir_edge).unwrap();
let mut elapsed_us: u32 = elapsed.to_micros() as u32;
// debug!("IR elapsed_us: {}", elapsed_us);
// The infrared module is a bit too picky about timing so we fudge it a bit to make the IR
// receiver *much* more reliable (at least with NEC remotes):
if elapsed_us < 850 {
elapsed_us = 550;
} else if elapsed_us > 1400 && elapsed_us < 2000 {
elapsed_us = 1600;
}
if let Ok(cmds) = ir_recv.event_iter(elapsed_us) {
for cmd in cmds {
// debug!("IR: {:?}", cmd); // TEMP
match cmd {
MultiReceiverCommand::Nec(nec) => {
debug!("Nec cmd: {:?}, elapsed_us: {}", nec, elapsed_us);
let since_last_cmd = (now
.checked_duration_since(*c.local.ir_last_cmd_time)
.unwrap())
.to_millis();
if let Some(button) = IRRemote::decode(&nec) {
// debug!("Button decoded: {}", button);
if since_last_cmd > MAX_REPEAT_TIME {
// No commands for a while so reset the repeat counter
*c.local.ir_last_cmd_time = now;
*c.local.ir_repeat_counter = 0;
}
c.shared.states.lock(|states| {
if !nec.repeat
|| *c.local.ir_repeat_counter == 0
|| *c.local.ir_repeat_counter >= REPEAT_INTERVAL
{
let index = IRRemote::index(button) as u8;
let (_code, _action) = IRRemote::BUTTONS[index as usize];
*states.ir_button = index; // This is how keeb_scanner() can know what was pressed
*c.local.ir_repeat_counter = 0; // Reset the repeat counter
}
});
*c.local.ir_repeat_counter += 1;
}
}
MultiReceiverCommand::NecSamsung(nec_samsung) => {
debug!("nec_samsung cmd: {:?}", nec_samsung);
}
MultiReceiverCommand::NecApple(nec_apple) => {
debug!("nec_apple cmd: {:?}", nec_apple);
}
MultiReceiverCommand::Rc5(rc5) => {
debug!("rc5 cmd: {:?}", rc5);
}
MultiReceiverCommand::Rc6(rc6) => {
debug!("rc6 cmd: {:?}", rc6);
}
MultiReceiverCommand::Denon(denon) => {
debug!("denon cmd: {:?}", denon);
}
_ => {} // Just ignore other protocols (since we can only support 6 at a time)
}
}
}
// Clear the interrupts (won't work unless we do this)
ir_recv.pin().clear_interrupt(Interrupt::EdgeLow); // Does the order matter?
ir_recv.pin().clear_interrupt(Interrupt::EdgeHigh); // I don't know!
// let elapsed_since_processing = monotonics::now().checked_duration_since(now).unwrap();
*ir_edge = now;
} I haven't had the chance to test it with other kinds of remotes yet. NEC is the one I'm planning on putting my full support behind regardless. |
Hi! Interesting. I have to look into this a bit more. Could you send me a log of the raw elapsed_us values? |
@riskable I found this issue a hard way. In my device I using internal MCU oscillator(too much ppm's) as system clocks and NEC command parsing become really unstable. |
No description provided.
The text was updated successfully, but these errors were encountered: