2019-09-15 03:21:55 +08:00
|
|
|
use core::fmt;
|
2019-09-15 01:03:52 +08:00
|
|
|
use nom::{
|
|
|
|
IResult,
|
|
|
|
branch::alt,
|
2019-09-17 05:41:22 +08:00
|
|
|
bytes::complete::{is_a, tag, take_while1},
|
2019-09-19 06:30:32 +08:00
|
|
|
character::{is_digit, complete::{char, one_of}},
|
|
|
|
combinator::{complete, map, value},
|
2019-09-15 03:40:49 +08:00
|
|
|
sequence::preceded,
|
2019-09-19 06:30:32 +08:00
|
|
|
multi::{fold_many0, fold_many1},
|
2019-09-15 01:03:52 +08:00
|
|
|
error::ErrorKind,
|
|
|
|
};
|
2019-09-17 05:41:22 +08:00
|
|
|
use lexical_core as lexical;
|
2019-09-11 05:37:51 +08:00
|
|
|
|
|
|
|
|
2019-09-15 03:11:26 +08:00
|
|
|
#[derive(Clone, Debug)]
|
2019-09-11 05:37:51 +08:00
|
|
|
pub enum Error {
|
2019-09-15 01:03:52 +08:00
|
|
|
Parser(ErrorKind),
|
|
|
|
Incomplete,
|
|
|
|
UnexpectedInput(u8),
|
2019-09-17 05:41:22 +08:00
|
|
|
ParseNumber(lexical::Error)
|
2019-09-14 09:09:07 +08:00
|
|
|
}
|
|
|
|
|
2019-09-15 01:03:52 +08:00
|
|
|
impl<'t> From<nom::Err<(&'t [u8], ErrorKind)>> for Error {
|
|
|
|
fn from(e: nom::Err<(&'t [u8], ErrorKind)>) -> Self {
|
|
|
|
match e {
|
|
|
|
nom::Err::Incomplete(_) =>
|
|
|
|
Error::Incomplete,
|
|
|
|
nom::Err::Error((_, e)) =>
|
|
|
|
Error::Parser(e),
|
|
|
|
nom::Err::Failure((_, e)) =>
|
|
|
|
Error::Parser(e),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-17 05:41:22 +08:00
|
|
|
impl From<lexical::Error> for Error {
|
|
|
|
fn from(e: lexical::Error) -> Self {
|
|
|
|
Error::ParseNumber(e)
|
2019-09-14 09:09:07 +08:00
|
|
|
}
|
2019-09-11 05:37:51 +08:00
|
|
|
}
|
|
|
|
|
2019-09-15 03:21:55 +08:00
|
|
|
impl fmt::Display for Error {
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
|
|
match self {
|
|
|
|
Error::Incomplete =>
|
|
|
|
"incomplete input".fmt(fmt),
|
|
|
|
Error::UnexpectedInput(c) => {
|
|
|
|
"unexpected input: ".fmt(fmt)?;
|
|
|
|
c.fmt(fmt)
|
|
|
|
}
|
|
|
|
Error::Parser(e) => {
|
|
|
|
"parser: ".fmt(fmt)?;
|
|
|
|
(e as &dyn core::fmt::Debug).fmt(fmt)
|
|
|
|
}
|
2019-09-17 05:41:22 +08:00
|
|
|
Error::ParseNumber(e) => {
|
2019-09-15 03:21:55 +08:00
|
|
|
"parsing number: ".fmt(fmt)?;
|
2019-09-17 05:41:22 +08:00
|
|
|
(e as &dyn core::fmt::Debug).fmt(fmt)
|
2019-09-15 03:21:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-15 01:03:52 +08:00
|
|
|
#[derive(Debug, Clone)]
|
2019-09-11 06:23:15 +08:00
|
|
|
pub enum ShowCommand {
|
2019-09-17 07:42:50 +08:00
|
|
|
Input,
|
|
|
|
Reporting,
|
2019-09-18 01:09:47 +08:00
|
|
|
Pwm,
|
2019-09-15 03:11:26 +08:00
|
|
|
Pid,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub enum PidParameter {
|
2019-09-15 03:35:06 +08:00
|
|
|
Target,
|
|
|
|
KP,
|
|
|
|
KI,
|
|
|
|
KD,
|
|
|
|
OutputMin,
|
|
|
|
OutputMax,
|
|
|
|
IntegralMin,
|
|
|
|
IntegralMax,
|
2019-09-12 22:12:03 +08:00
|
|
|
}
|
|
|
|
|
2019-09-18 01:09:47 +08:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub enum PwmMode {
|
|
|
|
Manual {
|
|
|
|
width: u32,
|
|
|
|
total: u32,
|
|
|
|
},
|
|
|
|
Pid,
|
|
|
|
}
|
|
|
|
|
2019-09-15 01:03:52 +08:00
|
|
|
#[derive(Debug, Clone)]
|
2019-09-11 05:37:51 +08:00
|
|
|
pub enum Command {
|
|
|
|
Quit,
|
2019-09-11 06:23:15 +08:00
|
|
|
Show(ShowCommand),
|
2019-09-17 07:42:50 +08:00
|
|
|
Reporting(bool),
|
2019-09-18 01:09:47 +08:00
|
|
|
Pwm(PwmMode),
|
2019-09-15 03:35:06 +08:00
|
|
|
Pid {
|
|
|
|
parameter: PidParameter,
|
|
|
|
value: f32,
|
|
|
|
},
|
2019-09-11 05:37:51 +08:00
|
|
|
}
|
|
|
|
|
2019-09-19 06:30:32 +08:00
|
|
|
fn end(input: &[u8]) -> IResult<&[u8], ()> {
|
|
|
|
complete(
|
|
|
|
fold_many0(
|
|
|
|
one_of("\r\n\t "),
|
|
|
|
(), |(), _| ()
|
|
|
|
)
|
|
|
|
)(input)
|
|
|
|
}
|
|
|
|
|
2019-09-15 01:03:52 +08:00
|
|
|
fn whitespace(input: &[u8]) -> IResult<&[u8], ()> {
|
|
|
|
fold_many1(char(' '), (), |(), _| ())(input)
|
|
|
|
}
|
2019-09-11 05:37:51 +08:00
|
|
|
|
2019-09-17 05:41:22 +08:00
|
|
|
fn unsigned(input: &[u8]) -> IResult<&[u8], Result<u32, lexical::Error>> {
|
2019-09-15 01:03:52 +08:00
|
|
|
take_while1(is_digit)(input)
|
2019-09-17 05:41:22 +08:00
|
|
|
.map(|(input, digits)| (input, lexical::parse(digits)))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn float(input: &[u8]) -> IResult<&[u8], Result<f32, lexical::Error>> {
|
|
|
|
let (input, sign) = is_a("-")(input)?;
|
|
|
|
let negative = sign.len() > 0;
|
|
|
|
let (input, digits) = take_while1(|c| is_digit(c) || c == '.' as u8)(input)?;
|
|
|
|
let result = lexical::parse(digits)
|
|
|
|
.map(|result: f32| if negative { -result } else { result });
|
|
|
|
Ok((input, result))
|
2019-09-15 01:03:52 +08:00
|
|
|
}
|
2019-09-11 05:37:51 +08:00
|
|
|
|
2019-09-17 07:42:50 +08:00
|
|
|
fn off_on(input: &[u8]) -> IResult<&[u8], bool> {
|
|
|
|
alt((value(false, tag("off")),
|
|
|
|
value(true, tag("on"))
|
2019-09-15 01:03:52 +08:00
|
|
|
))(input)
|
|
|
|
}
|
2019-09-14 09:09:07 +08:00
|
|
|
|
2019-09-15 01:03:52 +08:00
|
|
|
fn report(input: &[u8]) -> IResult<&[u8], Command> {
|
|
|
|
preceded(
|
2019-09-19 05:25:40 +08:00
|
|
|
tag("report"),
|
2019-09-15 01:03:52 +08:00
|
|
|
alt((
|
|
|
|
preceded(
|
|
|
|
whitespace,
|
|
|
|
preceded(
|
|
|
|
tag("mode"),
|
|
|
|
alt((
|
|
|
|
preceded(
|
|
|
|
whitespace,
|
2019-09-17 07:42:50 +08:00
|
|
|
// `report mode <on | off>` - Switch repoting mode
|
|
|
|
map(off_on,
|
|
|
|
|reporting| Command::Reporting(reporting))
|
2019-09-15 01:03:52 +08:00
|
|
|
),
|
2019-09-17 07:42:50 +08:00
|
|
|
// `report mode` - Show current reporting state
|
2019-09-19 06:30:32 +08:00
|
|
|
value(Command::Show(ShowCommand::Reporting), end)
|
2019-09-15 01:03:52 +08:00
|
|
|
))
|
|
|
|
)),
|
2019-09-17 07:42:50 +08:00
|
|
|
// `report` - Report once
|
2019-09-19 06:30:32 +08:00
|
|
|
value(Command::Show(ShowCommand::Input), end)
|
2019-09-15 01:03:52 +08:00
|
|
|
))
|
|
|
|
)(input)
|
|
|
|
}
|
2019-09-14 09:09:07 +08:00
|
|
|
|
2019-09-17 07:46:29 +08:00
|
|
|
/// `pwm <width> <total>` - Set pwm duty cycle
|
2019-09-18 01:09:47 +08:00
|
|
|
fn pwm_manual(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
2019-09-15 01:03:52 +08:00
|
|
|
let (input, width) = unsigned(input)?;
|
|
|
|
let width = match width {
|
|
|
|
Ok(width) => width,
|
|
|
|
Err(e) => return Ok((input, Err(e.into()))),
|
|
|
|
};
|
|
|
|
let (input, _) = whitespace(input)?;
|
|
|
|
let (input, total) = unsigned(input)?;
|
|
|
|
let total = match total {
|
|
|
|
Ok(total) => total,
|
|
|
|
Err(e) => return Ok((input, Err(e.into()))),
|
|
|
|
};
|
2019-09-18 01:09:47 +08:00
|
|
|
Ok((input, Ok(Command::Pwm(PwmMode::Manual { width, total }))))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `pwm pid` - Set PWM to be controlled by PID
|
|
|
|
fn pwm_pid(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
|
|
|
value(Ok(Command::Pwm(PwmMode::Pid)), tag("pid"))(input)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn pwm(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
|
|
|
let (input, _) = tag("pwm")(input)?;
|
|
|
|
alt((
|
|
|
|
preceded(
|
|
|
|
whitespace,
|
|
|
|
alt((
|
|
|
|
pwm_pid,
|
|
|
|
pwm_manual,
|
|
|
|
))),
|
2019-09-19 06:30:32 +08:00
|
|
|
value(Ok(Command::Show(ShowCommand::Pwm)), end)
|
2019-09-18 01:09:47 +08:00
|
|
|
))(input)
|
2019-09-15 01:03:52 +08:00
|
|
|
}
|
|
|
|
|
2019-09-15 03:35:06 +08:00
|
|
|
fn pid_parameter(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
|
|
|
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")),
|
|
|
|
value(PidParameter::IntegralMin, tag("integral_min")),
|
|
|
|
value(PidParameter::IntegralMax, tag("integral_max"))
|
2019-09-15 03:11:26 +08:00
|
|
|
))(input)?;
|
|
|
|
let (input, _) = whitespace(input)?;
|
2019-09-17 05:41:22 +08:00
|
|
|
let (input, value) = float(input)?;
|
2019-09-15 03:35:06 +08:00
|
|
|
let result = value
|
2019-09-17 05:41:22 +08:00
|
|
|
.map(|value| Command::Pid { parameter, value })
|
2019-09-15 03:11:26 +08:00
|
|
|
.map_err(|e| e.into());
|
2019-09-15 03:35:06 +08:00
|
|
|
Ok((input, result))
|
2019-09-15 03:11:26 +08:00
|
|
|
}
|
|
|
|
|
2019-09-17 07:46:29 +08:00
|
|
|
/// `pid <parameter> <value>`
|
2019-09-15 03:11:26 +08:00
|
|
|
fn pid(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
|
|
|
let (input, _) = tag("pid")(input)?;
|
|
|
|
let (input, _) = whitespace(input)?;
|
|
|
|
|
|
|
|
alt((
|
|
|
|
preceded(
|
|
|
|
whitespace,
|
2019-09-15 03:35:06 +08:00
|
|
|
pid_parameter
|
2019-09-15 03:11:26 +08:00
|
|
|
),
|
2019-09-19 06:30:32 +08:00
|
|
|
value(Ok(Command::Show(ShowCommand::Pid)), end)
|
2019-09-15 03:11:26 +08:00
|
|
|
))(input)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn command(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
|
|
|
alt((value(Ok(Command::Quit), tag("quit")),
|
2019-09-19 06:30:32 +08:00
|
|
|
map(report, Ok),
|
2019-09-15 03:11:26 +08:00
|
|
|
pwm,
|
|
|
|
pid,
|
2019-09-15 01:03:52 +08:00
|
|
|
))(input)
|
|
|
|
}
|
2019-09-14 09:09:07 +08:00
|
|
|
|
2019-09-15 01:03:52 +08:00
|
|
|
impl Command {
|
|
|
|
pub fn parse(input: &[u8]) -> Result<Self, Error> {
|
|
|
|
match command(input) {
|
2019-09-15 03:11:26 +08:00
|
|
|
Ok((b"", result)) =>
|
|
|
|
result,
|
2019-09-15 01:03:52 +08:00
|
|
|
Ok((input_remain, _)) =>
|
|
|
|
Err(Error::UnexpectedInput(input_remain[0])),
|
|
|
|
Err(e) =>
|
|
|
|
Err(e.into()),
|
|
|
|
}
|
2019-09-11 05:37:51 +08:00
|
|
|
}
|
|
|
|
}
|