From 2262076d24689965cd0422386c1cf491b4281605 Mon Sep 17 00:00:00 2001 From: Gabriele Baldoni Date: Wed, 4 Dec 2024 09:15:47 +0100 Subject: [PATCH 1/6] feat(init-reset): implemented small state machine for link opening and reset Signed-off-by: Gabriele Baldoni --- Cargo.toml | 2 +- examples/serial-echo.rs | 25 ++-- src/lib.rs | 315 +++++++++++++++++++++++++++++++++++----- 3 files changed, 294 insertions(+), 48 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 68da616..3790d83 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ readme = "README.md" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -tokio = {version = "1.17.0", features = ["io-util"] } +tokio = {version = "1.17.0", features = ["io-util", "time"] } tokio-serial = "5.4.1" futures = "0.3.21" cobs = "0.2" diff --git a/examples/serial-echo.rs b/examples/serial-echo.rs index 38e0632..09b91b0 100644 --- a/examples/serial-echo.rs +++ b/examples/serial-echo.rs @@ -41,20 +41,25 @@ async fn main() -> tokio_serial::Result<()> { println!("Arguments: {:?}", args); - let mut port = ZSerial::new(args.port, args.baud_rate, true)?; + let mut port = ZSerial::new(args.port, args.baud_rate, false)?; if args.server { loop { - match port.read_msg(&mut buff).await { - Ok(read) => { - println!(">> Read {read} bytes: {:02X?}", &buff[0..read]); + port.accept().await?; - port.write(&buff[..read]).await?; + 'inner: loop { + match port.read_msg(&mut buff).await { + Ok(read) => { + println!(">> Read {read} bytes: {:02X?}", &buff[0..read]); - println!("<< Echoed back"); - } - Err(e) => { - println!("Got error: {e} received {:02X?}", &buff[..8]); + port.write(&buff[..read]).await?; + + println!("<< Echoed back"); + } + Err(e) => { + println!("Got error: {e} received {:02X?}", &buff[..8]); + break 'inner; + } } } } @@ -68,6 +73,8 @@ async fn main() -> tokio_serial::Result<()> { 2.0 }; + port.connect().await?; + loop { tokio::time::sleep(Duration::from_secs_f64(args.interval)).await; diff --git a/src/lib.rs b/src/lib.rs index b860097..b094580 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // -use std::path::Path; +use std::{path::Path, time::Duration}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio_serial::{ClearBuffer, SerialPort, SerialPortBuilderExt, SerialStream}; @@ -22,29 +22,126 @@ pub const MAX_MTU: usize = 1500; const CRC32_LEN: usize = 4; // Given by cobs::max_encoding_length(MAX_FRAME_SIZE) -const COBS_BUF_SIZE: usize = 1516; +const COBS_BUF_SIZE: usize = 1517; const LEN_FIELD_LEN: usize = 2; +const KIND_FIELD_LEN: usize = 1; + const SENTINEL: u8 = 0x00; const CRC_TABLE_SIZE: usize = 256; const POLYNOMIA: u32 = 0x04C11DB7; +const SERIAL_CONNECT_THROTTLE_TIME_US: u64 = 250_000; + /// ZSerial Frame Format /// /// Using COBS /// +/// +-+-+----+------------+--------+-+ +/// |O|H|XXXX|ZZZZ....ZZZZ|CCCCCCCC|0| /// +-+----+------------+--------+-+ -/// |O|XXXX|ZZZZ....ZZZZ|CCCCCCCC|0| -/// +-+----+------------+--------+-+ -/// |O| Len| Data | CRC32 |C| -/// +-+-2--+----N-------+---4----+-+ +/// |O| |Len | Data | CRC32 |C| +/// +-+-+-2--+----N-------+---4----+-+ +/// +/// Header: 1byte +/// +---------------+ +/// |7|6|5|4|3|2|1|0| +/// +---------------+ +/// |x|x|x|x|x|R|A|I| +/// +---------------+ +/// +/// Flags: +/// I - Init +/// A - Ack +/// R - Reset /// /// Max Frame Size: 1510 /// Max MTU: 1500 -/// Max On-the-wire length: 1516 (MFS + Overhead Byte (OHB) + End of packet (EOP)) +/// Max On-the-wire length: 1516 (MFS + Overhead Byte (OHB) + Kind Byte + End of packet (EOP)) + +/// Initializaiton message exchange from cold start +/// +/// 1) Connect side sends a message with empty payload and I flag set. +/// 2) Listen side sends a message with empty payload and I+A flags set. +/// 3) Data can be exchanged from this point on. +/// +/// ┌─────────┐ ┌──────────┐ +/// │ Listen │ │ Connect │ +/// └────┬────┘ └────┬─────┘ +/// │ │ +/// │ Init │ +/// │◄─────────────────────────┤ +/// │ │ +/// │ Init + Ack │ +/// ├─────────────────────────►│ +/// │ Data │ +/// │◄─────────────────────────┤ +/// ├─────────────────────────►│ +/// │ │ +/// +/// If connect sides restarts: +/// +/// 1) Connect side sends a message with empty payload and I flag set. +/// 2) Listen side sends a message with empty payload and R flag set. +/// 3) Connect side waits and goes back to cold start case. +/// +/// ┌─────────┐ ┌──────────┐ +/// │ Listen │ │ Connect │ +/// └────┬────┘ └────┬─────┘ +/// │ Init │ +/// │◄─────────────────────────┤ +/// │ Reset │ +/// ├─────────────────────────►│ +/// │ │ +/// │ │ +/// │ │ +/// │ Init │ +/// │◄─────────────────────────┤ +/// │ Init + Ack │ +/// ├─────────────────────────►│ +/// │ Data │ +/// │◄─────────────────────────┤ +/// ├─────────────────────────►│ +/// │ │ +/// │ │ + +const I_FLAG: u8 = 0x01; +const A_FLAG: u8 = 0x02; +const R_FLAG: u8 = 0x04; + +#[derive(Debug)] +struct Header(u8); + +impl Header { + pub fn new(flags: u8) -> Self { + Header(flags) + } + + pub fn has_i_flag(&self) -> bool { + self.0 & I_FLAG == I_FLAG + } + + pub fn has_a_flag(&self) -> bool { + self.0 & A_FLAG == A_FLAG + } + + pub fn has_r_flag(&self) -> bool { + self.0 & R_FLAG == R_FLAG + } + + pub fn get_byte(&self) -> u8 { + self.0 + } +} + +impl From for Header { + fn from(value: u8) -> Self { + Self(value) + } +} #[derive(Debug)] pub struct CRC32 { @@ -105,6 +202,7 @@ impl WireFormat { &mut self, src: &[u8], dest: &mut [u8], + header: Header, ) -> tokio_serial::Result { if src.len() > MAX_MTU { return Err(tokio_serial::Error::new( @@ -122,12 +220,15 @@ impl WireFormat { let size_bytes = wire_size.to_ne_bytes(); // Copy into serialization buffer - self.buff[0..LEN_FIELD_LEN].copy_from_slice(&size_bytes); - self.buff[LEN_FIELD_LEN..LEN_FIELD_LEN + src.len()].copy_from_slice(src); - self.buff[LEN_FIELD_LEN + src.len()..LEN_FIELD_LEN + src.len() + CRC32_LEN] + self.buff[0] = header.get_byte(); + self.buff[KIND_FIELD_LEN..LEN_FIELD_LEN + KIND_FIELD_LEN].copy_from_slice(&size_bytes); + self.buff[LEN_FIELD_LEN + KIND_FIELD_LEN..LEN_FIELD_LEN + KIND_FIELD_LEN + src.len()] + .copy_from_slice(src); + self.buff[LEN_FIELD_LEN + KIND_FIELD_LEN + src.len() + ..LEN_FIELD_LEN + KIND_FIELD_LEN + src.len() + CRC32_LEN] .copy_from_slice(&crc32); - let total_len = LEN_FIELD_LEN + CRC32_LEN + src.len(); + let total_len = KIND_FIELD_LEN + LEN_FIELD_LEN + CRC32_LEN + src.len(); log::trace!( "Frame before COBS encoding {:02X?}", @@ -148,7 +249,7 @@ impl WireFormat { &self, src: &mut [u8], dst: &mut [u8], - ) -> tokio_serial::Result { + ) -> tokio_serial::Result<(usize, Header)> { let decoded_size = cobs::decode_in_place_with_sentinel(src, SENTINEL).map_err(|e| { tokio_serial::Error::new( tokio_serial::ErrorKind::InvalidInput, @@ -166,11 +267,13 @@ impl WireFormat { )); } + // Decoding message kind + let hdr = Header::from(src[0]); // Decoding message size - let wire_size = ((src[1] as u16) << 8 | src[0] as u16) as usize; + let wire_size = ((src[2] as u16) << 8 | src[1] as u16) as usize; // Check if the frame size is correct - if LEN_FIELD_LEN + wire_size + CRC32_LEN != decoded_size { + if KIND_FIELD_LEN + LEN_FIELD_LEN + wire_size + CRC32_LEN != decoded_size { return Err(tokio_serial::Error::new( tokio_serial::ErrorKind::InvalidInput, "Payload does not match the its size", @@ -178,10 +281,10 @@ impl WireFormat { } // Getting the data - let data = &src[LEN_FIELD_LEN..wire_size + LEN_FIELD_LEN]; + let data = &src[KIND_FIELD_LEN + LEN_FIELD_LEN..KIND_FIELD_LEN + wire_size + LEN_FIELD_LEN]; - let crc_received_bytes = - &src[LEN_FIELD_LEN + wire_size..LEN_FIELD_LEN + wire_size + CRC32_LEN]; + let crc_received_bytes = &src[KIND_FIELD_LEN + LEN_FIELD_LEN + wire_size + ..KIND_FIELD_LEN + LEN_FIELD_LEN + wire_size + CRC32_LEN]; let recv_crc: u32 = ((crc_received_bytes[3] as u32) << 24) | ((crc_received_bytes[2] as u32) << 16) @@ -207,10 +310,16 @@ impl WireFormat { // Copy into user slice. dst[0..wire_size].copy_from_slice(data); - Ok(wire_size) + Ok((wire_size, hdr)) } } +#[derive(PartialEq, Eq)] +enum Status { + Uninitialized, + Initialized, +} + pub struct ZSerial { port: String, baud_rate: u32, @@ -218,6 +327,7 @@ pub struct ZSerial { send_buff: Vec, recv_buff: Vec, formatter: WireFormat, + status: Status, } impl ZSerial { @@ -235,9 +345,82 @@ impl ZSerial { send_buff: vec![0u8; COBS_BUF_SIZE], recv_buff: vec![0u8; COBS_BUF_SIZE], formatter: WireFormat::new(), + status: Status::Uninitialized, }) } + pub fn close(&mut self) { + self.status = Status::Uninitialized; + } + + pub async fn accept(&mut self) -> tokio_serial::Result<()> { + if self.status == Status::Initialized { + return Err(tokio_serial::Error { + kind: tokio_serial::ErrorKind::InvalidInput, + description: "Cannot accept on an intialized connection!".into(), + }); + } + + log::trace!("Waiting for connection"); + let mut buff = vec![0u8; COBS_BUF_SIZE]; + + // Clear all buffers + self.clear()?; + + loop { + // while dbg!(self.bytes_to_read()?) == 0 { + // // Waiting to be ready, if not sleep some time. + // tokio::time::sleep(Duration::from_micros(SERIAL_ACCEPT_THROTTLE_TIME_MS)).await; + // } + + // wait for an empty message with I flag + + let (_read, hdr) = self.internal_read(&mut buff).await?; + log::trace!("Received header: {hdr:02X?}"); + if hdr.has_i_flag() { + // we send back a message with both I and A flags + self.internal_write(&[0u8], Header::new(I_FLAG | A_FLAG)) + .await?; + + // we must set our internal status to initialized + self.status = Status::Initialized; + return Ok(()); + } // otherwise ignore + } + } + + pub async fn connect(&mut self) -> tokio_serial::Result<()> { + let mut buff = vec![0u8; COBS_BUF_SIZE]; + + // we must first send a en emtpy message with I flag + loop { + let hdr = Header::new(I_FLAG); + log::trace!("Sending {hdr:02X?}"); + self.internal_write(&[0], hdr).await?; + + // we then wait for a message with both I and A flags + let (_read, hdr) = self.internal_read(&mut buff).await?; + log::trace!("Received header: {hdr:02X?}"); + + if hdr.has_a_flag() && hdr.has_i_flag() { + // correct initialiation + self.status = Status::Initialized; + break; + } else if hdr.has_r_flag() { + // we received a reset we must resend the init message after a small sleep + tokio::time::sleep(Duration::from_micros(SERIAL_CONNECT_THROTTLE_TIME_US)).await; + continue; + } else { + return Err(tokio_serial::Error { + kind: tokio_serial::ErrorKind::InvalidInput, + description: format!("Unknown header: {hdr:02X?}"), + }); + } + } + + Ok(()) + } + pub async fn dump(&mut self) -> tokio_serial::Result<()> { self.serial .read_exact(std::slice::from_mut(&mut self.recv_buff[0])) @@ -246,7 +429,7 @@ impl ZSerial { Ok(()) } - pub async fn read_msg(&mut self, buff: &mut [u8]) -> tokio_serial::Result { + async fn internal_read(&mut self, buff: &mut [u8]) -> tokio_serial::Result<(usize, Header)> { let mut start_count = 0; if buff.len() < MAX_MTU { @@ -260,7 +443,7 @@ impl ZSerial { loop { // Check if we are reading too much, maybe we lost the sentinel. if start_count == COBS_BUF_SIZE { - return Ok(0); + return Ok((0, Header::new(0u8))); } // Read one byte at time until we reach the sentinel @@ -286,6 +469,22 @@ impl ZSerial { .deserialize_into(&mut self.recv_buff[0..start_count], buff) } + pub async fn read_msg(&mut self, buff: &mut [u8]) -> tokio_serial::Result { + let (read, hdr) = self.internal_read(buff).await?; + //TODO: check the kind is the expected one. + if self.status == Status::Initialized && hdr.has_i_flag() { + // we must rest the connection here + self.internal_write(&[0u8], Header::new(R_FLAG)).await?; + self.status = Status::Uninitialized; + return Err(tokio_serial::Error { + kind: tokio_serial::ErrorKind::InvalidInput, + description: "Unexpected Init flag in message".into(), + }); + } + + Ok(read) + } + #[allow(dead_code)] async fn read(serial: &mut SerialStream, buff: &mut [u8]) -> tokio_serial::Result { Ok(serial.read(buff).await?) @@ -301,9 +500,11 @@ impl ZSerial { Ok(()) } - pub async fn write(&mut self, buff: &[u8]) -> tokio_serial::Result<()> { + async fn internal_write(&mut self, buff: &[u8], hdr: Header) -> tokio_serial::Result<()> { // Serialize - let written = self.formatter.serialize_into(buff, &mut self.send_buff)?; + let written = self + .formatter + .serialize_into(buff, &mut self.send_buff, hdr)?; log::trace!( "Wrote {written}bytes COBS {:02X?}", @@ -316,6 +517,10 @@ impl ZSerial { Ok(()) } + pub async fn write(&mut self, buff: &[u8]) -> tokio_serial::Result<()> { + self.internal_write(buff, Header::new(0u8)).await + } + /// Gets the configured baud rate pub fn baud_rate(&self) -> u32 { self.baud_rate @@ -356,6 +561,8 @@ pub fn get_available_port_names() -> tokio_serial::Result> { #[cfg(test)] mod tests { + use crate::Header; + use super::{WireFormat, COBS_BUF_SIZE}; #[test] @@ -365,14 +572,16 @@ mod tests { let data: Vec = vec![0x00, 0x11, 0x00]; - // COBS encoded | 0x03 0x00 | 0x00 0x11 0x00 | 0x73 0xEC 0x75 0xF9 | - // | Len | Data | CRC32 | + // COBS encoded 0x00 | 0x03 0x00 | 0x00 0x11 0x00 | 0x73 0xEC 0x75 0xF9 | + // Hdr | Len | Data | CRC32 | let serialzed_data: Vec = vec![ - 0x02, 0x03, 0x01, 0x02, 0x11, 0x05, 0x73, 0xEC, 0x75, 0xF9, 0x00, + 0x01, 0x02, 0x03, 0x01, 0x02, 0x11, 0x05, 0x73, 0xEC, 0x75, 0xF9, 0x00, ]; // Checks serialization - let written = formatter.serialize_into(&data, &mut ser_buff).unwrap(); + let written = formatter + .serialize_into(&data, &mut ser_buff, Header::new(0u8)) + .unwrap(); assert_eq!(written, serialzed_data.len()); assert_eq!(serialzed_data, ser_buff[0..written]); @@ -380,13 +589,15 @@ mod tests { let data: Vec = vec![0x11, 0x22, 0x00, 0x33]; - // COBS encoded | 0x04 0x00 | 0x11 0x22 0x00 0x33 | 0x8D 0x03 0x6D 0xFB | - // | Len | Data | CRC32 | + // COBS encoded 0x00 | 0x04 0x00 | 0x11 0x22 0x00 0x33 | 0x8D 0x03 0x6D 0xFB | + // Hdr | Len | Data | CRC32 | let serialzed_data: Vec = vec![ - 0x02, 0x04, 0x03, 0x11, 0x22, 0x06, 0x33, 0x8D, 0x03, 0x6D, 0xFB, 0x00, + 0x01, 0x02, 0x04, 0x03, 0x11, 0x22, 0x06, 0x33, 0x8D, 0x03, 0x6D, 0xFB, 0x00, ]; - let written = formatter.serialize_into(&data, &mut ser_buff).unwrap(); + let written = formatter + .serialize_into(&data, &mut ser_buff, Header::new(0u8)) + .unwrap(); assert_eq!(written, serialzed_data.len()); assert_eq!(serialzed_data, ser_buff[0..written]); } @@ -397,36 +608,64 @@ mod tests { let mut buff = vec![0u8; COBS_BUF_SIZE]; let data: Vec = vec![0x00, 0x11, 0x00]; - // COBS encoded | 0x03 0x00 | 0x00 0x11 0x00 | 0x73 0xEC 0x75 0xF9 | - // | Len | Data | CRC32 | + // COBS encoded 0x01 | 0x03 0x00 | 0x00 0x11 0x00 | 0x73 0xEC 0x75 0xF9 | + // Hdr | Len | Data | CRC32 | let mut serialzed_data: Vec = vec![ - 0x02, 0x03, 0x01, 0x02, 0x11, 0x05, 0x73, 0xEC, 0x75, 0xF9, 0x00, + 0x01, 0x02, 0x03, 0x01, 0x02, 0x11, 0x05, 0x73, 0xEC, 0x75, 0xF9, 0x00, ]; let serialized_len = serialzed_data.len(); - let read = formatter + let (read, hdr) = formatter .deserialize_into(&mut serialzed_data[0..serialized_len], &mut buff) .unwrap(); assert_eq!(read, data.len()); + assert!(!hdr.has_i_flag()); assert_eq!(buff[0..read], data); //2nd Check let data: Vec = vec![0x11, 0x22, 0x00, 0x33]; - // COBS encoded | 0x04 0x00 | 0x11 0x22 0x00 0x33 | 0x8D 0x03 0x6D 0xFB | - // | Len | Data | CRC32 | + // COBS encoded 0x02 | 0x04 0x00 | 0x11 0x22 0x00 0x33 | 0x8D 0x03 0x6D 0xFB | + // hdr | Len | Data | CRC32 | let mut serialzed_data: Vec = vec![ - 0x02, 0x04, 0x03, 0x11, 0x22, 0x06, 0x33, 0x8D, 0x03, 0x6D, 0xFB, 0x00, + 0x01, 0x02, 0x04, 0x03, 0x11, 0x22, 0x06, 0x33, 0x8D, 0x03, 0x6D, 0xFB, 0x00, ]; let serialized_len = serialzed_data.len(); - let read = formatter + let (read, hdr) = formatter .deserialize_into(&mut serialzed_data[0..serialized_len], &mut buff) .unwrap(); assert_eq!(read, data.len()); assert_eq!(buff[0..read], data); + assert!(!hdr.has_i_flag()); + } + + #[test] + fn test_serde_empty() { + let mut formatter = WireFormat::new(); + let mut ser_buff = vec![0u8; COBS_BUF_SIZE]; + let mut de_buff = vec![0u8; COBS_BUF_SIZE]; + + let data: Vec = vec![0x00]; + let written = formatter + .serialize_into(&data, &mut ser_buff, Header::new(0u8)) + .unwrap(); + + println!("Data: {data:02X?}"); + println!("Serialized: {:02X?}", &ser_buff[0..written]); + + let (read, hdr) = formatter + .deserialize_into(&mut ser_buff[0..written], &mut de_buff) + .unwrap(); + + println!("Deserialized: {:02X?}", &de_buff[0..read]); + + assert_eq!(read, data.len()); + assert!(!hdr.has_i_flag()); + + assert_eq!(data, de_buff[0..read]); } } From 43b978efa780b5b8150eaac96949f8545166f918 Mon Sep 17 00:00:00 2001 From: Gabriele Baldoni Date: Wed, 4 Dec 2024 10:48:14 +0100 Subject: [PATCH 2/6] feat: configurable timeout Signed-off-by: Gabriele Baldoni --- examples/serial-echo.rs | 2 +- src/lib.rs | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/examples/serial-echo.rs b/examples/serial-echo.rs index 09b91b0..bb2055f 100644 --- a/examples/serial-echo.rs +++ b/examples/serial-echo.rs @@ -73,7 +73,7 @@ async fn main() -> tokio_serial::Result<()> { 2.0 }; - port.connect().await?; + port.connect(None).await?; loop { tokio::time::sleep(Duration::from_secs_f64(args.interval)).await; diff --git a/src/lib.rs b/src/lib.rs index b094580..8bfcb08 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -368,11 +368,6 @@ impl ZSerial { self.clear()?; loop { - // while dbg!(self.bytes_to_read()?) == 0 { - // // Waiting to be ready, if not sleep some time. - // tokio::time::sleep(Duration::from_micros(SERIAL_ACCEPT_THROTTLE_TIME_MS)).await; - // } - // wait for an empty message with I flag let (_read, hdr) = self.internal_read(&mut buff).await?; @@ -389,7 +384,8 @@ impl ZSerial { } } - pub async fn connect(&mut self) -> tokio_serial::Result<()> { + pub async fn connect(&mut self, tout: Option) -> tokio_serial::Result<()> { + let tout = tout.unwrap_or(Duration::from_micros(SERIAL_CONNECT_THROTTLE_TIME_US)); let mut buff = vec![0u8; COBS_BUF_SIZE]; // we must first send a en emtpy message with I flag @@ -408,7 +404,7 @@ impl ZSerial { break; } else if hdr.has_r_flag() { // we received a reset we must resend the init message after a small sleep - tokio::time::sleep(Duration::from_micros(SERIAL_CONNECT_THROTTLE_TIME_US)).await; + tokio::time::sleep(tout).await; continue; } else { return Err(tokio_serial::Error { From 13146aeeabc00f31b40ff5eb0900b0ba06f9a210 Mon Sep 17 00:00:00 2001 From: Gabriele Baldoni Date: Mon, 9 Dec 2024 08:27:19 +0100 Subject: [PATCH 3/6] chore: adding test with empty payload for serialization Signed-off-by: Gabriele Baldoni --- src/lib.rs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 8bfcb08..266b114 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -640,7 +640,7 @@ mod tests { } #[test] - fn test_serde_empty() { + fn test_serde_one_byte() { let mut formatter = WireFormat::new(); let mut ser_buff = vec![0u8; COBS_BUF_SIZE]; let mut de_buff = vec![0u8; COBS_BUF_SIZE]; @@ -664,4 +664,30 @@ mod tests { assert_eq!(data, de_buff[0..read]); } + + #[test] + fn test_serde_emtpy() { + let mut formatter = WireFormat::new(); + let mut ser_buff = vec![0u8; COBS_BUF_SIZE]; + let mut de_buff = vec![0u8; COBS_BUF_SIZE]; + + let data: Vec = vec![]; + let written = formatter + .serialize_into(&data, &mut ser_buff, Header::new(0u8)) + .unwrap(); + + println!("Data: {data:02X?}"); + println!("Serialized: {:02X?}", &ser_buff[0..written]); + + let (read, hdr) = formatter + .deserialize_into(&mut ser_buff[0..written], &mut de_buff) + .unwrap(); + + println!("Deserialized: {:02X?}", &de_buff[0..read]); + + assert_eq!(read, data.len()); + assert!(!hdr.has_i_flag()); + + assert_eq!(data, de_buff[0..read]); + } } From 4d7f5fb343663501275b0cc3ac813d93fff82505 Mon Sep 17 00:00:00 2001 From: Gabriele Baldoni Date: Mon, 9 Dec 2024 08:28:44 +0100 Subject: [PATCH 4/6] fix: empty payload during handshake Signed-off-by: Gabriele Baldoni --- src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 266b114..6849a9f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -374,7 +374,7 @@ impl ZSerial { log::trace!("Received header: {hdr:02X?}"); if hdr.has_i_flag() { // we send back a message with both I and A flags - self.internal_write(&[0u8], Header::new(I_FLAG | A_FLAG)) + self.internal_write(&[], Header::new(I_FLAG | A_FLAG)) .await?; // we must set our internal status to initialized @@ -392,7 +392,7 @@ impl ZSerial { loop { let hdr = Header::new(I_FLAG); log::trace!("Sending {hdr:02X?}"); - self.internal_write(&[0], hdr).await?; + self.internal_write(&[], hdr).await?; // we then wait for a message with both I and A flags let (_read, hdr) = self.internal_read(&mut buff).await?; @@ -470,7 +470,7 @@ impl ZSerial { //TODO: check the kind is the expected one. if self.status == Status::Initialized && hdr.has_i_flag() { // we must rest the connection here - self.internal_write(&[0u8], Header::new(R_FLAG)).await?; + self.internal_write(&[], Header::new(R_FLAG)).await?; self.status = Status::Uninitialized; return Err(tokio_serial::Error { kind: tokio_serial::ErrorKind::InvalidInput, From bb00ed07424987d3fa983732741e0a1aaba24411 Mon Sep 17 00:00:00 2001 From: Gabriele Baldoni Date: Mon, 9 Dec 2024 08:30:35 +0100 Subject: [PATCH 5/6] tests: adding empty payload CRC test Signed-off-by: Gabriele Baldoni --- tests/crc.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/crc.rs b/tests/crc.rs index 854439e..bf6c22e 100644 --- a/tests/crc.rs +++ b/tests/crc.rs @@ -103,3 +103,11 @@ fn check_different_bitflips_crc() { assert_ne!(crc.compute_crc32(&data), crc.compute_crc32(&bitflipped)) } } + +#[test] +fn check_emtpy_crc() { + let crc = CRC32::default(); + let data: Vec = vec![]; + + assert_eq!(crc.compute_crc32(&data), crc.compute_crc32(&(data.clone()))) +} From d7496e671215ee04316bcb1f4b31b437d1ee87af Mon Sep 17 00:00:00 2001 From: Gabriele Baldoni Date: Tue, 10 Dec 2024 09:08:11 +0100 Subject: [PATCH 6/6] feat: adding check if file exists on read and write calls Signed-off-by: Gabriele Baldoni --- src/lib.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 6849a9f..dd11ff6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -425,7 +425,21 @@ impl ZSerial { Ok(()) } + async fn check_device(&self) -> tokio_serial::Result<()> { + // check if the file is still there + if !tokio::fs::metadata(self.port.clone()).await.is_ok() { + // the file does not exist anymore returing an error + return Err(tokio_serial::Error::new( + tokio_serial::ErrorKind::NoDevice, + format!("Serial device disappeared"), + )); + } + return Ok(()); + } async fn internal_read(&mut self, buff: &mut [u8]) -> tokio_serial::Result<(usize, Header)> { + //check if the device is sitll there + self.check_device().await?; + let mut start_count = 0; if buff.len() < MAX_MTU { @@ -497,6 +511,9 @@ impl ZSerial { } async fn internal_write(&mut self, buff: &[u8], hdr: Header) -> tokio_serial::Result<()> { + //check if the device is sitll there + self.check_device().await?; + // Serialize let written = self .formatter