From c24805b83dbbca091eaf11a00c171da641f7107e Mon Sep 17 00:00:00 2001 From: Turbo Fredriksson Date: Mon, 29 Apr 2024 12:45:08 +0100 Subject: [PATCH 1/3] Added PIO UART examples for rp to talk to an R503 fingerprint scanner. --- examples/rp/src/bin/uart_r503.rs | 113 +++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 examples/rp/src/bin/uart_r503.rs diff --git a/examples/rp/src/bin/uart_r503.rs b/examples/rp/src/bin/uart_r503.rs new file mode 100644 index 000000000..f8a9d8a9f --- /dev/null +++ b/examples/rp/src/bin/uart_r503.rs @@ -0,0 +1,113 @@ +#![no_std] +#![no_main] + +use defmt::{debug, info, unwrap}; +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::peripherals::UART0; +use embassy_rp::uart::{Async, Config, DataBits, InterruptHandler as UARTInterruptHandler, StopBits, Uart, UartRx}; +use embassy_time::Timer; +use heapless::Vec; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(pub struct Irqs { + UART0_IRQ => UARTInterruptHandler; // Fingerprint scanner (TX) +}); + +const ADDRESS: u32 = 0xFFFFFFFF; +const START: u16 = 0xEF01; + +// ================================================================================ + +fn write_cmd_bytes(buf: &mut Vec, bytes: &[u8]) { + let _ = buf.extend_from_slice(bytes); +} + +fn compute_checksum(buf: Vec) -> u16 { + let mut checksum = 0u16; + + let check_end = buf.len(); + let checked_bytes = &buf[6..check_end]; + for byte in checked_bytes { + checksum += (*byte) as u16; + } + return checksum; +} + +// NOTE: Doesn't work for some reason, it just hangs! +#[embassy_executor::task] +async fn reader(mut rx: UartRx<'static, UART0, Async>) { + loop { + let mut buf = [0; 32]; + debug!("Attempting read.."); + + //rx.read(&mut buf).await.unwrap(); + match rx.read(&mut buf).await { + Ok(v) => info!("Read successful: {:?}", v), + Err(e) => info!("Read error: {:?}", e), + } + info!("RX='{:?}'", buf); + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + info!("Start"); + + let p = embassy_rp::init(Default::default()); + + // Initialize the fingerprint scanner. + let mut config = Config::default(); + config.baudrate = 57600; + config.stop_bits = StopBits::STOP1; + config.data_bits = DataBits::DataBits8; + + let (uart, tx_pin, tx_dma, rx_pin, rx_dma) = (p.UART0, p.PIN_16, p.DMA_CH0, p.PIN_17, p.DMA_CH1); + let uart = Uart::new(uart, tx_pin, rx_pin, Irqs, tx_dma, rx_dma, config); + let (mut tx, rx) = uart.split(); + + unwrap!(spawner.spawn(reader(rx))); + Timer::after_secs(1).await; + + let mut vec_buf: Vec = heapless::Vec::new(); + { + // Clear buffers + vec_buf.clear(); + + // START + let _ = write_cmd_bytes(&mut vec_buf, &START.to_be_bytes()[..]); + + // ADDRESS + let _ = write_cmd_bytes(&mut vec_buf, &ADDRESS.to_be_bytes()[..]); + + // PID + let _ = vec_buf.push(0x01); + + // LENGTH + let len = >::try_into(vec_buf.len()).unwrap() as u16; + let _ = write_cmd_bytes(&mut vec_buf, &len.to_be_bytes()[..]); + + // COMMAND + let _ = vec_buf.push(0x35); // AuraLedConfig + + // DATA + let _ = vec_buf.push(0x01); // ctrl=Breathing light + let _ = vec_buf.push(0x50); // speed=80 + let _ = vec_buf.push(0x02); // colour=Blue + let _ = vec_buf.push(0x00); // times=Infinite + + // SUM + let chk = compute_checksum(vec_buf.clone()); + let _ = write_cmd_bytes(&mut vec_buf, &chk.to_be_bytes()[..]); + + // ===== + + // Send command buffer. + let data: [u8; 16] = vec_buf.clone().into_array().unwrap(); + debug!("data='{:?}'", data); + match tx.write(&data).await { + Ok(..) => info!("Write successful"), + Err(e) => info!("Write error: {:?}", e), + } + } +} From 61d0c068ff793febd711971ded749bae277f5cc0 Mon Sep 17 00:00:00 2001 From: Turbo Fredriksson Date: Mon, 29 Apr 2024 14:54:26 +0100 Subject: [PATCH 2/3] Finish the read part. * Don't need separate task for this. * **Must** read one byte at a time, then merge them into one Vec. * To better demonstrate, cycle through the three colours Red, Blue, Purple. --- examples/rp/src/bin/uart_r503.rs | 79 ++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 30 deletions(-) diff --git a/examples/rp/src/bin/uart_r503.rs b/examples/rp/src/bin/uart_r503.rs index f8a9d8a9f..c0676750c 100644 --- a/examples/rp/src/bin/uart_r503.rs +++ b/examples/rp/src/bin/uart_r503.rs @@ -1,17 +1,17 @@ #![no_std] #![no_main] -use defmt::{debug, info, unwrap}; +use defmt::info; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::UART0; -use embassy_rp::uart::{Async, Config, DataBits, InterruptHandler as UARTInterruptHandler, StopBits, Uart, UartRx}; +use embassy_rp::uart::{Config, DataBits, InterruptHandler as UARTInterruptHandler, Parity, StopBits, Uart}; use embassy_time::Timer; use heapless::Vec; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(pub struct Irqs { - UART0_IRQ => UARTInterruptHandler; // Fingerprint scanner (TX) + UART0_IRQ => UARTInterruptHandler; }); const ADDRESS: u32 = 0xFFFFFFFF; @@ -34,24 +34,8 @@ fn compute_checksum(buf: Vec) -> u16 { return checksum; } -// NOTE: Doesn't work for some reason, it just hangs! -#[embassy_executor::task] -async fn reader(mut rx: UartRx<'static, UART0, Async>) { - loop { - let mut buf = [0; 32]; - debug!("Attempting read.."); - - //rx.read(&mut buf).await.unwrap(); - match rx.read(&mut buf).await { - Ok(v) => info!("Read successful: {:?}", v), - Err(e) => info!("Read error: {:?}", e), - } - info!("RX='{:?}'", buf); - } -} - #[embassy_executor::main] -async fn main(spawner: Spawner) { +async fn main(_spawner: Spawner) { info!("Start"); let p = embassy_rp::init(Default::default()); @@ -61,16 +45,16 @@ async fn main(spawner: Spawner) { config.baudrate = 57600; config.stop_bits = StopBits::STOP1; config.data_bits = DataBits::DataBits8; + config.parity = Parity::ParityNone; let (uart, tx_pin, tx_dma, rx_pin, rx_dma) = (p.UART0, p.PIN_16, p.DMA_CH0, p.PIN_17, p.DMA_CH1); let uart = Uart::new(uart, tx_pin, rx_pin, Irqs, tx_dma, rx_dma, config); - let (mut tx, rx) = uart.split(); - - unwrap!(spawner.spawn(reader(rx))); - Timer::after_secs(1).await; + let (mut tx, mut rx) = uart.split(); let mut vec_buf: Vec = heapless::Vec::new(); - { + + // Cycle through the three colours Red, Blue and Purple. + for colour in 1..=3 { // Clear buffers vec_buf.clear(); @@ -93,7 +77,7 @@ async fn main(spawner: Spawner) { // DATA let _ = vec_buf.push(0x01); // ctrl=Breathing light let _ = vec_buf.push(0x50); // speed=80 - let _ = vec_buf.push(0x02); // colour=Blue + let _ = vec_buf.push(colour as u8); // colour=Red, Blue, Purple let _ = vec_buf.push(0x00); // times=Infinite // SUM @@ -103,11 +87,46 @@ async fn main(spawner: Spawner) { // ===== // Send command buffer. - let data: [u8; 16] = vec_buf.clone().into_array().unwrap(); - debug!("data='{:?}'", data); - match tx.write(&data).await { - Ok(..) => info!("Write successful"), + let data_write: [u8; 16] = vec_buf.clone().into_array().unwrap(); + info!("write ({})='{:?}'", colour, data_write); + match tx.write(&data_write).await { + Ok(..) => info!("Write successful."), Err(e) => info!("Write error: {:?}", e), } + + // ===== + + // Read command buffer. + let mut read_buf: [u8; 1] = [0; 1]; // Can only read one byte at a time! + let mut data_read: Vec = heapless::Vec::new(); // Return buffer. + let mut cnt: u8 = 0; // Keep track of how many packages we've received. + + info!("Attempting read."); + loop { + match rx.read(&mut read_buf).await { + Ok(..) => (), + Err(e) => info!(" Read error: {:?}", e), + } + + match cnt { + _ => data_read.push(read_buf[0]).unwrap(), + } + + if cnt > 10 { + info!("read ({})='{:?}'", colour, data_read[..]); + break; + } + + cnt = cnt + 1; + } + + // ===== + + if colour != 3 { + Timer::after_secs(2).await; + info!("Changing colour."); + } } + + info!("All done.."); } From 66ee0c44d31d53da00cd2726ecd0fc47681f6d52 Mon Sep 17 00:00:00 2001 From: Turbo Fredriksson Date: Wed, 1 May 2024 11:43:14 +0100 Subject: [PATCH 3/3] Example and documentation on how to Calculate correct checksum. + Include the package format documentation. + Cycle through all three colours in three different speed. - Remove the `write_cmd_bytes()`. Superfluous. --- examples/rp/src/bin/uart_r503.rs | 156 ++++++++++++++++++------------- 1 file changed, 91 insertions(+), 65 deletions(-) diff --git a/examples/rp/src/bin/uart_r503.rs b/examples/rp/src/bin/uart_r503.rs index c0676750c..085be280b 100644 --- a/examples/rp/src/bin/uart_r503.rs +++ b/examples/rp/src/bin/uart_r503.rs @@ -1,12 +1,12 @@ #![no_std] #![no_main] -use defmt::info; +use defmt::{debug, error, info}; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::UART0; use embassy_rp::uart::{Config, DataBits, InterruptHandler as UARTInterruptHandler, Parity, StopBits, Uart}; -use embassy_time::Timer; +use embassy_time::{with_timeout, Duration, Timer}; use heapless::Vec; use {defmt_rtt as _, panic_probe as _}; @@ -14,15 +14,34 @@ bind_interrupts!(pub struct Irqs { UART0_IRQ => UARTInterruptHandler; }); -const ADDRESS: u32 = 0xFFFFFFFF; const START: u16 = 0xEF01; +const ADDRESS: u32 = 0xFFFFFFFF; // ================================================================================ -fn write_cmd_bytes(buf: &mut Vec, bytes: &[u8]) { - let _ = buf.extend_from_slice(bytes); -} +// Data package format +// Name Length Description +// ========================================================================================================== +// Start 2 bytes Fixed value of 0xEF01; High byte transferred first. +// Address 4 bytes Default value is 0xFFFFFFFF, which can be modified by command. +// High byte transferred first and at wrong adder value, module +// will reject to transfer. +// PID 1 byte 01H Command packet; +// 02H Data packet; Data packet shall not appear alone in executing +// processs, must follow command packet or acknowledge packet. +// 07H Acknowledge packet; +// 08H End of Data packet. +// LENGTH 2 bytes Refers to the length of package content (command packets and data packets) +// plus the length of Checksum (2 bytes). Unit is byte. Max length is 256 bytes. +// And high byte is transferred first. +// DATA - It can be commands, data, command’s parameters, acknowledge result, etc. +// (fingerprint character value, template are all deemed as data); +// SUM 2 bytes The arithmetic sum of package identifier, package length and all package +// contens. Overflowing bits are omitted. high byte is transferred first. +// ================================================================================ + +// Checksum is calculated on 'length (2 bytes) + data (??)'. fn compute_checksum(buf: Vec) -> u16 { let mut checksum = 0u16; @@ -52,81 +71,88 @@ async fn main(_spawner: Spawner) { let (mut tx, mut rx) = uart.split(); let mut vec_buf: Vec = heapless::Vec::new(); + let mut data: Vec = heapless::Vec::new(); - // Cycle through the three colours Red, Blue and Purple. - for colour in 1..=3 { - // Clear buffers - vec_buf.clear(); + let mut speeds: Vec = heapless::Vec::new(); + let _ = speeds.push(0xC8); // Slow + let _ = speeds.push(0x20); // Medium + let _ = speeds.push(0x02); // Fast - // START - let _ = write_cmd_bytes(&mut vec_buf, &START.to_be_bytes()[..]); + // Cycle through the three colours Red, Blue and Purple forever. + loop { + for colour in 1..=3 { + for speed in &speeds { + // Set the data first, because the length is dependent on that. + // However, we write the length bits before we do the data. + data.clear(); + let _ = data.push(0x01); // ctrl=Breathing light + let _ = data.push(*speed); + let _ = data.push(colour as u8); // colour=Red, Blue, Purple + let _ = data.push(0x00); // times=Infinite - // ADDRESS - let _ = write_cmd_bytes(&mut vec_buf, &ADDRESS.to_be_bytes()[..]); + // Clear buffers + vec_buf.clear(); - // PID - let _ = vec_buf.push(0x01); + // START + let _ = vec_buf.extend_from_slice(&START.to_be_bytes()[..]); - // LENGTH - let len = >::try_into(vec_buf.len()).unwrap() as u16; - let _ = write_cmd_bytes(&mut vec_buf, &len.to_be_bytes()[..]); + // ADDRESS + let _ = vec_buf.extend_from_slice(&ADDRESS.to_be_bytes()[..]); - // COMMAND - let _ = vec_buf.push(0x35); // AuraLedConfig + // PID + let _ = vec_buf.extend_from_slice(&[0x01]); - // DATA - let _ = vec_buf.push(0x01); // ctrl=Breathing light - let _ = vec_buf.push(0x50); // speed=80 - let _ = vec_buf.push(colour as u8); // colour=Red, Blue, Purple - let _ = vec_buf.push(0x00); // times=Infinite + // LENGTH + let len: u16 = (1 + data.len() + 2).try_into().unwrap(); + let _ = vec_buf.extend_from_slice(&len.to_be_bytes()[..]); - // SUM - let chk = compute_checksum(vec_buf.clone()); - let _ = write_cmd_bytes(&mut vec_buf, &chk.to_be_bytes()[..]); + // COMMAND + let _ = vec_buf.push(0x35); // Command: AuraLedConfig - // ===== + // DATA + let _ = vec_buf.extend_from_slice(&data); - // Send command buffer. - let data_write: [u8; 16] = vec_buf.clone().into_array().unwrap(); - info!("write ({})='{:?}'", colour, data_write); - match tx.write(&data_write).await { - Ok(..) => info!("Write successful."), - Err(e) => info!("Write error: {:?}", e), - } + // SUM + let chk = compute_checksum(vec_buf.clone()); + let _ = vec_buf.extend_from_slice(&chk.to_be_bytes()[..]); - // ===== + // ===== - // Read command buffer. - let mut read_buf: [u8; 1] = [0; 1]; // Can only read one byte at a time! - let mut data_read: Vec = heapless::Vec::new(); // Return buffer. - let mut cnt: u8 = 0; // Keep track of how many packages we've received. + // Send command buffer. + let data_write: [u8; 16] = vec_buf.clone().into_array().unwrap(); + debug!(" write='{:?}'", data_write[..]); + match tx.write(&data_write).await { + Ok(..) => info!("Write successful."), + Err(e) => error!("Write error: {:?}", e), + } - info!("Attempting read."); - loop { - match rx.read(&mut read_buf).await { - Ok(..) => (), - Err(e) => info!(" Read error: {:?}", e), + // ===== + + // Read command buffer. + let mut read_buf: [u8; 1] = [0; 1]; // Can only read one byte at a time! + let mut data_read: Vec = heapless::Vec::new(); // Save buffer. + + info!("Attempting read."); + loop { + // Some commands, like `Img2Tz()` needs longer, but we hard-code this to 200ms + // for this command. + match with_timeout(Duration::from_millis(200), rx.read(&mut read_buf)).await { + Ok(..) => { + // Extract and save read byte. + debug!(" r='{=u8:#04x}H' ({:03}D)", read_buf[0], read_buf[0]); + let _ = data_read.push(read_buf[0]).unwrap(); + } + Err(..) => break, // TimeoutError -> Ignore. + } + } + info!("Read successful"); + debug!(" read='{:?}'", data_read[..]); + + Timer::after_secs(3).await; + info!("Changing speed."); } - match cnt { - _ => data_read.push(read_buf[0]).unwrap(), - } - - if cnt > 10 { - info!("read ({})='{:?}'", colour, data_read[..]); - break; - } - - cnt = cnt + 1; - } - - // ===== - - if colour != 3 { - Timer::after_secs(2).await; info!("Changing colour."); } } - - info!("All done.."); }