use scpi::prelude::*; use scpi::Context; use scpi::error::Result; use log::{trace, info}; use arrayvec::{ArrayVec}; pub trait MqttScpiTranslator { // Convert an MQTT publish message into SCPI compatible command // The argument part/ MQTT message must follow SCPI standard for parameter formatting fn run_with_mqtt(&mut self, topic: &str, args: &str, response: &mut FMT) -> Result<()>; } impl<'a, T: Device> MqttScpiTranslator for Context<'a, T> { fn run_with_mqtt(&mut self, topic: &str, args: &str, response: &mut FMT) -> Result<()> 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 command_topic.chars() { if i == '/' { // The topic separator is colon(':') in SCPI, and slash('/') in MQTT buffer.try_push(b':') .map_err(|_| ErrorCode::OutOfMemory)?; } else { buffer.try_push(i as u8) .map_err(|_| ErrorCode::OutOfMemory)?; } } // Place a space bar between header and parameter buffer.try_push(b' ') .map_err(|_| ErrorCode::OutOfMemory)?; // Copy the arguments into the buffer for i in args.chars() { buffer.try_push(i as u8) .map_err(|_| ErrorCode::OutOfMemory)?; } // Pass the message to SCPI processing unit trace!("Translated MQTT message into SCPI. Translated command: {}", core::str::from_utf8(buffer.as_slice()).unwrap()); self.run(buffer.as_slice(), response) } }