forked from M-Labs/humpback-dds
mqtt_mux: add cmd
This commit is contained in:
parent
d47f9b4655
commit
9ea56ebde5
35
src/lib.rs
35
src/lib.rs
@ -176,7 +176,18 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_clock_source(&mut self, source: ClockSource, frequency: f64) -> Result<(), Error<E>> {
|
fn set_clock(&mut self, source: ClockSource, frequency: f64, division: u8) -> Result<(), Error<E>> {
|
||||||
|
// Change clock source through configuration register
|
||||||
|
self.set_clock_source(source)?;
|
||||||
|
|
||||||
|
// Modify the master clock frequency
|
||||||
|
// Prevent redundunt call to change f_ref_clk
|
||||||
|
self.f_master_clk = frequency;
|
||||||
|
|
||||||
|
self.set_clock_division(division)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_clock_source(&mut self, source: ClockSource) -> Result<(), Error<E>> {
|
||||||
// Change clock source through configuration register
|
// Change clock source through configuration register
|
||||||
match source {
|
match source {
|
||||||
ClockSource::OSC => self.config_register.set_configurations(&mut [
|
ClockSource::OSC => self.config_register.set_configurations(&mut [
|
||||||
@ -190,19 +201,15 @@ where
|
|||||||
ClockSource::SMA => self.config_register.set_configurations(&mut [
|
ClockSource::SMA => self.config_register.set_configurations(&mut [
|
||||||
(CFGMask::CLK_SEL0, 1),
|
(CFGMask::CLK_SEL0, 1),
|
||||||
]),
|
]),
|
||||||
}?;
|
}.map(|_| ())
|
||||||
|
}
|
||||||
|
|
||||||
// Save the new master clock frequency
|
fn set_clock_frequency(&mut self, frequency: f64) -> Result<(), Error<E>> {
|
||||||
|
// Update master clock frequency
|
||||||
self.f_master_clk = frequency;
|
self.f_master_clk = frequency;
|
||||||
|
|
||||||
// Calculate reference clock frequency after clock division from configuration register
|
// Update all DDS f_ref_clk
|
||||||
let f_ref_clk = self.f_master_clk / (self.config_register.get_configuration(CFGMask::DIV) as f64);
|
self.set_dds_ref_clk()
|
||||||
|
|
||||||
// Update all DDS chips on reference clock frequency
|
|
||||||
for dds_channel in 0..4 {
|
|
||||||
self.dds[dds_channel].set_ref_clk_frequency(f_ref_clk)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_clock_division(&mut self, division: u8) -> Result<(), Error<E>> {
|
fn set_clock_division(&mut self, division: u8) -> Result<(), Error<E>> {
|
||||||
@ -219,8 +226,12 @@ where
|
|||||||
_ => Err(Error::ParameterError),
|
_ => Err(Error::ParameterError),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
self.set_dds_ref_clk()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_dds_ref_clk(&mut self) -> Result<(), Error<E>> {
|
||||||
// Calculate reference clock frequency after clock division from configuration register
|
// Calculate reference clock frequency after clock division from configuration register
|
||||||
let f_ref_clk = self.f_master_clk / (division as f64);
|
let f_ref_clk = self.f_master_clk / (self.config_register.get_configuration(CFGMask::DIV) as f64);
|
||||||
|
|
||||||
// Update all DDS chips on reference clock frequency
|
// Update all DDS chips on reference clock frequency
|
||||||
for dds_channel in 0..4 {
|
for dds_channel in 0..4 {
|
||||||
|
254
src/mqtt_mux.rs
254
src/mqtt_mux.rs
@ -22,6 +22,11 @@ use crate::Error;
|
|||||||
pub enum MqttTopic {
|
pub enum MqttTopic {
|
||||||
Switch(u8),
|
Switch(u8),
|
||||||
Attenuation(u8),
|
Attenuation(u8),
|
||||||
|
Clock,
|
||||||
|
ClockSource,
|
||||||
|
ClockFrequency,
|
||||||
|
ClockDivision,
|
||||||
|
SystemClock(u8),
|
||||||
Singletone(u8, u8),
|
Singletone(u8, u8),
|
||||||
SingletoneFrequency(u8, u8),
|
SingletoneFrequency(u8, u8),
|
||||||
SingletoneAmplitude(u8, u8),
|
SingletoneAmplitude(u8, u8),
|
||||||
@ -35,6 +40,11 @@ pub enum MqttTopic {
|
|||||||
pub enum MqttCommand {
|
pub enum MqttCommand {
|
||||||
Switch(u8, bool),
|
Switch(u8, bool),
|
||||||
Attenuation(u8, f32),
|
Attenuation(u8, f32),
|
||||||
|
Clock(UrukulClockSource, f64, u8),
|
||||||
|
ClockSource(UrukulClockSource),
|
||||||
|
ClockFrequency(f64),
|
||||||
|
ClockDivision(u8),
|
||||||
|
SystemClock(u8, f64),
|
||||||
Singletone(u8, u8, f64, f64, f64),
|
Singletone(u8, u8, f64, f64, f64),
|
||||||
SingletoneFrequency(u8, u8, f64),
|
SingletoneFrequency(u8, u8, f64),
|
||||||
SingletoneAmplitude(u8, u8, f64),
|
SingletoneAmplitude(u8, u8, f64),
|
||||||
@ -76,7 +86,7 @@ impl<SPI, E> MqttMux<SPI> where SPI: Transfer<u8, Error = E> {
|
|||||||
singletone_frequency,
|
singletone_frequency,
|
||||||
singletone_amplitude,
|
singletone_amplitude,
|
||||||
singletone_phase,
|
singletone_phase,
|
||||||
profile // Note: Put profile at the end
|
profile
|
||||||
))
|
))
|
||||||
)(topic)
|
)(topic)
|
||||||
}
|
}
|
||||||
@ -85,6 +95,11 @@ impl<SPI, E> MqttMux<SPI> where SPI: Transfer<u8, Error = E> {
|
|||||||
match topic {
|
match topic {
|
||||||
MqttTopic::Switch(ch) => switch_message(ch, message),
|
MqttTopic::Switch(ch) => switch_message(ch, message),
|
||||||
MqttTopic::Attenuation(ch) => attenuation_message(ch, message),
|
MqttTopic::Attenuation(ch) => attenuation_message(ch, message),
|
||||||
|
MqttTopic::Clock => clock_message(message),
|
||||||
|
MqttTopic::ClockSource => clock_source_message(message),
|
||||||
|
MqttTopic::ClockFrequency => clock_frequency_message(message),
|
||||||
|
MqttTopic::ClockDivision => clock_division_message(message),
|
||||||
|
MqttTopic::SystemClock(ch) => system_clock_message(ch, message),
|
||||||
MqttTopic::Singletone(ch, prof) => singletone_message(ch, prof, message),
|
MqttTopic::Singletone(ch, prof) => singletone_message(ch, prof, message),
|
||||||
MqttTopic::SingletoneFrequency(ch, prof) => singletone_frequency_message(ch, prof, message),
|
MqttTopic::SingletoneFrequency(ch, prof) => singletone_frequency_message(ch, prof, message),
|
||||||
MqttTopic::SingletoneAmplitude(ch, prof) => singletone_amplitude_message(ch, prof, message),
|
MqttTopic::SingletoneAmplitude(ch, prof) => singletone_amplitude_message(ch, prof, message),
|
||||||
@ -97,6 +112,11 @@ impl<SPI, E> MqttMux<SPI> where SPI: Transfer<u8, Error = E> {
|
|||||||
match command {
|
match command {
|
||||||
MqttCommand::Switch(ch, state) => self.urukul.set_channel_switch(ch.into(), state),
|
MqttCommand::Switch(ch, state) => self.urukul.set_channel_switch(ch.into(), state),
|
||||||
MqttCommand::Attenuation(ch, ampl) => self.urukul.set_channel_attenuation(ch, ampl),
|
MqttCommand::Attenuation(ch, ampl) => self.urukul.set_channel_attenuation(ch, ampl),
|
||||||
|
MqttCommand::Clock(src, freq, div) => self.urukul.set_clock(src, freq, div),
|
||||||
|
MqttCommand::ClockSource(src) => self.urukul.set_clock_source(src),
|
||||||
|
MqttCommand::ClockFrequency(freq) => self.urukul.set_clock_frequency(freq),
|
||||||
|
MqttCommand::ClockDivision(div) => self.urukul.set_clock_division(div),
|
||||||
|
MqttCommand::SystemClock(ch, freq) => self.urukul.set_channel_sys_clk(ch, freq),
|
||||||
MqttCommand::Singletone(ch, prof, freq, ampl, deg) => self.urukul.set_channel_single_tone_profile(ch, prof, freq, ampl, deg),
|
MqttCommand::Singletone(ch, prof, freq, ampl, deg) => self.urukul.set_channel_single_tone_profile(ch, prof, freq, ampl, deg),
|
||||||
MqttCommand::SingletoneFrequency(ch, prof, freq) => self.urukul.set_channel_single_tone_profile_frequency(ch, prof, freq),
|
MqttCommand::SingletoneFrequency(ch, prof, freq) => self.urukul.set_channel_single_tone_profile_frequency(ch, prof, freq),
|
||||||
MqttCommand::SingletoneAmplitude(ch, prof, ampl) => self.urukul.set_channel_single_tone_profile_amplitude(ch, prof, ampl),
|
MqttCommand::SingletoneAmplitude(ch, prof, ampl) => self.urukul.set_channel_single_tone_profile_amplitude(ch, prof, ampl),
|
||||||
@ -152,6 +172,16 @@ fn select_profile<'a>(topic: &'a str) -> IResult<&'a str, u8> {
|
|||||||
)(topic)
|
)(topic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn select_clock<'a>(topic: &'a str) -> IResult<&'a str, ()> {
|
||||||
|
value(
|
||||||
|
(),
|
||||||
|
preceded(
|
||||||
|
tag("Clock"),
|
||||||
|
topic_separator
|
||||||
|
)
|
||||||
|
)(topic)
|
||||||
|
}
|
||||||
|
|
||||||
// Selection parser for Singletone
|
// Selection parser for Singletone
|
||||||
// Note: This fucntion assumes singletone is not the most specific sub-topic
|
// Note: This fucntion assumes singletone is not the most specific sub-topic
|
||||||
fn select_singletone<'a>(topic: &'a str) -> IResult<&'a str, ()> {
|
fn select_singletone<'a>(topic: &'a str) -> IResult<&'a str, ()> {
|
||||||
@ -161,12 +191,6 @@ fn select_singletone<'a>(topic: &'a str) -> IResult<&'a str, ()> {
|
|||||||
)(topic)
|
)(topic)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_end_slice(message: &[u8]) -> IResult<&[u8], ()> {
|
|
||||||
not(
|
|
||||||
take(1_usize)
|
|
||||||
)(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read whitespace
|
// Read whitespace
|
||||||
fn whitespace(message: &[u8]) -> IResult<&[u8], ()> {
|
fn whitespace(message: &[u8]) -> IResult<&[u8], ()> {
|
||||||
value((), take_while(is_space))(message)
|
value((), take_while(is_space))(message)
|
||||||
@ -252,6 +276,175 @@ fn attenuation_message(channel: u8, message: &[u8]) -> IResult<&[u8], MqttComman
|
|||||||
)(message)
|
)(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parser for Clock Source Command Topic
|
||||||
|
fn clock_source<'a>(topic: &'a str) -> IResult<&'a str, MqttTopic> {
|
||||||
|
all_consuming(
|
||||||
|
value(
|
||||||
|
MqttTopic::ClockSource,
|
||||||
|
preceded(
|
||||||
|
clock_source,
|
||||||
|
tag("Source")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)(topic)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parser for Clock Source Command Message
|
||||||
|
fn clock_source_message(message: &[u8]) -> IResult<&[u8], MqttCommand> {
|
||||||
|
all_consuming(
|
||||||
|
alt((
|
||||||
|
value(MqttCommand::ClockSource(UrukulClockSource::OSC), tag_no_case("OSC")),
|
||||||
|
value(MqttCommand::ClockSource(UrukulClockSource::MMCX), tag_no_case("MMCX")),
|
||||||
|
value(MqttCommand::ClockSource(UrukulClockSource::SMA), tag_no_case("SMA"))
|
||||||
|
))
|
||||||
|
)(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parser for Clock Frequency Command Topic
|
||||||
|
fn clock_frequency<'a>(topic: &'a str) -> IResult<&'a str, MqttTopic> {
|
||||||
|
all_consuming(
|
||||||
|
value(
|
||||||
|
MqttTopic::ClockFrequency,
|
||||||
|
preceded(
|
||||||
|
clock_source,
|
||||||
|
tag("Frequency")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)(topic)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parser for Clock Frequency Command Message
|
||||||
|
fn clock_frequency_message(message: &[u8]) -> IResult<&[u8], MqttCommand> {
|
||||||
|
all_consuming(
|
||||||
|
map(
|
||||||
|
read_frequency,
|
||||||
|
|freq: f64| MqttCommand::ClockFrequency(freq)
|
||||||
|
)
|
||||||
|
)(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parser for Clock Division Command Topic
|
||||||
|
fn clock_division<'a>(topic: &'a str) -> IResult<&'a str, MqttTopic> {
|
||||||
|
all_consuming(
|
||||||
|
value(
|
||||||
|
MqttTopic::ClockDivision,
|
||||||
|
preceded(
|
||||||
|
clock_source,
|
||||||
|
tag("Division")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)(topic)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parser for Clock Division Command Message
|
||||||
|
fn clock_division_message(message: &[u8]) -> IResult<&[u8], MqttCommand> {
|
||||||
|
all_consuming(
|
||||||
|
map(
|
||||||
|
digit1,
|
||||||
|
|div: &[u8]| MqttCommand::ClockDivision(
|
||||||
|
u8::from_str_radix(
|
||||||
|
core::str::from_utf8(div).unwrap(),
|
||||||
|
10
|
||||||
|
).unwrap()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parser for one-command master clock setup topic
|
||||||
|
fn clock<'a>(topic: &'a str) -> IResult<&'a str, MqttTopic> {
|
||||||
|
all_consuming(
|
||||||
|
value(
|
||||||
|
MqttTopic::Clock,
|
||||||
|
tag("Clock")
|
||||||
|
)
|
||||||
|
)(topic)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parser for one-command master clock setup message
|
||||||
|
fn clock_message(message: &[u8]) -> IResult<&[u8], MqttCommand> {
|
||||||
|
all_consuming(
|
||||||
|
map(
|
||||||
|
delimited(
|
||||||
|
tag("{"),
|
||||||
|
tuple((
|
||||||
|
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
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)),
|
||||||
|
tag("}")
|
||||||
|
),
|
||||||
|
|(src, freq, div): (UrukulClockSource, f64, u8)| MqttCommand::Clock(src, freq, div)
|
||||||
|
)
|
||||||
|
)(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Topic parser for f_sys_clk of any channels
|
||||||
|
fn system_clock<'a>(topic: &'a str) -> IResult<&'a str, MqttTopic> {
|
||||||
|
all_consuming(
|
||||||
|
map(
|
||||||
|
terminated(
|
||||||
|
select_channel,
|
||||||
|
tag("SystemClock")
|
||||||
|
),
|
||||||
|
|channel: u8| MqttTopic::SystemClock(channel)
|
||||||
|
)
|
||||||
|
)(topic)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message parser for f_sys_clk of any channels
|
||||||
|
fn system_clock_message(channel: u8, message: &[u8]) -> IResult<&[u8], MqttCommand> {
|
||||||
|
all_consuming(
|
||||||
|
map(
|
||||||
|
read_frequency,
|
||||||
|
|freq: f64| MqttCommand::SystemClock(channel, freq)
|
||||||
|
)
|
||||||
|
)(message)
|
||||||
|
}
|
||||||
|
|
||||||
// Parser for Singletone frequenct Command Topic
|
// Parser for Singletone frequenct Command Topic
|
||||||
fn singletone_frequency<'a>(topic: &'a str) -> IResult<&'a str, MqttTopic> {
|
fn singletone_frequency<'a>(topic: &'a str) -> IResult<&'a str, MqttTopic> {
|
||||||
all_consuming(
|
all_consuming(
|
||||||
@ -364,28 +557,65 @@ fn singletone<'a>(topic: &'a str) -> IResult<&'a str, MqttTopic> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parser for one-command singletone profile Command
|
// Parser for one-command singletone profile Command
|
||||||
|
// Using JSON like command structure
|
||||||
|
// Possible enhancement: further modularize parsing of all separate fields
|
||||||
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((
|
tuple((
|
||||||
read_frequency,
|
|
||||||
preceded(
|
preceded(
|
||||||
message_separator,
|
tag("{"),
|
||||||
double
|
preceded(
|
||||||
|
whitespace,
|
||||||
|
preceded(
|
||||||
|
tag("\"frequency\":"),
|
||||||
|
preceded(
|
||||||
|
whitespace,
|
||||||
|
read_frequency
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
preceded(
|
preceded(
|
||||||
message_separator,
|
tag(","),
|
||||||
|
preceded(
|
||||||
|
whitespace,
|
||||||
|
preceded(
|
||||||
|
tag("\"amplitude\":"),
|
||||||
|
preceded(
|
||||||
|
whitespace,
|
||||||
|
double
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
preceded(
|
||||||
|
tag(","),
|
||||||
|
preceded(
|
||||||
|
whitespace,
|
||||||
|
preceded(
|
||||||
|
tag("\"phase\":"),
|
||||||
|
preceded(
|
||||||
|
whitespace,
|
||||||
terminated(
|
terminated(
|
||||||
double,
|
double,
|
||||||
|
preceded(
|
||||||
opt(
|
opt(
|
||||||
preceded(
|
preceded(
|
||||||
whitespace,
|
whitespace,
|
||||||
tag_no_case("deg")
|
tag_no_case("deg")
|
||||||
)
|
)
|
||||||
|
),
|
||||||
|
preceded(
|
||||||
|
whitespace,
|
||||||
|
tag("}")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
)),
|
)),
|
||||||
|(freq, ampl, phase): (f64, f64, f64)| MqttCommand::Singletone(channel, profile, freq, ampl, phase)
|
|(freq, ampl, phase): (f64, f64, f64)| MqttCommand::Singletone(channel, profile, freq, ampl, phase)
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user