diff --git a/src/mqtt_mux.rs b/src/mqtt_mux.rs index 3986d50..8b08171 100644 --- a/src/mqtt_mux.rs +++ b/src/mqtt_mux.rs @@ -1,22 +1,16 @@ use log::info; use nom::IResult; -use nom::combinator::{value, map, map_res, not, opt, all_consuming}; -use nom::sequence::{terminated, preceded, pair, delimited, tuple}; -use nom::bytes::complete::{take, tag, tag_no_case, take_while}; +use nom::combinator::{value, map, map_res, opt, all_consuming}; +use nom::sequence::{terminated, preceded, pair}; +use nom::bytes::complete::{tag, tag_no_case, take_while}; use nom::character::complete::digit1; use nom::character::is_space; -use nom::branch::alt; +use nom::branch::{permutation, alt}; 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 core::convert::TryInto; use crate::ClockSource as UrukulClockSource; -use crate::ClockSource::*; use crate::Urukul; use crate::Error; @@ -286,22 +280,13 @@ impl MqttMux where SPI: Transfer { } } -// Topic separator parser -fn topic_separator<'a>(topic: &'a str) -> IResult<&'a str, ()> { - value((), tag("/"))(topic) -} - -// Message separator parser +// Read message parameter separator (optional comma and whitespace) fn message_separator(message: &[u8]) -> IResult<&[u8], ()> { - value( - (), - preceded( - whitespace, - preceded( - tag("/"), - whitespace - ) - ) + preceded( + opt( + tag(",") + ), + whitespace )(message) } @@ -401,63 +386,48 @@ fn clock_division_message(message: &[u8]) -> IResult<&[u8], MqttCommand> { } // 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> { all_consuming( map( - delimited( - tag("{"), - tuple(( + permutation(( + preceded( + tag_no_case("source:"), preceded( whitespace, - preceded( - tag("\"source\":"), - preceded( - whitespace, - terminated( - alt(( - value(UrukulClockSource::OSC, tag_no_case("OSC")), - 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 - ) - ) + terminated( + alt(( + value(UrukulClockSource::OSC, tag_no_case("OSC")), + value(UrukulClockSource::MMCX, tag_no_case("MMCX")), + value(UrukulClockSource::SMA, tag_no_case("SMA")) + )), + message_separator ) ) - )), - 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) ) )(message) @@ -512,68 +482,50 @@ fn singletone_phase_message(channel: u8, profile: u8, message: &[u8]) -> IResult } // 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> { all_consuming( map( - tuple(( + permutation(( preceded( - tag("{"), + tag_no_case("frequency:"), preceded( whitespace, - preceded( - tag("\"frequency\":"), - preceded( - whitespace, - read_frequency - ) + terminated( + read_frequency, + message_separator ) ) ), preceded( - tag(","), + tag_no_case("phase:"), preceded( whitespace, - preceded( - tag("\"amplitude\":"), + terminated( + double, preceded( - whitespace, - double - ) - ) - ) - ), - preceded( - tag(","), - preceded( - whitespace, - preceded( - tag("\"phase\":"), - preceded( - whitespace, - terminated( - double, + opt( preceded( - opt( - preceded( - whitespace, - tag_no_case("deg") - ) - ), - preceded( - whitespace, - tag("}") - ) + whitespace, + tag_no_case("deg") ) - ) + ), + 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) }