diff --git a/src/dds.rs b/src/dds.rs index 5a0958c..ec398ea 100644 --- a/src/dds.rs +++ b/src/dds.rs @@ -382,10 +382,38 @@ where ]) } + /* + * Getter function for single tone profiles + */ + pub fn get_single_tone_profile(&mut self, profile: u8) -> Result<(f64, f64, f64), Error> { + + assert!(profile < 8); + + let mut profile_content: [u8; 8] = [0; 8]; + self.read_register(0x0E + profile, &mut profile_content)?; + + // Convert ftw, pow and asf to f_out, phase and amplitude factor + let ftw: u64 = (profile_content[4] as u64) << 24 | + (profile_content[5] as u64) << 16 | + (profile_content[6] as u64) << 8 | + (profile_content[7] as u64); + let f_out: f64 = ((ftw as f64)/(((1_u64) << 32) as f64))*self.f_sys_clk; + + let pow: u64 = (profile_content[2] as u64) << 8 | + (profile_content[3] as u64); + let phase: f64 = ((pow as f64)/(((1_u64) << 16) as f64))*360.0; + + let asf: u64 = (profile_content[0] as u64) << 8 | + (profile_content[1] as u64); + let amplitude: f64 = (asf as f64)/(((1_u64) << 14) as f64); + + Ok((f_out, phase, amplitude)) + } + /* * Set frequency of a single tone profile * Frequency: Must be non-negative - * Keep other field unchanged in the register + * Keep other field unchanged in the register */ pub fn set_single_tone_profile_frequency(&mut self, profile: u8, f_out: f64) -> Result<(), Error> { @@ -411,7 +439,7 @@ where /* * Set phase offset of a single tone profile * Phase: Expressed in positive degree, i.e. [0.0, 360.0) - * Keep other field unchanged in the register + * Keep other field unchanged in the register */ pub fn set_single_tone_profile_phase(&mut self, profile: u8, phase_offset: f64) -> Result<(), Error> { @@ -435,7 +463,7 @@ where /* * Set amplitude offset of a single tone profile * Amplitude: In a scale from 0 to 1, taking float - * Keep other field unchanged in the register + * Keep other field unchanged in the register */ pub fn set_single_tone_profile_amplitude(&mut self, profile: u8, amp_scale_factor: f64) -> Result<(), Error> { diff --git a/src/mqtt_mux.rs b/src/mqtt_mux.rs index c1eab5d..d00d9cb 100644 --- a/src/mqtt_mux.rs +++ b/src/mqtt_mux.rs @@ -123,15 +123,15 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { .map_err(|_| Error::StringOutOfSpace)?; topic_string }, - String::from( - match self.urukul.test() { - Ok(0) => "Reset successful.", - _ => "Reset error!", - } - ) + String::from( + match self.urukul.test() { + Ok(0) => "Reset successful.", + _ => "Reset error!", + } + ) )).map_err(|_| Error::VectorOutOfSpace)?; Ok(vec) - } + } MqttCommand::Switch(ch, _) => { vec.push(( @@ -177,10 +177,46 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { ) ) } - )) - ), - MqttCommand::SystemClock(ch, _) => Ok( - Some(( + )).map_err(|_| Error::VectorOutOfSpace)?; + Ok(vec) + } + + MqttCommand::Clock(_, _, _) => { + vec.push( + self.get_clock_source_message()? + ).map_err(|_| Error::VectorOutOfSpace)?; + vec.push( + self.get_clock_frequency_message()? + ).map_err(|_| Error::VectorOutOfSpace)?; + vec.push( + self.get_clock_division_message()? + ).map_err(|_| Error::VectorOutOfSpace)?; + Ok(vec) + } + + MqttCommand::ClockSource(_) => { + vec.push( + self.get_clock_source_message()? + ).map_err(|_| Error::VectorOutOfSpace)?; + Ok(vec) + } + + MqttCommand::ClockFrequency(_) => { + vec.push( + self.get_clock_frequency_message()? + ).map_err(|_| Error::VectorOutOfSpace)?; + Ok(vec) + } + + MqttCommand::ClockDivision(_) => { + vec.push( + self.get_clock_division_message()? + ).map_err(|_| Error::VectorOutOfSpace)?; + Ok(vec) + } + + MqttCommand::SystemClock(ch, _) => { + vec.push(( { let mut topic_string = String::from(self.name); topic_string.push_str("/Feedback/Channel") @@ -201,11 +237,32 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { .map_err(|_| Error::StringOutOfSpace)?; message_str } - )) - ), - MqttCommand::Profile(_) => Ok( - Some(( - "Urukul/Feedback/Profile", + )).map_err(|_| Error::VectorOutOfSpace)?; + Ok(vec) + } + + MqttCommand::Singletone(ch, pr, _, _, _) | + MqttCommand::SingletoneFrequency(ch, pr, _) | + MqttCommand::SingletoneAmplitude(ch, pr, _) | + MqttCommand::SingletonePhase(ch, pr, _) => { + let (f_out, phase, ampl) = self.urukul.get_channel_single_tone_profile(ch, pr)?; + vec.push(self.get_single_tone_frequency_message(ch, pr, f_out)?) + .map_err(|_| Error::StringOutOfSpace)?; + vec.push(self.get_single_tone_phase_message(ch, pr, phase)?) + .map_err(|_| Error::StringOutOfSpace)?; + vec.push(self.get_single_tone_amplitude_message(ch, pr, ampl)?) + .map_err(|_| Error::StringOutOfSpace)?; + Ok(vec) + } + + MqttCommand::Profile(_) => { + vec.push(( + { + let mut topic_string = String::from(self.name); + topic_string.push_str("/Feedback/Profile") + .map_err(|_| Error::StringOutOfSpace)?; + topic_string + }, { let mut message_str = String::new(); let prof = self.urukul.get_profile()?; @@ -213,11 +270,25 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { .map_err(|_| Error::StringOutOfSpace)?; message_str } - )) - ), - _ => Ok(Some(("Urukul/Feedback/Unimplemented", String::from("test")))), + )).map_err(|_| Error::VectorOutOfSpace)?; + Ok(vec) + } + + // _ => { + // vec.push(( + // { + // let mut topic_string = String::from(self.name); + // topic_string.push_str("/Feedback/Unimplemented") + // .map_err(|_| Error::StringOutOfSpace)?; + // topic_string + // }, + // String::from("test") + // )) + // .map_err(|_| Error::VectorOutOfSpace)?; + // Ok(vec) + // } }, - None => Ok(None), + None => Ok(vec), } } @@ -440,13 +511,142 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { } } - pub fn get_switch_status_message(&mut self, channel: u8) -> Result<&str, Error> { - self.urukul.get_channel_switch_status(channel.into()).map( - |stat| if stat { - "on" - } else { - "off" - }) + fn get_clock_source_message(&mut self) -> Result<(String, String), Error> { + Ok(( + { + let mut topic_string = String::from(self.name); + topic_string.push_str("/Feedback/Clock/Source") + .map_err(|_| Error::StringOutOfSpace)?; + topic_string + }, + self.urukul.get_clock_source().map( + |src| match src { + UrukulClockSource::OSC => String::from("OSC"), + UrukulClockSource::MMCX => String::from("MMCX"), + UrukulClockSource::SMA => String::from("SMA") + } + )? + )) + } + + fn get_clock_frequency_message(&mut self) -> Result<(String, String), Error> { + Ok(( + { + let mut topic_string = String::from(self.name); + topic_string.push_str("/Feedback/Clock/Frequency") + .map_err(|_| Error::StringOutOfSpace)?; + topic_string + }, + { + let mut freq_str = String::from( + self.float_buffer.format_finite( + self.urukul.get_clock_frequency() + ) + ); + freq_str.push_str(" Hz").map_err(|_| Error::StringOutOfSpace)?; + freq_str + } + )) + } + + fn get_clock_division_message(&mut self) -> Result<(String, String), Error> { + Ok(( + { + let mut topic_string = String::from(self.name); + topic_string.push_str("/Feedback/Clock/Division") + .map_err(|_| Error::StringOutOfSpace)?; + topic_string + }, + { + self.urukul.get_clock_division().map( + |src| match src { + 1 => String::from("1"), + 2 => String::from("2"), + 4 => String::from("4"), + _ => unreachable!() + } + )? + } + )) + } + + fn get_single_tone_frequency_message(&mut self, ch: u8, pr: u8, f_out: f64) -> Result<(String, String), Error> { + Ok(( + { + let mut topic_string = String::from(self.name); + topic_string.push_str("/Feedback/Channel") + .map_err(|_| Error::StringOutOfSpace)?; + topic_string.push(char::from_digit(ch.into(), 10).unwrap()) + .map_err(|_| Error::StringOutOfSpace)?; + topic_string.push_str("/Profile") + .map_err(|_| Error::StringOutOfSpace)?; + topic_string.push(char::from_digit(pr.into(), 10).unwrap()) + .map_err(|_| Error::StringOutOfSpace)?; + topic_string.push_str("/Singletone/Frequency") + .map_err(|_| Error::StringOutOfSpace)?; + topic_string + }, + { + let mut message_str = String::from( + self.float_buffer.format_finite(f_out) + ); + message_str.push_str(" Hz") + .map_err(|_| Error::StringOutOfSpace)?; + message_str + } + )) + } + + fn get_single_tone_amplitude_message(&mut self, ch: u8, pr: u8, ampl: f64) -> Result<(String, String), Error> { + Ok(( + { + let mut topic_string = String::from(self.name); + topic_string.push_str("/Feedback/Channel") + .map_err(|_| Error::StringOutOfSpace)?; + topic_string.push(char::from_digit(ch.into(), 10).unwrap()) + .map_err(|_| Error::StringOutOfSpace)?; + topic_string.push_str("/Profile") + .map_err(|_| Error::StringOutOfSpace)?; + topic_string.push(char::from_digit(pr.into(), 10).unwrap()) + .map_err(|_| Error::StringOutOfSpace)?; + topic_string.push_str("/Singletone/Amplitude") + .map_err(|_| Error::StringOutOfSpace)?; + topic_string + }, + { + let message_str = String::from( + self.float_buffer.format_finite(ampl) + ); + message_str + } + )) + } + + fn get_single_tone_phase_message(&mut self, ch: u8, pr: u8, phase: f64) -> Result<(String, String), Error> { + Ok(( + { + let mut topic_string = String::from(self.name); + topic_string.push_str("/Feedback/Channel") + .map_err(|_| Error::StringOutOfSpace)?; + topic_string.push(char::from_digit(ch.into(), 10).unwrap()) + .map_err(|_| Error::StringOutOfSpace)?; + topic_string.push_str("/Profile") + .map_err(|_| Error::StringOutOfSpace)?; + topic_string.push(char::from_digit(pr.into(), 10).unwrap()) + .map_err(|_| Error::StringOutOfSpace)?; + topic_string.push_str("/Singletone/Phase") + .map_err(|_| Error::StringOutOfSpace)?; + topic_string + }, + { + let mut message_str = String::from( + self.float_buffer.format_finite(phase) + ); + message_str.push_str(" deg") + .map_err(|_| Error::StringOutOfSpace)?; + message_str + } + )) } } diff --git a/src/urukul.rs b/src/urukul.rs index cba55a6..df9d57f 100644 --- a/src/urukul.rs +++ b/src/urukul.rs @@ -291,6 +291,10 @@ where } self.dds[usize::from(channel)].set_single_tone_profile(profile, frequency, phase, amplitude) } + + pub fn get_channel_single_tone_profile(&mut self, channel: u8, profile: u8) -> Result<(f64, f64, f64), Error> { + self.dds[usize::from(channel)].get_single_tone_profile(profile) + } pub fn set_channel_single_tone_profile_frequency(&mut self, channel: u8, profile: u8, frequency: f64)-> Result<(), Error> { if channel >= 4 || profile >= 8 || frequency < 0.0 {