1pub use device_envoy_core::rfid::{Rfid, RfidEvent};
8use embassy_executor::Spawner;
9use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
10use embassy_sync::channel::Channel as EmbassyChannel;
11use embassy_time::{Instant, Timer};
12use embedded_hal_bus::spi::{ExclusiveDevice, NoDelay};
13use esp_hal::gpio::interconnect::{PeripheralInput, PeripheralOutput};
14use esp_hal::gpio::{Level, Output, OutputConfig, OutputPin};
15use esp_hal::spi::master::{Config as SpiConfig, Instance, Spi};
16use esp_hal_mfrc522::consts::UidSize;
17use esp_hal_mfrc522::drivers::SpiDriver;
18use esp_hal_mfrc522::MFRC522;
19
20use crate::{Error, Result};
21
22type Mfrc522Device =
23 MFRC522<SpiDriver<ExclusiveDevice<Spi<'static, esp_hal::Async>, Output<'static>, NoDelay>>>;
24
25pub struct RfidStatic(EmbassyChannel<CriticalSectionRawMutex, RfidEvent, 4>);
27
28impl RfidStatic {
29 #[must_use]
31 pub const fn new() -> Self {
32 Self(EmbassyChannel::new())
33 }
34
35 async fn send(&self, event: RfidEvent) {
36 self.0.send(event).await;
37 }
38
39 async fn receive(&self) -> RfidEvent {
40 self.0.receive().await
41 }
42}
43
44pub struct RfidEsp<'a> {
89 rfid_static: &'a RfidStatic,
90}
91
92impl RfidEsp<'_> {
93 #[must_use]
95 pub const fn new_static() -> RfidStatic {
96 RfidStatic::new()
97 }
98
99 pub async fn new(
103 rfid_static: &'static RfidStatic,
104 spi: impl Instance + 'static,
105 sck: impl PeripheralOutput<'static>,
106 mosi: impl PeripheralOutput<'static>,
107 miso: impl PeripheralInput<'static>,
108 cs: impl OutputPin + 'static,
109 rst: impl OutputPin + 'static,
110 spawner: Spawner,
111 ) -> Result<Self> {
112 let mfrc522 = init_mfrc522_hardware(spi, sck, mosi, miso, cs, rst).await?;
113 let token = rfid_polling_task(mfrc522, rfid_static);
114 spawner.spawn(token).map_err(Error::TaskSpawn)?;
115 Ok(Self { rfid_static })
116 }
117}
118
119impl Rfid for RfidEsp<'_> {
120 async fn wait_for_tap(&self) -> RfidEvent {
121 self.rfid_static.receive().await
122 }
123}
124
125fn uid_to_fixed_array(uid_bytes: &[u8]) -> [u8; 10] {
126 let mut uid_key = [0u8; 10];
127 for (uid_index, &uid_byte) in uid_bytes.iter().enumerate() {
128 if uid_index < uid_key.len() {
129 uid_key[uid_index] = uid_byte;
130 }
131 }
132 uid_key
133}
134
135#[embassy_executor::task(pool_size = 2)]
136async fn rfid_polling_task(mut mfrc522: Mfrc522Device, rfid_static: &'static RfidStatic) -> ! {
137 loop {
138 let Ok(()) = mfrc522.picc_is_new_card_present().await else {
139 Timer::after_millis(500).await;
140 continue;
141 };
142
143 let Ok(uid) = mfrc522.get_card(UidSize::Four).await else {
144 Timer::after_millis(500).await;
145 continue;
146 };
147
148 let uid_key = uid_to_fixed_array(&uid.uid_bytes);
149 rfid_static
150 .send(RfidEvent::CardDetected { uid: uid_key })
151 .await;
152 Timer::after_millis(50).await;
153 }
154}
155
156async fn init_mfrc522_hardware(
157 spi: impl Instance + 'static,
158 sck: impl PeripheralOutput<'static>,
159 mosi: impl PeripheralOutput<'static>,
160 miso: impl PeripheralInput<'static>,
161 cs: impl OutputPin + 'static,
162 rst: impl OutputPin + 'static,
163) -> Result<Mfrc522Device> {
164 let spi_config = SpiConfig::default()
165 .with_frequency(esp_hal::time::Rate::from_hz(1_000_000))
166 .with_mode(esp_hal::spi::Mode::_0);
167 let spi = Spi::new(spi, spi_config)
168 .map_err(Error::SpiConfig)?
169 .with_sck(sck)
170 .with_mosi(mosi)
171 .with_miso(miso)
172 .into_async();
173
174 let cs = Output::new(cs, Level::High, OutputConfig::default());
175
176 let mut rst = Output::new(rst, Level::High, OutputConfig::default());
177 rst.set_low();
178 Timer::after_millis(10).await;
179 rst.set_high();
180 Timer::after_millis(50).await;
181
182 let spi_device = ExclusiveDevice::new_no_delay(spi, cs).expect("CS pin is infallible");
183 let spi_driver = SpiDriver::new(spi_device);
184 let mut mfrc522 = MFRC522::new(spi_driver, || Instant::now().as_millis());
185
186 mfrc522.pcd_init().await.map_err(Error::Mfrc522Init)?;
187 let _version = mfrc522
188 .pcd_get_version()
189 .await
190 .map_err(Error::Mfrc522Version)?;
191
192 Ok(mfrc522)
193}