mqtt_to_scpi: strip away expected topic

This commit is contained in:
occheung 2020-09-15 17:50:35 +08:00
parent b502b42c92
commit 331d1ff86f
6 changed files with 69 additions and 25 deletions

View File

@ -33,6 +33,12 @@ branch = "issue-4"
default-features = false default-features = false
features = [ "build-info", "unit-frequency" ] 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]] [[example]]
name = "ethernet" name = "ethernet"

View File

@ -53,6 +53,7 @@ use firmware::{
Channel3AttenuationCommand, Channel3AttenuationCommand,
ClockSourceCommand, ClockSourceCommand,
ClockDivisionCommand, ClockDivisionCommand,
ProfileCommand
}, },
Urukul, scpi_root, recursive_scpi_tree, scpi_tree Urukul, scpi_root, recursive_scpi_tree, scpi_tree
}; };

View File

@ -43,6 +43,7 @@ use firmware::{
Channel3AttenuationCommand, Channel3AttenuationCommand,
ClockSourceCommand, ClockSourceCommand,
ClockDivisionCommand, ClockDivisionCommand,
ProfileCommand,
}, },
Urukul, scpi_root, recursive_scpi_tree, scpi_tree Urukul, scpi_root, recursive_scpi_tree, scpi_tree
}; };

View File

@ -1,5 +1,6 @@
#![no_std] #![no_std]
#![feature(generic_associated_types)] #![feature(generic_associated_types)]
#![feature(str_strip)]
extern crate embedded_hal; extern crate embedded_hal;
use embedded_hal::{ use embedded_hal::{
digital::v2::OutputPin, 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_source(&mut self, source: ClockSource, frequency: f64) -> Result<(), Self::Error>;
fn set_clock_division(&mut self, division: u8) -> 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_channel_attenuation(&mut self, channel: u8, attenuation: f32) -> Result<(), Self::Error>;
fn set_profile(&mut self, profile: u8) -> Result<(), Self::Error>;
} }
impl<SPI, E> UrukulTraits for Urukul<SPI> impl<SPI, E> UrukulTraits for Urukul<SPI>
@ -234,4 +236,10 @@ where
fn set_channel_attenuation(&mut self, channel: u8, attenuation: f32) -> Result<(), Self::Error> { fn set_channel_attenuation(&mut self, channel: u8, attenuation: f32) -> Result<(), Self::Error> {
self.attenuator.set_channel_attenuation(channel, attenuation) 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(|_| ())
}
} }

View File

@ -114,30 +114,27 @@ macro_rules! scpi_root {
macro_rules! scpi_tree { macro_rules! scpi_tree {
() => { () => {
scpi_root!( scpi_root!(
["Control"] => { "CHANNEL0" => {
["Urukul"] => { "SWitch" => Channel0SwitchCommand,
"CHANNEL0" => { "Attenuation" => Channel0AttenuationCommand
"SWitch" => Channel0SwitchCommand,
"Attenuation" => Channel0AttenuationCommand
},
"CHANNEL1" => {
"SWitch" => Channel1SwitchCommand,
"Attenuation" => Channel1AttenuationCommand
},
"CHANNEL2" => {
"SWitch" => Channel2SwitchCommand,
"Attenuation" => Channel2AttenuationCommand
},
"CHANNEL3" => {
"SWitch" => Channel3SwitchCommand,
"Attenuation" => Channel3AttenuationCommand
},
"CLOCK" => {
"SOURCE" => ClockSourceCommand,
"DIVision" => ClockDivisionCommand
}
}
}, },
"CHANNEL1" => {
"SWitch" => Channel1SwitchCommand,
"Attenuation" => Channel1AttenuationCommand
},
"CHANNEL2" => {
"SWitch" => Channel2SwitchCommand,
"Attenuation" => Channel2AttenuationCommand
},
"CHANNEL3" => {
"SWitch" => Channel3SwitchCommand,
"Attenuation" => Channel3AttenuationCommand
},
"CLOCK" => {
"SOURCE" => ClockSourceCommand,
"DIVision" => ClockDivisionCommand
},
"PROFILE" => ProfileCommand,
["EXAMple"] => { ["EXAMple"] => {
"HELLO" => { "HELLO" => {
"WORLD" => HelloWorldCommand "WORLD" => HelloWorldCommand
@ -171,6 +168,7 @@ pub struct Channel0AttenuationCommand {}
pub struct Channel1AttenuationCommand {} pub struct Channel1AttenuationCommand {}
pub struct Channel2AttenuationCommand {} pub struct Channel2AttenuationCommand {}
pub struct Channel3AttenuationCommand {} pub struct Channel3AttenuationCommand {}
pub struct ProfileCommand {}
impl<T: Device + UrukulTraits> Command<T> for Channel0SwitchCommand { impl<T: Device + UrukulTraits> Command<T> for Channel0SwitchCommand {
nquery!(); nquery!();
@ -356,6 +354,28 @@ impl<T:Device + UrukulTraits> Command<T> for Channel3AttenuationCommand {
} }
} }
impl<T:Device + UrukulTraits> Command<T> for ProfileCommand {
nquery!();
fn event(&self, context: &mut Context<T>, 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 * Implement "Device" trait from SCPI
* TODO: Implement mandatory commands * TODO: Implement mandatory commands

View File

@ -1,7 +1,7 @@
use scpi::prelude::*; use scpi::prelude::*;
use scpi::Context; use scpi::Context;
use scpi::error::Result; use scpi::error::Result;
use log::trace; use log::{trace, info};
use arrayvec::{ArrayVec}; use arrayvec::{ArrayVec};
pub trait MqttScpiTranslator { pub trait MqttScpiTranslator {
@ -15,11 +15,19 @@ impl<'a, T: Device> MqttScpiTranslator for Context<'a, T> {
where where
FMT: Formatter, 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 // Create a fixed-size buffer to handle slice operation
let mut buffer = ArrayVec::<[u8; 1024]>::new(); let mut buffer = ArrayVec::<[u8; 1024]>::new();
// Copy MQTT topic, convert it into SCPI header format // Copy MQTT topic, convert it into SCPI header format
for i in topic.chars() { for i in command_topic.chars() {
if i == '/' { if i == '/' {
// The topic separator is colon(':') in SCPI, and slash('/') in MQTT // The topic separator is colon(':') in SCPI, and slash('/') in MQTT
buffer.try_push(b':') buffer.try_push(b':')