1pub(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 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
52pub(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
88pub(crate) struct NinaByteParam {
90 length: u8,
91 data: Vec<u8, 1>,
92}
93
94pub(crate) struct NinaWordParam {
96 length: u8,
97 data: Vec<u8, 2>,
98}
99
100pub(crate) struct NinaSmallArrayParam {
102 length: u8,
103 data: Vec<u8, MAX_NINA_PARAM_LENGTH>,
104}
105
106pub(crate) struct NinaLargeArrayParam {
108 length: u16,
109 data: Vec<u8, MAX_NINA_PARAM_LENGTH>,
110}
111
112pub(crate) struct NinaAbstractParam {
113 length_as_bytes: [u8; 2],
115 data: Vec<u8, MAX_NINA_PARAM_LENGTH>,
117 length: u16,
119 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 pub bus: RefCell<B>,
364 pub control_pins: C,
366}
367
368#[derive(Debug, Eq, PartialEq)]
372pub enum ProtocolError {
373 NinaProtocolVersionMismatch,
376 CommunicationTimeout,
378 InvalidCommand,
380 InvalidNumberOfParameters,
382 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}