From 8d41b67bcf9f7f659615dd4903fa1c4a83d5a7bd Mon Sep 17 00:00:00 2001 From: atse Date: Wed, 3 Jul 2024 11:03:12 +0800 Subject: [PATCH] Use SplitWhitespace for command parsing not uom --- src/command_parser.rs | 457 +++++------------------------------------- 1 file changed, 49 insertions(+), 408 deletions(-) diff --git a/src/command_parser.rs b/src/command_parser.rs index b9e70bb..a2cdf86 100644 --- a/src/command_parser.rs +++ b/src/command_parser.rs @@ -1,18 +1,8 @@ use core::fmt; use core::num::ParseIntError; -use core::str::{from_utf8, Utf8Error}; -use nom::{ - IResult, - branch::alt, - bytes::complete::{is_a, tag, take_while1}, - character::{is_digit, complete::{char, one_of}}, - combinator::{complete, map, opt, value}, - sequence::preceded, - multi::{fold_many0, fold_many1}, - error::ErrorKind, - Needed, -}; -use num_traits::{Num, ParseFloatError}; +use core::str::{from_utf8, Utf8Error, SplitAsciiWhitespace}; +use nom::error::ErrorKind; +use num_traits::ParseFloatError; use serde::{Serialize, Deserialize}; @@ -193,425 +183,76 @@ pub enum Command { ShowHWRev, } -fn end(input: &[u8]) -> IResult<&[u8], ()> { - complete( - fold_many0( - one_of("\r\n\t "), - (), |(), _| () - ) - )(input) +fn load(tokens: &mut SplitAsciiWhitespace) -> Result { + tokens.next(); + Err(Error::Incomplete) } -fn whitespace(input: &[u8]) -> IResult<&[u8], ()> { - fold_many1(char(' '), (), |(), _| ())(input) +fn save(_tokens: &mut SplitAsciiWhitespace) -> Result { + Err(Error::Incomplete) } -fn unsigned(input: &[u8]) -> IResult<&[u8], Result> { - take_while1(is_digit)(input) - .map(|(input, digits)| { - let result = - from_utf8(digits) - .map_err(|e| e.into()) - .and_then(|digits| u32::from_str_radix(digits, 10) - .map_err(|e| e.into()) - ); - (input, result) - }) +fn ipv4(_tokens: &mut SplitAsciiWhitespace) -> Result { + Err(Error::Incomplete) } -fn float(input: &[u8]) -> IResult<&[u8], Result> { - let (input, sign) = opt(is_a("-"))(input)?; - let negative = sign.is_some(); - let (input, digits) = take_while1(|c| is_digit(c) || c == '.' as u8)(input)?; - let result = - from_utf8(digits) - .map_err(|e| e.into()) - .and_then(|digits| f64::from_str_radix(digits, 10) - .map_err(|e| e.into()) - ) - .map(|result: f64| if negative { -result } else { result }); - Ok((input, result)) +fn report(_tokens: &mut SplitAsciiWhitespace) -> Result { + Err(Error::Incomplete) } -fn off_on(input: &[u8]) -> IResult<&[u8], bool> { - alt((value(false, tag("off")), - value(true, tag("on")) - ))(input) +fn pwm(_tokens: &mut SplitAsciiWhitespace) -> Result { + Err(Error::Incomplete) } -fn channel(input: &[u8]) -> IResult<&[u8], usize> { - map(one_of("01"), |c| (c as usize) - ('0' as usize))(input) +fn center(_tokens: &mut SplitAsciiWhitespace) -> Result { + Err(Error::Incomplete) } -fn report(input: &[u8]) -> IResult<&[u8], Command> { - preceded( - tag("report"), - alt(( - preceded( - whitespace, - preceded( - tag("mode"), - alt(( - preceded( - whitespace, - // `report mode ` - Switch repoting mode - map(off_on, Command::Reporting) - ), - // `report mode` - Show current reporting state - value(Command::Show(ShowCommand::Reporting), end) - )) - )), - // `report` - Report once - value(Command::Show(ShowCommand::Input), end) - )) - )(input) +fn pid(_tokens: &mut SplitAsciiWhitespace) -> Result { + Err(Error::Incomplete) } -fn pwm_setup(input: &[u8]) -> IResult<&[u8], Result<(PwmPin, f64), Error>> { - let result_with_pin = |pin: PwmPin| - move |result: Result| - result.map(|value| (pin, value)); - - alt(( - map( - preceded( - tag("i_set"), - preceded( - whitespace, - float - ) - ), - result_with_pin(PwmPin::ISet) - ), - map( - preceded( - tag("max_i_pos"), - preceded( - whitespace, - float - ) - ), - result_with_pin(PwmPin::MaxIPos) - ), - map( - preceded( - tag("max_i_neg"), - preceded( - whitespace, - float - ) - ), - result_with_pin(PwmPin::MaxINeg) - ), - map( - preceded( - tag("max_v"), - preceded( - whitespace, - float - ) - ), - result_with_pin(PwmPin::MaxV) - )) - )(input) +fn s_h(_tokens: &mut SplitAsciiWhitespace) -> Result { + Err(Error::Incomplete) } -/// `pwm <0-1> pid` - Set PWM to be controlled by PID -fn pwm_pid(input: &[u8]) -> IResult<&[u8], ()> { - value((), tag("pid"))(input) +fn postfilter(_tokens: &mut SplitAsciiWhitespace) -> Result { + Err(Error::Incomplete) } -fn pwm(input: &[u8]) -> IResult<&[u8], Result> { - let (input, _) = tag("pwm")(input)?; - alt(( - |input| { - let (input, _) = whitespace(input)?; - let (input, channel) = channel(input)?; - let (input, _) = whitespace(input)?; - let (input, result) = alt(( - |input| { - let (input, ()) = pwm_pid(input)?; - Ok((input, Ok(Command::PwmPid { channel }))) - }, - |input| { - let (input, config) = pwm_setup(input)?; - match config { - Ok((pin, value)) => - Ok((input, Ok(Command::Pwm { channel, pin, value }))), - Err(e) => - Ok((input, Err(e))), - } - }, - ))(input)?; - end(input)?; - Ok((input, result)) - }, - value(Ok(Command::Show(ShowCommand::Pwm)), end) - ))(input) +fn fan(_tokens: &mut SplitAsciiWhitespace) -> Result { + Err(Error::Incomplete) } -fn center_point(input: &[u8]) -> IResult<&[u8], Result> { - let (input, _) = tag("center")(input)?; - let (input, _) = whitespace(input)?; - let (input, channel) = channel(input)?; - let (input, _) = whitespace(input)?; - let (input, center) = alt(( - value(Ok(CenterPoint::Vref), tag("vref")), - |input| { - let (input, value) = float(input)?; - Ok((input, value.map(|value| CenterPoint::Override(value as f32)))) - } - ))(input)?; - end(input)?; - Ok((input, center.map(|center| Command::CenterPoint { - channel, - center, - }))) -} - -/// `pid <0-1> ` -fn pid_parameter(input: &[u8]) -> IResult<&[u8], Result> { - let (input, channel) = channel(input)?; - let (input, _) = whitespace(input)?; - let (input, parameter) = - alt((value(PidParameter::Target, tag("target")), - value(PidParameter::KP, tag("kp")), - value(PidParameter::KI, tag("ki")), - value(PidParameter::KD, tag("kd")), - value(PidParameter::OutputMin, tag("output_min")), - value(PidParameter::OutputMax, tag("output_max")), - ))(input)?; - let (input, _) = whitespace(input)?; - let (input, value) = float(input)?; - let result = value - .map(|value| Command::Pid { channel, parameter, value }); - Ok((input, result)) -} - -/// `pid` | `pid ` -fn pid(input: &[u8]) -> IResult<&[u8], Result> { - let (input, _) = tag("pid")(input)?; - alt(( - preceded( - whitespace, - pid_parameter - ), - value(Ok(Command::Show(ShowCommand::Pid)), end) - ))(input) -} - -/// `s-h <0-1> ` -fn steinhart_hart_parameter(input: &[u8]) -> IResult<&[u8], Result> { - let (input, channel) = channel(input)?; - let (input, _) = whitespace(input)?; - let (input, parameter) = - alt((value(ShParameter::T0, tag("t0")), - value(ShParameter::B, tag("b")), - value(ShParameter::R0, tag("r0")) - ))(input)?; - let (input, _) = whitespace(input)?; - let (input, value) = float(input)?; - let result = value - .map(|value| Command::SteinhartHart { channel, parameter, value }); - Ok((input, result)) -} - -/// `s-h` | `s-h ` -fn steinhart_hart(input: &[u8]) -> IResult<&[u8], Result> { - let (input, _) = tag("s-h")(input)?; - alt(( - preceded( - whitespace, - steinhart_hart_parameter - ), - value(Ok(Command::Show(ShowCommand::SteinhartHart)), end) - ))(input) -} - -fn postfilter(input: &[u8]) -> IResult<&[u8], Result> { - let (input, _) = tag("postfilter")(input)?; - alt(( - preceded( - whitespace, - |input| { - let (input, channel) = channel(input)?; - let (input, _) = whitespace(input)?; - alt(( - value(Ok(Command::PostFilter { - channel, - rate: None, - }), tag("off")), - move |input| { - let (input, _) = tag("rate")(input)?; - let (input, _) = whitespace(input)?; - let (input, rate) = float(input)?; - let result = rate - .map(|rate| Command::PostFilter { - channel, - rate: Some(rate as f32), - }); - Ok((input, result)) - } - ))(input) - } - ), - value(Ok(Command::Show(ShowCommand::PostFilter)), end) - ))(input) -} - -fn load(input: &[u8]) -> IResult<&[u8], Result> { - let (input, _) = tag("load")(input)?; - let (input, channel) = alt(( - |input| { - let (input, _) = whitespace(input)?; - let (input, channel) = channel(input)?; - let (input, _) = end(input)?; - Ok((input, Some(channel))) - }, - value(None, end) - ))(input)?; - - let result = Ok(Command::Load { channel }); - Ok((input, result)) -} - -fn save(input: &[u8]) -> IResult<&[u8], Result> { - let (input, _) = tag("save")(input)?; - let (input, channel) = alt(( - |input| { - let (input, _) = whitespace(input)?; - let (input, channel) = channel(input)?; - let (input, _) = end(input)?; - Ok((input, Some(channel))) - }, - value(None, end) - ))(input)?; - - let result = Ok(Command::Save { channel }); - Ok((input, result)) -} - -fn ipv4_addr(input: &[u8]) -> IResult<&[u8], Result<[u8; 4], Error>> { - let (input, a) = unsigned(input)?; - let (input, _) = tag(".")(input)?; - let (input, b) = unsigned(input)?; - let (input, _) = tag(".")(input)?; - let (input, c) = unsigned(input)?; - let (input, _) = tag(".")(input)?; - let (input, d) = unsigned(input)?; - let address = move || Ok([a? as u8, b? as u8, c? as u8, d? as u8]); - Ok((input, address())) -} - -fn ipv4(input: &[u8]) -> IResult<&[u8], Result> { - let (input, _) = tag("ipv4")(input)?; - alt(( - |input| { - let (input, _) = whitespace(input)?; - let (input, address) = ipv4_addr(input)?; - let (input, _) = tag("/")(input)?; - let (input, mask_len) = unsigned(input)?; - let (input, gateway) = alt(( - |input| { - let (input, _) = whitespace(input)?; - let (input, gateway) = ipv4_addr(input)?; - Ok((input, gateway.map(Some))) - }, - value(Ok(None), end), - ))(input)?; - - let result = move || { - Ok(Command::Ipv4(Ipv4Config { - address: address?, - mask_len: mask_len? as u8, - gateway: gateway?, - })) - }; - Ok((input, result())) - }, - value(Ok(Command::Show(ShowCommand::Ipv4)), end), - ))(input) -} - -fn fan(input: &[u8]) -> IResult<&[u8], Result> { - let (input, _) = tag("fan")(input)?; - alt(( - |input| { - let (input, _) = whitespace(input)?; - - let (input, result) = alt(( - |input| { - let (input, _) = tag("auto")(input)?; - Ok((input, Ok(Command::FanAuto))) - }, - |input| { - let (input, value) = unsigned(input)?; - Ok((input, Ok(Command::FanSet { fan_pwm: value.unwrap_or(0)}))) - }, - ))(input)?; - Ok((input, result)) - }, - value(Ok(Command::ShowFan), end) - ))(input) -} - -fn fan_curve(input: &[u8]) -> IResult<&[u8], Result> { - let (input, _) = tag("fcurve")(input)?; - alt(( - |input| { - let (input, _) = whitespace(input)?; - let (input, result) = alt(( - |input| { - let (input, _) = tag("default")(input)?; - Ok((input, Ok(Command::FanCurveDefaults))) - }, - |input| { - let (input, k_a) = float(input)?; - let (input, _) = whitespace(input)?; - let (input, k_b) = float(input)?; - let (input, _) = whitespace(input)?; - let (input, k_c) = float(input)?; - if k_a.is_ok() && k_b.is_ok() && k_c.is_ok() { - Ok((input, Ok(Command::FanCurve { k_a: k_a.unwrap() as f32, k_b: k_b.unwrap() as f32, k_c: k_c.unwrap() as f32 }))) - } else { - Err(nom::Err::Incomplete(Needed::Size(3))) - } - }, - ))(input)?; - Ok((input, result)) - }, - value(Err(Error::Incomplete), end) - ))(input) -} - -fn command(input: &[u8]) -> IResult<&[u8], Result> { - alt((value(Ok(Command::Quit), tag("quit")), - load, - save, - value(Ok(Command::Reset), tag("reset")), - ipv4, - map(report, Ok), - pwm, - center_point, - pid, - steinhart_hart, - postfilter, - value(Ok(Command::Dfu), tag("dfu")), - fan, - fan_curve, - value(Ok(Command::ShowHWRev), tag("hwrev")), - ))(input) +fn fcurve(_tokens: &mut SplitAsciiWhitespace) -> Result { + Err(Error::Incomplete) } impl Command { pub fn parse(input: &[u8]) -> Result { - match command(input) { - Ok((input_remain, result)) if input_remain.len() == 0 => - result, - Ok((input_remain, _)) => - Err(Error::UnexpectedInput(input_remain[0])), - Err(e) => - Err(e.into()), + let mut tokens = from_utf8(input).unwrap().split_ascii_whitespace(); + match tokens.next() { + Some(keyword) => { + match keyword { + "quit" => Ok(Command::Quit), + "load" => load(&mut tokens), + "save" => save(&mut tokens), + "reset" => Ok(Command::Reset), + "ipv4" => ipv4(&mut tokens), + "report" => report(&mut tokens), + "pwm" => pwm(&mut tokens), + "center" => center(&mut tokens), + "pid" => pid(&mut tokens), + "s-h" => s_h(&mut tokens), + "postfilter" => postfilter(&mut tokens), + "dfu" => Ok(Command::Dfu), + "fan" => fan(&mut tokens), + "fcurve" => fcurve(&mut tokens), + "hwrev" => Ok(Command::ShowHWRev), + _ => Err(Error::Incomplete), + } + } + None => Err(Error::Incomplete), } } }