rust: esp8266at: Wrap parsing of responses to avoid exposing dependency on nom

Makes it possible to switch parser later for whatever reason,
it's undesirable to expose these implementation details to clients.
This commit is contained in:
Wladimir J. van der Laan 2019-06-01 23:04:31 +00:00
parent d20791330d
commit 610af76592
5 changed files with 41 additions and 27 deletions

View File

@ -2,7 +2,7 @@ use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use esp8266at::response::parse_response;
use esp8266at::response::{parse,ParseResult};
fn main() {
let f = File::open("data/parses.txt").unwrap();
@ -13,14 +13,16 @@ fn main() {
let mut lb = l[2..].as_bytes().to_vec();
lb.push(13);
lb.push(10);
let res = parse_response(&lb);
let res = parse(&lb);
match res {
Err(x) => {
ParseResult::Err => {
println!("failed command was: {}", l);
println!("{:?}", x);
}
Ok((res, x)) => {
if res.is_empty() {
ParseResult::Incomplete => {
println!("incomplete command was: {}", l);
}
ParseResult::Ok(res, x) => {
if res == lb.len() {
println!("{:?}", x);
} else {
println!("non-empty residue command was: {}", l);

View File

@ -1,10 +1,9 @@
/** Example synchronous serial receive event loop (for std) */
use nom::Offset;
use std::fmt;
use std::io;
use crate::handler::{NetworkEvent, SerialNetworkHandler};
use crate::response::parse_response;
use crate::response::{parse, ParseResult};
/** Mainloop handling serial input and dispatching network events */
pub fn mainloop<P, F, X>(
@ -34,24 +33,24 @@ where
while start < ofs {
// try parsing
let tail = &serial_buf[start..ofs];
let erase = match parse_response(tail) {
Ok((residue, resp)) => {
let erase = match parse(tail) {
ParseResult::Ok(offset, resp) => {
h.message(
&resp,
&mut |a, b, debug| {
|a, b, debug| {
running = f(a, b, debug);
},
debug,
)?;
tail.offset(residue)
offset
}
Err(nom::Err::Incomplete(_)) => {
ParseResult::Incomplete => {
// Incomplete, ignored, just retry after a new receive
0
}
Err(err) => {
writeln!(debug, "err: {:?}", err).unwrap();
ParseResult::Err => {
writeln!(debug, "err: {:?}", tail).unwrap();
// Erase unparseable data to next line, if line is complete
if let Some(ofs) = tail.iter().position(|&x| x == b'\n') {
ofs + 1

View File

@ -1,6 +1,6 @@
use core::str;
/** Parser for ESP8266 AT responses */
use nom::{digit, hex_digit};
use core::str;
use nom::{Offset, digit, hex_digit};
/** Connection type for CIPSTATUS etc */
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@ -73,6 +73,13 @@ pub enum Response<'a> {
RecvPrompt,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParseResult<'a> {
Ok(usize, Response<'a>),
Incomplete,
Err,
}
/* Decimal unsigned integer */
named!(num_u32<&[u8], u32>,
// The unwrap() here is safe because digit will never return non-UTF8
@ -279,7 +286,7 @@ named!(ipd_data<&[u8],Response>,
);
/* Parse response from line */
named!(pub parse_response<&[u8],Response>,
named!(parse_response<&[u8],Response>,
alt!(
nl_terminated
| ipd_data
@ -288,6 +295,14 @@ named!(pub parse_response<&[u8],Response>,
)
);
pub fn parse(response: &[u8]) -> ParseResult {
match parse_response(response) {
Ok((residue, resp)) => ParseResult::Ok(response.offset(residue), resp),
Err(nom::Err::Incomplete(_)) => ParseResult::Incomplete,
Err(_) => ParseResult::Err,
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -13,4 +13,3 @@ riscv = "0.5"
k210-shared = { path = "../k210-shared" }
k210-console = { path = "../k210-console" }
esp8266at = { path = "../esp8266at", default-features = false }
nom = { version = "4", default-features = false }

View File

@ -7,7 +7,7 @@
use core::str;
use embedded_hal::serial;
use esp8266at::handler::{NetworkEvent, SerialNetworkHandler};
use esp8266at::response::{parse_response, ConnectionType};
use esp8266at::response::{parse, ConnectionType, ParseResult};
use esp8266at::traits::{self, Write};
use k210_hal::pac;
use k210_hal::prelude::*;
@ -21,7 +21,6 @@ use k210_shared::soc::sleep::usleep;
use k210_shared::soc::spi::SPIExt;
use k210_shared::soc::sysctl;
use nb::block;
use nom::Offset;
use riscv::register::mcycle;
use riscv_rt::entry;
use k210_console::console::{Console, ScreenImage, DISP_HEIGHT, DISP_WIDTH};
@ -159,8 +158,8 @@ fn main() -> ! {
while start < ofs {
// try parsing
let tail = &serial_buf[start..ofs];
let erase = match parse_response(tail) {
Ok((residue, resp)) => {
let erase = match parse(tail) {
ParseResult::Ok(offset, resp) => {
sh.message(&resp, |port, ev, _debug| {
match ev {
NetworkEvent::Ready => {
@ -195,17 +194,17 @@ fn main() -> ! {
}
}, &mut debug).unwrap();
tail.offset(residue)
offset
}
Err(nom::Err::Incomplete(_)) => {
ParseResult::Incomplete => {
// Incomplete, ignored, just retry after a new receive
0
}
Err(err) => {
ParseResult::Err => {
if tail.len() > 100 {
writeln!(debug, "err: Error([too long ...])").unwrap();
} else {
writeln!(debug, "err: {:?}", err).unwrap();
writeln!(debug, "err: {:?}", tail).unwrap();
}
// Erase unparseable data to next line, if line is complete
if let Some(ofs) = tail.iter().position(|&x| x == b'\n') {