mqtt_mux: make one-command setter less chunky

This commit is contained in:
occheung 2020-09-23 12:34:13 +08:00
parent 2ef6bb393c
commit bd80274e86
1 changed files with 69 additions and 117 deletions

View File

@ -1,22 +1,16 @@
use log::info; use log::info;
use nom::IResult; use nom::IResult;
use nom::combinator::{value, map, map_res, not, opt, all_consuming}; use nom::combinator::{value, map, map_res, opt, all_consuming};
use nom::sequence::{terminated, preceded, pair, delimited, tuple}; use nom::sequence::{terminated, preceded, pair};
use nom::bytes::complete::{take, tag, tag_no_case, take_while}; use nom::bytes::complete::{tag, tag_no_case, take_while};
use nom::character::complete::digit1; use nom::character::complete::digit1;
use nom::character::is_space; use nom::character::is_space;
use nom::branch::alt; use nom::branch::{permutation, alt};
use nom::number::complete::{float, double}; use nom::number::complete::{float, double};
use uom::si::f64::Frequency;
use uom::si::frequency::{hertz, kilohertz, megahertz, gigahertz};
use arrayvec::ArrayVec;
use embedded_hal::blocking::spi::Transfer; use embedded_hal::blocking::spi::Transfer;
use core::convert::TryInto; use core::convert::TryInto;
use crate::ClockSource as UrukulClockSource; use crate::ClockSource as UrukulClockSource;
use crate::ClockSource::*;
use crate::Urukul; use crate::Urukul;
use crate::Error; use crate::Error;
@ -286,22 +280,13 @@ impl<SPI, E> MqttMux<SPI> where SPI: Transfer<u8, Error = E> {
} }
} }
// Topic separator parser // Read message parameter separator (optional comma and whitespace)
fn topic_separator<'a>(topic: &'a str) -> IResult<&'a str, ()> {
value((), tag("/"))(topic)
}
// Message separator parser
fn message_separator(message: &[u8]) -> IResult<&[u8], ()> { fn message_separator(message: &[u8]) -> IResult<&[u8], ()> {
value( preceded(
(), opt(
preceded( tag(",")
whitespace, ),
preceded( whitespace
tag("/"),
whitespace
)
)
)(message) )(message)
} }
@ -401,63 +386,48 @@ fn clock_division_message(message: &[u8]) -> IResult<&[u8], MqttCommand> {
} }
// Parser for one-command master clock setup message // Parser for one-command master clock setup message
// Possible improvements: Chop off redundant braces and quotes
// Allow optional parameters/permutation of parameters
fn clock_message(message: &[u8]) -> IResult<&[u8], MqttCommand> { fn clock_message(message: &[u8]) -> IResult<&[u8], MqttCommand> {
all_consuming( all_consuming(
map( map(
delimited( permutation((
tag("{"), preceded(
tuple(( tag_no_case("source:"),
preceded( preceded(
whitespace, whitespace,
preceded( terminated(
tag("\"source\":"), alt((
preceded( value(UrukulClockSource::OSC, tag_no_case("OSC")),
whitespace, value(UrukulClockSource::MMCX, tag_no_case("MMCX")),
terminated( value(UrukulClockSource::SMA, tag_no_case("SMA"))
alt(( )),
value(UrukulClockSource::OSC, tag_no_case("OSC")), message_separator
value(UrukulClockSource::MMCX, tag_no_case("MMCX")),
value(UrukulClockSource::SMA, tag_no_case("SMA"))
)),
tag(",")
)
)
)
),
preceded(
whitespace,
preceded(
tag("\"frequency\":"),
preceded(
whitespace,
terminated(
read_frequency,
tag(",")
)
)
)
),
preceded(
whitespace,
preceded(
tag("\"division\":"),
preceded(
whitespace,
terminated(
map_res(
digit1,
|div: &[u8]| u8::from_str_radix(core::str::from_utf8(div).unwrap(), 10)
),
whitespace
)
)
) )
) )
)), ),
tag("}") preceded(
), tag_no_case("frequency:"),
preceded(
whitespace,
terminated(
read_frequency,
message_separator
)
)
),
preceded(
tag_no_case("division:"),
preceded(
whitespace,
terminated(
map_res(
digit1,
|div: &[u8]| u8::from_str_radix(core::str::from_utf8(div).unwrap(), 10)
),
message_separator
)
)
)
)),
|(src, freq, div): (UrukulClockSource, f64, u8)| MqttCommand::Clock(src, freq, div) |(src, freq, div): (UrukulClockSource, f64, u8)| MqttCommand::Clock(src, freq, div)
) )
)(message) )(message)
@ -512,68 +482,50 @@ fn singletone_phase_message(channel: u8, profile: u8, message: &[u8]) -> IResult
} }
// Parser for one-command singletone profile Command // Parser for one-command singletone profile Command
// Using JSON like command structure
// Possible improvements: Chop off redundant braces and quotes
// Allow optional parameters/permutation of parameters
fn singletone_message(channel: u8, profile: u8, message: &[u8]) -> IResult<&[u8], MqttCommand> { fn singletone_message(channel: u8, profile: u8, message: &[u8]) -> IResult<&[u8], MqttCommand> {
all_consuming( all_consuming(
map( map(
tuple(( permutation((
preceded( preceded(
tag("{"), tag_no_case("frequency:"),
preceded( preceded(
whitespace, whitespace,
preceded( terminated(
tag("\"frequency\":"), read_frequency,
preceded( message_separator
whitespace,
read_frequency
)
) )
) )
), ),
preceded( preceded(
tag(","), tag_no_case("phase:"),
preceded( preceded(
whitespace, whitespace,
preceded( terminated(
tag("\"amplitude\":"), double,
preceded( preceded(
whitespace, opt(
double
)
)
)
),
preceded(
tag(","),
preceded(
whitespace,
preceded(
tag("\"phase\":"),
preceded(
whitespace,
terminated(
double,
preceded( preceded(
opt( whitespace,
preceded( tag_no_case("deg")
whitespace,
tag_no_case("deg")
)
),
preceded(
whitespace,
tag("}")
)
) )
) ),
message_separator
) )
) )
) )
),
preceded(
tag_no_case("amplitude:"),
preceded(
whitespace,
terminated(
double,
message_separator
)
)
) )
)), )),
|(freq, ampl, phase): (f64, f64, f64)| MqttCommand::Singletone(channel, profile, freq, phase, ampl) |(freq, phase, ampl): (f64, f64, f64)| MqttCommand::Singletone(channel, profile, freq, phase, ampl)
) )
)(message) )(message)
} }