drogue_esp8266/
adapter.rs

1use embedded_hal::{digital::v2::OutputPin, serial::Read, serial::Write};
2
3use crate::protocol::{Command, ConnectionType, FirmwareInfo, IpAddresses, Response, WifiConnectionFailure, WiFiMode, ResolverAddresses};
4
5use heapless::{consts::{U16, U2}, spsc::{Consumer, Queue}, String};
6
7use log::info;
8
9use crate::adapter::AdapterError::UnableToInitialize;
10use crate::ingress::Ingress;
11use crate::network::Esp8266IpNetworkDriver;
12use core::fmt::Debug;
13use nom::lib::std::fmt::Formatter;
14use crate::protocol::Response::IpAddress;
15use drogue_network::dns::DnsError;
16use drogue_network::addr::{Ipv4Addr, HostAddr, HostSocketAddr};
17
18#[derive(Debug)]
19pub enum AdapterError {
20    UnableToInitialize,
21    NoAvailableSockets,
22    Timeout,
23    UnableToOpen,
24    UnableToClose,
25    WriteError,
26    ReadError,
27    InvalidSocket,
28}
29
30#[derive(Debug)]
31enum SocketState {
32    HalfClosed,
33    Closed,
34    Open,
35    Connected,
36}
37
38type Initialized<'a, Tx, Rx> = (Adapter<'a, Tx>, Ingress<'a, Rx>);
39
40/// Initialize an ESP8266 board for usage as a Wifi-offload device.
41///
42/// * tx: Serial transmitter.
43/// * rx: Serial receiver.
44/// * enable_pin: Pin connected to the ESP's `en` pin.
45/// * reset_pin: Pin connect to the ESP's `rst` pin.
46/// * response_queue: Queue for inbound AT command responses.
47/// * notification_queue: Queue for inbound unsolicited AT notification messages.
48pub fn initialize<'a, Tx, Rx, EnablePin, ResetPin>(
49    mut tx: Tx,
50    mut rx: Rx,
51    enable_pin: &mut EnablePin,
52    reset_pin: &mut ResetPin,
53    response_queue: &'a mut Queue<Response, U2>,
54    notification_queue: &'a mut Queue<Response, U16>,
55) -> Result<Initialized<'a, Tx, Rx>, AdapterError>
56    where
57        Tx: Write<u8>,
58        Rx: Read<u8>,
59        EnablePin: OutputPin,
60        ResetPin: OutputPin,
61{
62    let mut buffer: [u8; 1024] = [0; 1024];
63    let mut pos = 0;
64
65    const READY: [u8; 7] = *b"ready\r\n";
66
67    let mut counter = 0;
68
69    enable_pin
70        .set_high()
71        .map_err(|_| AdapterError::UnableToInitialize)?;
72    reset_pin
73        .set_high()
74        .map_err(|_| AdapterError::UnableToInitialize)?;
75
76    log::debug!("waiting for adapter to become ready");
77
78    loop {
79        let result = rx.read();
80        match result {
81            Ok(c) => {
82                buffer[pos] = c;
83                pos += 1;
84                if pos >= READY.len() && buffer[pos - READY.len()..pos] == READY {
85                    log::debug!("adapter is ready");
86                    disable_echo(&mut tx, &mut rx)?;
87                    enable_mux(&mut tx, &mut rx)?;
88                    set_recv_mode(&mut tx, &mut rx)?;
89                    return Ok(build_adapter_and_ingress(
90                        tx,
91                        rx,
92                        response_queue,
93                        notification_queue,
94                    ));
95                }
96            }
97            Err(nb::Error::WouldBlock) => {
98                continue;
99            }
100            Err(_) if counter > 10_000 => {
101                break;
102            }
103            Err(_) => {
104                counter += 1;
105            }
106        }
107    }
108
109    Err(AdapterError::UnableToInitialize)
110}
111
112fn build_adapter_and_ingress<'a, Tx, Rx>(
113    tx: Tx,
114    rx: Rx,
115    response_queue: &'a mut Queue<Response, U2>,
116    notification_queue: &'a mut Queue<Response, U16>,
117) -> Initialized<'a, Tx, Rx>
118    where
119        Tx: Write<u8>,
120        Rx: Read<u8>,
121{
122    let (response_producer, response_consumer) = response_queue.split();
123    let (notification_producer, notification_consumer) = notification_queue.split();
124    (
125        Adapter {
126            tx,
127            response_consumer,
128            notification_consumer,
129            sockets: initialize_sockets(),
130        },
131        Ingress::new(rx, response_producer, notification_producer),
132    )
133}
134
135fn initialize_sockets() -> [Socket; 5] {
136    [
137        Socket::new(),
138        Socket::new(),
139        Socket::new(),
140        Socket::new(),
141        Socket::new(),
142    ]
143}
144
145fn write_command<Tx>(tx: &mut Tx, cmd: &[u8]) -> Result<(), Tx::Error>
146    where
147        Tx: Write<u8>,
148{
149    for b in cmd.iter() {
150        nb::block!(tx.write(*b))?;
151    }
152    Ok(())
153}
154
155fn disable_echo<Tx, Rx>(tx: &mut Tx, rx: &mut Rx) -> Result<(), AdapterError>
156    where
157        Tx: Write<u8>,
158        Rx: Read<u8>,
159{
160    write_command(tx, b"ATE0\r\n").map_err(|_| UnableToInitialize)?;
161    Ok(wait_for_ok(rx).map_err(|_| UnableToInitialize)?)
162}
163
164fn enable_mux<Tx, Rx>(tx: &mut Tx, rx: &mut Rx) -> Result<(), AdapterError>
165    where
166        Tx: Write<u8>,
167        Rx: Read<u8>,
168{
169    write_command(tx, b"AT+CIPMUX=1\r\n").map_err(|_| UnableToInitialize)?;
170    Ok(wait_for_ok(rx).map_err(|_| UnableToInitialize)?)
171}
172
173fn set_recv_mode<Tx, Rx>(tx: &mut Tx, rx: &mut Rx) -> Result<(), AdapterError>
174    where
175        Tx: Write<u8>,
176        Rx: Read<u8>,
177{
178    write_command(tx, b"AT+CIPRECVMODE=1\r\n").map_err(|_| UnableToInitialize)?;
179    Ok(wait_for_ok(rx).map_err(|_| UnableToInitialize)?)
180}
181
182fn wait_for_ok<Rx>(rx: &mut Rx) -> Result<(), Rx::Error>
183    where
184        Rx: Read<u8>,
185{
186    let mut buf: [u8; 64] = [0; 64];
187    let mut pos = 0;
188
189    loop {
190        let b = nb::block!(rx.read())?;
191        buf[pos] = b;
192        pos += 1;
193        if buf[0..pos].ends_with(b"OK\r\n") {
194            return Ok(());
195        }
196    }
197}
198
199struct Socket {
200    state: SocketState,
201    available: usize,
202}
203
204impl Socket {
205    fn new() -> Self {
206        Self {
207            state: SocketState::Closed,
208            available: 0,
209        }
210    }
211
212    #[allow(dead_code)]
213    pub fn is_closed(&self) -> bool {
214        matches!(self.state, SocketState::Closed)
215    }
216
217    #[allow(dead_code)]
218    pub fn is_half_closed(&self) -> bool {
219        matches!(self.state, SocketState::HalfClosed)
220    }
221
222    #[allow(dead_code)]
223    pub fn is_open(&self) -> bool {
224        matches!(self.state, SocketState::Open)
225    }
226
227    #[allow(dead_code)]
228    pub fn is_connected(&self) -> bool {
229        matches!(self.state, SocketState::Connected)
230    }
231}
232
233pub struct Adapter<'a, Tx>
234    where
235        Tx: Write<u8>,
236{
237    tx: Tx,
238    response_consumer: Consumer<'a, Response, U2>,
239    notification_consumer: Consumer<'a, Response, U16>,
240    sockets: [Socket; 5],
241}
242
243impl<'a, Tx> Debug for Adapter<'a, Tx>
244    where
245        Tx: Write<u8>,
246{
247    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
248        f.debug_struct("Adapter")
249            .finish()
250    }
251}
252
253impl<'a, Tx> Adapter<'a, Tx>
254    where
255        Tx: Write<u8>,
256{
257    fn send<'c>(&mut self, command: Command<'c>) -> Result<Response, AdapterError> {
258        let bytes = command.as_bytes();
259
260        info!(
261            "writing command {}",
262            core::str::from_utf8(bytes.as_bytes()).unwrap()
263        );
264        for b in bytes.as_bytes().iter() {
265            nb::block!(self.tx.write(*b)).map_err(|_| AdapterError::WriteError)?;
266        }
267        nb::block!(self.tx.write(b'\r')).map_err(|_| AdapterError::WriteError)?;
268        nb::block!(self.tx.write(b'\n')).map_err(|_| AdapterError::WriteError)?;
269        self.wait_for_response()
270    }
271
272    fn wait_for_response(&mut self) -> Result<Response, AdapterError> {
273        loop {
274            // busy loop until a response is received.
275            if let Some(response) = self.response_consumer.dequeue() {
276                return Ok(response);
277            }
278        }
279    }
280
281    /// Retrieve the firmware version for the adapter.
282    pub fn get_firmware_info(&mut self) -> Result<FirmwareInfo, ()> {
283        let command = Command::QueryFirmwareInfo;
284
285        if let Ok(Response::FirmwareInfo(info)) = self.send(command) {
286            return Ok(info);
287        }
288
289        Err(())
290    }
291
292    /// Get the board's IP address. Only valid if connected to an access-point.
293    pub fn get_ip_address(&mut self) -> Result<IpAddresses, ()> {
294        let command = Command::QueryIpAddress;
295
296        if let Ok(Response::IpAddresses(addresses)) = self.send(command) {
297            return Ok(addresses);
298        }
299
300        Err(())
301    }
302
303    /// Set the mode of the Wi-Fi stack
304    ///
305    /// Must be done before joining an access point.
306    pub fn set_mode(&mut self, mode: WiFiMode) -> Result<(), ()> {
307        let command = Command::SetMode(mode);
308
309        match self.send(command) {
310            Ok(Response::Ok) => Ok(()),
311            _ => Err(()),
312        }
313    }
314
315    /// Join a wifi access-point.
316    ///
317    /// The board will expect to obtain an IP address from DHCP.
318    ///
319    /// * `ssid`: The access-point's SSID to join
320    /// * `password`: The password for the access-point.
321    pub fn join<'c>(
322        &mut self,
323        ssid: &'c str,
324        password: &'c str,
325    ) -> Result<(), WifiConnectionFailure> {
326        let command = Command::JoinAp { ssid, password };
327
328        match self.send(command) {
329            Ok(Response::Ok) => {
330                Ok(())
331            }
332            Ok(Response::WifiConnectionFailure(reason)) => {
333                Err(reason)
334            }
335            _ => {
336                Err(WifiConnectionFailure::ConnectionFailed)
337            }
338        }
339    }
340
341    pub fn query_dns_resolvers(&mut self) -> Result<ResolverAddresses, ()> {
342        let command = Command::QueryDnsResolvers;
343        if let Ok(Response::Resolvers(resolvers)) = self.send(command) {
344            Ok(resolvers)
345        } else {
346            Err(())
347        }
348    }
349
350    pub fn set_dns_resolvers(&mut self, resolver1: Ipv4Addr, resolver2: Option<Ipv4Addr>) -> Result<(), ()> {
351        let command = Command::SetDnsResolvers(
352            ResolverAddresses {
353                resolver1,
354                resolver2
355            }
356        );
357
358        if let Ok(Response::Ok) = self.send(command) {
359            Ok(())
360        } else {
361            Err(())
362        }
363    }
364
365    /// Consume the adapter and produce a `NetworkStack`.
366    pub fn into_network_stack(self) -> Esp8266IpNetworkDriver<'a, Tx> {
367        Esp8266IpNetworkDriver::new(self)
368    }
369
370    // ----------------------------------------------------------------------
371    // TCP Stack
372    // ----------------------------------------------------------------------
373
374    fn process_notifications(&mut self) {
375        while let Some(response) = self.notification_consumer.dequeue() {
376            match response {
377                Response::DataAvailable { link_id, len } => {
378                    self.sockets[link_id].available += len;
379                }
380                Response::Connect(_) => {}
381                Response::Closed(link_id) => {
382                    match self.sockets[link_id].state {
383                        SocketState::HalfClosed => {
384                            self.sockets[link_id].state = SocketState::Closed;
385                        }
386                        SocketState::Open | SocketState::Connected => {
387                            self.sockets[link_id].state = SocketState::HalfClosed;
388                        }
389                        SocketState::Closed => {
390                            // nothing
391                        }
392                    }
393                }
394                _ => { /* ignore */ }
395            }
396        }
397    }
398
399    pub(crate) fn open(&mut self) -> Result<usize, AdapterError> {
400        if let Some((index, socket)) = self
401            .sockets
402            .iter_mut()
403            .enumerate()
404            .find(|(_, e)| e.is_closed())
405        {
406            socket.state = SocketState::Open;
407            return Ok(index);
408        }
409
410        Err(AdapterError::NoAvailableSockets)
411    }
412
413    pub(crate) fn close(&mut self, link_id: usize) -> Result<(), AdapterError> {
414        let command = Command::CloseConnection(link_id);
415        match self.send(command) {
416            Ok(Response::Ok) | Ok(Response::UnlinkFail) => {
417                self.sockets[link_id].state = SocketState::Closed;
418                Ok(())
419            },
420            _=> Err(AdapterError::UnableToClose),
421        }
422    }
423
424    pub(crate) fn connect_tcp(
425        &mut self,
426        link_id: usize,
427        remote: HostSocketAddr,
428    ) -> Result<(), AdapterError> {
429        let command = Command::StartConnection(link_id, ConnectionType::TCP, remote.as_socket_addr());
430        if let Ok(Response::Connect(..)) = self.send(command) {
431            self.sockets[link_id].state = SocketState::Connected;
432            return Ok(());
433        }
434
435        Err(AdapterError::UnableToOpen)
436    }
437
438    pub(crate) fn write(
439        &mut self,
440        link_id: usize,
441        buffer: &[u8],
442    ) -> nb::Result<usize, AdapterError> {
443        self.process_notifications();
444
445        let command = Command::Send {
446            link_id,
447            len: buffer.len(),
448        };
449
450        if let Ok(response) = self.send(command) {
451            if let Response::Ok = response {
452                if let Ok(response) = self.wait_for_response() {
453                    if let Response::ReadyForData = response {
454                        for b in buffer.iter() {
455                            nb::block!(self.tx.write(*b))
456                                .map_err(|_| nb::Error::from(AdapterError::WriteError))?;
457                        }
458                        let mut data_sent: Option<usize> = None;
459                        loop {
460                            match self.wait_for_response() {
461                                Ok(Response::ReceivedDataToSend(len)) => {
462                                    data_sent.replace(len);
463                                }
464                                Ok(Response::SendOk) => {
465                                    return Ok(data_sent.unwrap_or_default());
466                                }
467                                _ => {
468                                    break; // unknown response
469                                }
470                            }
471                        }
472                    }
473                }
474            }
475        }
476        Err(nb::Error::from(AdapterError::WriteError))
477    }
478
479    pub(crate) fn read(
480        &mut self,
481        link_id: usize,
482        buffer: &mut [u8],
483    ) -> nb::Result<usize, AdapterError> {
484        self.process_notifications();
485
486        if matches!( self.sockets[link_id].state, SocketState::Closed ) {
487            return Err(nb::Error::Other(AdapterError::InvalidSocket));
488        }
489
490        if self.sockets[link_id].available == 0 {
491            if matches!( self.sockets[link_id].state, SocketState::HalfClosed ) {
492                return Err(nb::Error::Other(AdapterError::InvalidSocket));
493            } else {
494                return Err(nb::Error::WouldBlock);
495            }
496        }
497
498        let mut actual_len = buffer.len();
499        if actual_len > crate::BUFFER_LEN {
500            actual_len = crate::BUFFER_LEN;
501        }
502
503        let command = Command::Receive {
504            link_id,
505            len: actual_len,
506        };
507
508        match self.send(command) {
509            Ok(Response::DataReceived(inbound, len)) => {
510                for (i, b) in inbound[0..len].iter().enumerate() {
511                    buffer[i] = *b;
512                }
513                self.sockets[link_id].available -= len;
514                Ok(len)
515            }
516            Ok(Response::Ok) => Err(nb::Error::WouldBlock),
517            _=> Err(nb::Error::Other(AdapterError::ReadError)),
518        }
519    }
520
521    pub(crate) fn is_connected(&self, link_id: usize) -> Result<bool, AdapterError> {
522        Ok(match self.sockets[link_id].state {
523            SocketState::HalfClosed => {
524                self.sockets[link_id].available > 0
525            }
526            SocketState::Closed => {
527                false
528            }
529            SocketState::Open => {
530                false
531            }
532            SocketState::Connected => {
533                true
534            }
535        })
536    }
537
538    // ----------------------------------------------------------------------
539    // DNS
540    // ----------------------------------------------------------------------
541
542    pub(crate) fn get_host_by_name(&mut self, hostname: &str) -> Result<HostAddr, DnsError> {
543        let command = Command::GetHostByName {
544            hostname
545        };
546
547        if let Ok(IpAddress(ip_addr)) = self.send(command) {
548            Ok(
549                HostAddr::new(ip_addr, Some(String::from(hostname)))
550            )
551        } else {
552            Err(DnsError::NoSuchHost)
553        }
554    }
555}