esp8266_wifi_serial/
network_session.rs

1use core::format_args;
2
3use embedded_hal::serial;
4use heapless::Vec;
5use simple_clock::SimpleClock;
6
7use crate::{
8    module::{CarretCondition, Module, OkCondition},
9    net::{IpAddr, SocketAddr},
10    parser::CommandResponse,
11    reader_part::{ReadData, ReaderPart},
12    Error,
13};
14
15/// Network session information.
16#[derive(Debug, PartialEq, Eq)]
17pub struct SessionInfo {
18    pub softap_address: Option<IpAddr>,
19    pub listen_address: Option<IpAddr>,
20}
21
22/// A session with the typical network operations.
23#[derive(Debug)]
24pub struct NetworkSession<Rx, Tx, C, const N: usize>
25where
26    Rx: serial::Read<u8> + 'static,
27    Tx: serial::Write<u8> + 'static,
28    C: SimpleClock,
29{
30    module: Module<Rx, Tx, C, N>,
31}
32
33impl<Rx, Tx, C, const N: usize> NetworkSession<Rx, Tx, C, N>
34where
35    Rx: serial::Read<u8> + 'static,
36    Tx: serial::Write<u8> + 'static,
37    C: SimpleClock,
38{
39    pub(crate) fn new(module: Module<Rx, Tx, C, N>) -> Self {
40        Self { module }
41    }
42
43    /// Begins to listen to the incoming TCP connections on the specified port.
44    pub fn listen(&mut self, port: u16) -> crate::Result<()> {
45        // Setup a TCP server.
46        self.module
47            .send_at_command(format_args!("AT+CIPSERVER=1,{}", port))?
48            .expect("Malformed command");
49
50        Ok(())
51    }
52
53    /// Establishes a TCP connection with the specified IP address, link identifier will
54    /// be associated with the given IP address.
55    /// Then it will be possible to [send](Self::send) data using this link ID.
56    pub fn connect(&mut self, link_id: usize, address: SocketAddr) -> crate::Result<()> {
57        self.module
58            .send_at_command(format_args!(
59                "AT+CIPSTART={},\"{}\",\"{}\",{}",
60                link_id,
61                "TCP",
62                address.ip(),
63                address.port(),
64            ))?
65            .expect("Malformed command");
66
67        Ok(())
68    }
69
70    /// Non-blocking polling to get a new network event.
71    pub fn poll_network_event(&mut self) -> nb::Result<NetworkEvent<'_, N>, Error> {
72        let reader = self.reader_mut();
73
74        let response =
75            CommandResponse::parse(reader.buf()).map(|(remainder, event)| (remainder.len(), event));
76
77        if let Some((remaining_bytes, response)) = response {
78            let pos = reader.buf().len() - remaining_bytes;
79            truncate_buf(reader.buf_mut(), pos);
80
81            let event = match response {
82                CommandResponse::Connected { link_id } => NetworkEvent::Connected { link_id },
83                CommandResponse::Closed { link_id } => NetworkEvent::Closed { link_id },
84                CommandResponse::DataAvailable { link_id, size } => {
85                    let current_pos = reader.buf().len();
86                    for _ in current_pos..size as usize {
87                        let byte = nb::block!(reader.read_byte())?;
88                        reader.buf_mut().push(byte).map_err(|_| Error::BufferFull)?;
89                    }
90
91                    NetworkEvent::DataAvailable {
92                        link_id,
93                        data: ReadData::new(reader.buf_mut()),
94                    }
95                }
96                CommandResponse::WifiDisconnect => return Err(nb::Error::WouldBlock),
97            };
98
99            return Ok(event);
100        }
101
102        reader.read_bytes()?;
103        Err(nb::Error::WouldBlock)
104    }
105
106    /// Sends data packet via the TCP socket with the link given identifier.
107    ///
108    /// # Notes
109    ///
110    /// No more than 2048 bytes can be sent at a time.
111    pub fn send<I>(&mut self, link_id: usize, bytes: I) -> crate::Result<()>
112    where
113        I: Iterator<Item = u8> + ExactSizeIterator,
114    {
115        let bytes_len = bytes.len();
116        // TODO Implement sending of the whole bytes by splitting them into chunks.
117        assert!(
118            bytes_len < 2048,
119            "Total packet size should not be greater than the 2048 bytes"
120        );
121        assert!(self.reader().buf().is_empty());
122
123        self.module
124            .write_command_fmt(format_args!("AT+CIPSEND={},{}", link_id, bytes_len))?;
125        self.module.read_until(CarretCondition)?;
126
127        for byte in bytes {
128            nb::block!(self.module.writer.write_byte(byte))?;
129        }
130
131        self.module
132            .read_until(OkCondition)?
133            .expect("Malformed command");
134        Ok(())
135    }
136
137    /// Gets network session information.
138    pub fn get_info(&mut self) -> crate::Result<SessionInfo> {
139        let info = self.module.get_network_info()?;
140        Ok(SessionInfo {
141            softap_address: info.ap_ip,
142            listen_address: info.sta_ip,
143        })
144    }
145
146    /// Returns a reference to underlying clock instance.
147    pub fn clock(&self) -> &C {
148        &self.module.clock
149    }
150
151    /// Returns an operations timeout.
152    pub fn timeout(&self) -> Option<u64> {
153        self.module.timeout
154    }
155
156    fn reader(&self) -> &ReaderPart<Rx, N> {
157        &self.module.reader
158    }
159
160    fn reader_mut(&mut self) -> &mut ReaderPart<Rx, N> {
161        &mut self.module.reader
162    }
163}
164
165/// Incoming network event.
166#[derive(Debug)]
167pub enum NetworkEvent<'a, const N: usize> {
168    /// A new peer connected.
169    Connected {
170        /// Connection identifier.
171        link_id: u16,
172    },
173    /// The connection with the peer is closed.
174    Closed {
175        /// Connection identifier.
176        link_id: u16,
177    },
178    /// Bytes received from the peer.
179    DataAvailable {
180        /// Connection identifier.
181        link_id: u16,
182        /// Received data.
183        data: ReadData<'a, N>,
184    },
185}
186
187// FIXME: Reduce complexity of this operation.
188fn truncate_buf<const N: usize>(buf: &mut Vec<u8, N>, at: usize) {
189    let buf_len = buf.len();
190
191    assert!(at <= buf_len);
192
193    for from in at..buf_len {
194        let to = from - at;
195        buf[to] = buf[from];
196    }
197
198    // Safety: `u8` is aprimitive type and doesn't have drop implementation so we can just
199    // modify the buffer length.
200    unsafe {
201        buf.set_len(buf_len - at);
202    }
203}