forked from M-Labs/humpback-dds
mqtt_to_scpi: strip away expected topic
This commit is contained in:
parent
b502b42c92
commit
331d1ff86f
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
|
@ -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(|_| ())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
28
src/scpi.rs
28
src/scpi.rs
|
@ -114,8 +114,6 @@ macro_rules! scpi_root {
|
||||||
macro_rules! scpi_tree {
|
macro_rules! scpi_tree {
|
||||||
() => {
|
() => {
|
||||||
scpi_root!(
|
scpi_root!(
|
||||||
["Control"] => {
|
|
||||||
["Urukul"] => {
|
|
||||||
"CHANNEL0" => {
|
"CHANNEL0" => {
|
||||||
"SWitch" => Channel0SwitchCommand,
|
"SWitch" => Channel0SwitchCommand,
|
||||||
"Attenuation" => Channel0AttenuationCommand
|
"Attenuation" => Channel0AttenuationCommand
|
||||||
|
@ -135,9 +133,8 @@ macro_rules! scpi_tree {
|
||||||
"CLOCK" => {
|
"CLOCK" => {
|
||||||
"SOURCE" => ClockSourceCommand,
|
"SOURCE" => ClockSourceCommand,
|
||||||
"DIVision" => ClockDivisionCommand
|
"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
|
||||||
|
|
|
@ -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':')
|
||||||
|
|
Loading…
Reference in New Issue