use embassy_executor::Spawner;
use embassy_rp::Peri;
use embassy_rp::gpio::{Pin, Pull};
use embassy_rp::pio::{
Common, Config, FifoJoin, Instance, PioPin, ShiftConfig, ShiftDirection, StateMachine,
};
use fixed::traits::ToFixed;
use crate::{Error, Result};
use device_envoy_core::ir::IrStatic;
use device_envoy_core::ir::decode_nec_frame;
pub use device_envoy_core::ir::{Ir, IrEvent, IrKepler, IrMapping};
#[doc(hidden)]
pub use paste;
#[doc(hidden)]
pub use device_envoy_core::ir::IrStatic as __IrStatic;
#[doc(hidden)]
pub use device_envoy_core::ir::kepler::KEPLER_MAPPING as __KEPLER_MAPPING;
pub mod ir_generated;
mod kepler;
mod mapping;
pub use kepler::KeplerKeys;
pub use mapping::__build_button_map;
#[doc(hidden)] pub struct NecReceiver<'d, PIO: Instance, const SM: usize> {
sm: StateMachine<'d, PIO, SM>,
}
#[doc(hidden)]
pub trait IrPioPeripheral: crate::pio_irqs::PioIrqMap {
fn spawn_task_sm0(
receiver: NecReceiver<'static, Self, 0>,
ir_static: &'static IrStatic,
spawner: Spawner,
) -> Result<()>;
fn spawn_task_sm1(
receiver: NecReceiver<'static, Self, 1>,
ir_static: &'static IrStatic,
spawner: Spawner,
) -> Result<()>;
fn spawn_task_sm2(
receiver: NecReceiver<'static, Self, 2>,
ir_static: &'static IrStatic,
spawner: Spawner,
) -> Result<()>;
fn spawn_task_sm3(
receiver: NecReceiver<'static, Self, 3>,
ir_static: &'static IrStatic,
spawner: Spawner,
) -> Result<()>;
}
impl IrPioPeripheral for embassy_rp::peripherals::PIO0 {
fn spawn_task_sm0(
receiver: NecReceiver<'static, Self, 0>,
ir_static: &'static IrStatic,
spawner: Spawner,
) -> Result<()> {
let token = ir_pio0_sm0_task(receiver, ir_static);
spawner.spawn(token.map_err(Error::TaskSpawn)?);
Ok(())
}
fn spawn_task_sm1(
receiver: NecReceiver<'static, Self, 1>,
ir_static: &'static IrStatic,
spawner: Spawner,
) -> Result<()> {
let token = ir_pio0_sm1_task(receiver, ir_static);
spawner.spawn(token.map_err(Error::TaskSpawn)?);
Ok(())
}
fn spawn_task_sm2(
receiver: NecReceiver<'static, Self, 2>,
ir_static: &'static IrStatic,
spawner: Spawner,
) -> Result<()> {
let token = ir_pio0_sm2_task(receiver, ir_static);
spawner.spawn(token.map_err(Error::TaskSpawn)?);
Ok(())
}
fn spawn_task_sm3(
receiver: NecReceiver<'static, Self, 3>,
ir_static: &'static IrStatic,
spawner: Spawner,
) -> Result<()> {
let token = ir_pio0_sm3_task(receiver, ir_static);
spawner.spawn(token.map_err(Error::TaskSpawn)?);
Ok(())
}
}
impl IrPioPeripheral for embassy_rp::peripherals::PIO1 {
fn spawn_task_sm0(
receiver: NecReceiver<'static, Self, 0>,
ir_static: &'static IrStatic,
spawner: Spawner,
) -> Result<()> {
let token = ir_pio1_sm0_task(receiver, ir_static);
spawner.spawn(token.map_err(Error::TaskSpawn)?);
Ok(())
}
fn spawn_task_sm1(
receiver: NecReceiver<'static, Self, 1>,
ir_static: &'static IrStatic,
spawner: Spawner,
) -> Result<()> {
let token = ir_pio1_sm1_task(receiver, ir_static);
spawner.spawn(token.map_err(Error::TaskSpawn)?);
Ok(())
}
fn spawn_task_sm2(
receiver: NecReceiver<'static, Self, 2>,
ir_static: &'static IrStatic,
spawner: Spawner,
) -> Result<()> {
let token = ir_pio1_sm2_task(receiver, ir_static);
spawner.spawn(token.map_err(Error::TaskSpawn)?);
Ok(())
}
fn spawn_task_sm3(
receiver: NecReceiver<'static, Self, 3>,
ir_static: &'static IrStatic,
spawner: Spawner,
) -> Result<()> {
let token = ir_pio1_sm3_task(receiver, ir_static);
spawner.spawn(token.map_err(Error::TaskSpawn)?);
Ok(())
}
}
#[cfg(feature = "pico2")]
impl IrPioPeripheral for embassy_rp::peripherals::PIO2 {
fn spawn_task_sm0(
receiver: NecReceiver<'static, Self, 0>,
ir_static: &'static IrStatic,
spawner: Spawner,
) -> Result<()> {
let token = ir_pio2_sm0_task(receiver, ir_static);
spawner.spawn(token.map_err(Error::TaskSpawn)?);
Ok(())
}
fn spawn_task_sm1(
receiver: NecReceiver<'static, Self, 1>,
ir_static: &'static IrStatic,
spawner: Spawner,
) -> Result<()> {
let token = ir_pio2_sm1_task(receiver, ir_static);
spawner.spawn(token.map_err(Error::TaskSpawn)?);
Ok(())
}
fn spawn_task_sm2(
receiver: NecReceiver<'static, Self, 2>,
ir_static: &'static IrStatic,
spawner: Spawner,
) -> Result<()> {
let token = ir_pio2_sm2_task(receiver, ir_static);
spawner.spawn(token.map_err(Error::TaskSpawn)?);
Ok(())
}
fn spawn_task_sm3(
receiver: NecReceiver<'static, Self, 3>,
ir_static: &'static IrStatic,
spawner: Spawner,
) -> Result<()> {
let token = ir_pio2_sm3_task(receiver, ir_static);
spawner.spawn(token.map_err(Error::TaskSpawn)?);
Ok(())
}
}
#[doc(hidden)]
pub fn __new_receiver<P, PIO, const SM: usize>(
common: &mut Common<'static, PIO>,
sm: StateMachine<'static, PIO, SM>,
pin: Peri<'static, P>,
) -> NecReceiver<'static, PIO, SM>
where
P: Pin + PioPin,
PIO: Instance,
{
let mut ir_pin = common.make_pio_pin(pin);
ir_pin.set_pull(Pull::Up);
NecReceiver::new(common, sm, ir_pin)
}
#[doc(hidden)]
pub fn __new_ir_on_sm0<P, PIO>(
ir_static: &'static IrStatic,
pin: Peri<'static, P>,
pio: Peri<'static, PIO>,
spawner: Spawner,
) -> Result<()>
where
P: Pin + PioPin,
PIO: IrPioPeripheral,
{
let pio_instance = embassy_rp::pio::Pio::new(pio, <PIO as crate::pio_irqs::PioIrqMap>::irqs());
let embassy_rp::pio::Pio {
mut common, sm0, ..
} = pio_instance;
let nec_receiver = __new_receiver(&mut common, sm0, pin);
PIO::spawn_task_sm0(nec_receiver, ir_static, spawner)?;
Ok(())
}
#[doc(hidden)]
pub fn __new_ir_on_sm1<P, PIO>(
ir_static: &'static IrStatic,
pin: Peri<'static, P>,
pio: Peri<'static, PIO>,
spawner: Spawner,
) -> Result<()>
where
P: Pin + PioPin,
PIO: IrPioPeripheral,
{
let pio_instance = embassy_rp::pio::Pio::new(pio, <PIO as crate::pio_irqs::PioIrqMap>::irqs());
let embassy_rp::pio::Pio {
mut common, sm1, ..
} = pio_instance;
let nec_receiver = __new_receiver(&mut common, sm1, pin);
PIO::spawn_task_sm1(nec_receiver, ir_static, spawner)?;
Ok(())
}
#[doc(hidden)]
pub fn __new_ir_on_sm2<P, PIO>(
ir_static: &'static IrStatic,
pin: Peri<'static, P>,
pio: Peri<'static, PIO>,
spawner: Spawner,
) -> Result<()>
where
P: Pin + PioPin,
PIO: IrPioPeripheral,
{
let pio_instance = embassy_rp::pio::Pio::new(pio, <PIO as crate::pio_irqs::PioIrqMap>::irqs());
let embassy_rp::pio::Pio {
mut common, sm2, ..
} = pio_instance;
let nec_receiver = __new_receiver(&mut common, sm2, pin);
PIO::spawn_task_sm2(nec_receiver, ir_static, spawner)?;
Ok(())
}
#[doc(hidden)]
pub fn __new_ir_on_sm3<P, PIO>(
ir_static: &'static IrStatic,
pin: Peri<'static, P>,
pio: Peri<'static, PIO>,
spawner: Spawner,
) -> Result<()>
where
P: Pin + PioPin,
PIO: IrPioPeripheral,
{
let pio_instance = embassy_rp::pio::Pio::new(pio, <PIO as crate::pio_irqs::PioIrqMap>::irqs());
let embassy_rp::pio::Pio {
mut common, sm3, ..
} = pio_instance;
let nec_receiver = __new_receiver(&mut common, sm3, pin);
PIO::spawn_task_sm3(nec_receiver, ir_static, spawner)?;
Ok(())
}
#[doc(hidden)]
#[macro_export]
macro_rules! irs {
(
pio: $pio:ident,
$group_name:ident {
$first_name:ident : { pin: $first_pin:ident $(,)? }
$(, $rest_name:ident : { pin: $rest_pin:ident $(,)? })* $(,)?
}
) => {
$crate::__irs_impl! {
pio: $pio,
$group_name,
[($first_name, $first_pin) $(, ($rest_name, $rest_pin))*]
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __irs_impl {
(
pio: $pio:ident,
$group_name:ident,
[($name0:ident, $pin0:ident)]
) => {
$crate::ir::paste::paste! {
static [<$name0:upper _IR_STATIC>]: $crate::ir::__IrStatic = $crate::ir::__IrStatic::new();
static [<$name0:upper _IR>]: $name0 = $name0 { ir_static: &[<$name0:upper _IR_STATIC>] };
pub struct $name0 {
ir_static: &'static $crate::ir::__IrStatic,
}
impl $name0 {
pub fn new(
pio: embassy_rp::Peri<'static, embassy_rp::peripherals::$pio>,
pin: embassy_rp::Peri<'static, embassy_rp::peripherals::$pin0>,
spawner: embassy_executor::Spawner,
) -> $crate::Result<&'static Self> {
let _ = $crate::ir::__new_ir_on_sm0(&[<$name0:upper _IR_STATIC>], pin, pio, spawner)?;
Ok(&[<$name0:upper _IR>])
}
}
impl $crate::ir::Ir for $name0 {
async fn wait_for_press(&self) -> $crate::ir::IrEvent {
self.ir_static.receive().await
}
}
pub struct $group_name;
impl $group_name {
pub fn new(
pio: embassy_rp::Peri<'static, embassy_rp::peripherals::$pio>,
pin0: embassy_rp::Peri<'static, embassy_rp::peripherals::$pin0>,
spawner: embassy_executor::Spawner,
) -> $crate::Result<(&'static $name0,)> {
let name0 = $name0::new(pio, pin0, spawner)?;
Ok((name0,))
}
}
}
};
(
pio: $pio:ident,
$group_name:ident,
[($name0:ident, $pin0:ident), ($name1:ident, $pin1:ident)]
) => {
$crate::ir::paste::paste! {
static [<$name0:upper _IR_STATIC>]: $crate::ir::__IrStatic = $crate::ir::__IrStatic::new();
static [<$name1:upper _IR_STATIC>]: $crate::ir::__IrStatic = $crate::ir::__IrStatic::new();
static [<$name0:upper _IR>]: $name0 = $name0 { ir_static: &[<$name0:upper _IR_STATIC>] };
static [<$name1:upper _IR>]: $name1 = $name1 { ir_static: &[<$name1:upper _IR_STATIC>] };
pub struct $name0 {
ir_static: &'static $crate::ir::__IrStatic,
}
pub struct $name1 {
ir_static: &'static $crate::ir::__IrStatic,
}
impl $name0 {
pub fn new(
pio: embassy_rp::Peri<'static, embassy_rp::peripherals::$pio>,
pin: embassy_rp::Peri<'static, embassy_rp::peripherals::$pin0>,
spawner: embassy_executor::Spawner,
) -> $crate::Result<&'static Self> {
let _ = $crate::ir::__new_ir_on_sm0(&[<$name0:upper _IR_STATIC>], pin, pio, spawner)?;
Ok(&[<$name0:upper _IR>])
}
}
impl $name1 {
pub fn new(
pio: embassy_rp::Peri<'static, embassy_rp::peripherals::$pio>,
pin: embassy_rp::Peri<'static, embassy_rp::peripherals::$pin1>,
spawner: embassy_executor::Spawner,
) -> $crate::Result<&'static Self> {
let _ = $crate::ir::__new_ir_on_sm1(&[<$name1:upper _IR_STATIC>], pin, pio, spawner)?;
Ok(&[<$name1:upper _IR>])
}
}
impl $crate::ir::Ir for $name0 {
async fn wait_for_press(&self) -> $crate::ir::IrEvent {
self.ir_static.receive().await
}
}
impl $crate::ir::Ir for $name1 {
async fn wait_for_press(&self) -> $crate::ir::IrEvent {
self.ir_static.receive().await
}
}
pub struct $group_name;
impl $group_name {
pub fn new(
pio: embassy_rp::Peri<'static, embassy_rp::peripherals::$pio>,
pin0: embassy_rp::Peri<'static, embassy_rp::peripherals::$pin0>,
pin1: embassy_rp::Peri<'static, embassy_rp::peripherals::$pin1>,
spawner: embassy_executor::Spawner,
) -> $crate::Result<(&'static $name0, &'static $name1)> {
let pio_instance = embassy_rp::pio::Pio::new(
pio,
<embassy_rp::peripherals::$pio as $crate::pio_irqs::PioIrqMap>::irqs(),
);
let embassy_rp::pio::Pio {
mut common, sm0, sm1, ..
} = pio_instance;
let receiver0 = $crate::ir::__new_receiver(&mut common, sm0, pin0);
<embassy_rp::peripherals::$pio as $crate::ir::IrPioPeripheral>::spawn_task_sm0(
receiver0,
&[<$name0:upper _IR_STATIC>],
spawner,
)?;
let receiver1 = $crate::ir::__new_receiver(&mut common, sm1, pin1);
<embassy_rp::peripherals::$pio as $crate::ir::IrPioPeripheral>::spawn_task_sm1(
receiver1,
&[<$name1:upper _IR_STATIC>],
spawner,
)?;
let ir0 = &[<$name0:upper _IR>];
let ir1 = &[<$name1:upper _IR>];
Ok((ir0, ir1))
}
}
}
};
(
pio: $pio:ident,
$group_name:ident,
[($name0:ident, $pin0:ident), ($name1:ident, $pin1:ident), ($name2:ident, $pin2:ident)]
) => {
$crate::ir::paste::paste! {
static [<$name0:upper _IR_STATIC>]: $crate::ir::__IrStatic = $crate::ir::__IrStatic::new();
static [<$name1:upper _IR_STATIC>]: $crate::ir::__IrStatic = $crate::ir::__IrStatic::new();
static [<$name2:upper _IR_STATIC>]: $crate::ir::__IrStatic = $crate::ir::__IrStatic::new();
static [<$name0:upper _IR>]: $name0 = $name0 { ir_static: &[<$name0:upper _IR_STATIC>] };
static [<$name1:upper _IR>]: $name1 = $name1 { ir_static: &[<$name1:upper _IR_STATIC>] };
static [<$name2:upper _IR>]: $name2 = $name2 { ir_static: &[<$name2:upper _IR_STATIC>] };
pub struct $name0 {
ir_static: &'static $crate::ir::__IrStatic,
}
pub struct $name1 {
ir_static: &'static $crate::ir::__IrStatic,
}
pub struct $name2 {
ir_static: &'static $crate::ir::__IrStatic,
}
impl $name0 {
pub fn new(
pio: embassy_rp::Peri<'static, embassy_rp::peripherals::$pio>,
pin: embassy_rp::Peri<'static, embassy_rp::peripherals::$pin0>,
spawner: embassy_executor::Spawner,
) -> $crate::Result<&'static Self> {
let _ = $crate::ir::__new_ir_on_sm0(&[<$name0:upper _IR_STATIC>], pin, pio, spawner)?;
Ok(&[<$name0:upper _IR>])
}
}
impl $name1 {
pub fn new(
pio: embassy_rp::Peri<'static, embassy_rp::peripherals::$pio>,
pin: embassy_rp::Peri<'static, embassy_rp::peripherals::$pin1>,
spawner: embassy_executor::Spawner,
) -> $crate::Result<&'static Self> {
let _ = $crate::ir::__new_ir_on_sm1(&[<$name1:upper _IR_STATIC>], pin, pio, spawner)?;
Ok(&[<$name1:upper _IR>])
}
}
impl $name2 {
pub fn new(
pio: embassy_rp::Peri<'static, embassy_rp::peripherals::$pio>,
pin: embassy_rp::Peri<'static, embassy_rp::peripherals::$pin2>,
spawner: embassy_executor::Spawner,
) -> $crate::Result<&'static Self> {
let _ = $crate::ir::__new_ir_on_sm2(&[<$name2:upper _IR_STATIC>], pin, pio, spawner)?;
Ok(&[<$name2:upper _IR>])
}
}
impl $crate::ir::Ir for $name0 {
async fn wait_for_press(&self) -> $crate::ir::IrEvent {
self.ir_static.receive().await
}
}
impl $crate::ir::Ir for $name1 {
async fn wait_for_press(&self) -> $crate::ir::IrEvent {
self.ir_static.receive().await
}
}
impl $crate::ir::Ir for $name2 {
async fn wait_for_press(&self) -> $crate::ir::IrEvent {
self.ir_static.receive().await
}
}
pub struct $group_name;
impl $group_name {
pub fn new(
pio: embassy_rp::Peri<'static, embassy_rp::peripherals::$pio>,
pin0: embassy_rp::Peri<'static, embassy_rp::peripherals::$pin0>,
pin1: embassy_rp::Peri<'static, embassy_rp::peripherals::$pin1>,
pin2: embassy_rp::Peri<'static, embassy_rp::peripherals::$pin2>,
spawner: embassy_executor::Spawner,
) -> $crate::Result<(&'static $name0, &'static $name1, &'static $name2)> {
let pio_instance = embassy_rp::pio::Pio::new(
pio,
<embassy_rp::peripherals::$pio as $crate::pio_irqs::PioIrqMap>::irqs(),
);
let embassy_rp::pio::Pio {
mut common, sm0, sm1, sm2, ..
} = pio_instance;
let receiver0 = $crate::ir::__new_receiver(&mut common, sm0, pin0);
<embassy_rp::peripherals::$pio as $crate::ir::IrPioPeripheral>::spawn_task_sm0(
receiver0,
&[<$name0:upper _IR_STATIC>],
spawner,
)?;
let receiver1 = $crate::ir::__new_receiver(&mut common, sm1, pin1);
<embassy_rp::peripherals::$pio as $crate::ir::IrPioPeripheral>::spawn_task_sm1(
receiver1,
&[<$name1:upper _IR_STATIC>],
spawner,
)?;
let receiver2 = $crate::ir::__new_receiver(&mut common, sm2, pin2);
<embassy_rp::peripherals::$pio as $crate::ir::IrPioPeripheral>::spawn_task_sm2(
receiver2,
&[<$name2:upper _IR_STATIC>],
spawner,
)?;
let ir0 = &[<$name0:upper _IR>];
let ir1 = &[<$name1:upper _IR>];
let ir2 = &[<$name2:upper _IR>];
Ok((ir0, ir1, ir2))
}
}
}
};
(
pio: $pio:ident,
$group_name:ident,
[($name0:ident, $pin0:ident), ($name1:ident, $pin1:ident), ($name2:ident, $pin2:ident), ($name3:ident, $pin3:ident)]
) => {
$crate::ir::paste::paste! {
static [<$name0:upper _IR_STATIC>]: $crate::ir::__IrStatic = $crate::ir::__IrStatic::new();
static [<$name1:upper _IR_STATIC>]: $crate::ir::__IrStatic = $crate::ir::__IrStatic::new();
static [<$name2:upper _IR_STATIC>]: $crate::ir::__IrStatic = $crate::ir::__IrStatic::new();
static [<$name3:upper _IR_STATIC>]: $crate::ir::__IrStatic = $crate::ir::__IrStatic::new();
static [<$name0:upper _IR>]: $name0 = $name0 { ir_static: &[<$name0:upper _IR_STATIC>] };
static [<$name1:upper _IR>]: $name1 = $name1 { ir_static: &[<$name1:upper _IR_STATIC>] };
static [<$name2:upper _IR>]: $name2 = $name2 { ir_static: &[<$name2:upper _IR_STATIC>] };
static [<$name3:upper _IR>]: $name3 = $name3 { ir_static: &[<$name3:upper _IR_STATIC>] };
pub struct $name0 {
ir_static: &'static $crate::ir::__IrStatic,
}
pub struct $name1 {
ir_static: &'static $crate::ir::__IrStatic,
}
pub struct $name2 {
ir_static: &'static $crate::ir::__IrStatic,
}
pub struct $name3 {
ir_static: &'static $crate::ir::__IrStatic,
}
impl $name0 {
pub fn new(
pio: embassy_rp::Peri<'static, embassy_rp::peripherals::$pio>,
pin: embassy_rp::Peri<'static, embassy_rp::peripherals::$pin0>,
spawner: embassy_executor::Spawner,
) -> $crate::Result<&'static Self> {
let _ = $crate::ir::__new_ir_on_sm0(&[<$name0:upper _IR_STATIC>], pin, pio, spawner)?;
Ok(&[<$name0:upper _IR>])
}
}
impl $name1 {
pub fn new(
pio: embassy_rp::Peri<'static, embassy_rp::peripherals::$pio>,
pin: embassy_rp::Peri<'static, embassy_rp::peripherals::$pin1>,
spawner: embassy_executor::Spawner,
) -> $crate::Result<&'static Self> {
let _ = $crate::ir::__new_ir_on_sm1(&[<$name1:upper _IR_STATIC>], pin, pio, spawner)?;
Ok(&[<$name1:upper _IR>])
}
}
impl $name2 {
pub fn new(
pio: embassy_rp::Peri<'static, embassy_rp::peripherals::$pio>,
pin: embassy_rp::Peri<'static, embassy_rp::peripherals::$pin2>,
spawner: embassy_executor::Spawner,
) -> $crate::Result<&'static Self> {
let _ = $crate::ir::__new_ir_on_sm2(&[<$name2:upper _IR_STATIC>], pin, pio, spawner)?;
Ok(&[<$name2:upper _IR>])
}
}
impl $name3 {
pub fn new(
pio: embassy_rp::Peri<'static, embassy_rp::peripherals::$pio>,
pin: embassy_rp::Peri<'static, embassy_rp::peripherals::$pin3>,
spawner: embassy_executor::Spawner,
) -> $crate::Result<&'static Self> {
let _ = $crate::ir::__new_ir_on_sm3(&[<$name3:upper _IR_STATIC>], pin, pio, spawner)?;
Ok(&[<$name3:upper _IR>])
}
}
impl $crate::ir::Ir for $name0 {
async fn wait_for_press(&self) -> $crate::ir::IrEvent {
self.ir_static.receive().await
}
}
impl $crate::ir::Ir for $name1 {
async fn wait_for_press(&self) -> $crate::ir::IrEvent {
self.ir_static.receive().await
}
}
impl $crate::ir::Ir for $name2 {
async fn wait_for_press(&self) -> $crate::ir::IrEvent {
self.ir_static.receive().await
}
}
impl $crate::ir::Ir for $name3 {
async fn wait_for_press(&self) -> $crate::ir::IrEvent {
self.ir_static.receive().await
}
}
pub struct $group_name;
impl $group_name {
pub fn new(
pio: embassy_rp::Peri<'static, embassy_rp::peripherals::$pio>,
pin0: embassy_rp::Peri<'static, embassy_rp::peripherals::$pin0>,
pin1: embassy_rp::Peri<'static, embassy_rp::peripherals::$pin1>,
pin2: embassy_rp::Peri<'static, embassy_rp::peripherals::$pin2>,
pin3: embassy_rp::Peri<'static, embassy_rp::peripherals::$pin3>,
spawner: embassy_executor::Spawner,
) -> $crate::Result<(&'static $name0, &'static $name1, &'static $name2, &'static $name3)> {
let pio_instance = embassy_rp::pio::Pio::new(
pio,
<embassy_rp::peripherals::$pio as $crate::pio_irqs::PioIrqMap>::irqs(),
);
let embassy_rp::pio::Pio {
mut common, sm0, sm1, sm2, sm3, ..
} = pio_instance;
let receiver0 = $crate::ir::__new_receiver(&mut common, sm0, pin0);
<embassy_rp::peripherals::$pio as $crate::ir::IrPioPeripheral>::spawn_task_sm0(
receiver0,
&[<$name0:upper _IR_STATIC>],
spawner,
)?;
let receiver1 = $crate::ir::__new_receiver(&mut common, sm1, pin1);
<embassy_rp::peripherals::$pio as $crate::ir::IrPioPeripheral>::spawn_task_sm1(
receiver1,
&[<$name1:upper _IR_STATIC>],
spawner,
)?;
let receiver2 = $crate::ir::__new_receiver(&mut common, sm2, pin2);
<embassy_rp::peripherals::$pio as $crate::ir::IrPioPeripheral>::spawn_task_sm2(
receiver2,
&[<$name2:upper _IR_STATIC>],
spawner,
)?;
let receiver3 = $crate::ir::__new_receiver(&mut common, sm3, pin3);
<embassy_rp::peripherals::$pio as $crate::ir::IrPioPeripheral>::spawn_task_sm3(
receiver3,
&[<$name3:upper _IR_STATIC>],
spawner,
)?;
let ir0 = &[<$name0:upper _IR>];
let ir1 = &[<$name1:upper _IR>];
let ir2 = &[<$name2:upper _IR>];
let ir3 = &[<$name3:upper _IR>];
Ok((ir0, ir1, ir2, ir3))
}
}
}
};
(
pio: $pio:ident,
$group_name:ident,
[($name0:ident, $pin0:ident), ($name1:ident, $pin1:ident), ($name2:ident, $pin2:ident), ($name3:ident, $pin3:ident), ($($tail:tt)+)]
) => {
compile_error!("irs! currently supports up to 4 receivers in one group.");
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! ir {
(
$(#[$attrs:meta])*
$vis:vis $name:ident : { $($deprecated_fields:tt)* }
) => {
compile_error!(
"ir! no longer supports `Name: { ... }`. Use `Name { ... }` instead."
);
};
(
$(#[$attrs:meta])*
$vis:vis $name:ident { pio: $pio:ident, pin: $pin:ident $(,)? }
) => {
$crate::ir::paste::paste! {
$crate::irs! {
pio: $pio,
[<__ $name:camel Group>] {
[<__ $name:camel Ir>]: { pin: $pin }
}
}
$(#[$attrs])*
$vis type $name = [<__ $name:camel Ir>];
}
};
}
#[allow(unused_imports)]
#[doc(inline)]
pub use crate::ir_kepler;
#[allow(unused_imports)]
#[doc(inline)]
pub use crate::ir_keplers;
#[allow(unused_imports)]
#[doc(inline)]
pub use crate::ir_mapping;
#[allow(unused_imports)]
#[doc(inline)]
pub use crate::ir_mappings;
#[allow(unused_imports)]
#[doc(inline)]
pub use ir;
#[allow(unused_imports)]
#[doc(inline)]
pub use irs;
macro_rules! __define_ir_task {
($task_name:ident, $pio:ty, $sm:literal) => {
#[embassy_executor::task]
async fn $task_name(
mut nec_receiver: NecReceiver<'static, $pio, $sm>,
ir_static: &'static IrStatic,
) -> ! {
loop {
let raw_frame = nec_receiver.receive_frame().await;
if let Some((addr, cmd)) = decode_nec_frame(raw_frame) {
ir_static.send(IrEvent::Press { addr, cmd }).await;
}
}
}
};
}
__define_ir_task!(ir_pio0_sm0_task, embassy_rp::peripherals::PIO0, 0);
__define_ir_task!(ir_pio0_sm1_task, embassy_rp::peripherals::PIO0, 1);
__define_ir_task!(ir_pio0_sm2_task, embassy_rp::peripherals::PIO0, 2);
__define_ir_task!(ir_pio0_sm3_task, embassy_rp::peripherals::PIO0, 3);
__define_ir_task!(ir_pio1_sm0_task, embassy_rp::peripherals::PIO1, 0);
__define_ir_task!(ir_pio1_sm1_task, embassy_rp::peripherals::PIO1, 1);
__define_ir_task!(ir_pio1_sm2_task, embassy_rp::peripherals::PIO1, 2);
__define_ir_task!(ir_pio1_sm3_task, embassy_rp::peripherals::PIO1, 3);
#[cfg(feature = "pico2")]
__define_ir_task!(ir_pio2_sm0_task, embassy_rp::peripherals::PIO2, 0);
#[cfg(feature = "pico2")]
__define_ir_task!(ir_pio2_sm1_task, embassy_rp::peripherals::PIO2, 1);
#[cfg(feature = "pico2")]
__define_ir_task!(ir_pio2_sm2_task, embassy_rp::peripherals::PIO2, 2);
#[cfg(feature = "pico2")]
__define_ir_task!(ir_pio2_sm3_task, embassy_rp::peripherals::PIO2, 3);
impl<'d, PIO: Instance, const SM: usize> NecReceiver<'d, PIO, SM> {
fn new(
common: &mut Common<'d, PIO>,
mut sm: StateMachine<'d, PIO, SM>,
ir_pin: embassy_rp::pio::Pin<'d, PIO>,
) -> Self {
let prg = pio::pio_asm!(
r#"
; Constants for burst detection and bit sampling
; These values are calibrated for 10 SM clock ticks per 562.5µs burst period
.define BURST_LOOP_COUNTER 30 ; threshold for sync burst detection
.define BIT_SAMPLE_DELAY 15 ; wait 1.5 burst periods before sampling
.wrap_target
next_burst:
set x, BURST_LOOP_COUNTER
wait 0 pin 0 ; wait for burst to start (active low)
burst_loop:
jmp pin data_bit ; burst ended before counter expired
jmp x-- burst_loop ; keep waiting for burst to end
; counter expired = sync burst detected
mov isr, null ; reset ISR for new frame
wait 1 pin 0 ; wait for sync burst to finish
jmp next_burst ; ready for first data bit
data_bit:
nop [BIT_SAMPLE_DELAY - 1] ; wait 1.5 burst periods
in pins, 1 ; sample gap length: short=0, long=1
; autopush after 32 bits
.wrap
"#
);
let mut cfg = Config::default();
let mut shift_config = ShiftConfig::default();
shift_config.direction = ShiftDirection::Right;
shift_config.auto_fill = true;
shift_config.threshold = 32;
cfg.shift_in = shift_config;
cfg.fifo_join = FifoJoin::RxOnly;
cfg.set_in_pins(&[&ir_pin]);
cfg.set_jmp_pin(&ir_pin);
let clock_freq = 125_000_000.0_f32; let target_freq = 10.0_f32 / 562.5e-6_f32; let divisor: f32 = clock_freq / target_freq;
cfg.clock_divider = divisor.to_fixed();
let loaded_program = common.load_program(&prg.program);
cfg.use_program(&loaded_program, &[]);
sm.set_config(&cfg);
sm.set_pin_dirs(embassy_rp::pio::Direction::In, &[&ir_pin]);
sm.set_enable(true);
let _ = loaded_program;
Self { sm }
}
async fn receive_frame(&mut self) -> u32 {
self.sm.rx().wait_pull().await
}
}