diff --git a/src/ntag5/mod.rs b/src/ntag5/mod.rs index 1ccc490..0de14d8 100644 --- a/src/ntag5/mod.rs +++ b/src/ntag5/mod.rs @@ -18,6 +18,17 @@ pub const SESSION_CONFIG_REG: u16 = 0x10A1; // CONFIG_0_REG, CONFIG_1_REG, CONFI pub const SESSION_EH_CONFIG_REG: u16 = 0x10A7; // EH_CONFIG_REG, RFU pub const SESSION_I2C_SLAVE_REG: u16 = 0x10A9; // I2C_SLAVE_ADDR_REG, I2C_SLAVE_CONFIG_REG +// SRAM I2C block address range (64 blocks × 4 bytes = 256 bytes) +pub const SRAM_BASE_BLOCK: u16 = 0x10F8; +pub const SRAM_BLOCK_COUNT: u16 = 64; +pub const SRAM_SIZE: usize = 256; + +// Session register for ED/FD pin configuration +pub const SESSION_ED_FD_PIN_CFG: u16 = 0x10A3; + +// FD pin mode: active on SRAM write by RF, cleared on I2C read +pub const FD_MODE_SRAM_RF_WRITE: u8 = 0x04; + // EEPROM user memory I2C block addresses // Block 0 = CC (capability container), blocks 1+ = NDEF data pub const EEPROM_BLOCK_0: u16 = 0x0000; @@ -143,6 +154,47 @@ where Ok(buf[0]) } + /// Write a single session register byte (WRITE REGISTER command). + /// Protocol: write [BL_AD1, BL_AD0, REGA, MASK, REGDATA]. + /// The MASK selects which bits to modify (1 = modify, 0 = keep). + pub fn write_register(&mut self, block: u16, reg_addr: u8, mask: u8, data: u8) -> Result<(), E> { + let addr_bytes = block.to_be_bytes(); + self.i2c.write( + self.addr, + &[addr_bytes[0], addr_bytes[1], reg_addr, mask, data], + ) + } + + // ---- SRAM access ---- + + /// Read N bytes from SRAM starting at byte offset 0. + /// SRAM is at I2C blocks 0x10F8-0x10FF (64 blocks × 4 bytes = 256 bytes). + /// Always reads from the start of SRAM (block-aligned). + pub fn read_sram(&mut self, buf: &mut [u8]) -> Result<(), E> { + self.read_memory(SRAM_BASE_BLOCK, buf) + } + + /// Write data to SRAM starting at block offset from SRAM base. + /// Data length must be a multiple of 4 (NTAG5 block size). + pub fn write_sram_blocks(&mut self, block_offset: u16, data: &[u8]) -> Result<(), E> { + for (i, chunk) in data.chunks(4).enumerate() { + let mut block_data = [0u8; 4]; + for (j, &b) in chunk.iter().enumerate() { + block_data[j] = b; + } + self.write_memory_block(SRAM_BASE_BLOCK + block_offset + i as u16, &block_data)?; + } + Ok(()) + } + + /// Configure FD pin for SRAM-write-by-RF indication. + /// FD goes low when phone writes to SRAM, returns high when MCU reads SRAM. + pub fn configure_fd_sram_write(&mut self) -> Result<(), E> { + // ED_FD_PIN_CFG register index 1 within the session block + // Bits 2:0 control FD output mode + self.write_register(SESSION_ED_FD_PIN_CFG, 0x01, 0x07, FD_MODE_SRAM_RF_WRITE) + } + // ---- Config check ---- /// Read session registers and compare against expected xblink config.