1use std::{path::Path, time::Duration};
16use tokio::io::{AsyncReadExt, AsyncWriteExt};
17use tokio_serial::{ClearBuffer, SerialPort, SerialPortBuilderExt, SerialStream};
18
19pub const MAX_FRAME_SIZE: usize = 1510;
20pub const MAX_MTU: usize = 1500;
21
22const CRC32_LEN: usize = 4;
23
24const COBS_BUF_SIZE: usize = 1517;
26
27const LEN_FIELD_LEN: usize = 2;
28
29const KIND_FIELD_LEN: usize = 1;
30
31const SENTINEL: u8 = 0x00;
32
33const CRC_TABLE_SIZE: usize = 256;
34
35const POLYNOMIA: u32 = 0x04C11DB7;
36
37const SERIAL_CONNECT_THROTTLE_TIME_US: u64 = 250_000;
38
39const I_FLAG: u8 = 0x01;
112const A_FLAG: u8 = 0x02;
113const R_FLAG: u8 = 0x04;
114
115#[derive(Debug)]
116struct Header(u8);
117
118impl Header {
119 pub fn new(flags: u8) -> Self {
120 Header(flags)
121 }
122
123 pub fn has_i_flag(&self) -> bool {
124 self.0 & I_FLAG == I_FLAG
125 }
126
127 pub fn has_a_flag(&self) -> bool {
128 self.0 & A_FLAG == A_FLAG
129 }
130
131 pub fn has_r_flag(&self) -> bool {
132 self.0 & R_FLAG == R_FLAG
133 }
134
135 pub fn get_byte(&self) -> u8 {
136 self.0
137 }
138}
139
140impl From<u8> for Header {
141 fn from(value: u8) -> Self {
142 Self(value)
143 }
144}
145
146#[derive(Debug)]
147pub struct CRC32 {
148 table: [u32; CRC_TABLE_SIZE],
149}
150
151impl CRC32 {
152 pub fn compute_crc32(&self, buff: &[u8]) -> u32 {
153 let mut acc: u32 = !0;
154
155 for b in buff {
156 let octect = *b;
157 acc = (acc >> 8) ^ self.table[((acc & 0xFF) ^ octect as u32) as usize]
158 }
159
160 !acc
161 }
162}
163
164impl Default for CRC32 {
165 fn default() -> Self {
166 let mut table = [0u32; CRC_TABLE_SIZE];
167 for n in 0..256 {
168 let mut rem = n;
169
170 for _ in 0..8 {
171 match rem & 1 {
172 1 => rem = POLYNOMIA ^ (rem >> 1),
173 _ => rem >>= 1,
174 }
175 }
176
177 table[n as usize] = rem;
178 }
179
180 Self { table }
181 }
182}
183
184#[derive(Debug)]
185struct WireFormat {
186 buff: Vec<u8>,
187 crc: CRC32,
188}
189
190impl WireFormat {
191 pub(crate) fn new() -> Self {
192 let crc = CRC32::default();
194
195 Self {
196 buff: vec![0u8; COBS_BUF_SIZE],
197 crc,
198 }
199 }
200
201 pub(crate) fn serialize_into(
202 &mut self,
203 src: &[u8],
204 dest: &mut [u8],
205 header: Header,
206 ) -> tokio_serial::Result<usize> {
207 if src.len() > MAX_MTU {
208 return Err(tokio_serial::Error::new(
209 tokio_serial::ErrorKind::InvalidInput,
210 "Payload is too big",
211 ));
212 }
213
214 let crc32 = self.crc.compute_crc32(src).to_ne_bytes();
216
217 let wire_size: u16 = src.len() as u16;
219
220 let size_bytes = wire_size.to_ne_bytes();
221
222 self.buff[0] = header.get_byte();
224 self.buff[KIND_FIELD_LEN..LEN_FIELD_LEN + KIND_FIELD_LEN].copy_from_slice(&size_bytes);
225 self.buff[LEN_FIELD_LEN + KIND_FIELD_LEN..LEN_FIELD_LEN + KIND_FIELD_LEN + src.len()]
226 .copy_from_slice(src);
227 self.buff[LEN_FIELD_LEN + KIND_FIELD_LEN + src.len()
228 ..LEN_FIELD_LEN + KIND_FIELD_LEN + src.len() + CRC32_LEN]
229 .copy_from_slice(&crc32);
230
231 let total_len = KIND_FIELD_LEN + LEN_FIELD_LEN + CRC32_LEN + src.len();
232
233 log::trace!(
234 "Frame before COBS encoding {:02X?}",
235 &self.buff[0..total_len]
236 );
237
238 let mut written = cobs::encode_with_sentinel(&self.buff[0..total_len], dest, SENTINEL);
240
241 dest[written] = SENTINEL;
243 written += 1;
244
245 Ok(written)
246 }
247
248 pub(crate) fn deserialize_into(
249 &self,
250 src: &mut [u8],
251 dst: &mut [u8],
252 ) -> tokio_serial::Result<(usize, Header)> {
253 let decoded_size = cobs::decode_in_place_with_sentinel(src, SENTINEL).map_err(|e| {
254 tokio_serial::Error::new(
255 tokio_serial::ErrorKind::InvalidInput,
256 format!("Unable COBS decode: {e:?}"),
257 )
258 })?;
259
260 log::trace!("Frame after COBS encoding {:02X?}", &src[0..decoded_size]);
261
262 if decoded_size < LEN_FIELD_LEN + CRC32_LEN {
264 return Err(tokio_serial::Error::new(
265 tokio_serial::ErrorKind::InvalidInput,
266 "Serial is smaller than the minimum size",
267 ));
268 }
269
270 let hdr = Header::from(src[0]);
272 let wire_size = ((src[2] as u16) << 8 | src[1] as u16) as usize;
274
275 if KIND_FIELD_LEN + LEN_FIELD_LEN + wire_size + CRC32_LEN != decoded_size {
277 return Err(tokio_serial::Error::new(
278 tokio_serial::ErrorKind::InvalidInput,
279 "Payload does not match the its size",
280 ));
281 }
282
283 let data = &src[KIND_FIELD_LEN + LEN_FIELD_LEN..KIND_FIELD_LEN + wire_size + LEN_FIELD_LEN];
285
286 let crc_received_bytes = &src[KIND_FIELD_LEN + LEN_FIELD_LEN + wire_size
287 ..KIND_FIELD_LEN + LEN_FIELD_LEN + wire_size + CRC32_LEN];
288
289 let recv_crc: u32 = ((crc_received_bytes[3] as u32) << 24)
290 | ((crc_received_bytes[2] as u32) << 16)
291 | ((crc_received_bytes[1] as u32) << 8)
292 | (crc_received_bytes[0] as u32);
293
294 let computed_crc = self.crc.compute_crc32(&data[0..wire_size]);
296
297 log::trace!("Received CRC {recv_crc:02X?} Computed CRC {computed_crc:02X?}");
298
299 if recv_crc != computed_crc {
301 return Err(tokio_serial::Error::new(
302 tokio_serial::ErrorKind::InvalidInput,
303 format!(
304 "CRC does not match Received {:02X?} Computed {:02X?}",
305 recv_crc, computed_crc
306 ),
307 ));
308 }
309
310 dst[0..wire_size].copy_from_slice(data);
312
313 Ok((wire_size, hdr))
314 }
315}
316
317#[derive(PartialEq, Eq)]
318enum Status {
319 Uninitialized,
320 Initialized,
321}
322
323pub struct ZSerial {
324 port: String,
325 baud_rate: u32,
326 serial: SerialStream,
327 send_buff: Vec<u8>,
328 recv_buff: Vec<u8>,
329 formatter: WireFormat,
330 status: Status,
331}
332
333
334#[cfg(windows)]
335unsafe impl Send for ZSerial {}
336
337#[cfg(windows)]
338unsafe impl Sync for ZSerial {}
339
340impl ZSerial {
341 pub fn new(port: String, baud_rate: u32, exclusive: bool) -> tokio_serial::Result<Self> {
342 let mut serial = tokio_serial::new(port.clone(), baud_rate).open_native_async()?;
343
344 #[cfg(unix)]
345 serial.set_exclusive(exclusive)?;
346 serial.clear(ClearBuffer::All)?;
347
348 Ok(Self {
349 port,
350 baud_rate,
351 serial,
352 send_buff: vec![0u8; COBS_BUF_SIZE],
353 recv_buff: vec![0u8; COBS_BUF_SIZE],
354 formatter: WireFormat::new(),
355 status: Status::Uninitialized,
356 })
357 }
358
359 pub fn close(&mut self) {
360 self.status = Status::Uninitialized;
361 }
362
363 pub async fn accept(&mut self) -> tokio_serial::Result<()> {
364 if self.status == Status::Initialized {
365 return Err(tokio_serial::Error {
366 kind: tokio_serial::ErrorKind::InvalidInput,
367 description: "Cannot accept on an intialized connection!".into(),
368 });
369 }
370
371 log::trace!("Waiting for connection");
372 let mut buff = vec![0u8; COBS_BUF_SIZE];
373
374 self.clear()?;
376
377 loop {
378 let (_read, hdr) = self.internal_read(&mut buff).await?;
381 log::trace!("Received header: {hdr:02X?}");
382 if hdr.has_i_flag() {
383 self.internal_write(&[], Header::new(I_FLAG | A_FLAG))
385 .await?;
386
387 self.status = Status::Initialized;
389 return Ok(());
390 } }
392 }
393
394 pub async fn connect(&mut self, tout: Option<Duration>) -> tokio_serial::Result<()> {
395 let tout = tout.unwrap_or(Duration::from_micros(SERIAL_CONNECT_THROTTLE_TIME_US));
396 let mut buff = vec![0u8; COBS_BUF_SIZE];
397
398 loop {
400 let hdr = Header::new(I_FLAG);
401 log::trace!("Sending {hdr:02X?}");
402 self.internal_write(&[], hdr).await?;
403
404 let (_read, hdr) = self.internal_read(&mut buff).await?;
406 log::trace!("Received header: {hdr:02X?}");
407
408 if hdr.has_a_flag() && hdr.has_i_flag() {
409 self.status = Status::Initialized;
411 break;
412 } else if hdr.has_r_flag() {
413 tokio::time::sleep(tout).await;
415 continue;
416 } else {
417 return Err(tokio_serial::Error {
418 kind: tokio_serial::ErrorKind::InvalidInput,
419 description: format!("Unknown header: {hdr:02X?}"),
420 });
421 }
422 }
423
424 Ok(())
425 }
426
427 pub async fn dump(&mut self) -> tokio_serial::Result<()> {
428 self.serial
429 .read_exact(std::slice::from_mut(&mut self.recv_buff[0]))
430 .await?;
431 println!("Read {:02X?}", self.recv_buff[0]);
432 Ok(())
433 }
434
435 async fn check_device(&self) -> tokio_serial::Result<()> {
436 if tokio::fs::metadata(self.port.clone()).await.is_err() {
438 return Err(tokio_serial::Error::new(
440 tokio_serial::ErrorKind::NoDevice,
441 "Serial device disappeared".to_string(),
442 ));
443 }
444 Ok(())
445 }
446 async fn internal_read(&mut self, buff: &mut [u8]) -> tokio_serial::Result<(usize, Header)> {
447 self.check_device().await?;
449
450 let mut start_count = 0;
451
452 if buff.len() < MAX_MTU {
453 return Err(tokio_serial::Error::new(
454 tokio_serial::ErrorKind::InvalidInput,
455 format!("Recv buffer is too small, required minimum {MAX_MTU}"),
456 ));
457 }
458
459 loop {
461 if start_count == COBS_BUF_SIZE {
463 return Ok((0, Header::new(0u8)));
464 }
465
466 self.serial
468 .read_exact(std::slice::from_mut(&mut self.recv_buff[start_count]))
469 .await?;
470
471 if self.recv_buff[start_count] == SENTINEL {
472 break;
473 }
474 start_count += 1;
475 }
476
477 start_count += 1;
478
479 log::trace!(
480 "Read {start_count} bytes COBS {:02X?}",
481 &self.recv_buff[0..start_count]
482 );
483
484 self.formatter
486 .deserialize_into(&mut self.recv_buff[0..start_count], buff)
487 }
488
489 pub async fn read_msg(&mut self, buff: &mut [u8]) -> tokio_serial::Result<usize> {
490 let (read, hdr) = self.internal_read(buff).await?;
491 if self.status == Status::Initialized && hdr.has_i_flag() {
493 self.internal_write(&[], Header::new(R_FLAG)).await?;
495 self.status = Status::Uninitialized;
496 return Err(tokio_serial::Error {
497 kind: tokio_serial::ErrorKind::InvalidInput,
498 description: "Unexpected Init flag in message".into(),
499 });
500 }
501
502 Ok(read)
503 }
504
505 #[allow(dead_code)]
506 async fn read(serial: &mut SerialStream, buff: &mut [u8]) -> tokio_serial::Result<usize> {
507 Ok(serial.read(buff).await?)
508 }
509
510 #[allow(dead_code)]
511 async fn read_all(serial: &mut SerialStream, buff: &mut [u8]) -> tokio_serial::Result<()> {
512 let mut read: usize = 0;
513 while read < buff.len() {
514 let n = Self::read(serial, &mut buff[read..]).await?;
515 read += n;
516 }
517 Ok(())
518 }
519
520 async fn internal_write(&mut self, buff: &[u8], hdr: Header) -> tokio_serial::Result<()> {
521 self.check_device().await?;
523
524 let written = self
526 .formatter
527 .serialize_into(buff, &mut self.send_buff, hdr)?;
528
529 log::trace!(
530 "Wrote {written}bytes COBS {:02X?}",
531 &self.send_buff[0..written]
532 );
533
534 self.serial.write_all(&self.send_buff[0..written]).await?;
536 self.serial.flush().await?;
537 Ok(())
538 }
539
540 pub async fn write(&mut self, buff: &[u8]) -> tokio_serial::Result<()> {
541 self.internal_write(buff, Header::new(0u8)).await
542 }
543
544 pub fn baud_rate(&self) -> u32 {
546 self.baud_rate
547 }
548
549 pub fn port(&self) -> String {
551 self.port.clone()
552 }
553
554 pub fn bytes_to_read(&self) -> tokio_serial::Result<u32> {
555 self.serial.bytes_to_read()
556 }
557
558 pub fn clear(&self) -> tokio_serial::Result<()> {
559 self.serial.clear(ClearBuffer::All)
560 }
561}
562
563pub fn get_available_port_names() -> tokio_serial::Result<Vec<String>> {
564 let port_names: Vec<String> = tokio_serial::available_ports()?
565 .iter()
566 .map(|info| {
567 Path::new(&info.port_name)
568 .file_name()
569 .map(|os_str| os_str.to_string_lossy().to_string())
570 .ok_or_else(|| {
571 tokio_serial::Error::new(
572 tokio_serial::ErrorKind::Unknown,
573 "Unsupported port name",
574 )
575 })
576 })
577 .collect::<Result<Vec<String>, _>>()?;
578
579 Ok(port_names)
580}
581
582#[cfg(test)]
583mod tests {
584 use crate::Header;
585
586 use super::{WireFormat, COBS_BUF_SIZE};
587
588 #[test]
589 fn test_ser() {
590 let mut formatter = WireFormat::new();
591 let mut ser_buff = vec![0u8; COBS_BUF_SIZE];
592
593 let data: Vec<u8> = vec![0x00, 0x11, 0x00];
594
595 let serialzed_data: Vec<u8> = vec![
598 0x01, 0x02, 0x03, 0x01, 0x02, 0x11, 0x05, 0x73, 0xEC, 0x75, 0xF9, 0x00,
599 ];
600
601 let written = formatter
603 .serialize_into(&data, &mut ser_buff, Header::new(0u8))
604 .unwrap();
605 assert_eq!(written, serialzed_data.len());
606 assert_eq!(serialzed_data, ser_buff[0..written]);
607
608 let data: Vec<u8> = vec![0x11, 0x22, 0x00, 0x33];
611
612 let serialzed_data: Vec<u8> = vec![
615 0x01, 0x02, 0x04, 0x03, 0x11, 0x22, 0x06, 0x33, 0x8D, 0x03, 0x6D, 0xFB, 0x00,
616 ];
617
618 let written = formatter
619 .serialize_into(&data, &mut ser_buff, Header::new(0u8))
620 .unwrap();
621 assert_eq!(written, serialzed_data.len());
622 assert_eq!(serialzed_data, ser_buff[0..written]);
623 }
624
625 #[test]
626 fn test_de() {
627 let formatter = WireFormat::new();
628 let mut buff = vec![0u8; COBS_BUF_SIZE];
629
630 let data: Vec<u8> = vec![0x00, 0x11, 0x00];
631 let mut serialzed_data: Vec<u8> = vec![
634 0x01, 0x02, 0x03, 0x01, 0x02, 0x11, 0x05, 0x73, 0xEC, 0x75, 0xF9, 0x00,
635 ];
636 let serialized_len = serialzed_data.len();
637
638 let (read, hdr) = formatter
639 .deserialize_into(&mut serialzed_data[0..serialized_len], &mut buff)
640 .unwrap();
641
642 assert_eq!(read, data.len());
643 assert!(!hdr.has_i_flag());
644 assert_eq!(buff[0..read], data);
645
646 let data: Vec<u8> = vec![0x11, 0x22, 0x00, 0x33];
649
650 let mut serialzed_data: Vec<u8> = vec![
653 0x01, 0x02, 0x04, 0x03, 0x11, 0x22, 0x06, 0x33, 0x8D, 0x03, 0x6D, 0xFB, 0x00,
654 ];
655 let serialized_len = serialzed_data.len();
656
657 let (read, hdr) = formatter
658 .deserialize_into(&mut serialzed_data[0..serialized_len], &mut buff)
659 .unwrap();
660
661 assert_eq!(read, data.len());
662 assert_eq!(buff[0..read], data);
663 assert!(!hdr.has_i_flag());
664 }
665
666 #[test]
667 fn test_serde_one_byte() {
668 let mut formatter = WireFormat::new();
669 let mut ser_buff = vec![0u8; COBS_BUF_SIZE];
670 let mut de_buff = vec![0u8; COBS_BUF_SIZE];
671
672 let data: Vec<u8> = vec![0x00];
673 let written = formatter
674 .serialize_into(&data, &mut ser_buff, Header::new(0u8))
675 .unwrap();
676
677 println!("Data: {data:02X?}");
678 println!("Serialized: {:02X?}", &ser_buff[0..written]);
679
680 let (read, hdr) = formatter
681 .deserialize_into(&mut ser_buff[0..written], &mut de_buff)
682 .unwrap();
683
684 println!("Deserialized: {:02X?}", &de_buff[0..read]);
685
686 assert_eq!(read, data.len());
687 assert!(!hdr.has_i_flag());
688
689 assert_eq!(data, de_buff[0..read]);
690 }
691
692 #[test]
693 fn test_serde_emtpy() {
694 let mut formatter = WireFormat::new();
695 let mut ser_buff = vec![0u8; COBS_BUF_SIZE];
696 let mut de_buff = vec![0u8; COBS_BUF_SIZE];
697
698 let data: Vec<u8> = vec![];
699 let written = formatter
700 .serialize_into(&data, &mut ser_buff, Header::new(0u8))
701 .unwrap();
702
703 println!("Data: {data:02X?}");
704 println!("Serialized: {:02X?}", &ser_buff[0..written]);
705
706 let (read, hdr) = formatter
707 .deserialize_into(&mut ser_buff[0..written], &mut de_buff)
708 .unwrap();
709
710 println!("Deserialized: {:02X?}", &de_buff[0..read]);
711
712 assert_eq!(read, data.len());
713 assert!(!hdr.has_i_flag());
714
715 assert_eq!(data, de_buff[0..read]);
716 }
717}