1use core::fmt::Write;
2
3use embedded_hal::serial;
4use simple_clock::{Deadline, ElapsedTimer, SimpleClock};
5
6use crate::{
7 error::{Error, Result},
8 parser::CifsrResponse,
9 reader_part::{ReadData, ReaderPart},
10};
11
12const RESET_DELAY_US: u64 = 3_000_000;
13
14pub type RawResponse<'a, const N: usize> = core::result::Result<ReadData<'a, N>, ReadData<'a, N>>;
16
17pub trait AtCommand: private::Sealed {
19 #[doc(hidden)]
21 fn send<Rx, Tx, C, const N: usize>(
22 self,
23 module: &mut Module<Rx, Tx, C, N>,
24 ) -> Result<RawResponse<'_, N>>
25 where
26 Rx: serial::Read<u8> + 'static,
27 Tx: serial::Write<u8> + 'static,
28 C: SimpleClock;
29}
30
31impl AtCommand for &str {
32 fn send<Rx, Tx, C, const N: usize>(
33 self,
34 module: &mut Module<Rx, Tx, C, N>,
35 ) -> Result<RawResponse<'_, N>>
36 where
37 Rx: serial::Read<u8> + 'static,
38 Tx: serial::Write<u8> + 'static,
39 C: SimpleClock,
40 {
41 module.send_at_command_str(self)
42 }
43}
44
45impl AtCommand for core::fmt::Arguments<'_> {
46 fn send<Rx, Tx, C, const N: usize>(
47 self,
48 module: &mut Module<Rx, Tx, C, N>,
49 ) -> Result<RawResponse<'_, N>>
50 where
51 Rx: serial::Read<u8> + 'static,
52 Tx: serial::Write<u8> + 'static,
53 C: SimpleClock,
54 {
55 module.send_at_command_fmt(self)
56 }
57}
58
59const NEWLINE: &[u8] = b"\r\n";
60
61#[derive(Debug)]
65pub struct Module<Rx, Tx, C, const N: usize>
66where
67 Rx: serial::Read<u8> + 'static,
68 Tx: serial::Write<u8> + 'static,
69 C: SimpleClock,
70{
71 pub(crate) reader: ReaderPart<Rx, N>,
72 pub(crate) writer: WriterPart<Tx>,
73 pub(crate) clock: C,
74 pub(crate) timeout: Option<u64>,
75}
76
77impl<'a, Rx, Tx, C, const N: usize> Module<Rx, Tx, C, N>
78where
79 Rx: serial::Read<u8> + 'static,
80 Tx: serial::Write<u8> + 'static,
81 C: SimpleClock,
82{
83 pub fn new(rx: Rx, tx: Tx, clock: C) -> Result<Self> {
85 let mut module = Self {
86 reader: ReaderPart::new(rx),
87 writer: WriterPart { tx },
88 clock,
89 timeout: None,
90 };
91 module.init()?;
92 Ok(module)
93 }
94
95 fn init(&mut self) -> Result<()> {
96 self.disable_echo()?;
97 Ok(())
98 }
99
100 fn reset_cmd(&mut self) -> Result<()> {
101 self.write_command(b"AT+RST")?;
102
103 let timer = ElapsedTimer::new(&self.clock);
105 while timer.elapsed() < RESET_DELAY_US {
106 core::hint::spin_loop();
107 }
108
109 self.read_until(ReadyCondition)?;
110
111 Ok(())
112 }
113
114 pub fn set_timeout(&mut self, us: Option<u64>) {
118 self.timeout = us;
119 }
120
121 pub fn reset(&mut self) -> Result<()> {
123 self.reset_cmd().ok();
125 for _ in 0..100 {
127 self.send_at_command_str("ATE1").ok();
128 }
129
130 self.disable_echo()?;
131 Ok(())
132 }
133
134 pub fn send_at_command<T: AtCommand>(&mut self, cmd: T) -> Result<RawResponse<'_, N>> {
136 cmd.send(self)
137 }
138
139 fn send_at_command_str(&mut self, cmd: &str) -> Result<RawResponse<'_, N>> {
140 self.write_command(cmd.as_ref())?;
141 self.read_until(OkCondition)
142 }
143
144 fn send_at_command_fmt(&mut self, args: core::fmt::Arguments) -> Result<RawResponse<'_, N>> {
145 self.write_command_fmt(args)?;
146 self.read_until(OkCondition)
147 }
148
149 fn disable_echo(&mut self) -> Result<()> {
150 self.send_at_command_str("ATE0").map(drop)
151 }
152
153 fn write_command(&mut self, cmd: &[u8]) -> Result<()> {
154 self.writer.write_bytes(cmd)?;
155 self.writer.write_bytes(NEWLINE)
156 }
157
158 pub(crate) fn write_command_fmt(&mut self, args: core::fmt::Arguments) -> Result<()> {
159 self.writer.write_fmt(args)?;
160 self.writer.write_bytes(NEWLINE)
161 }
162
163 pub(crate) fn read_until<'b, T>(&'b mut self, condition: T) -> Result<T::Output>
164 where
165 T: Condition<'b, N>,
166 {
167 let clock = &self.clock;
168 let deadline = self.timeout.map(|timeout| Deadline::new(clock, timeout));
169
170 loop {
171 match self.reader.read_bytes() {
172 Ok(_) => {
173 if self.reader.buf().is_full() {
174 return Err(Error::BufferFull);
175 }
176 }
177 Err(nb::Error::WouldBlock) => {}
178 Err(nb::Error::Other(_)) => {
179 return Err(Error::ReadBuffer);
180 }
181 };
182
183 if condition.is_performed(&self.reader.buf()) {
184 break;
185 }
186
187 if let Some(deadline) = deadline.as_ref() {
188 deadline.reached().map_err(|_| Error::Timeout)?;
189 }
190 }
191
192 let read_data = ReadData::new(self.reader.buf_mut());
193 Ok(condition.output(read_data))
194 }
195
196 pub(crate) fn get_network_info(&mut self) -> Result<CifsrResponse> {
197 let res = self.send_at_command("AT+CIFSR")?;
199 let raw_resp = res.expect("Malformed command");
200
201 let resp = CifsrResponse::parse(&raw_resp)
202 .unwrap_or_else(|| panic!("Unable to parse response: {:?}", raw_resp))
203 .1;
204 Ok(resp)
205 }
206}
207
208pub(crate) trait Condition<'a, const N: usize>: Copy {
209 type Output: 'a;
210
211 fn is_performed(self, buf: &[u8]) -> bool;
212
213 fn output(self, buf: ReadData<'a, N>) -> Self::Output;
214}
215
216#[derive(Clone, Copy)]
217struct ReadyCondition;
218
219impl ReadyCondition {
220 const MSG: &'static [u8] = b"ready\r\n";
221}
222
223impl<'a, const N: usize> Condition<'a, N> for ReadyCondition {
224 type Output = ReadData<'a, N>;
225
226 fn is_performed(self, buf: &[u8]) -> bool {
227 buf.ends_with(Self::MSG)
228 }
229
230 fn output(self, mut buf: ReadData<'a, N>) -> Self::Output {
231 buf.subslice(0, buf.len() - Self::MSG.len());
232 buf
233 }
234}
235
236#[derive(Clone, Copy)]
237pub(crate) struct CarretCondition;
238
239impl CarretCondition {
240 const MSG: &'static [u8] = b"> ";
241}
242
243impl<'a, const N: usize> Condition<'a, N> for CarretCondition {
244 type Output = ReadData<'a, N>;
245
246 fn is_performed(self, buf: &[u8]) -> bool {
247 buf.ends_with(Self::MSG)
248 }
249
250 fn output(self, mut buf: ReadData<'a, N>) -> Self::Output {
251 buf.subslice(0, buf.len() - Self::MSG.len());
252 buf
253 }
254}
255
256#[derive(Clone, Copy)]
257pub(crate) struct OkCondition;
258
259impl OkCondition {
260 const OK: &'static [u8] = b"OK\r\n";
261 const ERROR: &'static [u8] = b"ERROR\r\n";
262 const FAIL: &'static [u8] = b"FAIL\r\n";
263}
264
265impl<'a, const N: usize> Condition<'a, N> for OkCondition {
267 type Output = RawResponse<'a, N>;
268
269 fn is_performed(self, buf: &[u8]) -> bool {
270 buf.ends_with(Self::OK) || buf.ends_with(Self::ERROR) || buf.ends_with(Self::FAIL)
271 }
272
273 fn output(self, mut buf: ReadData<'a, N>) -> Self::Output {
274 if buf.ends_with(Self::OK) {
275 buf.subslice(0, buf.len() - Self::OK.len());
276 Ok(buf)
277 } else if buf.ends_with(Self::ERROR) {
278 buf.subslice(0, buf.len() - Self::ERROR.len());
279 Err(buf)
280 } else {
281 buf.subslice(0, buf.len() - Self::FAIL.len());
282 Err(buf)
283 }
284 }
285}
286
287#[derive(Debug)]
288pub struct WriterPart<Tx> {
289 tx: Tx,
290}
291
292impl<Tx> WriterPart<Tx>
293where
294 Tx: serial::Write<u8> + 'static,
295{
296 fn write_fmt(&mut self, args: core::fmt::Arguments) -> Result<()> {
297 let writer = &mut self.tx as &mut (dyn serial::Write<u8, Error = Tx::Error> + 'static);
298 writer.write_fmt(args).map_err(|_| Error::WriteBuffer)
299 }
300
301 pub(crate) fn write_byte(&mut self, byte: u8) -> nb::Result<(), Error> {
302 self.tx
303 .write(byte)
304 .map_err(|err| err.map(|_| Error::WriteBuffer))
305 }
306
307 fn write_bytes(&mut self, bytes: &[u8]) -> Result<()> {
308 for byte in bytes.iter() {
309 nb::block!(self.write_byte(*byte))?;
310 }
311 Ok(())
312 }
313}
314
315mod private {
316 pub trait Sealed {}
317
318 impl Sealed for &str {}
319 impl Sealed for core::fmt::Arguments<'_> {}
320}