diff --git a/Cargo.toml b/Cargo.toml index b678d44..f024764 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,12 @@ branch = "issue-4" default-features = false features = [ "build-info", "unit-frequency" ] +# Use below SCPI dependency when need to modify SCPI fork offline +# [dependencies.scpi] +# path = "../scpi-fork/scpi" +# default-features = false +# features = [ "build-info", "unit-frequency" ] + [[example]] name = "ethernet" diff --git a/examples/ethernet.rs b/examples/ethernet.rs index b004ce3..2b77806 100644 --- a/examples/ethernet.rs +++ b/examples/ethernet.rs @@ -53,6 +53,7 @@ use firmware::{ Channel3AttenuationCommand, ClockSourceCommand, ClockDivisionCommand, + ProfileCommand }, Urukul, scpi_root, recursive_scpi_tree, scpi_tree }; diff --git a/examples/mqtt_client.rs b/examples/mqtt_client.rs index a09b618..b126864 100644 --- a/examples/mqtt_client.rs +++ b/examples/mqtt_client.rs @@ -43,6 +43,7 @@ use firmware::{ Channel3AttenuationCommand, ClockSourceCommand, ClockDivisionCommand, + ProfileCommand, }, Urukul, scpi_root, recursive_scpi_tree, scpi_tree }; diff --git a/src/lib.rs b/src/lib.rs index 52ef2f4..8bb8e31 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![feature(generic_associated_types)] +#![feature(str_strip)] extern crate embedded_hal; use embedded_hal::{ digital::v2::OutputPin, @@ -156,6 +157,7 @@ pub trait UrukulTraits { fn set_clock_source(&mut self, source: ClockSource, frequency: f64) -> Result<(), Self::Error>; fn set_clock_division(&mut self, division: u8) -> Result<(), Self::Error>; fn set_channel_attenuation(&mut self, channel: u8, attenuation: f32) -> Result<(), Self::Error>; + fn set_profile(&mut self, profile: u8) -> Result<(), Self::Error>; } impl UrukulTraits for Urukul @@ -234,4 +236,10 @@ where fn set_channel_attenuation(&mut self, channel: u8, attenuation: f32) -> Result<(), Self::Error> { self.attenuator.set_channel_attenuation(channel, attenuation) } + + fn set_profile(&mut self, profile: u8) -> Result<(), Self::Error> { + self.config_register.set_configurations(&mut [ + (CFGMask::PROFILE, profile.into()) + ]).map(|_| ()) + } } diff --git a/src/scpi.rs b/src/scpi.rs index 1017ea6..c3bfc68 100644 --- a/src/scpi.rs +++ b/src/scpi.rs @@ -114,30 +114,27 @@ macro_rules! scpi_root { macro_rules! scpi_tree { () => { scpi_root!( - ["Control"] => { - ["Urukul"] => { - "CHANNEL0" => { - "SWitch" => Channel0SwitchCommand, - "Attenuation" => Channel0AttenuationCommand - }, - "CHANNEL1" => { - "SWitch" => Channel1SwitchCommand, - "Attenuation" => Channel1AttenuationCommand - }, - "CHANNEL2" => { - "SWitch" => Channel2SwitchCommand, - "Attenuation" => Channel2AttenuationCommand - }, - "CHANNEL3" => { - "SWitch" => Channel3SwitchCommand, - "Attenuation" => Channel3AttenuationCommand - }, - "CLOCK" => { - "SOURCE" => ClockSourceCommand, - "DIVision" => ClockDivisionCommand - } - } + "CHANNEL0" => { + "SWitch" => Channel0SwitchCommand, + "Attenuation" => Channel0AttenuationCommand }, + "CHANNEL1" => { + "SWitch" => Channel1SwitchCommand, + "Attenuation" => Channel1AttenuationCommand + }, + "CHANNEL2" => { + "SWitch" => Channel2SwitchCommand, + "Attenuation" => Channel2AttenuationCommand + }, + "CHANNEL3" => { + "SWitch" => Channel3SwitchCommand, + "Attenuation" => Channel3AttenuationCommand + }, + "CLOCK" => { + "SOURCE" => ClockSourceCommand, + "DIVision" => ClockDivisionCommand + }, + "PROFILE" => ProfileCommand, ["EXAMple"] => { "HELLO" => { "WORLD" => HelloWorldCommand @@ -171,6 +168,7 @@ pub struct Channel0AttenuationCommand {} pub struct Channel1AttenuationCommand {} pub struct Channel2AttenuationCommand {} pub struct Channel3AttenuationCommand {} +pub struct ProfileCommand {} impl Command for Channel0SwitchCommand { nquery!(); @@ -356,6 +354,28 @@ impl Command for Channel3AttenuationCommand { } } +impl Command for ProfileCommand { + nquery!(); + + fn event(&self, context: &mut Context, args: &mut Tokenizer) -> Result<()> { + let profile :f32 = args.next_data(false)? + .map_or(Err(Error::new(ErrorCode::IllegalParameterValue)), + |token| token.try_into())?; + if ((profile as u8) as f32) != profile { + return Err(Error::new(ErrorCode::IllegalParameterValue)); + } + + trace!("Selected Profile :{}", profile); + let profile = profile as u8; + if profile >= 8 { + Err(Error::new(ErrorCode::IllegalParameterValue)) + } else { + context.device.set_profile(profile) + .map_err(|_| Error::new(ErrorCode::HardwareError)) + } + } +} + /* * Implement "Device" trait from SCPI * TODO: Implement mandatory commands diff --git a/src/translation.rs b/src/translation.rs index 74f14a0..ee13727 100644 --- a/src/translation.rs +++ b/src/translation.rs @@ -1,7 +1,7 @@ use scpi::prelude::*; use scpi::Context; use scpi::error::Result; -use log::trace; +use log::{trace, info}; use arrayvec::{ArrayVec}; pub trait MqttScpiTranslator { @@ -15,11 +15,19 @@ impl<'a, T: Device> MqttScpiTranslator for Context<'a, T> { where FMT: Formatter, { + if !topic.starts_with("Urukul/Control") { + info!("Received a publish, but not for control! Topic: {}", topic); + return Ok(()); + } + + let command_topic = topic.strip_prefix("Urukul/Control/") + .unwrap_or(""); + // Create a fixed-size buffer to handle slice operation let mut buffer = ArrayVec::<[u8; 1024]>::new(); // Copy MQTT topic, convert it into SCPI header format - for i in topic.chars() { + for i in command_topic.chars() { if i == '/' { // The topic separator is colon(':') in SCPI, and slash('/') in MQTT buffer.try_push(b':')