From 37b7cc71b78a6d605938a52504e2ec32d77e3cb3 Mon Sep 17 00:00:00 2001 From: occheung Date: Thu, 3 Sep 2020 17:41:27 +0800 Subject: [PATCH] scpi: add switch ctrl command --- .cargo/config | 2 +- Cargo.toml | 7 ++- examples/ethernet.rs | 100 +++++++++++++++++++++++++++++++++++--- src/lib.rs | 27 +++++++++++ src/scpi.rs | 112 +++++++++++++++---------------------------- 5 files changed, 166 insertions(+), 82 deletions(-) diff --git a/.cargo/config b/.cargo/config index c0ce242..86b3292 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,5 +1,5 @@ [target.thumbv7em-none-eabihf] -runner = "gdb -q -x gdb_config/fpga_config.gdb" +runner = "gdb -q -x gdb_config/openocd.gdb" rustflags = [ "-C", "link-arg=-Tlink.x", ] diff --git a/Cargo.toml b/Cargo.toml index 48beb79..8048ea0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,9 @@ stm32h7xx-hal = {version = "0.6.0", features = [ "stm32h743v", "rt", "unproven" stm32h7-ethernet = { version = "0.2.0", features = [ "phy_lan8742a", "stm32h743v" ] } smoltcp = { version = "0.6.0", default-features = false, features = [ "ethernet", "proto-ipv4", "proto-ipv6", "socket-raw" ] } nb = "1.0.0" -scpi = { git = "https://github.com/occheung/scpi-rs", branch = "issue-4" } +scpi = { path = "../scpi-fork/scpi", version = "0.3.4" } +# scpi = { git = "https://github.com/occheung/scpi-rs", branch = "issue-4" } + lexical-core = { version="0.7.1", features=["radix"], default-features=false } libm = "0.2.0" embedded-nal = "0.1.0" @@ -39,6 +41,9 @@ name = "fpga_config" [[example]] name = "tcp_client" +[[example]] +name = "mqtt_client" + # Uncomment for the allocator example. # alloc-cortex-m = "0.3.5" diff --git a/examples/ethernet.rs b/examples/ethernet.rs index c76a090..3e3f43b 100644 --- a/examples/ethernet.rs +++ b/examples/ethernet.rs @@ -76,10 +76,31 @@ use firmware::{ cpld::{ CPLD, }, - scpi::TREE, + scpi::{ HelloWorldCommand, SwitchOnCommand }, Urukul, }; use scpi::prelude::*; +use scpi::ieee488::commands::*; +use scpi::scpi::commands::*; +use scpi::{ + ieee488_cls, + ieee488_ese, + ieee488_esr, + ieee488_idn, + ieee488_opc, + ieee488_rst, + ieee488_sre, + ieee488_stb, + ieee488_tst, + ieee488_wai, + nquery, + //Helpers + qonly, + scpi_crate_version, + scpi_status, + scpi_system, + scpi_tree, +}; /// Configure SYSTICK for 1ms timebase fn systick_init(syst: &mut stm32::SYST, clocks: CoreClocks) { @@ -274,14 +295,82 @@ fn main() -> ! { .finalize(); // SCPI configs - // Device was declared in prior + // TODO: String for *idn? mandated command + + // SCPI tree + let tree = scpi_tree![ + // Create default IEEE488 mandated commands + ieee488_cls!(), + ieee488_ese!(), + ieee488_esr!(), + // ieee488_idn!(b"manufacturer", b"model", b"serial", "0.1.2".as_bytes()), + ieee488_opc!(), + ieee488_rst!(), + ieee488_sre!(), + ieee488_stb!(), + ieee488_tst!(), + ieee488_wai!(), + // Create default SCPI mandated STATus subsystem + scpi_status!(), + // Create default SCPI mandated SYSTem subsystem + scpi_system!(), + // + scpi_crate_version!(), + //Test + Node { + name: b"ABORt", + handler: None, + optional: false, + sub: &[], + }, + Node { + name: b"INITiate", + handler: None, + optional: false, + sub: &[ + Node { + name: b"IMMediate", + handler: None, + optional: true, + sub: &[], + } + ], + }, + Node { + name: b"EXAMple", + optional: true, + handler: None, + sub: &[ + Node { + name: b"HELLO", + optional: false, + handler: None, + sub: &[ + Node { + name: b"WORLD", + optional: true, + handler: Some(&HelloWorldCommand {}), + sub: &[], + } + ], + }, + ], + }, + Node { + name: b"SWitch", + optional: false, + handler: Some(&SwitchOnCommand {}), + sub: &[], + } + ]; + + // Device was declared in prior let mut errors = ArrayErrorQueue::<[Error; 10]>::new(); - let mut context = Context::new(&mut urukul, &mut errors, TREE); + let mut context = Context::new(&mut urukul, &mut errors, tree); //Response bytebuffer let mut buf = ArrayVecFormatter::<[u8; 256]>::new(); - // SCPI configs END // TCP socket buffers @@ -353,9 +442,6 @@ fn main() -> ! { } if socket.can_recv() { - // let result = context.run(socket.recv(|buffer| { - // (buffer.len(), buffer) - // }).unwrap(), &mut buf); let mut data = socket.recv(|buffer| { (buffer.len(), buffer) }).unwrap(); diff --git a/src/lib.rs b/src/lib.rs index 48260cf..fd3219e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -140,6 +140,33 @@ where } } +pub trait UrukulTraits { + type Error; + fn switch(&mut self, channel: u32) -> Result<(), Self::Error>; +} + +impl UrukulTraits for Urukul +where + SPI: Transfer +{ + type Error = Error; + + fn switch(&mut self, channel: u32) -> Result<(), Self::Error>{ + if channel < 16 { + let switch_set = channel | u32::from(self.config_register.get_status(StatusMask::RF_SW)?); + + match self.config_register.set_configurations(&mut [ + (CFGMask::RF_SW, switch_set), + ]) { + Ok(_) => Ok(()), + Err(_e) => Err(_e), + } + } else { + Err(Error::ConfigRegisterError) + } + } +} + // /* // * Struct for a better Urukul master device // */ diff --git a/src/scpi.rs b/src/scpi.rs index 5780d1d..c08bcd6 100644 --- a/src/scpi.rs +++ b/src/scpi.rs @@ -31,17 +31,17 @@ use scpi::{ use embedded_hal::blocking::spi::Transfer; use cortex_m_semihosting::hprintln; -use crate::Urukul; +use crate::{Urukul, UrukulTraits}; // pub struct MyDevice; pub struct HelloWorldCommand {} -impl Command for HelloWorldCommand { +impl Command for HelloWorldCommand { qonly!(); fn query( &self, - _context: &mut Context, + _context: &mut Context, _args: &mut Tokenizer, response: &mut ResponseUnit, ) -> Result<()> { @@ -49,6 +49,39 @@ impl Command for HelloWorldCommand { } } +pub struct SwitchOnCommand {} +impl Command for SwitchOnCommand { + nquery!(); + + fn event(&self, context: &mut Context, args: &mut Tokenizer) -> Result<()> { + let mut channel :u32 = 0; + let mut channel_index = 0; + while true { + match args.next_data(channel_index != 0) { + Ok(Some(token)) => { + match u32::try_from(token) { + Ok(shift) => { + if shift >= 4 { + return Err(ErrorCode::IllegalParameterValue.into()); + } + channel |= (1 << shift); + }, + Err(_) => return Err(ErrorCode::IllegalParameterValue.into()), + } + }, + Ok(None) => break, + Ok(_) => return Err(ErrorCode::MissingParameter.into()), + Err(_e) => return Err(_e), + }; + channel_index += 1; + } + match context.device.switch(channel) { + Ok(()) => Ok(()), + Err(_) => Err(Error::new(ErrorCode::HardwareError)), + } + } +} + /* * Implement "Device" trait from SCPI * TODO: Implement mandatory commands @@ -64,82 +97,15 @@ where fn rst(&mut self) -> Result<()> { match self.reset() { Ok(_) => Ok(()), - Err(_) => Err(Error::new( - ErrorCode::HardwareError - )) + Err(_) => Err(Error::new(ErrorCode::HardwareError)) } } fn tst(&mut self) -> Result<()> { - hprintln!("Testing Urukul...").unwrap(); match self.test() { Ok(0) => Ok(()), - Ok(_) => Err(Error::new( - ErrorCode::SelfTestFailed - )), - Err(_) => Err(Error::new( - ErrorCode::SelfTestFailed - )), + Ok(_) => Err(Error::new(ErrorCode::SelfTestFailed)), + Err(_) => Err(Error::new(ErrorCode::SelfTestFailed)), } } } - -pub const TREE: &Node = scpi_tree![ - // Create default IEEE488 mandated commands - ieee488_cls!(), - ieee488_ese!(), - ieee488_esr!(), - ieee488_idn!(b"manufacturer", b"model", b"serial", "0.1.2".as_bytes()), - ieee488_opc!(), - ieee488_rst!(), - ieee488_sre!(), - ieee488_stb!(), - ieee488_tst!(), - ieee488_wai!(), - // Create default SCPI mandated STATus subsystem - scpi_status!(), - // Create default SCPI mandated SYSTem subsystem - scpi_system!(), - // - scpi_crate_version!(), - //Test - Node { - name: b"ABORt", - handler: None, - optional: false, - sub: &[], - }, - Node { - name: b"INITiate", - handler: None, - optional: false, - sub: &[ - Node { - name: b"IMMediate", - handler: None, - optional: true, - sub: &[], - } - ], - }, - Node { - name: b"EXAMple", - optional: true, - handler: None, - sub: &[ - Node { - name: b"HELLO", - optional: false, - handler: None, - sub: &[ - Node { - name: b"WORLD", - optional: true, - handler: Some(&HelloWorldCommand {}), - sub: &[], - } - ], - }, - ], - } -]; \ No newline at end of file