use crate::types::{LoraPublisher, SharedI2c}; use defmt::Debug2Format; use embassy_sync::once_lock::OnceLock; use embassy_time::{Delay, Timer}; use esp_hal::gpio; use esp_hal::rng::Trng; use pn532::types::felica::felica_lite_s::auth::{CardKey, CardKeyVersion}; use pn532::types::felica::felica_lite_s::config::{MemoryConfig, RFParameter}; use pn532::types::felica::{CardSession, FelicaLiteSBlock}; use pn532::Pn532; static CARD_KEY: OnceLock = OnceLock::new(); const CARD_KEY_STR: &str = env!("CARD_KEY"); fn get_card_key() -> &'static CardKey { CARD_KEY.get_or_init(|| { let mut buffer = [0u8; 16]; hex::decode_to_slice(CARD_KEY_STR, &mut buffer).unwrap(); CardKey::from(buffer) }) } pub struct CardReader<'a> { driver: Pn532< gpio::Output<'a>, gpio::Input<'a>, Delay, pn532::I2cInterface, Delay, gpio::Output<'a>, gpio::Input<'a>>, >, } impl<'a> CardReader<'a> { pub fn new(i2c: SharedI2c<'a>, irq: gpio::Input<'a>, reset: gpio::Output<'a>) -> Self { Self { driver: Pn532::new(pn532::I2cInterface::with_reset_irq(i2c, Delay, reset, irq)), } } pub fn init(&mut self) -> Result<(), crate::error::Error> { self.driver.begin()?; self.driver.sam_config()?; self.driver.set_passive_activation_retries(5)?; Ok(()) } } #[embassy_executor::task] pub async fn start_card_reader( mut card_reader: CardReader<'static>, _publisher: LoraPublisher<'static>, mut trng: Trng, ) -> () { loop { match _start_card_reader(&mut card_reader, &_publisher, &mut trng).await { Ok(_) => {} Err(e) => { defmt::error!("Error while reading card: {}", e); } } } } async fn _start_card_reader( card_reader: &mut CardReader<'static>, _publisher: &LoraPublisher<'static>, trng: &mut Trng, ) -> Result<(), crate::error::Error> { let card_key = get_card_key(); defmt::trace!("card_key: {}", card_key); let driver = &mut card_reader.driver; loop { Timer::after_millis(10).await; let Some(response) = (match driver.felica_polling(Default::default()) { Ok(v) => v, Err(e) => { defmt::error!("card_reader driver error: {}", e); continue; } }) else { defmt::trace!("No card detected"); continue; }; defmt::info!("Polling card: {}", Debug2Format(&response)); defmt::debug!("IDm: {}", response.idm.into_bytes()); let card = CardSession::from(response); // if let Err(e) = card_reader.driver.felica_write_without_encryption( // &response.idm, &response.pmm, // &[FelicaLiteSServiceCode::Write], // &[FelicaLiteSBlock::CK], // &[*card_key] // ) { // defmt::error!("card_reader write ck error: {}", e); // continue; // } let id = driver.get_id(&card)?; defmt::debug!("ID: {}", id); if let Some(card_id) = option_env!("CARD_ID") { let mut id = [0u8; 6]; hex::decode_to_slice(card_id,&mut id)?; driver.set_id(&card, id, None)?; } let mut mc = driver.get_mc(&card)?; defmt::info!("Config: {}", mc); mc.access.set_system_block(0x00); mc.ndef = 0x00; mc.rf = RFParameter::from(0xFF); mc.access.set_is_ck_ckv_rewritable(true); let mut read_auth = mc.auth.scratch_pad_read(); read_auth.set_pad0(true); mc.auth.set_scratch_pad_read(read_auth); let mut write_auth = mc.auth.scratch_pad_write(); write_auth.set_pad0(true); mc.auth.set_scratch_pad_write(write_auth); let mut mac_auth = mc.auth.scratch_pad_mac_write(); mac_auth.set_pad0(true); mc.auth.set_scratch_pad_mac_write(mac_auth); let block: [u8; 16] = mc.into(); defmt::debug!("1st insurance Config: {}", block); driver.set_mc(&card, mc)?; let session = match driver.try_authenticate(trng, &card, card_key) { Ok(Some(sk)) => sk, Ok(None) => { defmt::warn!("card key is invalid"); continue; } Err(e) => { defmt::error!("card_reader auth error: {}", e); continue; } }; driver.set_ck_with_mac(&card, &session, &card_key)?; driver.set_ckv_with_mac(&card, &session, &CardKeyVersion::new(1))?; driver.get_ckv(&card)?; let _read_data = match driver.read_with_mac(&card, &session, FelicaLiteSBlock::PAD0) { Ok(d) => d, Err(e) => { defmt::error!("card_reader read with mac error: {}", e); continue; } }; match driver.release() { Ok(_) => {} Err(e) => { defmt::error!("card_reader release error: {}", e); continue; } }; // InRelease switches the RF field off when no target remains // (UM0701-02 ยง7.3.11), so re-enable it before the next poll. if let Err(e) = driver.set_rf_field(0x00, 0x01) { defmt::error!("card_reader RF field error: {}", e); } Timer::after_millis(200).await; } }