cobs_io_async/
protocol.rs1use crate::{max_encoding_length, sync};
2
3pub(crate) const KIND_DATA: u8 = 1;
4pub(crate) const KIND_ACK: u8 = 2;
5
6const HEADER_LEN: usize = 1 + 8 + 4;
7const CRC_LEN: usize = 4;
8const OVERHEAD: usize = HEADER_LEN + CRC_LEN;
9
10pub(crate) const ACK_FRAME_LEN: usize = max_encoding_length(OVERHEAD) + 2;
11
12pub(crate) enum Packet<'a> {
13 Data {
14 session: u64,
15 seq: u32,
16 payload: &'a [u8],
17 },
18 Ack {
19 session: u64,
20 seq: u32,
21 },
22}
23
24const CRC_TABLE: [u32; 256] = {
26 let mut table = [0u32; 256];
27 let mut i = 0;
28 while i < 256 {
29 let mut crc = i as u32;
30 let mut bit = 0;
31 while bit < 8 {
32 crc = if crc & 1 != 0 {
33 (crc >> 1) ^ 0xEDB8_8320
34 } else {
35 crc >> 1
36 };
37 bit += 1;
38 }
39 table[i] = crc;
40 i += 1;
41 }
42 table
43};
44
45pub(crate) fn crc32(data: &[u8]) -> u32 {
46 !data.iter().fold(!0u32, |crc, &byte| {
47 CRC_TABLE[usize::from((crc as u8) ^ byte)] ^ (crc >> 8)
48 })
49}
50
51pub(crate) const fn max_payload(capacity: usize) -> usize {
54 let Some(body) = capacity.checked_sub(2) else {
55 return 0;
56 };
57 let mut len = body;
58 while len > OVERHEAD && max_encoding_length(len) > body {
59 len -= 1;
60 }
61 len.saturating_sub(OVERHEAD)
62}
63
64fn seal(decoded: &mut [u8], len: usize, frame: &mut [u8]) -> usize {
65 let crc = crc32(&decoded[..len - CRC_LEN]);
66 decoded[len - CRC_LEN..len].copy_from_slice(&crc.to_be_bytes());
67 sync::encode_from_slice_including_sentinels(&decoded[..len], frame)
68 .expect("frame buffer holds the encoded packet")
69}
70
71fn header(decoded: &mut [u8], kind: u8, session: u64, seq: u32) {
72 decoded[0] = kind;
73 decoded[1..9].copy_from_slice(&session.to_be_bytes());
74 decoded[9..HEADER_LEN].copy_from_slice(&seq.to_be_bytes());
75}
76
77pub(crate) fn encode_data(
80 session: u64,
81 seq: u32,
82 payload: &[u8],
83 scratch: &mut [u8],
84 frame: &mut [u8],
85) -> usize {
86 header(scratch, KIND_DATA, session, seq);
87 scratch[HEADER_LEN..HEADER_LEN + payload.len()].copy_from_slice(payload);
88 seal(scratch, OVERHEAD + payload.len(), frame)
89}
90
91pub(crate) fn encode_ack(session: u64, seq: u32, frame: &mut [u8; ACK_FRAME_LEN]) -> usize {
93 let mut decoded = [0u8; OVERHEAD];
94 header(&mut decoded, KIND_ACK, session, seq);
95 seal(&mut decoded, OVERHEAD, frame)
96}
97
98pub(crate) fn parse(decoded: &[u8]) -> Option<Packet<'_>> {
99 if decoded.len() < OVERHEAD {
100 return None;
101 }
102 let (body, crc) = decoded.split_at(decoded.len() - CRC_LEN);
103 if crc32(body) != u32::from_be_bytes(crc.try_into().ok()?) {
104 return None;
105 }
106 let session = u64::from_be_bytes(body[1..9].try_into().ok()?);
107 let seq = u32::from_be_bytes(body[9..HEADER_LEN].try_into().ok()?);
108 let payload = &body[HEADER_LEN..];
109 match body[0] {
110 KIND_DATA if !payload.is_empty() => Some(Packet::Data {
111 session,
112 seq,
113 payload,
114 }),
115 KIND_ACK if payload.is_empty() => Some(Packet::Ack { session, seq }),
116 _ => None,
117 }
118}