1use core::sync::atomic::{AtomicU16, Ordering};
5
6use defmt::Format;
7use num_enum::TryFromPrimitive;
8
9use crate::{copy_le, parse_le, rpc::{EndpointType, RpcEndpoint}, transport::{PacketType, RPC_EP_NAME_RSP, compute_checksum}, EspError};
10
11pub(crate) const PL_HEADER_SIZE: usize = 12; const TLV_HEADER_SIZE: usize = 6;
16pub(crate) const TLV_SIZE: usize = TLV_HEADER_SIZE + RPC_EP_NAME_RSP.len();
18
19pub(crate) const CRC_SIZE: usize = 2; pub const HEADER_SIZE: usize = PL_HEADER_SIZE + TLV_SIZE;
22
23static SEQ_NUM: AtomicU16 = AtomicU16::new(0);
24
25#[derive(Clone, Copy, PartialEq, TryFromPrimitive, Format)]
26#[repr(u8)]
27pub(crate) enum InterfaceType {
30 Invalid = 0,
31 Sta = 1,
32 Ap = 2,
33 Serial = 3,
34 Hci = 4,
35 Priv = 5,
36 Test = 6,
37 Eth = 7,
38 Max = 8,
39}
40
41#[derive(Clone, Copy, PartialEq, TryFromPrimitive)]
42#[repr(u8)]
43pub(crate) enum Module {
45 Ctrl = 0x00,
47 Wifi = 0x01,
48 Ble = 0x02,
49}
50
51#[derive(Format)]
55pub struct PayloadHeader {
56 pub if_type: InterfaceType, pub if_num: u8, pub flags: u8,
61 pub len: u16,
64 pub offset: u16,
67 pub checksum: u16,
69 pub seq_num: u16,
71 pub throttle_cmd: u8, pub pkt_type: PacketType,
78}
79
80impl PayloadHeader {
81 pub fn new(if_type: InterfaceType, pkt_type: PacketType, payload_len: usize) -> Self {
82 let len = (TLV_SIZE + payload_len) as u16;
84
85 Self {
86 if_type,
87 if_num: 0,
89 flags: 0,
90 len,
91 offset: PL_HEADER_SIZE as u16,
92 checksum: 0,
95 seq_num: SEQ_NUM.fetch_add(1, Ordering::SeqCst),
96 throttle_cmd: 0,
97 pkt_type,
98 }
99 }
100 pub fn to_bytes(&self) -> [u8; PL_HEADER_SIZE] {
102 let mut buf = [0; PL_HEADER_SIZE];
103
104 buf[0] = (self.if_num << 4) | ((self.if_type as u8) & 0x0F);
106
107 buf[1] = self.flags;
108
109 copy_le!(buf, self.len, 2..4);
110 copy_le!(buf, self.offset, 4..6);
111 copy_le!(buf, self.checksum, 6..8);
112 copy_le!(buf, self.seq_num, 8..10);
113
114 buf[10] = self.throttle_cmd; buf[11] = self.pkt_type as u8;
119
120 buf
121 }
122
123 pub fn from_bytes(buf: &[u8]) -> Result<Self, EspError> {
125 let if_type = (buf[0] & 0x0F).try_into().map_err(|_| EspError::InvalidData)?;
126 let if_num = (buf[0] >> 4) & 0x0F;
127 let flags = buf[1];
128
129 let len = parse_le!(buf, u16, 2..4);
130 let offset = parse_le!(buf, u16, 4..6);
131 let checksum = parse_le!(buf, u16, 6..8);
132 let seq_num = parse_le!(buf, u16, 8..10);
133
134 let throttle_cmd = buf[10] & 3;
135 let pkt_type = buf[11].try_into().map_err(|_| EspError::InvalidData)?;
136
137 Ok(Self {
138 if_type,
139 if_num,
140 flags,
141 len,
142 offset,
143 checksum,
144 seq_num,
145 throttle_cmd,
146 pkt_type,
147 })
148 }
149}
150
151pub(crate) fn build_frame(out: &mut [u8], payload: &[u8]) -> usize {
155 let payload_len = payload.len();
157
158 let endpoint_value = RpcEndpoint::CtrlResp.as_bytes();
160 let endpoint_len = endpoint_value.len() as u16;
161
162 let packet_type = PacketType::None;
165
166 let payload_header = PayloadHeader::new(
167 InterfaceType::Serial,
169 packet_type,
170 payload_len,
171 );
172 out[..PL_HEADER_SIZE].copy_from_slice(&payload_header.to_bytes());
173
174 let mut i = PL_HEADER_SIZE;
175
176 out[i] = EndpointType::EndpointName as _;
177 i += 1;
178
179 copy_le!(out, endpoint_len, i..i + 2);
180 i += 2;
181
182 out[i..i + endpoint_len as usize].copy_from_slice(endpoint_value);
183 i += endpoint_len as usize;
184
185 out[i] = EndpointType::Data as _;
186 i += 1;
187
188 copy_le!(out, payload_len as u16, i..i + 2);
189 i += 2;
190
191 out[i..i + payload_len].copy_from_slice(payload);
192 i += payload_len;
193
194 let pl_checksum = compute_checksum(&out[..i]);
198 copy_le!(out, pl_checksum, 6..8);
199
200 i
201}