1use core::sync::atomic::{AtomicU16, Ordering};
5
6use defmt::Format;
7use num_enum::TryFromPrimitive;
8
9use crate::{
10 EspError,
11 ble::HciPkt,
12 copy_le, parse_le,
13 rpc::{EndpointType, RpcEndpoint},
14 transport::{PacketType, RPC_EP_NAME_RSP, compute_checksum},
15};
16
17pub(crate) const PL_HEADER_SIZE: usize = 12; const TLV_HEADER_SIZE: usize = 6;
22pub(crate) const TLV_SIZE: usize = TLV_HEADER_SIZE + RPC_EP_NAME_RSP.len();
24
25pub(crate) const CRC_SIZE: usize = 2; pub const HEADER_SIZE: usize = PL_HEADER_SIZE + TLV_SIZE;
28
29static SEQ_NUM: AtomicU16 = AtomicU16::new(0);
30
31#[derive(Clone, Copy, PartialEq, TryFromPrimitive, Format)]
32#[repr(u8)]
33pub enum InterfaceType {
36 Invalid = 0,
37 Sta = 1,
38 Ap = 2,
39 Serial = 3,
40 Hci = 4,
41 Priv = 5,
42 Test = 6,
43 Eth = 7,
44 Max = 8,
45}
46
47#[derive(Clone, Copy, PartialEq, TryFromPrimitive)]
48#[repr(u8)]
49pub(crate) enum Module {
51 Ctrl = 0x00,
53 Wifi = 0x01,
54 Ble = 0x02,
55}
56
57#[derive(Format)]
61pub struct PayloadHeader {
62 pub if_type: InterfaceType, pub if_num: u8, pub flags: u8,
67 pub len: u16,
70 pub offset: u16,
73 pub checksum: u16,
75 pub seq_num: u16,
77 pub throttle_cmd: u8, pub pkt_type: PacketType,
84}
85
86impl PayloadHeader {
87 pub fn new(
88 if_type: InterfaceType,
89 if_num: u8,
90 pkt_type: PacketType,
91 payload_len: usize,
92 ) -> Self {
93 Self {
95 if_type,
96 if_num,
98 flags: 0,
99 len: payload_len as u16,
100 offset: PL_HEADER_SIZE as u16,
101 checksum: 0,
104 seq_num: SEQ_NUM.fetch_add(1, Ordering::SeqCst),
105 throttle_cmd: 0,
106 pkt_type,
107 }
108 }
109
110 pub fn to_bytes(&self) -> [u8; PL_HEADER_SIZE] {
112 let mut buf = [0; PL_HEADER_SIZE];
113
114 buf[0] = (self.if_num << 4) | ((self.if_type as u8) & 0x0F);
116
117 buf[1] = self.flags;
118
119 copy_le!(buf, self.len, 2..4);
120 copy_le!(buf, self.offset, 4..6);
121 copy_le!(buf, self.checksum, 6..8);
122 copy_le!(buf, self.seq_num, 8..10);
123
124 buf[10] = self.throttle_cmd; buf[11] = self.pkt_type.val();
129
130 buf
131 }
132
133 pub fn from_bytes(buf: &[u8]) -> Result<Self, EspError> {
135 let if_type = (buf[0] & 0x0F)
136 .try_into()
137 .map_err(|_| EspError::InvalidData)?;
138 let if_num = (buf[0] >> 4) & 0x0F;
139 let flags = buf[1];
140
141 let len = parse_le!(buf, u16, 2..4);
142 let offset = parse_le!(buf, u16, 4..6);
143 let checksum = parse_le!(buf, u16, 6..8);
144 let seq_num = parse_le!(buf, u16, 8..10);
145
146 let throttle_cmd = buf[10] & 3;
147 let pkt_type = PacketType::from_byte(buf[11])?;
148
149 Ok(Self {
150 if_type,
151 if_num,
152 flags,
153 len,
154 offset,
155 checksum,
156 seq_num,
157 throttle_cmd,
158 pkt_type,
159 })
160 }
161}
162
163pub(crate) fn build_frame_wifi(out: &mut [u8], payload: &[u8]) -> usize {
167 let payload_len = payload.len();
169
170 let endpoint_value = RpcEndpoint::CtrlResp.as_bytes();
172 let endpoint_len = endpoint_value.len() as u16;
173
174 let hdr = PayloadHeader::new(
175 InterfaceType::Serial,
176 0,
177 PacketType::None,
178 payload_len + TLV_SIZE,
179 );
180 out[..PL_HEADER_SIZE].copy_from_slice(&hdr.to_bytes());
181
182 let mut i = PL_HEADER_SIZE;
184
185 out[i] = EndpointType::EndpointName as _;
186 i += 1;
187
188 copy_le!(out, endpoint_len, i..i + 2);
189 i += 2;
190
191 out[i..i + endpoint_len as usize].copy_from_slice(endpoint_value);
192 i += endpoint_len as usize;
193
194 out[i] = EndpointType::Data as _;
195 i += 1;
196
197 copy_le!(out, payload_len as u16, i..i + 2);
198 i += 2;
199
200 out[i..i + payload_len].copy_from_slice(payload);
201 i += payload_len;
202
203 let pl_checksum = compute_checksum(&out[..i]);
207 copy_le!(out, pl_checksum, 6..8);
208
209 i
210}
211
212pub fn build_frame_ble(out: &mut [u8], pkt_type: HciPkt, hci_payload: &[u8]) -> usize {
214 let payload_len = hci_payload.len();
216
217 let packet_type = PacketType::None;
218
219 let mut hdr = PayloadHeader::new(InterfaceType::Hci, 0, packet_type, payload_len);
220 hdr.pkt_type = PacketType::Hci(pkt_type);
221
222 out[..PL_HEADER_SIZE].copy_from_slice(&hdr.to_bytes());
223
224 let mut i = PL_HEADER_SIZE;
225
226 out[i..i + payload_len].copy_from_slice(hci_payload);
227 i += payload_len;
228
229 let pl_checksum = compute_checksum(&out[..i]);
233 copy_le!(out, pl_checksum, 6..8);
234 i
235}