esp32_wroom_rp/
protocol.rs

1//! Defines functions, types and error definitions related to the WiFiNINA protocol communication specification.
2//!
3
4pub(crate) mod operation;
5
6use core::cell::RefCell;
7
8use defmt::{write, Format, Formatter};
9
10use embedded_hal::blocking::delay::DelayMs;
11
12use heapless::{String, Vec};
13
14use super::network::{ConnectionState, IpAddress, Port, Socket, TransportMode};
15use super::wifi::ConnectionStatus;
16use super::{Error, FirmwareVersion, ARRAY_LENGTH_PLACEHOLDER};
17
18pub(crate) const MAX_NINA_PARAM_LENGTH: usize = 4096;
19
20#[repr(u8)]
21#[derive(Copy, Clone, Debug)]
22pub(crate) enum NinaCommand {
23    SetPassphrase = 0x11u8,
24    SetDNSConfig = 0x15u8,
25    GetConnStatus = 0x20u8,
26    StartClientTcp = 0x2du8,
27    StopClientTcp = 0x2eu8,
28    GetClientStateTcp = 0x2fu8,
29    Disconnect = 0x30u8,
30    ReqHostByName = 0x34u8,
31    GetHostByName = 0x35u8,
32    GetFwVersion = 0x37u8,
33    GetSocket = 0x3fu8,
34    SendDataTcp = 0x44,
35}
36
37pub(crate) trait NinaConcreteParam {
38    // Length of parameter in bytes
39    type LengthAsBytes: IntoIterator<Item = u8>;
40
41    fn new(data: &str) -> Self;
42
43    fn from_bytes(bytes: &[u8]) -> Self;
44
45    fn data(&self) -> &[u8];
46
47    fn length_as_bytes(&self) -> Self::LengthAsBytes;
48
49    fn length(&self) -> u16;
50}
51
52// Used for Nina protocol commands with no parameters
53pub(crate) struct NinaNoParams {
54    _placeholder: u8,
55}
56
57impl NinaConcreteParam for NinaNoParams {
58    type LengthAsBytes = [u8; 0];
59
60    fn new(_data: &str) -> Self {
61        Self { _placeholder: 0 }
62    }
63
64    fn from_bytes(_bytes: &[u8]) -> Self {
65        Self { _placeholder: 0 }
66    }
67
68    fn data(&self) -> &[u8] {
69        &[0u8]
70    }
71
72    fn length_as_bytes(&self) -> Self::LengthAsBytes {
73        []
74    }
75
76    fn length(&self) -> u16 {
77        0u16
78    }
79}
80
81pub(crate) trait NinaParam {
82    fn length_as_bytes(&self) -> [u8; 2];
83    fn data(&self) -> &[u8];
84    fn length(&self) -> u16;
85    fn length_size(&self) -> u8;
86}
87
88// Used for single byte params
89pub(crate) struct NinaByteParam {
90    length: u8,
91    data: Vec<u8, 1>,
92}
93
94// Used for 2-byte params
95pub(crate) struct NinaWordParam {
96    length: u8,
97    data: Vec<u8, 2>,
98}
99
100// Used for params that are smaller than 255 bytes
101pub(crate) struct NinaSmallArrayParam {
102    length: u8,
103    data: Vec<u8, MAX_NINA_PARAM_LENGTH>,
104}
105
106// Used for params that can be larger than 255 bytes up to MAX_NINA_PARAM_LENGTH
107pub(crate) struct NinaLargeArrayParam {
108    length: u16,
109    data: Vec<u8, MAX_NINA_PARAM_LENGTH>,
110}
111
112pub(crate) struct NinaAbstractParam {
113    // Byte representation of length of data
114    length_as_bytes: [u8; 2],
115    // Data to be transfered over SPI bus
116    data: Vec<u8, MAX_NINA_PARAM_LENGTH>,
117    // Number of bytes in data
118    length: u16,
119    // The number of bytes needed to represent
120    // length_as_bytes
121    length_size: u8,
122}
123
124impl NinaParam for NinaAbstractParam {
125    fn length_as_bytes(&self) -> [u8; 2] {
126        self.length_as_bytes
127    }
128
129    fn data(&self) -> &[u8] {
130        self.data.as_slice()
131    }
132
133    fn length(&self) -> u16 {
134        self.length
135    }
136
137    fn length_size(&self) -> u8 {
138        self.length_size
139    }
140}
141
142impl From<NinaNoParams> for NinaAbstractParam {
143    fn from(concrete_param: NinaNoParams) -> NinaAbstractParam {
144        NinaAbstractParam {
145            length_as_bytes: [0, 0],
146            data: Vec::from_slice(concrete_param.data()).unwrap(),
147            length: concrete_param.length(),
148            length_size: 0,
149        }
150    }
151}
152
153impl From<NinaByteParam> for NinaAbstractParam {
154    fn from(concrete_param: NinaByteParam) -> NinaAbstractParam {
155        NinaAbstractParam {
156            length_as_bytes: [concrete_param.length_as_bytes()[0], 0],
157            data: Vec::from_slice(concrete_param.data()).unwrap(),
158            length: concrete_param.length(),
159            length_size: 1,
160        }
161    }
162}
163
164impl From<NinaWordParam> for NinaAbstractParam {
165    fn from(concrete_param: NinaWordParam) -> NinaAbstractParam {
166        NinaAbstractParam {
167            length_as_bytes: [concrete_param.length_as_bytes()[0], 0],
168            data: Vec::from_slice(concrete_param.data()).unwrap(),
169            length: concrete_param.length(),
170            length_size: 1,
171        }
172    }
173}
174
175impl From<NinaSmallArrayParam> for NinaAbstractParam {
176    fn from(concrete_param: NinaSmallArrayParam) -> NinaAbstractParam {
177        NinaAbstractParam {
178            length_as_bytes: [concrete_param.length_as_bytes()[0], 0],
179            data: Vec::from_slice(concrete_param.data()).unwrap(),
180            length: concrete_param.length(),
181            length_size: 1,
182        }
183    }
184}
185
186impl From<NinaLargeArrayParam> for NinaAbstractParam {
187    fn from(concrete_param: NinaLargeArrayParam) -> NinaAbstractParam {
188        NinaAbstractParam {
189            length_as_bytes: concrete_param.length_as_bytes(),
190            data: Vec::from_slice(concrete_param.data()).unwrap(),
191            length: concrete_param.length(),
192            length_size: 2,
193        }
194    }
195}
196
197impl NinaConcreteParam for NinaByteParam {
198    type LengthAsBytes = [u8; 1];
199
200    fn new(data: &str) -> Self {
201        let data_as_bytes: Vec<u8, 1> = String::from(data).into_bytes();
202        Self {
203            length: data_as_bytes.len() as u8,
204            data: data_as_bytes,
205        }
206    }
207
208    fn from_bytes(bytes: &[u8]) -> Self {
209        let mut data_as_bytes: Vec<u8, 1> = Vec::new();
210        data_as_bytes.extend_from_slice(bytes).unwrap_or_default();
211        Self {
212            length: data_as_bytes.len() as u8,
213            data: data_as_bytes,
214        }
215    }
216
217    fn data(&self) -> &[u8] {
218        self.data.as_slice()
219    }
220
221    fn length(&self) -> u16 {
222        self.length as u16
223    }
224
225    fn length_as_bytes(&self) -> Self::LengthAsBytes {
226        [self.length]
227    }
228}
229
230impl NinaConcreteParam for NinaWordParam {
231    type LengthAsBytes = [u8; 1];
232
233    fn new(data: &str) -> Self {
234        let data_as_bytes: Vec<u8, 2> = String::from(data).into_bytes();
235        Self {
236            length: data_as_bytes.len() as u8,
237            data: data_as_bytes,
238        }
239    }
240
241    fn from_bytes(bytes: &[u8]) -> Self {
242        let mut data_as_bytes: Vec<u8, 2> = Vec::new();
243        data_as_bytes.extend_from_slice(bytes).unwrap_or_default();
244        Self {
245            length: data_as_bytes.len() as u8,
246            data: data_as_bytes,
247        }
248    }
249
250    fn data(&self) -> &[u8] {
251        self.data.as_slice()
252    }
253
254    fn length(&self) -> u16 {
255        self.length as u16
256    }
257
258    fn length_as_bytes(&self) -> Self::LengthAsBytes {
259        [self.length]
260    }
261}
262
263impl NinaConcreteParam for NinaSmallArrayParam {
264    type LengthAsBytes = [u8; 1];
265
266    fn new(data: &str) -> Self {
267        let data_as_bytes: Vec<u8, MAX_NINA_PARAM_LENGTH> = String::from(data).into_bytes();
268        Self {
269            length: data_as_bytes.len() as u8,
270            data: data_as_bytes,
271        }
272    }
273
274    fn from_bytes(bytes: &[u8]) -> Self {
275        let mut data_as_bytes: Vec<u8, MAX_NINA_PARAM_LENGTH> = Vec::new();
276        data_as_bytes.extend_from_slice(bytes).unwrap_or_default();
277        Self {
278            length: data_as_bytes.len() as u8,
279            data: data_as_bytes,
280        }
281    }
282
283    fn data(&self) -> &[u8] {
284        self.data.as_slice()
285    }
286
287    fn length(&self) -> u16 {
288        self.length as u16
289    }
290
291    fn length_as_bytes(&self) -> Self::LengthAsBytes {
292        [self.length]
293    }
294}
295
296impl NinaConcreteParam for NinaLargeArrayParam {
297    type LengthAsBytes = [u8; 2];
298
299    fn new(data: &str) -> Self {
300        let data_as_bytes: Vec<u8, MAX_NINA_PARAM_LENGTH> = String::from(data).into_bytes();
301        Self {
302            length: data_as_bytes.len() as u16,
303            data: data_as_bytes,
304        }
305    }
306
307    fn from_bytes(bytes: &[u8]) -> Self {
308        let mut data_as_bytes: Vec<u8, MAX_NINA_PARAM_LENGTH> = Vec::new();
309        data_as_bytes.extend_from_slice(bytes).unwrap_or_default();
310        Self {
311            length: data_as_bytes.len() as u16,
312            data: data_as_bytes,
313        }
314    }
315
316    fn data(&self) -> &[u8] {
317        self.data.as_slice()
318    }
319
320    fn length(&self) -> u16 {
321        self.length
322    }
323
324    fn length_as_bytes(&self) -> Self::LengthAsBytes {
325        [
326            ((self.length & 0xff00) >> 8) as u8,
327            (self.length & 0xff) as u8,
328        ]
329    }
330}
331
332pub(crate) trait ProtocolInterface {
333    fn init(&mut self);
334    fn reset<D: DelayMs<u16>>(&mut self, delay: &mut D);
335    fn get_fw_version(&mut self) -> Result<FirmwareVersion, Error>;
336    fn set_passphrase(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error>;
337    fn disconnect(&mut self) -> Result<(), Error>;
338    fn get_conn_status(&mut self) -> Result<ConnectionStatus, Error>;
339    fn set_dns_config(&mut self, dns1: IpAddress, dns2: Option<IpAddress>) -> Result<(), Error>;
340    fn req_host_by_name(&mut self, hostname: &str) -> Result<u8, Error>;
341    fn get_host_by_name(&mut self) -> Result<[u8; 8], Error>;
342    fn resolve(&mut self, hostname: &str) -> Result<IpAddress, Error>;
343    fn get_socket(&mut self) -> Result<Socket, Error>;
344    fn start_client_tcp(
345        &mut self,
346        socket: Socket,
347        ip: IpAddress,
348        port: Port,
349        mode: &TransportMode,
350    ) -> Result<(), Error>;
351    fn stop_client_tcp(&mut self, socket: Socket, _mode: &TransportMode) -> Result<(), Error>;
352    fn get_client_state_tcp(&mut self, socket: Socket) -> Result<ConnectionState, Error>;
353    fn send_data(
354        &mut self,
355        data: &str,
356        socket: Socket,
357    ) -> Result<[u8; ARRAY_LENGTH_PLACEHOLDER], Error>;
358}
359
360#[derive(Debug)]
361pub(crate) struct NinaProtocolHandler<B, C> {
362    /// A Spi or I2c instance
363    pub bus: RefCell<B>,
364    /// An EspControlPins instance
365    pub control_pins: C,
366}
367
368// TODO: look at Nina Firmware code to understand conditions
369// that lead to NinaProtocolVersionMismatch
370/// Errors related to communication with NINA firmware
371#[derive(Debug, Eq, PartialEq)]
372pub enum ProtocolError {
373    /// TODO: look at Nina Firmware code to understand conditions
374    /// that lead to NinaProtocolVersionMismatch
375    NinaProtocolVersionMismatch,
376    /// A timeout occurred.
377    CommunicationTimeout,
378    /// An invalid NINA command has been sent over the data bus.
379    InvalidCommand,
380    /// An invalid number of parameters sent over the data bus.
381    InvalidNumberOfParameters,
382    /// Too many parameters sent over the data bus.
383    TooManyParameters,
384}
385
386impl Format for ProtocolError {
387    fn format(&self, fmt: Formatter) {
388        match self {
389            ProtocolError::NinaProtocolVersionMismatch => write!(fmt, "Encountered an unsupported version of the NINA protocol."),
390            ProtocolError::CommunicationTimeout => write!(fmt, "Communication with ESP32 target timed out."),
391            ProtocolError::InvalidCommand => write!(fmt, "Encountered an invalid command while communicating with ESP32 target."),
392            ProtocolError::InvalidNumberOfParameters => write!(fmt, "Encountered an unexpected number of parameters for a NINA command while communicating with ESP32 target."),
393            ProtocolError::TooManyParameters => write!(fmt, "Encountered too many parameters for a NINA command while communicating with ESP32 target.")
394        }
395    }
396}