1#![no_std]
2
3use embedded_hal as hal;
4
5use nb::block;
6
7use core::cmp::min;
8use core::fmt::{self};
9use arrayvec::{CapacityError, ArrayString};
10use itoa;
11
12mod serial;
13mod timing;
14
15pub use timing::{LongTimer, Second, Millisecond};
16
17const AT_RESPONSE_BUFFER_SIZE: usize = 13;
23
24#[derive(Debug, PartialEq)]
31pub enum ATResponse {
32 Ok,
33 Error,
34 Busy,
35 WiFiGotIp,
36}
37
38#[derive(Debug)]
44pub enum Error<R, T, P> {
45 TxError(T),
47 RxError(R),
49 PinError(P),
51 UnexpectedResponse(ATResponse),
53 Fmt(fmt::Error),
55 Capacity(CapacityError)
57}
58impl<R,T, P> From<fmt::Error> for Error<R,T, P> {
59 fn from(other: fmt::Error) -> Error<R,T, P> {
60 Error::Fmt(other)
61 }
62}
63impl<R,T,ErrType,P> From<CapacityError<ErrType>> for Error<R,T,P> {
64 fn from(other: CapacityError<ErrType>) -> Error<R,T,P> {
65 Error::Capacity(other.simplify())
66 }
67}
68
69#[derive(Debug)]
74pub enum TransmissionStep {
75 Connect,
76 Send,
77 Close
78}
79#[derive(Debug)]
83pub struct TransmissionError<R, T, P> {
84 step: TransmissionStep,
85 cause: Error<R, T, P>
86}
87
88impl<R, T, P> TransmissionError<R, T, P> {
89 pub fn try_step<RetType>(step: TransmissionStep, cause: Result<RetType, Error<R, T, P>>)
90 -> Result<RetType, Self>
91 {
92 cause.map_err(|e| {
93 Self {
94 step,
95 cause: e
96 }
97 })
98 }
99}
100
101
102pub enum ConnectionType {
103 Tcp,
104 Udp
105}
106impl ConnectionType {
107 pub fn as_str(&self) -> &str {
108 match *self {
109 ConnectionType::Tcp => "TCP",
110 ConnectionType::Udp => "UDP"
111 }
112 }
113}
114
115
116macro_rules! return_type {
117 ($ok:ty) => {
118 Result<$ok, Error<serial::Error<Rx::Error>, Tx::Error, Rst::Error>>
119 }
120}
121
122macro_rules! transmission_return_type {
123 ($ok:ty) => {
124 Result<$ok, TransmissionError<serial::Error<Rx::Error>, Tx::Error, Rst::Error>>
125 }
126}
127
128
129const STARTUP_TIMEOUT: Second = Second(10);
133const DEFAULT_TIMEOUT: Second = Second(5);
134
135
136pub struct Esp8266<Tx, Rx, Timer, Rst>
140where Tx: hal::serial::Write<u8>,
141 Rx: hal::serial::Read<u8>,
142 Timer: LongTimer,
143 Rst: hal::digital::v2::OutputPin
144{
145 tx: Tx,
146 rx: Rx,
147 timer: Timer,
148 chip_enable_pin: Rst
149}
150
151impl<Tx, Rx, Timer, Rst> Esp8266<Tx, Rx, Timer, Rst>
152where Tx: hal::serial::Write<u8>,
153 Rx: hal::serial::Read<u8>,
154 Timer: LongTimer,
155 Rst: hal::digital::v2::OutputPin,
156{
157 pub fn new(tx: Tx, rx: Rx, timer: Timer, chip_enable_pin: Rst)
166 -> return_type!(Self)
167 {
168 let mut result = Self {tx, rx, timer, chip_enable_pin};
169
170 result.reset()?;
171
172 Ok(result)
173 }
174
175 pub fn send_data(
176 &mut self,
177 connection_type: ConnectionType,
178 address: &str,
179 port: u16,
180 data: &str
181 ) -> transmission_return_type!(())
182 {
183 let tcp_start_result = self.start_tcp_connection(connection_type, address, port);
185 TransmissionError::try_step(TransmissionStep::Connect, tcp_start_result)?;
186
187 TransmissionError::try_step(TransmissionStep::Send, self.transmit_data(data))?;
188
189 TransmissionError::try_step(TransmissionStep::Close, self.close_connection())
190 }
191
192 pub fn close_connection(&mut self) -> return_type!(()) {
193 self.send_at_command("+CIPCLOSE")?;
194 self.wait_for_ok(DEFAULT_TIMEOUT.into())
195 }
196
197 pub fn power_down(&mut self) -> return_type!(()) {
201 self.chip_enable_pin.set_low().map_err(Error::PinError)
202 }
203
204 pub fn reset(&mut self) -> return_type!(()) {
208 self.power_down()?;
209 self.timer.start(Millisecond(10));
210 block!(self.timer.wait()).unwrap();
211 self.power_up()
212 }
213
214 pub fn power_up(&mut self) -> return_type!(()) {
218 self.chip_enable_pin.set_high().map_err(Error::PinError)?;
219
220 let mut error_count = 0;
223 loop {
224 match self.wait_for_got_ip(STARTUP_TIMEOUT.into()) {
225 Ok(()) => break,
226 e @ Err(Error::RxError(serial::Error::TimedOut)) => return e,
227 e => {
228 if error_count < 255 {
229 error_count += 1;
230 continue
231 }
232 else {
233 return e
234 }
235 }
236 }
237 }
238
239 self.send_at_command("E0")?;
241 self.wait_for_ok(DEFAULT_TIMEOUT.into())?;
242
243 Ok(())
244 }
245
246 pub fn pull_some_current(&mut self) -> return_type!(()) {
247 self.chip_enable_pin.set_high().map_err(Error::PinError)?;
248
249 self.timer.start(Millisecond(500));
250 block!(self.timer.wait()).unwrap();
251 self.chip_enable_pin.set_low().map_err(Error::PinError)
252 }
253
254 fn transmit_data(&mut self, data: &str) -> return_type!(()) {
255 self.start_transmission(data.len())?;
256 self.wait_for_prompt(DEFAULT_TIMEOUT.into())?;
257 self.send_raw(data.as_bytes())?;
258 self.wait_for_ok(DEFAULT_TIMEOUT.into())
259 }
260
261 fn start_tcp_connection (
262 &mut self,
263 connection_type: ConnectionType,
264 address: &str,
265 port: u16
266 ) -> return_type!(())
267 {
268 const PORT_STRING_LENGTH: usize = 5;
270 let mut port_str = ArrayString::<[_;PORT_STRING_LENGTH]>::new();
271 itoa::fmt(&mut port_str, port)?;
273
274 self.send_raw("AT+CIPSTART=\"".as_bytes())?;
275 self.send_raw(connection_type.as_str().as_bytes())?;
276 self.send_raw("\",\"".as_bytes())?;
277 self.send_raw(address.as_bytes())?;
278 self.send_raw("\",".as_bytes())?;
279 self.send_raw(port_str.as_bytes())?;
280 self.send_raw("\r\n".as_bytes())?;
281 self.wait_for_ok(DEFAULT_TIMEOUT.into())
282 }
283
284 fn start_transmission(&mut self, message_length: usize) -> return_type!(()) {
285 assert!(message_length < 2048);
287 let mut length_buffer = ArrayString::<[_; 4]>::new();
288 itoa::fmt(&mut length_buffer, message_length)?;
290
291 self.send_raw(b"AT+CIPSEND=")?;
292 self.send_raw(length_buffer.as_bytes())?;
293 self.send_raw(b"\r\n")?;
294 Ok(())
295 }
296
297 fn send_at_command(&mut self, command: &str) -> return_type!(()) {
301 self.send_raw(b"AT")?;
302 self.send_raw(command.as_bytes())?;
303 self.send_raw(b"\r\n")?;
304 Ok(())
305 }
306
307 fn wait_for_at_response(
308 &mut self,
309 expected_response: &ATResponse,
310 timeout: Millisecond
311 ) -> return_type!(()) {
312 let mut buffer = [0; AT_RESPONSE_BUFFER_SIZE];
313 let response = serial::read_until_message(
314 &mut self.rx,
315 &mut self.timer,
316 timeout,
317 &mut buffer,
318 &parse_at_response
319 );
320
321 match response {
322 Ok(ref resp) if resp == expected_response => {
323 Ok(())
324 },
325 Ok(other) => {
326 Err(Error::UnexpectedResponse(other))
327 }
328 Err(e) => {
329 Err(Error::RxError(e))
330 }
331 }
332 }
333
334 fn wait_for_ok(&mut self, timeout: Millisecond) -> return_type!(()) {
335 self.wait_for_at_response(&ATResponse::Ok, timeout)
336 }
337 fn wait_for_got_ip(&mut self, timeout: Millisecond) -> return_type!(()) {
338 self.wait_for_at_response(&ATResponse::WiFiGotIp, timeout)
339 }
340
341 fn wait_for_prompt(&mut self, timeout: Millisecond) -> return_type!(()) {
342 let mut buffer = [0; 1];
343 let result = serial::read_until_message(
344 &mut self.rx,
345 &mut self.timer,
346 timeout,
347 &mut buffer,
348 &|buf, _ptr| {
349 if buf[0] == '>' as u8 {
350 Some(())
351 }
352 else {
353 None
354 }
355 }
356 );
357 match result {
358 Ok(_) => Ok(()),
359 Err(e) => Err(Error::RxError(e))
360 }
361 }
362
363 fn send_raw(&mut self, bytes: &[u8]) -> return_type!(()) {
364 match serial::write_all(&mut self.tx, bytes) {
365 Ok(_) => Ok(()),
366 Err(e) => Err(Error::TxError(e))
367 }
368 }
369}
370
371pub fn parse_at_response(buffer: &[u8], offset: usize) -> Option<ATResponse> {
376 if compare_circular_buffer(buffer, offset, "OK\r\n".as_bytes()) {
377 Some(ATResponse::Ok)
378 }
379 else if compare_circular_buffer(buffer, offset, "ERROR\r\n".as_bytes()) {
380 Some(ATResponse::Error)
381 }
382 else if compare_circular_buffer(buffer, offset, "busy p...\r\n".as_bytes()) {
383 Some(ATResponse::Busy)
384 }
385 else if compare_circular_buffer(buffer, offset, "WIFI GOT IP\r\n".as_bytes()) {
386 Some(ATResponse::WiFiGotIp)
387 }
388 else {
389 None
390 }
391}
392
393pub fn compare_circular_buffer(
405 circular_buffer: &[u8],
406 offset: usize,
407 comparison: &[u8]
408) -> bool
409{
410 let comparison_length = min(circular_buffer.len(), comparison.len());
411 for i in 0..comparison_length {
412 let circular_index = (circular_buffer.len() + offset - 1 - i) % circular_buffer.len();
415 let comparison_index = comparison.len() - 1 - i;
416 if circular_buffer[circular_index] != comparison[comparison_index] {
417 return false;
418 }
419 }
420 true
421}
422