diff --git a/build.rs b/build.rs index 54a1a41..5c1aa73 100644 --- a/build.rs +++ b/build.rs @@ -2,9 +2,9 @@ use std::process::Command; fn main() { Command::new("python3") - .arg("fpga/fpga_config.py") - .spawn() - .expect("FPGA bitstream file cannot be built!"); + .arg("fpga/fpga_config.py") + .spawn() + .expect("FPGA bitstream file cannot be built!"); println!("cargo:rerun-if-changed=fpga/fpga_config.py") } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 22512b8..6d05d22 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -3,4 +3,4 @@ channel = "nightly-2020-10-30" targets = [ "thumbv7em-none-eabihf", ] -profile = "minimal" +profile = "default" diff --git a/src/attenuator.rs b/src/attenuator.rs index ca9eaba..95484c9 100644 --- a/src/attenuator.rs +++ b/src/attenuator.rs @@ -1,5 +1,5 @@ -use embedded_hal::blocking::spi::Transfer; use core::assert; +use embedded_hal::blocking::spi::Transfer; use crate::urukul::Error; @@ -10,7 +10,7 @@ pub struct Attenuator { impl Attenuator where - SPI: Transfer + SPI: Transfer, { pub fn new(spi: SPI) -> Self { Attenuator { @@ -36,16 +36,21 @@ where // Set data as attenuation * 2 // Flip data using bitwise XOR, active low data // Data is most signifant attenuator first - self.data[3-i] = (((atten * 2.0) as u8) ^ 0xFF) << 2 + self.data[3 - i] = (((atten * 2.0) as u8) ^ 0xFF) << 2 } let mut clone = self.data.clone(); // Transmit SPI once to set attenuation - self.spi.transfer(&mut clone) - .map(|_| ()) - .map_err(|_| Error::AttenuatorError) + self.spi + .transfer(&mut clone) + .map(|_| ()) + .map_err(|_| Error::AttenuatorError) } - pub fn set_channel_attenuation(&mut self, channel: u8, attenuation: f32) -> Result<(), Error> { + pub fn set_channel_attenuation( + &mut self, + channel: u8, + attenuation: f32, + ) -> Result<(), Error> { assert!(channel < 4); let mut arr: [f32; 4] = self.get_attenuation()?; arr[channel as usize] = attenuation; @@ -64,12 +69,12 @@ where let mut clone = self.data.clone(); match self.spi.transfer(&mut clone).map_err(Error::SPI) { Ok(arr) => { - let mut ret :[f32; 4] = [0.0; 4]; + let mut ret: [f32; 4] = [0.0; 4]; for index in 0..4 { ret[index] = ((arr[3 - index] ^ 0xFC) as f32) / 8.0; } Ok(ret) - }, + } Err(e) => Err(e), } } @@ -82,16 +87,14 @@ where // Test attenuators by getting back the attenuation let mut error_count = 0; // Convert cached SPI data into attenuation floats - let att_floats :[f32; 4] = [ + let att_floats: [f32; 4] = [ ((self.data[3] ^ 0xFC) as f32) / 8.0, ((self.data[2] ^ 0xFC) as f32) / 8.0, ((self.data[1] ^ 0xFC) as f32) / 8.0, ((self.data[0] ^ 0xFC) as f32) / 8.0, ]; // Set the attenuation to an arbitrary value, then read the attenuation - self.set_attenuation([ - 3.5, 9.5, 20.0, 28.5 - ])?; + self.set_attenuation([3.5, 9.5, 20.0, 28.5])?; match self.get_attenuation() { Ok(arr) => { if arr[0] != 3.5 { @@ -106,7 +109,7 @@ where if arr[3] != 28.5 { error_count += 1; } - }, + } Err(_) => return Err(Error::AttenuatorError), }; self.set_attenuation(att_floats)?; @@ -116,7 +119,7 @@ where impl Transfer for Attenuator where - SPI: Transfer + SPI: Transfer, { type Error = Error; diff --git a/src/config.rs b/src/config.rs index ed483d5..50a8a92 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,16 +1,16 @@ -use smoltcp as net; -use net::wire::IpCidr; use net::wire::EthernetAddress; +use net::wire::IpCidr; +use smoltcp as net; use embedded_nal as nal; use nal::IpAddr; -use heapless::{ String, consts::* }; +use heapless::{consts::*, String}; -use serde::{ Serialize, Deserialize }; +use serde::{Deserialize, Serialize}; -use crate::urukul::ClockSource; use crate::flash_store::FlashStore; +use crate::urukul::ClockSource; use core::str::FromStr; @@ -72,7 +72,7 @@ pub fn get_net_config(store: &mut FlashStore) -> NetConfig { eth_addr: { match store.read_str("MAC").unwrap() { Some(mac) => EthernetAddress::from_str(mac).unwrap(), - None => EthernetAddress::from_str("AC:6F:7A:DE:D6:C8").unwrap() + None => EthernetAddress::from_str("AC:6F:7A:DE:D6:C8").unwrap(), } }, broker_ip: { @@ -84,9 +84,9 @@ pub fn get_net_config(store: &mut FlashStore) -> NetConfig { name: { match store.read_str("Name").unwrap() { Some(name) => String::from(name), - None => String::from("HumpbackDDS") + None => String::from("HumpbackDDS"), } - } + }, }; log::info!("Net config: {:?}", net_config); net_config diff --git a/src/config_register.rs b/src/config_register.rs index 879bd87..ae5f85f 100644 --- a/src/config_register.rs +++ b/src/config_register.rs @@ -1,6 +1,6 @@ -use embedded_hal::blocking::spi::Transfer; use crate::urukul::Error; use core::mem::size_of; +use embedded_hal::blocking::spi::Transfer; // Bitmasks for CFG construct_bitmask!(CFGMask; u32; @@ -23,7 +23,7 @@ construct_bitmask!(StatusMask; u32; SMP_ERR, 4, 4, PLL_LOCK, 8, 4, IFC_MODE, 12, 4, - PROTO_KEY, 16, 7 + PROTO_KEY, 16, 7 ); pub struct ConfigRegister { @@ -33,13 +33,10 @@ pub struct ConfigRegister { impl ConfigRegister where - SPI: Transfer + SPI: Transfer, { pub fn new(spi: SPI) -> Self { - ConfigRegister { - spi, - data: 0, - } + ConfigRegister { spi, data: 0 } } /* @@ -47,16 +44,16 @@ where * Return status */ fn set_all_configurations(&mut self) -> Result> { - match self.spi.transfer(&mut [ - ((self.data & 0x00FF0000) >> 16) as u8, - ((self.data & 0x0000FF00) >> 8) as u8, - ((self.data & 0x000000FF) >> 0) as u8, - ]).map_err(Error::SPI) { - Ok(arr) => Ok( - ((arr[0] as u32) << 16) | - ((arr[1] as u32) << 8) | - arr[2] as u32 - ), + match self + .spi + .transfer(&mut [ + ((self.data & 0x00FF0000) >> 16) as u8, + ((self.data & 0x0000FF00) >> 8) as u8, + ((self.data & 0x000000FF) >> 0) as u8, + ]) + .map_err(Error::SPI) + { + Ok(arr) => Ok(((arr[0] as u32) << 16) | ((arr[1] as u32) << 8) | arr[2] as u32), Err(e) => Err(e), } } @@ -64,8 +61,8 @@ where /* * Set configuration bits according to supplied configs * Return status - */ - pub fn set_configurations(&mut self, configs: &mut[(CFGMask, u32)]) -> Result> { + */ + pub fn set_configurations(&mut self, configs: &mut [(CFGMask, u32)]) -> Result> { for config in configs.into_iter() { config.0.set_data_by_arg(&mut self.data, config.1) } @@ -113,7 +110,7 @@ where impl Transfer for ConfigRegister where - SPI: Transfer + SPI: Transfer, { type Error = Error; @@ -121,4 +118,3 @@ where self.spi.transfer(words).map_err(Error::SPI) } } - diff --git a/src/cpld.rs b/src/cpld.rs index 3f00e5a..5b3cabc 100644 --- a/src/cpld.rs +++ b/src/cpld.rs @@ -1,10 +1,7 @@ -use crate::urukul::Error; use crate::spi_slave::Parts; +use crate::urukul::Error; -use embedded_hal::{ - digital::v2::OutputPin, - blocking::spi::Transfer, -}; +use embedded_hal::{blocking::spi::Transfer, digital::v2::OutputPin}; use core::cell; @@ -35,20 +32,25 @@ where match chip & (1 << 0) { 0 => self.chip_select.0.set_low(), _ => self.chip_select.0.set_high(), - }.map_err(|_| Error::CSError)?; + } + .map_err(|_| Error::CSError)?; match chip & (1 << 1) { 0 => self.chip_select.1.set_low(), _ => self.chip_select.1.set_high(), - }.map_err(|_| Error::CSError)?; + } + .map_err(|_| Error::CSError)?; match chip & (1 << 2) { 0 => self.chip_select.2.set_low(), _ => self.chip_select.2.set_high(), - }.map_err(|_| Error::CSError)?; + } + .map_err(|_| Error::CSError)?; Ok(()) } pub(crate) fn issue_io_update(&mut self) -> Result<(), Error> { - self.io_update.set_high().map_err(|_| Error::IOUpdateError)?; + self.io_update + .set_high() + .map_err(|_| Error::IOUpdateError)?; // I/O Update minimum pulse width: 1 SYNC_CLK cycle // 1 SYNC_CLK cycle = 4 REF_CLK cycle, where f_ref_clk is at least 3.2 MHz // Therefore the maximum required pulse length is 1.25 us, @@ -69,20 +71,25 @@ where type Error = Error; fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { - self.data.try_borrow_mut().map_err(|_| Error::GetRefMutDataError)?.spi.transfer(words).map_err(Error::SPI) + self.data + .try_borrow_mut() + .map_err(|_| Error::GetRefMutDataError)? + .spi + .transfer(words) + .map_err(Error::SPI) } } -impl CPLD where +impl CPLD +where SPI: Transfer, CS0: OutputPin, CS1: OutputPin, CS2: OutputPin, - GPIO: OutputPin + GPIO: OutputPin, { // Constructor for CPLD pub fn new(spi: SPI, chip_select: (CS0, CS1, CS2), io_update: GPIO) -> Self { - // Init data let data = CPLDData { spi, diff --git a/src/dds.rs b/src/dds.rs index 972f55d..e12db17 100644 --- a/src/dds.rs +++ b/src/dds.rs @@ -1,9 +1,9 @@ -use embedded_hal::blocking::spi::Transfer; use crate::urukul::Error; -use core::mem::size_of; use core::convert::TryInto; -use heapless::Vec; +use core::mem::size_of; +use embedded_hal::blocking::spi::Transfer; use heapless::consts::*; +use heapless::Vec; use log::debug; /* @@ -48,7 +48,7 @@ construct_bitmask!(DDSCFRMask; u32; DIGITAL_RAMP_NO_DWELL_HIGH, 18 +32, 1, DIGITAL_RAMP_ENABLE, 19 +32, 1, DIGITAL_RAMP_DEST, 20 +32, 2, - SYNC_CLK_ENABLE, 22 +32, 1, + SYNC_CLK_ENABLE, 22 +32, 1, INT_IO_UPDATE_ACTIVE, 23 +32, 1, EN_AMP_SCALE_SINGLE_TONE_PRO, 24 +32, 1, @@ -63,8 +63,8 @@ construct_bitmask!(DDSCFRMask; u32; DRV0, 28 +64, 2 ); -const WRITE_MASK :u8 = 0x00; -const READ_MASK :u8 = 0x80; +const WRITE_MASK: u8 = 0x00; +const READ_MASK: u8 = 0x80; #[link_section = ".sram2.ram"] static mut RAM_VEC: Vec = Vec(heapless::i::Vec::new()); @@ -90,12 +90,12 @@ pub struct DDS { spi: SPI, f_ref_clk: f64, f_sys_clk: f64, - ram_dest: RAMDestination + ram_dest: RAMDestination, } impl DDS where - SPI: Transfer + SPI: Transfer, { pub fn new(spi: SPI, f_ref_clk: f64) -> Self { DDS { @@ -109,7 +109,7 @@ where impl Transfer for DDS where - SPI: Transfer + SPI: Transfer, { type Error = Error; @@ -118,18 +118,15 @@ where } } - impl DDS where - SPI: Transfer + SPI: Transfer, { /* * Implement init: Set SDIO to be input only, using LSB first */ pub fn init(&mut self) -> Result<(), Error> { - match self.write_register(0x00, &mut [ - 0x00, 0x00, 0x00, 0x02 - ]) { + match self.write_register(0x00, &mut [0x00, 0x00, 0x00, 0x02]) { Ok(_) => Ok(()), Err(e) => Err(e), } @@ -182,9 +179,7 @@ where // Reset PLL lock before re-enabling it (DDSCFRMask::PFD_RESET, 1), ])?; - self.set_configurations(&mut [ - (DDSCFRMask::PFD_RESET, 0), - ])?; + self.set_configurations(&mut [(DDSCFRMask::PFD_RESET, 0)])?; self.f_sys_clk = self.f_ref_clk * (divider as f64); Ok(()) } @@ -204,13 +199,13 @@ where // Acquire N-divider, to adjust VCO if necessary (DDSCFRMask::N, 0), // Acquire REF_CLK divider bypass - (DDSCFRMask::REFCLK_IN_DIV_BYPASS, 0) + (DDSCFRMask::REFCLK_IN_DIV_BYPASS, 0), ]; self.get_configurations(&mut configuration_queries)?; if configuration_queries[0].1 == 1 { // Recalculate sys_clk - let divider :f64 = configuration_queries[1].1.into(); + let divider: f64 = configuration_queries[1].1.into(); let f_sys_clk = self.f_ref_clk * divider; // Adjust VCO match self.get_VCO_no(f_sys_clk, divider as u8) { @@ -221,24 +216,20 @@ where // Reset PLL lock before re-enabling it (DDSCFRMask::PFD_RESET, 1), ])?; - self.set_configurations(&mut [ - (DDSCFRMask::PFD_RESET, 0), - ])?; + self.set_configurations(&mut [(DDSCFRMask::PFD_RESET, 0)])?; // Update f_sys_clk from recalculation self.f_sys_clk = f_sys_clk; Ok(()) - }, + } Err(_) => { // Forcibly turn off PLL, enable default clk tree (divide by 2) self.enable_divided_ref_clk() } } - } - else if configuration_queries[2].1 == 0 { + } else if configuration_queries[2].1 == 0 { self.f_sys_clk = self.f_ref_clk / 2.0; Ok(()) - } - else { + } else { self.f_sys_clk = self.f_ref_clk; Ok(()) } @@ -269,7 +260,7 @@ where fn get_VCO_no(&mut self, f_sys_clk: f64, divider: u8) -> Result> { // Select a VCO if divider == 1 { - Ok(6) // Bypass PLL if no frequency division needed + Ok(6) // Bypass PLL if no frequency division needed } else if f_sys_clk > 1_150_000_000.0 { Err(Error::DDSCLKError) } else if f_sys_clk > 820_000_000.0 { @@ -285,7 +276,7 @@ where } else if f_sys_clk > 370_000_000.0 { Ok(0) } else { - Ok(7) // Bypass PLL if f_sys_clk is too low + Ok(7) // Bypass PLL if f_sys_clk is too low } } @@ -300,16 +291,28 @@ where self.read_register(0x01, &mut cfr_reg[4..8])?; self.read_register(0x02, &mut cfr_reg[8..12])?; Ok([ - (cfr_reg[0] as u32) << 24 | (cfr_reg[1] as u32) << 16 | (cfr_reg[2] as u32) << 8 | (cfr_reg[3] as u32), - (cfr_reg[4] as u32) << 24 | (cfr_reg[5] as u32) << 16 | (cfr_reg[6] as u32) << 8 | (cfr_reg[7] as u32), - (cfr_reg[8] as u32) << 24 | (cfr_reg[9] as u32) << 16 | (cfr_reg[10] as u32) << 8 | (cfr_reg[11] as u32) + (cfr_reg[0] as u32) << 24 + | (cfr_reg[1] as u32) << 16 + | (cfr_reg[2] as u32) << 8 + | (cfr_reg[3] as u32), + (cfr_reg[4] as u32) << 24 + | (cfr_reg[5] as u32) << 16 + | (cfr_reg[6] as u32) << 8 + | (cfr_reg[7] as u32), + (cfr_reg[8] as u32) << 24 + | (cfr_reg[9] as u32) << 16 + | (cfr_reg[10] as u32) << 8 + | (cfr_reg[11] as u32), ]) } /* * Get a set of configurations using DDSCFRMask */ - pub fn get_configurations<'w>(&mut self, mask_pairs: &'w mut[(DDSCFRMask, u32)]) -> Result<&'w [(DDSCFRMask, u32)], Error> { + pub fn get_configurations<'w>( + &mut self, + mask_pairs: &'w mut [(DDSCFRMask, u32)], + ) -> Result<&'w [(DDSCFRMask, u32)], Error> { let data_array = self.get_all_configurations()?; for index in 0..mask_pairs.len() { mask_pairs[index].1 = match mask_pairs[index].0.get_shift() { @@ -327,12 +330,15 @@ where */ fn set_all_configurations(&mut self, data_array: [u32; 3]) -> Result<(), Error> { for register in 0x00..=0x02 { - self.write_register(register, &mut [ - ((data_array[register as usize] >> 24) & 0xFF) as u8, - ((data_array[register as usize] >> 16) & 0xFF) as u8, - ((data_array[register as usize] >> 8 ) & 0xFF) as u8, - ((data_array[register as usize] >> 0 ) & 0xFF) as u8 - ])?; + self.write_register( + register, + &mut [ + ((data_array[register as usize] >> 24) & 0xFF) as u8, + ((data_array[register as usize] >> 16) & 0xFF) as u8, + ((data_array[register as usize] >> 8) & 0xFF) as u8, + ((data_array[register as usize] >> 0) & 0xFF) as u8, + ], + )?; } Ok(()) } @@ -340,17 +346,28 @@ where /* * Set a set of configurations using DDSCFRMask */ - pub fn set_configurations(&mut self, mask_pairs: &mut[(DDSCFRMask, u32)]) -> Result<(), Error> { + pub fn set_configurations( + &mut self, + mask_pairs: &mut [(DDSCFRMask, u32)], + ) -> Result<(), Error> { let mut data_array = self.get_all_configurations()?; for index in 0..mask_pairs.len() { // Reject any attempt to rewrite LSB_FIRST and SDIO_INPUT_ONLY - if mask_pairs[index].0 == DDSCFRMask::LSB_FIRST || mask_pairs[index].0 == DDSCFRMask::SDIO_IN_ONLY { + if mask_pairs[index].0 == DDSCFRMask::LSB_FIRST + || mask_pairs[index].0 == DDSCFRMask::SDIO_IN_ONLY + { continue; } match mask_pairs[index].0.get_shift() { - 0..=31 => mask_pairs[index].0.set_data_by_arg(&mut data_array[0], mask_pairs[index].1), - 32..=63 => mask_pairs[index].0.set_data_by_arg(&mut data_array[1], mask_pairs[index].1), - 64..=95 => mask_pairs[index].0.set_data_by_arg(&mut data_array[2], mask_pairs[index].1), + 0..=31 => mask_pairs[index] + .0 + .set_data_by_arg(&mut data_array[0], mask_pairs[index].1), + 32..=63 => mask_pairs[index] + .0 + .set_data_by_arg(&mut data_array[1], mask_pairs[index].1), + 64..=95 => mask_pairs[index] + .0 + .set_data_by_arg(&mut data_array[2], mask_pairs[index].1), _ => panic!("Invalid DDSCFRMask!"), }; } @@ -366,12 +383,17 @@ where * Frequency: Must be non-negative * Amplitude: In a scale from 0 to 1, taking float */ - pub fn set_single_tone_profile(&mut self, profile: u8, f_out: f64, phase_offset: f64, amp_scale_factor: f64) -> Result<(), Error> { - + pub fn set_single_tone_profile( + &mut self, + profile: u8, + f_out: f64, + phase_offset: f64, + amp_scale_factor: f64, + ) -> Result<(), Error> { assert!(profile < 8); assert!(f_out >= 0.0); assert!(phase_offset >= 0.0 && phase_offset < 360.0); - assert!(amp_scale_factor >=0.0 && amp_scale_factor <= 1.0); + assert!(amp_scale_factor >= 0.0 && amp_scale_factor <= 1.0); let ftw = self.frequency_to_ftw(f_out); let pow = self.degree_to_pow(phase_offset); @@ -379,44 +401,44 @@ where // Setup configuration registers before writing single tone register self.enable_single_tone_configuration()?; - + // Transfer single tone profile data - self.write_register(0x0E + profile, &mut [ - ((asf >> 8 ) & 0xFF) as u8, - ((asf >> 0 ) & 0xFF) as u8, - ((pow >> 8 ) & 0xFF) as u8, - ((pow >> 0 ) & 0xFF) as u8, - ((ftw >> 24) & 0xFF) as u8, - ((ftw >> 16) & 0xFF) as u8, - ((ftw >> 8 ) & 0xFF) as u8, - ((ftw >> 0 ) & 0xFF) as u8, - ]) + self.write_register( + 0x0E + profile, + &mut [ + ((asf >> 8) & 0xFF) as u8, + ((asf >> 0) & 0xFF) as u8, + ((pow >> 8) & 0xFF) as u8, + ((pow >> 0) & 0xFF) as u8, + ((ftw >> 24) & 0xFF) as u8, + ((ftw >> 16) & 0xFF) as u8, + ((ftw >> 8) & 0xFF) as u8, + ((ftw >> 0) & 0xFF) as u8, + ], + ) } /* * Getter function for single tone profiles */ pub fn get_single_tone_profile(&mut self, profile: u8) -> Result<(f64, f64, f64), Error> { - assert!(profile < 8); let mut profile_content: [u8; 8] = [0; 8]; self.read_register(0x0E + profile, &mut profile_content)?; // Convert ftw, pow and asf to f_out, phase and amplitude factor - let ftw: u64 = (profile_content[4] as u64) << 24 | - (profile_content[5] as u64) << 16 | - (profile_content[6] as u64) << 8 | - (profile_content[7] as u64); - let f_out: f64 = ((ftw as f64)/(((1_u64) << 32) as f64))*self.f_sys_clk; + let ftw: u64 = (profile_content[4] as u64) << 24 + | (profile_content[5] as u64) << 16 + | (profile_content[6] as u64) << 8 + | (profile_content[7] as u64); + let f_out: f64 = ((ftw as f64) / (((1_u64) << 32) as f64)) * self.f_sys_clk; - let pow: u64 = (profile_content[2] as u64) << 8 | - (profile_content[3] as u64); - let phase: f64 = ((pow as f64)/(((1_u64) << 16) as f64))*360.0; + let pow: u64 = (profile_content[2] as u64) << 8 | (profile_content[3] as u64); + let phase: f64 = ((pow as f64) / (((1_u64) << 16) as f64)) * 360.0; - let asf: u64 = ((profile_content[0] & 0x3F) as u64) << 8 | - (profile_content[1] as u64); - let amplitude: f64 = (asf as f64)/(((1_u64) << 14) as f64); + let asf: u64 = ((profile_content[0] & 0x3F) as u64) << 8 | (profile_content[1] as u64); + let amplitude: f64 = (asf as f64) / (((1_u64) << 14) as f64); Ok((f_out, phase, amplitude)) } @@ -426,8 +448,11 @@ where * Frequency: Must be non-negative * Keep other field unchanged in the register */ - pub fn set_single_tone_profile_frequency(&mut self, profile: u8, f_out: f64) -> Result<(), Error> { - + pub fn set_single_tone_profile_frequency( + &mut self, + profile: u8, + f_out: f64, + ) -> Result<(), Error> { // Setup configuration registers before writing single tone register self.enable_single_tone_configuration()?; @@ -440,8 +465,8 @@ where // Overwrite FTW register[4] = ((ftw >> 24) & 0xFF) as u8; register[5] = ((ftw >> 16) & 0xFF) as u8; - register[6] = ((ftw >> 8) & 0xFF) as u8; - register[7] = ((ftw >> 0) & 0xFF) as u8; + register[6] = ((ftw >> 8) & 0xFF) as u8; + register[7] = ((ftw >> 0) & 0xFF) as u8; // Update FTW by writing back the register self.write_register(0x0E + profile, &mut register) @@ -452,8 +477,11 @@ where * Phase: Expressed in positive degree, i.e. [0.0, 360.0) * Keep other field unchanged in the register */ - pub fn set_single_tone_profile_phase(&mut self, profile: u8, phase_offset: f64) -> Result<(), Error> { - + pub fn set_single_tone_profile_phase( + &mut self, + profile: u8, + phase_offset: f64, + ) -> Result<(), Error> { // Setup configuration registers before writing single tone register self.enable_single_tone_configuration()?; @@ -464,8 +492,8 @@ where self.read_register(0x0E + profile, &mut register)?; // Overwrite POW - register[2] = ((pow >> 8) & 0xFF) as u8; - register[3] = ((pow >> 0) & 0xFF) as u8; + register[2] = ((pow >> 8) & 0xFF) as u8; + register[3] = ((pow >> 0) & 0xFF) as u8; // Update POW by writing back the register self.write_register(0x0E + profile, &mut register) @@ -476,8 +504,11 @@ where * Amplitude: In a scale from 0 to 1, taking float * Keep other field unchanged in the register */ - pub fn set_single_tone_profile_amplitude(&mut self, profile: u8, amp_scale_factor: f64) -> Result<(), Error> { - + pub fn set_single_tone_profile_amplitude( + &mut self, + profile: u8, + amp_scale_factor: f64, + ) -> Result<(), Error> { // Setup configuration registers before writing single tone register self.enable_single_tone_configuration()?; @@ -489,8 +520,8 @@ where self.read_register(0x0E + profile, &mut register)?; // Overwrite POW - register[0] = ((asf >> 8) & 0xFF) as u8; - register[1] = ((asf >> 0) & 0xFF) as u8; + register[0] = ((asf >> 8) & 0xFF) as u8; + register[1] = ((asf >> 0) & 0xFF) as u8; // Update POW by writing back the register self.write_register(0x0E + profile, &mut register) @@ -499,16 +530,13 @@ where // Helper function to switch into single tone mode // Need to setup configuration registers before writing single tone register fn enable_single_tone_configuration(&mut self) -> Result<(), Error> { - self.set_configurations(&mut [ (DDSCFRMask::RAM_ENABLE, 0), (DDSCFRMask::DIGITAL_RAMP_ENABLE, 0), (DDSCFRMask::OSK_ENABLE, 0), (DDSCFRMask::PARALLEL_DATA_PORT_ENABLE, 0), ])?; - self.set_configurations(&mut [ - (DDSCFRMask::EN_AMP_SCALE_SINGLE_TONE_PRO, 1), - ]) + self.set_configurations(&mut [(DDSCFRMask::EN_AMP_SCALE_SINGLE_TONE_PRO, 1)]) } // Helper function to configure the default frequency in the FTW register (0x07) @@ -531,19 +559,18 @@ where pub fn get_default_ftw(&mut self) -> Result> { let mut ftw_bytes: [u8; 4] = [0; 4]; self.read_register(0x07, &mut ftw_bytes)?; - let ftw: u64 = (ftw_bytes[0] as u64) << 24 | - (ftw_bytes[1] as u64) << 16 | - (ftw_bytes[2] as u64) << 8 | - (ftw_bytes[3] as u64); - Ok(((ftw as f64)/(((1_u64) << 32) as f64))*self.f_sys_clk) + let ftw: u64 = (ftw_bytes[0] as u64) << 24 + | (ftw_bytes[1] as u64) << 16 + | (ftw_bytes[2] as u64) << 8 + | (ftw_bytes[3] as u64); + Ok(((ftw as f64) / (((1_u64) << 32) as f64)) * self.f_sys_clk) } pub fn get_default_asf(&mut self) -> Result> { let mut asf_register: [u8; 4] = [0; 4]; self.read_register(0x09, &mut asf_register)?; - let asf: u64 = ((asf_register[2] as u64) << 6) | - ((asf_register[3] as u64) >> 2); - Ok((asf as f64)/(((1_u64) << 14) as f64)) + let asf: u64 = ((asf_register[2] as u64) << 6) | ((asf_register[3] as u64) >> 2); + Ok((asf as f64) / (((1_u64) << 14) as f64)) } // Helper function to switch into RAM mode @@ -558,38 +585,44 @@ where // Helper function to switch out of RAM mode // Need to setup configuration registers before writing into RAM profile register fn disable_ram_configuration(&mut self) -> Result<(), Error> { - self.set_configurations(&mut [ - (DDSCFRMask::RAM_ENABLE, 0), - ]) + self.set_configurations(&mut [(DDSCFRMask::RAM_ENABLE, 0)]) } // Setup a RAM profile - pub fn set_up_ram_profile(&mut self, profile: u8, start_addr: u16, - end_addr: u16, no_dwell_high: bool, zero_crossing: bool, - op_mode: RAMOperationMode, ramp_rate: u16 - )-> Result<(), Error> - { + pub fn set_up_ram_profile( + &mut self, + profile: u8, + start_addr: u16, + end_addr: u16, + no_dwell_high: bool, + zero_crossing: bool, + op_mode: RAMOperationMode, + ramp_rate: u16, + ) -> Result<(), Error> { assert!(profile <= 7); assert!(end_addr >= start_addr); assert!(end_addr < 1024); self.enable_ram_configuration(self.ram_dest)?; - self.write_register(0x0E + profile, &mut [ - 0x00, - ((ramp_rate >> 8) & 0xFF).try_into().unwrap(), - ((ramp_rate >> 0) & 0xFF).try_into().unwrap(), - ((end_addr >> 2) & 0xFF).try_into().unwrap(), - ((end_addr & 0x3) << 6).try_into().unwrap(), - ((start_addr >> 2) & 0xFF).try_into().unwrap(), - ((start_addr & 0x3) << 6).try_into().unwrap(), - ((no_dwell_high as u8) << 5) | ((zero_crossing as u8) << 3) | (op_mode as u8) - ]) + self.write_register( + 0x0E + profile, + &mut [ + 0x00, + ((ramp_rate >> 8) & 0xFF).try_into().unwrap(), + ((ramp_rate >> 0) & 0xFF).try_into().unwrap(), + ((end_addr >> 2) & 0xFF).try_into().unwrap(), + ((end_addr & 0x3) << 6).try_into().unwrap(), + ((start_addr >> 2) & 0xFF).try_into().unwrap(), + ((start_addr & 0x3) << 6).try_into().unwrap(), + ((no_dwell_high as u8) << 5) | ((zero_crossing as u8) << 3) | (op_mode as u8), + ], + ) } pub fn get_ram_profile(&mut self, profile: u8) -> Result<(u16, u16, u16, u8), Error> { assert!(profile <= 7); - + let mut buffer: [u8; 8] = [0; 8]; self.read_register(0x0E + profile, &mut buffer)?; let start = u16::from_be_bytes([buffer[5], buffer[6]]) >> 6; @@ -627,29 +660,42 @@ where // Write RAM bytes into DDS channel // Assume profile 7 is selected by the CPLD in prior - pub unsafe fn commit_ram_buffer(&mut self, start_addr: u16, ram_dest: RAMDestination) -> Result<(), Error> { - let ram_size = ((RAM_VEC.len() - 1) as u16)/4; - if RAM_VEC.len() == 0 || RAM_VEC[0] != 0x16 || - (start_addr + ram_size) > 1024 || start_addr >= 1024 { - return Err(Error::DDSRAMError) + pub unsafe fn commit_ram_buffer( + &mut self, + start_addr: u16, + ram_dest: RAMDestination, + ) -> Result<(), Error> { + let ram_size = ((RAM_VEC.len() - 1) as u16) / 4; + if RAM_VEC.len() == 0 + || RAM_VEC[0] != 0x16 + || (start_addr + ram_size) > 1024 + || start_addr >= 1024 + { + return Err(Error::DDSRAMError); } let end_addr: [u8; 2] = ((ram_size + start_addr - 1) << 6).to_be_bytes(); // Use profile 7 to setup a temperory RAM profile self.enable_ram_configuration(ram_dest.clone())?; - self.write_register(0x15, &mut [ - 0x00, - 0x00, 0x01, - end_addr[0], end_addr[1], - ((start_addr >> 2) & 0xFF).try_into().unwrap(), - ((start_addr & 0x3) << 6).try_into().unwrap(), - 0x00 - ])?; + self.write_register( + 0x15, + &mut [ + 0x00, + 0x00, + 0x01, + end_addr[0], + end_addr[1], + ((start_addr >> 2) & 0xFF).try_into().unwrap(), + ((start_addr & 0x3) << 6).try_into().unwrap(), + 0x00, + ], + )?; self.disable_ram_configuration()?; log::info!("RAM buffer: {:?}", RAM_VEC); - self.spi.transfer(&mut RAM_VEC) + self.spi + .transfer(&mut RAM_VEC) .map(|_| ()) .map_err(Error::SPI)?; RAM_VEC.clear(); @@ -664,10 +710,7 @@ where pub fn test(&mut self) -> Result> { // Test configuration register by getting SDIO_IN_ONLY and LSB_FIRST. let mut error_count = 0; - let mut config_checks = [ - (DDSCFRMask::SDIO_IN_ONLY, 1), - (DDSCFRMask::LSB_FIRST, 0) - ]; + let mut config_checks = [(DDSCFRMask::SDIO_IN_ONLY, 1), (DDSCFRMask::LSB_FIRST, 0)]; self.get_configurations(&mut config_checks)?; if config_checks[0].1 == 0 { error_count += 1; @@ -688,7 +731,7 @@ where pub fn get_f_sys_clk(&mut self) -> f64 { self.f_sys_clk } - + // Acquire real f_sys_clk pub fn get_sys_clk_frequency(&mut self) -> Result> { // Calculate the new system clock frequency, examine the clock tree @@ -698,19 +741,17 @@ where // Acquire N-divider, to adjust VCO if necessary (DDSCFRMask::N, 0), // Acquire REF_CLK divider bypass - (DDSCFRMask::REFCLK_IN_DIV_BYPASS, 0) + (DDSCFRMask::REFCLK_IN_DIV_BYPASS, 0), ]; self.get_configurations(&mut configuration_queries)?; if configuration_queries[0].1 == 1 { // Recalculate sys_clk - let divider :f64 = configuration_queries[1].1.into(); + let divider: f64 = configuration_queries[1].1.into(); Ok(self.f_ref_clk * divider) - } - else if configuration_queries[2].1 == 0 { + } else if configuration_queries[2].1 == 0 { Ok(self.f_ref_clk / 2.0) - } - else { + } else { Ok(self.f_ref_clk) } } @@ -772,26 +813,8 @@ macro_rules! impl_register_io { } impl_register_io!( - 0x00, 4, - 0x01, 4, - 0x02, 4, - 0x03, 4, - 0x04, 4, - 0x07, 4, - 0x08, 2, - 0x09, 4, - 0x0A, 4, - 0x0B, 8, - 0x0C, 8, - 0x0D, 4, - 0x0E, 8, - 0x0F, 8, - 0x10, 8, - 0x11, 8, - 0x12, 8, - 0x13, 8, - 0x14, 8, - 0x15, 8 + 0x00, 4, 0x01, 4, 0x02, 4, 0x03, 4, 0x04, 4, 0x07, 4, 0x08, 2, 0x09, 4, 0x0A, 4, 0x0B, 8, 0x0C, + 8, 0x0D, 4, 0x0E, 8, 0x0F, 8, 0x10, 8, 0x11, 8, 0x12, 8, 0x13, 8, 0x14, 8, 0x15, 8 ); // Append bytes to the RAM buffer diff --git a/src/flash.rs b/src/flash.rs index f3229c9..e0fffa5 100644 --- a/src/flash.rs +++ b/src/flash.rs @@ -22,7 +22,7 @@ pub enum Error { ErrorCorrectionCode, ReadProtection, ReadSecure, - WriteError + WriteError, } /// Embedded flash memory. @@ -45,46 +45,58 @@ impl Flash { // Unlock bank 1 if needed. if self.bank1_is_locked() { - self.registers.bank1_mut().keyr.write(|w| unsafe { - w.keyr().bits(0x45670123) - }); - self.registers.bank1_mut().keyr.write(|w| unsafe { - w.keyr().bits(0xCDEF89AB) - }); + self.registers + .bank1_mut() + .keyr + .write(|w| unsafe { w.keyr().bits(0x45670123) }); + self.registers + .bank1_mut() + .keyr + .write(|w| unsafe { w.keyr().bits(0xCDEF89AB) }); } // Unlock bank 2 if needed. if self.bank2_is_locked() { - self.registers.bank2_mut().keyr.write(|w| unsafe { - w.keyr().bits(0x45670123) - }); - self.registers.bank2_mut().keyr.write(|w| unsafe { - w.keyr().bits(0xCDEF89AB) - }); + self.registers + .bank2_mut() + .keyr + .write(|w| unsafe { w.keyr().bits(0x45670123) }); + self.registers + .bank2_mut() + .keyr + .write(|w| unsafe { w.keyr().bits(0xCDEF89AB) }); } } /// Unlocks the FLASH_OPTCR register pub fn unlock_optcr(&mut self) { if self.optcr_is_locked() { - self.registers.optkeyr_mut().write(|w| unsafe { - w.optkeyr().bits(0x08192A3B) - }); - self.registers.optkeyr_mut().write(|w| unsafe { - w.optkeyr().bits(0x4C5D6E7F) - }); + self.registers + .optkeyr_mut() + .write(|w| unsafe { w.optkeyr().bits(0x08192A3B) }); + self.registers + .optkeyr_mut() + .write(|w| unsafe { w.optkeyr().bits(0x4C5D6E7F) }); } } /// Locks the FLASH_CR1/2 register. pub fn lock(&mut self) { - self.registers.bank1_mut().cr.modify(|_, w| w.lock().set_bit()); - self.registers.bank2_mut().cr.modify(|_, w| w.lock().set_bit()); + self.registers + .bank1_mut() + .cr + .modify(|_, w| w.lock().set_bit()); + self.registers + .bank2_mut() + .cr + .modify(|_, w| w.lock().set_bit()); } /// Lock the FLASH_OPTCR register pub fn lock_optcr(&mut self) { - self.registers.optcr_mut().modify(|_, w| w.optlock().set_bit()); + self.registers + .optcr_mut() + .modify(|_, w| w.optlock().set_bit()); } // More literal methods to get bank status @@ -106,7 +118,7 @@ impl Flash { fn is_busy(&self) -> bool { let (sr1, sr2) = ( self.registers.bank1_mut().sr.read(), - self.registers.bank2_mut().sr.read() + self.registers.bank2_mut().sr.read(), ); sr1.bsy().bit_is_set() || sr2.bsy().bit_is_set() } @@ -115,7 +127,7 @@ impl Flash { fn is_queuing(&self) -> bool { let (sr1, sr2) = ( self.registers.bank1_mut().sr.read(), - self.registers.bank2_mut().sr.read() + self.registers.bank2_mut().sr.read(), ); sr1.qw().bit_is_set() || sr2.qw().bit_is_set() } @@ -145,28 +157,26 @@ impl Flash { // 4. Set START1/2 bit in FLASH_CR1/2 register match bank_number { 1 => { - self.registers.bank1_mut().cr.modify(|_, w| unsafe { - w.ser() - .set_bit() - .snb() - .bits(sector_number) - }); - self.registers.bank1_mut().cr.modify(|_, w| { - w.start().set_bit() - }); - }, + self.registers + .bank1_mut() + .cr + .modify(|_, w| unsafe { w.ser().set_bit().snb().bits(sector_number) }); + self.registers + .bank1_mut() + .cr + .modify(|_, w| w.start().set_bit()); + } 2 => { - self.registers.bank2_mut().cr.modify(|_, w| unsafe { - w.ser() - .set_bit() - .snb() - .bits(sector_number) - }); - self.registers.bank2_mut().cr.modify(|_, w| { - w.start().set_bit() - }); - }, - _ => unreachable!() + self.registers + .bank2_mut() + .cr + .modify(|_, w| unsafe { w.ser().set_bit().snb().bits(sector_number) }); + self.registers + .bank2_mut() + .cr + .modify(|_, w| w.start().set_bit()); + } + _ => unreachable!(), } // Lock the flash CR again self.lock(); @@ -187,24 +197,20 @@ impl Flash { // mass erase is invoked since it supersedes sector erase. match bank_number { 1 => { - self.registers.bank1_mut().cr.modify(|_, w| { - w.ber() - .set_bit() - .start() - .set_bit() - }); + self.registers + .bank1_mut() + .cr + .modify(|_, w| w.ber().set_bit().start().set_bit()); while self.registers.bank1_mut().sr.read().qw().bit_is_set() {} - }, + } 2 => { - self.registers.bank2_mut().cr.modify(|_, w| { - w.ber() - .set_bit() - .start() - .set_bit() - }); + self.registers + .bank2_mut() + .cr + .modify(|_, w| w.ber().set_bit().start().set_bit()); while self.registers.bank2_mut().sr.read().qw().bit_is_set() {} - }, - _ => unreachable!() + } + _ => unreachable!(), } // Lock the flash CR again self.lock(); @@ -219,9 +225,7 @@ impl Flash { self.unlock(); self.unlock_optcr(); // 3. Set MER in FLASH_OPTCR to 1, wait until both QW to clear - self.registers.optcr_mut().modify(|_, w| { - w.mer().set_bit() - }); + self.registers.optcr_mut().modify(|_, w| w.mer().set_bit()); while self.is_queuing() {} // Lock the flash CR and OPTCR again self.lock(); @@ -231,11 +235,7 @@ impl Flash { /// Program flash words (32-bytes). /// Flashing incomplete flash word is "tolerated", but you have been warned.. - pub fn program<'a, 'b>( - &'a mut self, - start_offset: usize, - data: &'b [u8], - ) -> Result<(), Error> { + pub fn program<'a, 'b>(&'a mut self, start_offset: usize, data: &'b [u8]) -> Result<(), Error> { if (start_offset % 32 != 0) || (data.len() % 32 != 0) { log::warn!("Warning: This flash operation might not be supported..."); log::warn!("Consider force writing the data in buffer..."); @@ -247,20 +247,19 @@ impl Flash { while remaining_data.len() != 0 { let single_write_size = 32 - (current_address % 32); // Determine the index that split the coming row and the remaining bytes. - let splitting_index = core::cmp::min( - single_write_size, - remaining_data.len() - ); + let splitting_index = core::cmp::min(single_write_size, remaining_data.len()); let single_row_data = &remaining_data[..splitting_index]; // 1. Unlock FLASH_CR1/2 register if necessary self.unlock(); // 2. Set PG bit in FLASH_CR1/2 - self.registers.bank1_mut().cr.modify(|_, w| { - w.pg().set_bit() - }); - self.registers.bank2_mut().cr.modify(|_, w| { - w.pg().set_bit() - }); + self.registers + .bank1_mut() + .cr + .modify(|_, w| w.pg().set_bit()); + self.registers + .bank2_mut() + .cr + .modify(|_, w| w.pg().set_bit()); // 3. Check Protection // There should not be any data protection anyway... // 4. Write data byte by byte @@ -268,22 +267,32 @@ impl Flash { while self.is_busy() {} match self.check_errors() { Ok(_) => { - let address: *mut u8 = unsafe { - FLASH_BASE.add(current_address + index) - }; + let address: *mut u8 = unsafe { FLASH_BASE.add(current_address + index) }; if address > MAX_FLASH_ADDRESS { - self.registers.bank1_mut().cr.modify(|_, w| w.pg().clear_bit()); - self.registers.bank2_mut().cr.modify(|_, w| w.pg().clear_bit()); + self.registers + .bank1_mut() + .cr + .modify(|_, w| w.pg().clear_bit()); + self.registers + .bank2_mut() + .cr + .modify(|_, w| w.pg().clear_bit()); return Err(Error::WriteError); } else { unsafe { core::ptr::write_volatile(address, *byte); } } - }, + } Err(error) => { - self.registers.bank1_mut().cr.modify(|_, w| w.pg().clear_bit()); - self.registers.bank2_mut().cr.modify(|_, w| w.pg().clear_bit()); + self.registers + .bank1_mut() + .cr + .modify(|_, w| w.pg().clear_bit()); + self.registers + .bank2_mut() + .cr + .modify(|_, w| w.pg().clear_bit()); return Err(error); } } @@ -295,8 +304,14 @@ impl Flash { current_address += single_row_data.len(); } // Reset PG1/2 - self.registers.bank1_mut().cr.modify(|_, w| w.pg().clear_bit()); - self.registers.bank2_mut().cr.modify(|_, w| w.pg().clear_bit()); + self.registers + .bank1_mut() + .cr + .modify(|_, w| w.pg().clear_bit()); + self.registers + .bank2_mut() + .cr + .modify(|_, w| w.pg().clear_bit()); // Lock FLASH_CR1/2 register self.lock(); Ok(()) @@ -304,27 +319,25 @@ impl Flash { /// Force empty the bytes buffer for flash programming /// Warning: It can invalidate the whole flash due to invalid CRC. - pub fn force_write<'a>( - &'a mut self - ) -> Result<(), Error> { + pub fn force_write<'a>(&'a mut self) -> Result<(), Error> { if self.bank1_is_buffering() { - self.registers.bank1_mut().cr.modify( - |_, w| w.fw().set_bit() - ); + self.registers + .bank1_mut() + .cr + .modify(|_, w| w.fw().set_bit()); } if self.bank2_is_buffering() { - self.registers.bank2_mut().cr.modify( - |_, w| w.fw().set_bit() - ); + self.registers + .bank2_mut() + .cr + .modify(|_, w| w.fw().set_bit()); } Ok(()) } /// Read a slice from flash memory pub fn read(&self, start_offset: usize, len: usize) -> &'static [u8] { - let address = unsafe { - FLASH_BASE.add(start_offset) - }; + let address = unsafe { FLASH_BASE.add(start_offset) }; unsafe { core::slice::from_raw_parts(address, len) } } @@ -337,7 +350,7 @@ impl Flash { fn check_errors(&self) -> Result<(), Error> { let (sr1, sr2) = ( self.registers.bank1_mut().sr.read(), - self.registers.bank2_mut().sr.read() + self.registers.bank2_mut().sr.read(), ); if sr1.wrperr().bit_is_set() || sr2.wrperr().bit_is_set() { @@ -350,8 +363,11 @@ impl Flash { Err(Error::Inconsistency) } else if sr1.operr().bit_is_set() || sr2.operr().bit_is_set() { Err(Error::Operation) - } else if sr1.sneccerr1().bit_is_set() || sr1.dbeccerr().bit_is_set() - || sr2.sneccerr1().bit_is_set() || sr2.dbeccerr().bit_is_set() { + } else if sr1.sneccerr1().bit_is_set() + || sr1.dbeccerr().bit_is_set() + || sr2.sneccerr1().bit_is_set() + || sr2.dbeccerr().bit_is_set() + { Err(Error::ErrorCorrectionCode) } else if sr1.rdperr().bit_is_set() || sr2.rdperr().bit_is_set() { Err(Error::ReadProtection) diff --git a/src/flash_store.rs b/src/flash_store.rs index 89c097a..be8255d 100644 --- a/src/flash_store.rs +++ b/src/flash_store.rs @@ -1,8 +1,8 @@ -use crate::flash::Flash; use crate::flash::Error as FlashError; +use crate::flash::Flash; +use sfkv::{Store, StoreBackend}; use stm32h7xx_hal::pac::FLASH; -use sfkv::{ StoreBackend, Store }; use log::error; @@ -32,13 +32,13 @@ pub enum SFKVProcessType { // Idea: Forces BACKUP_SPACE to act as a cache. pub struct FakeFlashManager { // FSM: Track the type of data being programmed - process_type: SFKVProcessType + process_type: SFKVProcessType, } impl StoreBackend for FakeFlashManager { type Data = [u8]; - // Return + // Return fn data(&self) -> &Self::Data { unsafe { &BACKUP_SPACE } } @@ -64,7 +64,7 @@ impl StoreBackend for FakeFlashManager { let cache_ptr: *const u8 = &BACKUP_SPACE[offset] as *const u8; let payload_ptr: *const u8 = &(*payload)[0] as *const u8; - BACKUP_SPACE[offset..(offset+payload.len())].copy_from_slice(payload); + BACKUP_SPACE[offset..(offset + payload.len())].copy_from_slice(payload); // This part program extra trailing termination bytes (4 0xFF s) // However, if the remaining space is too small, there is also no need to program these bytes @@ -74,10 +74,11 @@ impl StoreBackend for FakeFlashManager { // then we can assert that no k-v pair were ditched // Then there is no concern of accidentally interpreting unused flash memory as malformatted. if (cache_ptr != payload_ptr) - && (offset+payload.len()+4 <= FLASH_SECTOR_SIZE) + && (offset + payload.len() + 4 <= FLASH_SECTOR_SIZE) && self.process_type == SFKVProcessType::Data { - BACKUP_SPACE[(offset+payload.len())..(offset+payload.len()+4)].copy_from_slice(&[0xFF; 4]); + BACKUP_SPACE[(offset + payload.len())..(offset + payload.len() + 4)] + .copy_from_slice(&[0xFF; 4]); } } self.advance_state(); @@ -98,18 +99,10 @@ impl FakeFlashManager { pub fn advance_state(&mut self) { self.process_type = match self.process_type { - SFKVProcessType::Length => { - SFKVProcessType::Type - }, - SFKVProcessType::Type => { - SFKVProcessType::Space - }, - SFKVProcessType::Space => { - SFKVProcessType::Data - }, - SFKVProcessType::Data => { - SFKVProcessType::Length - } + SFKVProcessType::Length => SFKVProcessType::Type, + SFKVProcessType::Type => SFKVProcessType::Space, + SFKVProcessType::Space => SFKVProcessType::Data, + SFKVProcessType::Data => SFKVProcessType::Length, }; } @@ -127,9 +120,7 @@ fn init_flash_cache(flash: FLASH) -> Flash { // sfkv will perform in-place operation in cache // flash will only be updated after invoking `save()` unsafe { - BACKUP_SPACE.copy_from_slice( - flash.read(FLASH_SECTOR_OFFSET, FLASH_SECTOR_SIZE) - ); + BACKUP_SPACE.copy_from_slice(flash.read(FLASH_SECTOR_OFFSET, FLASH_SECTOR_SIZE)); } flash } @@ -143,7 +134,8 @@ fn init_flash_store() -> FlashStore { Ok(_) => {} Err(e) => { error!("corrupt store, erasing. error: {:?}", e); - let _ = store.erase() + let _ = store + .erase() .map_err(|e| error!("flash erase failed: {:?}", e)); } } @@ -166,6 +158,8 @@ pub fn update_flash(flash: &mut Flash, store: &FlashStore) -> Result<(), FlashEr flash_size + 0x20 - (flash_size % 0x20) }; unsafe { - flash.program(FLASH_SECTOR_OFFSET, &BACKUP_SPACE[..save_size]).map(|_| ()) + flash + .program(FLASH_SECTOR_OFFSET, &BACKUP_SPACE[..save_size]) + .map(|_| ()) } -} \ No newline at end of file +} diff --git a/src/fpga.rs b/src/fpga.rs index 36c19a9..50ee796 100644 --- a/src/fpga.rs +++ b/src/fpga.rs @@ -1,7 +1,7 @@ use embedded_hal::{ - digital::v2::{OutputPin, InputPin}, - blocking::spi::Transfer, blocking::delay::DelayUs, + blocking::spi::Transfer, + digital::v2::{InputPin, OutputPin}, }; #[derive(Debug)] @@ -14,31 +14,38 @@ pub enum FPGAFlashError { const DATA: &'static [u8] = include_bytes!("../build/top.bin"); // A public method to flash iCE40 FPGA on Humpback -pub fn flash_ice40_fpga, - SS: OutputPin, - RST: OutputPin, - DELAY: DelayUs, - DONE: InputPin> - (mut spi: SPI, mut ss: SS, mut creset: RST, cdone: DONE, mut delay: DELAY) -> Result<(), FPGAFlashError> -{ +pub fn flash_ice40_fpga< + SPI: Transfer, + SS: OutputPin, + RST: OutputPin, + DELAY: DelayUs, + DONE: InputPin, +>( + mut spi: SPI, + mut ss: SS, + mut creset: RST, + cdone: DONE, + mut delay: DELAY, +) -> Result<(), FPGAFlashError> { // Data buffer setup - let mut dummy_byte :[u8; 1] = [0x00]; - let mut dummy_13_bytes :[u8; 13] = [0x00; 13]; + let mut dummy_byte: [u8; 1] = [0x00]; + let mut dummy_13_bytes: [u8; 13] = [0x00; 13]; // Drive CRESET_B low - creset.set_low() - .map_err(|_| FPGAFlashError::NegotiationError)?; + creset + .set_low() + .map_err(|_| FPGAFlashError::NegotiationError)?; // Drive SPI_SS_B low - ss.set_low() - .map_err(|_| FPGAFlashError::NegotiationError)?; + ss.set_low().map_err(|_| FPGAFlashError::NegotiationError)?; // Wait at least 200ns delay.delay_us(1_u32); // Drive CRESET_B high - creset.set_high() - .map_err(|_| FPGAFlashError::NegotiationError)?; + creset + .set_high() + .map_err(|_| FPGAFlashError::NegotiationError)?; // Wait at least another 1200us to clear internal config memory delay.delay_us(1200_u32); @@ -46,7 +53,7 @@ pub fn flash_ice40_fpga, // Before data transmission starts, check if C_DONE is truly low // If C_DONE is high, the FPGA reset procedure is unsuccessful match cdone.is_low() { - Ok(true) => {}, + Ok(true) => {} _ => return Err(FPGAFlashError::ResetStatusError), }; @@ -59,8 +66,7 @@ pub fn flash_ice40_fpga, .map_err(|_| FPGAFlashError::SPICommunicationError)?; // Drive SPI_SS_B low - ss.set_low() - .map_err(|_| FPGAFlashError::NegotiationError)?; + ss.set_low().map_err(|_| FPGAFlashError::NegotiationError)?; // Send the whole image without interruption for byte in DATA.into_iter() { @@ -80,12 +86,12 @@ pub fn flash_ice40_fpga, // Check the CDONE output from FPGA // CDONE needs to be high match cdone.is_high() { - Ok(true) => {}, + Ok(true) => {} _ => return Err(FPGAFlashError::ResetStatusError), }; // Send at least another 49 clock cycles to activate IO pins (choosing same 13 bytes) - spi.transfer(&mut dummy_13_bytes).map_err(|_| FPGAFlashError::SPICommunicationError)?; + spi.transfer(&mut dummy_13_bytes) + .map_err(|_| FPGAFlashError::SPICommunicationError)?; Ok(()) - } diff --git a/src/logger.rs b/src/logger.rs index b277fe9..939ceb6 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -2,7 +2,7 @@ pub unsafe fn enable_itm( dbgmcu: &stm32h7xx_hal::stm32::DBGMCU, dcb: &mut cortex_m::peripheral::DCB, - itm: &mut cortex_m::peripheral::ITM + itm: &mut cortex_m::peripheral::ITM, ) { // ARMv7-M DEMCR: Set TRCENA. Enables DWT and ITM units //unsafe { *(0xE000_EDFC as *mut u32) |= 1 << 24 }; @@ -56,23 +56,17 @@ use log::LevelFilter; pub use cortex_m_log::log::Logger; use cortex_m_log::{ - destination::Itm as ItmDest, - printer::itm::InterruptSync, - modes::InterruptFree, - printer::itm::ItmSync + destination::Itm as ItmDest, modes::InterruptFree, printer::itm::InterruptSync, + printer::itm::ItmSync, }; lazy_static! { static ref LOGGER: Logger> = Logger { level: LevelFilter::Info, - inner: unsafe { - InterruptSync::new( - ItmDest::new(cortex_m::Peripherals::steal().ITM) - ) - }, + inner: unsafe { InterruptSync::new(ItmDest::new(cortex_m::Peripherals::steal().ITM)) }, }; } pub fn init() { cortex_m_log::log::init(&LOGGER).unwrap(); -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index dba1d44..154ea8b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,36 +4,36 @@ #![feature(assoc_char_funcs)] #![feature(alloc_error_handler)] -use log::{ trace, warn }; +use log::{trace, warn}; +use stm32h7xx_hal::ethernet; use stm32h7xx_hal::gpio::Speed; use stm32h7xx_hal::rng::Rng; use stm32h7xx_hal::{pac, prelude::*, spi}; -use stm32h7xx_hal::ethernet; use smoltcp as net; use SaiTLS as tls; -use minimq::{ MqttClient, QoS }; +use minimq::{MqttClient, QoS}; +use alloc_cortex_m::CortexMHeap; use cortex_m; use cortex_m_rt::entry; -use alloc_cortex_m::CortexMHeap; +use rand_core::{CryptoRng, RngCore}; use rtic::cyccnt::{Instant, U32Ext}; -use rand_core::{RngCore, CryptoRng}; -use tls::TlsRng; -use tls::tls::TlsSocket; -use tls::tcp_stack::NetworkStack; -use heapless::{ String, consts, consts::* }; use core::alloc::Layout; +use heapless::{consts, consts::*, String}; +use tls::tcp_stack::NetworkStack; +use tls::tls::TlsSocket; +use tls::TlsRng; #[macro_use] pub mod bitmask_macro; -pub mod spi_slave; pub mod cpld; +pub mod spi_slave; use crate::cpld::CPLD; -pub mod config_register; pub mod attenuator; +pub mod config_register; pub mod dds; pub mod net_store; use crate::net_store::NetStorage; @@ -43,8 +43,8 @@ pub mod mqtt_mux; use crate::mqtt_mux::MqttMux; pub mod urukul; use crate::urukul::Urukul; -pub mod flash; pub mod config; +pub mod flash; use crate::config::get_net_config; pub mod flash_store; use crate::flash_store::init_flash; @@ -77,7 +77,7 @@ static mut TX_STORAGE: [u8; 8192] = [0; 8192]; static mut RX_STORAGE: [u8; 8192] = [0; 8192]; struct RngStruct { - rng: Rng + rng: Rng, } impl RngCore for RngStruct { @@ -104,7 +104,6 @@ impl TlsRng for RngStruct {} #[entry] fn main() -> ! { - // Initialize the allocator BEFORE you use it let start = cortex_m_rt::heap_start() as usize; let size = 32768; // in bytes @@ -134,9 +133,9 @@ fn main() -> ! { .pll1_q_ck(48.mhz()) .pll1_r_ck(400.mhz()) .freeze(vos, &dp.SYSCFG); - + let delay = cp.SYST.delay(ccdr.clocks); - + cp.SCB.invalidate_icache(); cp.SCB.enable_icache(); @@ -144,7 +143,7 @@ fn main() -> ! { // Instantiate random number generator let mut rng = RngStruct { - rng: dp.RNG.constrain(ccdr.peripheral.RNG, &ccdr.clocks) + rng: dp.RNG.constrain(ccdr.peripheral.RNG, &ccdr.clocks), }; // Create sfkv store and flash storage manager @@ -267,7 +266,7 @@ fn main() -> ! { let parts = switch.split(); let urukul = Urukul::new( - parts.spi1, parts.spi2, parts.spi3, parts.spi4, parts.spi5, parts.spi6, parts.spi7 + parts.spi1, parts.spi2, parts.spi3, parts.spi4, parts.spi5, parts.spi6, parts.spi7, ); let mut mqtt_mux = MqttMux::new(urukul, flash, flash_store, net_config.name.as_str()); @@ -281,27 +280,17 @@ fn main() -> ! { next_ms += 400_000.cycles(); let mut tls_socket_entries: [_; 1] = Default::default(); - let mut tls_socket_set = tls::set::TlsSocketSet::new( - &mut tls_socket_entries[..] - ); + let mut tls_socket_set = tls::set::TlsSocketSet::new(&mut tls_socket_entries[..]); let tx_buffer = net::socket::TcpSocketBuffer::new(unsafe { &mut TX_STORAGE[..] }); let rx_buffer = net::socket::TcpSocketBuffer::new(unsafe { &mut RX_STORAGE[..] }); let mut tcp_socket = net::socket::TcpSocket::new(rx_buffer, tx_buffer); - tcp_socket.set_keep_alive( - Some(net::time::Duration::from_secs(2)) - ); + tcp_socket.set_keep_alive(Some(net::time::Duration::from_secs(2))); - let tls_socket = TlsSocket::new( - tcp_socket, - &mut rng, - None - ); + let tls_socket = TlsSocket::new(tcp_socket, &mut rng, None); let _ = tls_socket_set.add(tls_socket); - let tls_stack = NetworkStack::new( - tls_socket_set - ); + let tls_stack = NetworkStack::new(tls_socket_set); let mut client = MqttClient::::new( net_config.broker_ip, @@ -325,37 +314,35 @@ fn main() -> ! { // eth Poll if necessary // Do not poll if eth link is down while !eth_mac.phy_poll_link() {} - client.network_stack.poll(&mut net_interface, net::time::Instant::from_millis(time)); + client + .network_stack + .poll(&mut net_interface, net::time::Instant::from_millis(time)); // Process MQTT messages about Urukul/Control - let connection = match client - .poll(|_client, topic, message, _properties| { - mqtt_mux.process_mqtt_ingress(topic, message); - }) { - Ok(_) => true, - Err(e) => { - log::info!("Warn: {:?}", e); - false - }, - }; - + let connection = match client.poll(|_client, topic, message, _properties| { + mqtt_mux.process_mqtt_ingress(topic, message); + }) { + Ok(_) => true, + Err(e) => { + log::info!("Warn: {:?}", e); + false + } + }; + // Process MQTT response messages about Urukul for (topic, message) in mqtt_mux.process_mqtt_egress().unwrap() { - client.publish( - topic.as_str(), - message.as_bytes(), - QoS::AtMostOnce, - &[] - ).unwrap(); + client + .publish(topic.as_str(), message.as_bytes(), QoS::AtMostOnce, &[]) + .unwrap(); } - + if connection && !has_subscribed && tick { let mut str_builder: String = String::from(net_config.name.as_str()); str_builder.push_str("/Control/#").unwrap(); match client.subscribe(str_builder.as_str(), &[]) { Ok(()) => has_subscribed = true, - Err(minimq::Error::NotReady) => {}, - _e => {}, + Err(minimq::Error::NotReady) => {} + _e => {} }; } @@ -363,4 +350,3 @@ fn main() -> ! { tick = false; } } - diff --git a/src/mqtt_mux.rs b/src/mqtt_mux.rs index 7bd0871..b8ac5a8 100644 --- a/src/mqtt_mux.rs +++ b/src/mqtt_mux.rs @@ -1,22 +1,22 @@ -use nom::IResult; -use nom::combinator::{value, map, map_res, opt, all_consuming}; -use nom::sequence::{terminated, preceded, pair}; +use crate::config::{ChannelConfig, ProfileSetup, SingleTone, UrukulConfig, RAM}; +use crate::dds::{RAMDestination, RAMOperationMode}; +use crate::flash::Flash; +use crate::flash_store::{update_flash, FlashStore}; +use crate::urukul::ClockSource as UrukulClockSource; +use crate::urukul::Error; +use crate::urukul::Urukul; +use core::convert::TryInto; +use embedded_hal::blocking::spi::Transfer; +use heapless::{consts::*, String, Vec}; +use nom::branch::{alt, permutation}; use nom::bytes::complete::{tag, tag_no_case, take_while}; use nom::character::complete::digit1; use nom::character::is_space; -use nom::branch::{permutation, alt}; -use nom::number::complete::{float, double}; -use heapless::{ Vec, String, consts::* }; +use nom::combinator::{all_consuming, map, map_res, opt, value}; +use nom::number::complete::{double, float}; +use nom::sequence::{pair, preceded, terminated}; +use nom::IResult; use ryu; -use embedded_hal::blocking::spi::Transfer; -use core::convert::TryInto; -use crate::urukul::ClockSource as UrukulClockSource; -use crate::urukul::Urukul; -use crate::urukul::Error; -use crate::flash_store::{ FlashStore, update_flash }; -use crate::flash::Flash; -use crate::config::{ UrukulConfig, ChannelConfig, ProfileSetup, SingleTone, RAM }; -use crate::dds::{ RAMDestination, RAMOperationMode }; #[derive(Debug, Clone, PartialEq)] pub enum MqttTopic { @@ -78,11 +78,19 @@ pub struct MqttMux<'s, SPI> { float_buffer: ryu::Buffer, } -const CHANNELS: [&str; 4] = [ "ch0", "ch1", "ch2", "ch3" ]; +const CHANNELS: [&str; 4] = ["ch0", "ch1", "ch2", "ch3"]; static mut SERDE_BUFFER: [u8; 64] = [0; 64]; -impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { - pub fn new(urukul: Urukul, flash_controller: Flash, flash_store: FlashStore, name: &'s str) -> Self { +impl<'s, SPI, E> MqttMux<'s, SPI> +where + SPI: Transfer, +{ + pub fn new( + urukul: Urukul, + flash_controller: Flash, + flash_store: FlashStore, + name: &'s str, + ) -> Self { Self { urukul: urukul, yet_to_respond: None, @@ -95,7 +103,8 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { fn load_device(&mut self) -> Result<(), Error> { self.urukul.reset()?; - let profile = match self.flash_store + let profile = match self + .flash_store .read_value::("urukul") .unwrap() { @@ -103,47 +112,38 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { self.urukul.set_clock( urukul_config.clk_src, urukul_config.clk_freq, - urukul_config.clk_div + urukul_config.clk_div, )?; self.urukul.set_profile(urukul_config.profile)?; urukul_config.profile - }, + } None => 0, }; for (channel, channel_tag) in CHANNELS.iter().enumerate() { - match self.flash_store + match self + .flash_store .read_value::(channel_tag) .unwrap() { Some(channel_config) => { - self.urukul.set_channel_switch( - channel as u32, - channel_config.sw - )?; - self.urukul.set_channel_attenuation( - channel as u8, - channel_config.att - )?; - self.urukul.set_channel_sys_clk( - channel as u8, - channel_config.sys_clk - )?; - self.urukul.set_channel_default_ftw( - channel as u8, - channel_config.freq - )?; - self.urukul.set_channel_default_asf( - channel as u8, - channel_config.asf - )?; + self.urukul + .set_channel_switch(channel as u32, channel_config.sw)?; + self.urukul + .set_channel_attenuation(channel as u8, channel_config.att)?; + self.urukul + .set_channel_sys_clk(channel as u8, channel_config.sys_clk)?; + self.urukul + .set_channel_default_ftw(channel as u8, channel_config.freq)?; + self.urukul + .set_channel_default_asf(channel as u8, channel_config.asf)?; if let ProfileSetup::Singletone(singletone) = channel_config.profile { self.urukul.set_channel_single_tone_profile( channel as u8, profile, singletone.freq, singletone.phase, - singletone.asf + singletone.asf, )?; } else if let ProfileSetup::RAM(ram) = channel_config.profile { let op_mode = match ram.op_mode { @@ -159,11 +159,11 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { ram.start, ram.end, op_mode, - ram.stride + ram.stride, )?; } - }, - None => () + } + None => (), }; } Ok(()) @@ -171,63 +171,50 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { fn save_device(&mut self) -> Result<(), Error> { let urukul_config = UrukulConfig { - clk_src: { - self.urukul.get_clock_source()? - }, - clk_freq: { - self.urukul.get_clock_frequency() - }, - clk_div: { - self.urukul.get_clock_division()? - }, - profile: { - self.urukul.get_profile()? - } + clk_src: { self.urukul.get_clock_source()? }, + clk_freq: { self.urukul.get_clock_frequency() }, + clk_div: { self.urukul.get_clock_division()? }, + profile: { self.urukul.get_profile()? }, }; - unsafe { self.flash_store.write_value("urukul", &urukul_config, &mut SERDE_BUFFER).unwrap(); } + unsafe { + self.flash_store + .write_value("urukul", &urukul_config, &mut SERDE_BUFFER) + .unwrap(); + } for channel in 0..4 { - let ram = self.urukul.get_channel_ram_mode_enabled(channel as u8)?; + let ram = self.urukul.get_channel_ram_mode_enabled(channel as u8)?; let profile_setup = if ram { - let (start, end, stride, op_mode) = self.urukul.get_channel_ram_profile( - channel as u8, - urukul_config.profile - )?; + let (start, end, stride, op_mode) = self + .urukul + .get_channel_ram_profile(channel as u8, urukul_config.profile)?; let ram_profile = RAM { - start, end, stride, op_mode + start, + end, + stride, + op_mode, }; ProfileSetup::RAM(ram_profile) } else { - let (freq, phase, asf) = self.urukul.get_channel_single_tone_profile( - channel as u8, - urukul_config.profile - )?; - let singletone_profile = SingleTone { - freq, phase, asf - }; + let (freq, phase, asf) = self + .urukul + .get_channel_single_tone_profile(channel as u8, urukul_config.profile)?; + let singletone_profile = SingleTone { freq, phase, asf }; ProfileSetup::Singletone(singletone_profile) }; let channel_config = ChannelConfig { - sw: { - self.urukul.get_channel_switch_status(channel as u32)? - }, - att: { - self.urukul.get_channel_attenuation(channel as u8)? - }, - sys_clk: { - self.urukul.get_channel_sys_clk(channel as u8)? - }, - freq: { - self.urukul.get_channel_default_ftw(channel as u8)? - }, - asf: { - self.urukul.get_channel_default_asf(channel as u8)? - }, - profile: profile_setup + sw: { self.urukul.get_channel_switch_status(channel as u32)? }, + att: { self.urukul.get_channel_attenuation(channel as u8)? }, + sys_clk: { self.urukul.get_channel_sys_clk(channel as u8)? }, + freq: { self.urukul.get_channel_default_ftw(channel as u8)? }, + asf: { self.urukul.get_channel_default_asf(channel as u8)? }, + profile: profile_setup, }; unsafe { - self.flash_store.write_value(CHANNELS[channel], &channel_config, &mut SERDE_BUFFER).unwrap(); + self.flash_store + .write_value(CHANNELS[channel], &channel_config, &mut SERDE_BUFFER) + .unwrap(); } } @@ -251,7 +238,8 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { let command = if topic == MqttTopic::AppendBytes { let length = message.len(); if self.urukul.append_dds_ram_buffer(message).is_err() { - self.yet_to_respond = Some(MqttCommand::ProcessError("Cannot push bytes to buffer")); + self.yet_to_respond = + Some(MqttCommand::ProcessError("Cannot push bytes to buffer")); return; } MqttCommand::AppendBytes(length) @@ -259,7 +247,8 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { match self.parse_message(topic, message) { Ok((_, cmd)) => cmd, Err(_) => { - self.yet_to_respond = Some(MqttCommand::ProcessError("Cannot parse MQTT message")); + self.yet_to_respond = + Some(MqttCommand::ProcessError("Cannot parse MQTT message")); return; } } @@ -267,14 +256,16 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { self.yet_to_respond = match self.execute(command.clone()) { Err(_) => Some(MqttCommand::ProcessError("Cannot execute MQTT command")), - Ok(()) => Some(command) + Ok(()) => Some(command), }; } // Be sure to call egress function after each ingress. // Otherwise, response will be lost if successive valid MQTT messages were captured // without calling egress in between - pub fn process_mqtt_egress(&mut self) -> Result, String), U4>, Error> { + pub fn process_mqtt_egress( + &mut self, + ) -> Result, String), U4>, Error> { // Remove previously executed command, and process it afterwards let prev_cmd = self.yet_to_respond.clone(); self.yet_to_respond = None; @@ -286,12 +277,14 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { vec.push(( { let mut topic_string = String::from(self.name); - topic_string.push_str("/Feedback/Error") + topic_string + .push_str("/Feedback/Error") .map_err(|_| Error::StringOutOfSpace)?; topic_string }, - String::from(e_str) - )).map_err(|_| Error::VectorOutOfSpace)?; + String::from(e_str), + )) + .map_err(|_| Error::VectorOutOfSpace)?; Ok(vec) } @@ -299,17 +292,17 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { vec.push(( { let mut topic_string = String::from(self.name); - topic_string.push_str("/Feedback/Reset") + topic_string + .push_str("/Feedback/Reset") .map_err(|_| Error::StringOutOfSpace)?; topic_string }, - String::from( - match self.urukul.test() { - Ok(0) => "Reset successful.", - _ => "Reset error!", - } - ) - )).map_err(|_| Error::VectorOutOfSpace)?; + String::from(match self.urukul.test() { + Ok(0) => "Reset successful.", + _ => "Reset error!", + }), + )) + .map_err(|_| Error::VectorOutOfSpace)?; Ok(vec) } @@ -317,24 +310,26 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { vec.push(( { let mut topic_string = String::from(self.name); - topic_string.push_str("/Feedback/Channel") + topic_string + .push_str("/Feedback/Channel") .map_err(|_| Error::StringOutOfSpace)?; - topic_string.push(char::from_digit(ch.into(), 10).unwrap()) + topic_string + .push(char::from_digit(ch.into(), 10).unwrap()) .map_err(|_| Error::StringOutOfSpace)?; - topic_string.push_str("/Switch") + topic_string + .push_str("/Switch") .map_err(|_| Error::StringOutOfSpace)?; topic_string }, { - String::from( - if self.urukul.get_channel_switch_status(ch.into())? { - "on" - } else { - "off" - } - ) - } - )).map_err(|_| Error::VectorOutOfSpace)?; + String::from(if self.urukul.get_channel_switch_status(ch.into())? { + "on" + } else { + "off" + }) + }, + )) + .map_err(|_| Error::VectorOutOfSpace)?; Ok(vec) } @@ -342,56 +337,53 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { vec.push(( { let mut topic_string = String::from(self.name); - topic_string.push_str("/Feedback/Channel") + topic_string + .push_str("/Feedback/Channel") .map_err(|_| Error::StringOutOfSpace)?; - topic_string.push(char::from_digit(ch.into(), 10).unwrap()) + topic_string + .push(char::from_digit(ch.into(), 10).unwrap()) .map_err(|_| Error::StringOutOfSpace)?; - topic_string.push_str("/Attenuation") + topic_string + .push_str("/Attenuation") .map_err(|_| Error::StringOutOfSpace)?; topic_string }, { String::from( - self.float_buffer.format_finite( - self.urukul.get_channel_attenuation(ch)? - ) + self.float_buffer + .format_finite(self.urukul.get_channel_attenuation(ch)?), ) - } - )).map_err(|_| Error::VectorOutOfSpace)?; + }, + )) + .map_err(|_| Error::VectorOutOfSpace)?; Ok(vec) } MqttCommand::Clock(_, _, _) => { - vec.push( - self.get_clock_source_message()? - ).map_err(|_| Error::VectorOutOfSpace)?; - vec.push( - self.get_clock_frequency_message()? - ).map_err(|_| Error::VectorOutOfSpace)?; - vec.push( - self.get_clock_division_message()? - ).map_err(|_| Error::VectorOutOfSpace)?; + vec.push(self.get_clock_source_message()?) + .map_err(|_| Error::VectorOutOfSpace)?; + vec.push(self.get_clock_frequency_message()?) + .map_err(|_| Error::VectorOutOfSpace)?; + vec.push(self.get_clock_division_message()?) + .map_err(|_| Error::VectorOutOfSpace)?; Ok(vec) } MqttCommand::ClockSource(_) => { - vec.push( - self.get_clock_source_message()? - ).map_err(|_| Error::VectorOutOfSpace)?; + vec.push(self.get_clock_source_message()?) + .map_err(|_| Error::VectorOutOfSpace)?; Ok(vec) } MqttCommand::ClockFrequency(_) => { - vec.push( - self.get_clock_frequency_message()? - ).map_err(|_| Error::VectorOutOfSpace)?; + vec.push(self.get_clock_frequency_message()?) + .map_err(|_| Error::VectorOutOfSpace)?; Ok(vec) } MqttCommand::ClockDivision(_) => { - vec.push( - self.get_clock_division_message()? - ).map_err(|_| Error::VectorOutOfSpace)?; + vec.push(self.get_clock_division_message()?) + .map_err(|_| Error::VectorOutOfSpace)?; Ok(vec) } @@ -399,33 +391,38 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { vec.push(( { let mut topic_string = String::from(self.name); - topic_string.push_str("/Feedback/Channel") + topic_string + .push_str("/Feedback/Channel") .map_err(|_| Error::StringOutOfSpace)?; - topic_string.push(char::from_digit(ch.into(), 10).unwrap()) + topic_string + .push(char::from_digit(ch.into(), 10).unwrap()) .map_err(|_| Error::StringOutOfSpace)?; - topic_string.push_str("/SystemClock") + topic_string + .push_str("/SystemClock") .map_err(|_| Error::StringOutOfSpace)?; topic_string }, { let mut message_str = String::from( - self.float_buffer.format_finite( - self.urukul.get_channel_sys_clk(ch)? - ) + self.float_buffer + .format_finite(self.urukul.get_channel_sys_clk(ch)?), ); - message_str.push_str(" Hz") + message_str + .push_str(" Hz") .map_err(|_| Error::StringOutOfSpace)?; message_str - } - )).map_err(|_| Error::VectorOutOfSpace)?; + }, + )) + .map_err(|_| Error::VectorOutOfSpace)?; Ok(vec) } - MqttCommand::Singletone(ch, pr, _, _, _) | - MqttCommand::SingletoneFrequency(ch, pr, _) | - MqttCommand::SingletoneAmplitude(ch, pr, _) | - MqttCommand::SingletonePhase(ch, pr, _) => { - let (f_out, phase, ampl) = self.urukul.get_channel_single_tone_profile(ch, pr)?; + MqttCommand::Singletone(ch, pr, _, _, _) + | MqttCommand::SingletoneFrequency(ch, pr, _) + | MqttCommand::SingletoneAmplitude(ch, pr, _) + | MqttCommand::SingletonePhase(ch, pr, _) => { + let (f_out, phase, ampl) = + self.urukul.get_channel_single_tone_profile(ch, pr)?; vec.push(self.get_single_tone_frequency_message(ch, f_out)?) .map_err(|_| Error::StringOutOfSpace)?; vec.push(self.get_single_tone_phase_message(ch, phase)?) @@ -439,18 +436,21 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { vec.push(( { let mut topic_string = String::from(self.name); - topic_string.push_str("/Feedback/Profile") + topic_string + .push_str("/Feedback/Profile") .map_err(|_| Error::StringOutOfSpace)?; topic_string }, { let mut message_str = String::new(); let prof = self.urukul.get_profile()?; - message_str.push(char::from_digit(prof.into(), 10).unwrap()) + message_str + .push(char::from_digit(prof.into(), 10).unwrap()) .map_err(|_| Error::StringOutOfSpace)?; message_str - } - )).map_err(|_| Error::VectorOutOfSpace)?; + }, + )) + .map_err(|_| Error::VectorOutOfSpace)?; Ok(vec) } @@ -458,12 +458,14 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { vec.push(( { let mut topic_string = String::from(self.name); - topic_string.push_str("/Feedback/Save") + topic_string + .push_str("/Feedback/Save") .map_err(|_| Error::StringOutOfSpace)?; topic_string }, - String::from("Saved device.") - )).map_err(|_| Error::VectorOutOfSpace)?; + String::from("Saved device."), + )) + .map_err(|_| Error::VectorOutOfSpace)?; Ok(vec) } @@ -471,12 +473,14 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { vec.push(( { let mut topic_string = String::from(self.name); - topic_string.push_str("/Feedback/Load") + topic_string + .push_str("/Feedback/Load") .map_err(|_| Error::StringOutOfSpace)?; topic_string }, - String::from("Loaded from flash.") - )).map_err(|_| Error::VectorOutOfSpace)?; + String::from("Loaded from flash."), + )) + .map_err(|_| Error::VectorOutOfSpace)?; Ok(vec) } @@ -484,24 +488,28 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { vec.push(( { let mut topic_string = String::from(self.name); - topic_string.push_str("/Feedback/Channel") + topic_string + .push_str("/Feedback/Channel") .map_err(|_| Error::StringOutOfSpace)?; - topic_string.push(char::from_digit(ch.into(), 10).unwrap()) + topic_string + .push(char::from_digit(ch.into(), 10).unwrap()) .map_err(|_| Error::StringOutOfSpace)?; - topic_string.push_str("/Background/Frequency") + topic_string + .push_str("/Background/Frequency") .map_err(|_| Error::StringOutOfSpace)?; topic_string }, { let freq = self.urukul.get_channel_default_ftw(ch)?; - let mut message_str = String::from( - self.float_buffer.format_finite(freq) - ); - message_str.push_str(" Hz") + let mut message_str = + String::from(self.float_buffer.format_finite(freq)); + message_str + .push_str(" Hz") .map_err(|_| Error::StringOutOfSpace)?; message_str - } - )).map_err(|_| Error::VectorOutOfSpace)?; + }, + )) + .map_err(|_| Error::VectorOutOfSpace)?; Ok(vec) } @@ -509,22 +517,24 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { vec.push(( { let mut topic_string = String::from(self.name); - topic_string.push_str("/Feedback/Channel") + topic_string + .push_str("/Feedback/Channel") .map_err(|_| Error::StringOutOfSpace)?; - topic_string.push(char::from_digit(ch.into(), 10).unwrap()) + topic_string + .push(char::from_digit(ch.into(), 10).unwrap()) .map_err(|_| Error::StringOutOfSpace)?; - topic_string.push_str("/Background/Amplitude") + topic_string + .push_str("/Background/Amplitude") .map_err(|_| Error::StringOutOfSpace)?; topic_string }, { let ampl = self.urukul.get_channel_default_asf(ch)?; - let message_str = String::from( - self.float_buffer.format_finite(ampl) - ); + let message_str = String::from(self.float_buffer.format_finite(ampl)); message_str - } - )).map_err(|_| Error::VectorOutOfSpace)?; + }, + )) + .map_err(|_| Error::VectorOutOfSpace)?; Ok(vec) } @@ -532,19 +542,23 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { vec.push(( { let mut topic_string = String::from(self.name); - topic_string.push_str("/Feedback/Buffer/Append") + topic_string + .push_str("/Feedback/Buffer/Append") .map_err(|_| Error::StringOutOfSpace)?; topic_string }, { let mut message_str = String::from("Pushed "); - message_str.push_str(self.float_buffer.format_finite(len as f64)) - .map_err(|_| Error::StringOutOfSpace)?; - message_str.push_str(" bytes to buffer.") + message_str + .push_str(self.float_buffer.format_finite(len as f64)) .map_err(|_| Error::StringOutOfSpace)?; message_str - } - )).map_err(|_| Error::VectorOutOfSpace)?; + .push_str(" bytes to buffer.") + .map_err(|_| Error::StringOutOfSpace)?; + message_str + }, + )) + .map_err(|_| Error::VectorOutOfSpace)?; Ok(vec) } @@ -552,17 +566,20 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { vec.push(( { let mut topic_string = String::from(self.name); - topic_string.push_str("/Feedback/Buffer/Commit") + topic_string + .push_str("/Feedback/Buffer/Commit") .map_err(|_| Error::StringOutOfSpace)?; topic_string }, { let mut message_str = String::from("Pushed bytes to channel "); - message_str.push(char::from_digit(ch.into(), 10).unwrap()) + message_str + .push(char::from_digit(ch.into(), 10).unwrap()) .map_err(|_| Error::StringOutOfSpace)?; message_str - } - )).map_err(|_| Error::VectorOutOfSpace)?; + }, + )) + .map_err(|_| Error::VectorOutOfSpace)?; Ok(vec) } @@ -570,17 +587,20 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { vec.push(( { let mut topic_string = String::from(self.name); - topic_string.push_str("/Feedback/RAM") + topic_string + .push_str("/Feedback/RAM") .map_err(|_| Error::StringOutOfSpace)?; topic_string }, { let mut message_str = String::from("Selected RAM profile for channel "); - message_str.push(char::from_digit(ch.into(), 10).unwrap()) + message_str + .push(char::from_digit(ch.into(), 10).unwrap()) .map_err(|_| Error::StringOutOfSpace)?; message_str - } - )).map_err(|_| Error::VectorOutOfSpace)?; + }, + )) + .map_err(|_| Error::VectorOutOfSpace)?; Ok(vec) } }, @@ -591,20 +611,24 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { fn parse_topic<'a>(&mut self, topic: &'a str) -> Result> { let mut assigned_channel = false; let mut assigned_profile = false; - let mut channel :u8 = 0; - let mut profile :u8 = 0; + let mut channel: u8 = 0; + let mut profile: u8 = 0; // Verify that the topic starts with /Control/ or //Control/ let mut header = { let mut topic_builder_with_slash: String = String::from("/"); - topic_builder_with_slash.push_str(self.name) + topic_builder_with_slash + .push_str(self.name) .map_err(|_| Error::StringOutOfSpace)?; - topic_builder_with_slash.push_str("/Control/") + topic_builder_with_slash + .push_str("/Control/") .map_err(|_| Error::StringOutOfSpace)?; - let topic_builder: &str = topic_builder_with_slash.as_str() - .strip_prefix("/") - .ok_or(Error::StringOutOfSpace)?; - topic.strip_prefix(topic_builder_with_slash.as_str()) + let topic_builder: &str = topic_builder_with_slash + .as_str() + .strip_prefix("/") + .ok_or(Error::StringOutOfSpace)?; + topic + .strip_prefix(topic_builder_with_slash.as_str()) .or_else(|| topic.strip_prefix(topic_builder)) .ok_or(Error::MqttCommandError)? }; @@ -620,25 +644,26 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { return Err(Error::MqttCommandError); } // Remove the "Channel" part of the subtopic - header = header.strip_prefix("Channel") - .ok_or(Error::MqttCommandError)?; + header = header + .strip_prefix("Channel") + .ok_or(Error::MqttCommandError)?; // Remove the channel number at the end of the subtopic // But store the channel as a char, so it can be removed easily - let numeric_char :char = header.chars() - .next() - .ok_or(Error::MqttCommandError)?; + let numeric_char: char = + header.chars().next().ok_or(Error::MqttCommandError)?; // Record the channel number - channel = numeric_char.to_digit(10) - .ok_or(Error::MqttCommandError)? - .try_into() - .unwrap(); + channel = numeric_char + .to_digit(10) + .ok_or(Error::MqttCommandError)? + .try_into() + .unwrap(); assigned_channel = true; - header = header.strip_prefix(numeric_char) - .ok_or(Error::MqttCommandError)?; + header = header + .strip_prefix(numeric_char) + .ok_or(Error::MqttCommandError)?; // Remove forward slash ("/") - header = header.strip_prefix("/") - .ok_or(Error::MqttCommandError)?; - }, + header = header.strip_prefix("/").ok_or(Error::MqttCommandError)?; + } _ if (header.starts_with("Profile") && assigned_channel) => { // MQTT command should only mention profile once appropriately @@ -646,32 +671,33 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { return Err(Error::MqttCommandError); } // Remove the "Profile" part of the subtopic - header = header.strip_prefix("Profile") - .ok_or(Error::MqttCommandError)?; + header = header + .strip_prefix("Profile") + .ok_or(Error::MqttCommandError)?; // Remove the profile number at the end of the subtopic // But store the profile as a char, so it can be removed easily - let numeric_char :char = header.chars() - .next() - .ok_or(Error::MqttCommandError)?; + let numeric_char: char = + header.chars().next().ok_or(Error::MqttCommandError)?; // Record the channel number - profile = numeric_char.to_digit(10) - .ok_or(Error::MqttCommandError)? - .try_into() - .unwrap(); + profile = numeric_char + .to_digit(10) + .ok_or(Error::MqttCommandError)? + .try_into() + .unwrap(); assigned_profile = true; - header = header.strip_prefix(numeric_char) - .ok_or(Error::MqttCommandError)?; + header = header + .strip_prefix(numeric_char) + .ok_or(Error::MqttCommandError)?; // Remove forward slash ("/") - header = header.strip_prefix("/") - .ok_or(Error::MqttCommandError)?; - }, + header = header.strip_prefix("/").ok_or(Error::MqttCommandError)?; + } "Reset" => { if assigned_channel || assigned_profile { return Err(Error::MqttCommandError); } return Ok(MqttTopic::Reset); - }, + } "Switch" => { // Switch is a channel specific topic @@ -679,7 +705,7 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { return Err(Error::MqttCommandError); } return Ok(MqttTopic::Switch(channel)); - }, + } "Attenuation" => { // Attenuation is a channel specific topic @@ -687,14 +713,14 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { return Err(Error::MqttCommandError); } return Ok(MqttTopic::Attenuation(channel)); - }, + } "Clock" => { if assigned_channel || assigned_profile { return Err(Error::MqttCommandError); } return Ok(MqttTopic::Clock); - }, + } "Clock/Source" => { // Clock/Source refers to the Urukul clock source @@ -703,7 +729,7 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { return Err(Error::MqttCommandError); } return Ok(MqttTopic::ClockSource); - }, + } "Clock/Frequency" => { // Clock/Frequency refers to the Urukul clock frequency @@ -712,7 +738,7 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { return Err(Error::MqttCommandError); } return Ok(MqttTopic::ClockFrequency); - }, + } "Clock/Division" => { // Clock/Division refers to the Urukul clock division @@ -721,7 +747,7 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { return Err(Error::MqttCommandError); } return Ok(MqttTopic::ClockDivision); - }, + } "SystemClock" => { if !(assigned_channel && !assigned_profile) { @@ -732,84 +758,84 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { "Singletone" => { if !(assigned_channel && assigned_profile) { - return Err(Error::MqttCommandError) + return Err(Error::MqttCommandError); } return Ok(MqttTopic::Singletone(channel, profile)); } "Singletone/Frequency" => { if !(assigned_channel && assigned_profile) { - return Err(Error::MqttCommandError) + return Err(Error::MqttCommandError); } return Ok(MqttTopic::SingletoneFrequency(channel, profile)); } "Singletone/Amplitude" => { if !(assigned_channel && assigned_profile) { - return Err(Error::MqttCommandError) + return Err(Error::MqttCommandError); } return Ok(MqttTopic::SingletoneAmplitude(channel, profile)); } "Singletone/Phase" => { if !(assigned_channel && assigned_profile) { - return Err(Error::MqttCommandError) + return Err(Error::MqttCommandError); } return Ok(MqttTopic::SingletonePhase(channel, profile)); } "Profile" => { if assigned_channel || assigned_profile { - return Err(Error::MqttCommandError) + return Err(Error::MqttCommandError); } return Ok(MqttTopic::Profile); } "Save" => { if assigned_channel || assigned_profile { - return Err(Error::MqttCommandError) + return Err(Error::MqttCommandError); } return Ok(MqttTopic::Save); } "Load" => { if assigned_channel || assigned_profile { - return Err(Error::MqttCommandError) + return Err(Error::MqttCommandError); } return Ok(MqttTopic::Load); } "Background/Frequency" => { if !assigned_channel || assigned_profile { - return Err(Error::MqttCommandError) + return Err(Error::MqttCommandError); } return Ok(MqttTopic::DefaultFTW(channel)); } "Background/Amplitude" => { if !assigned_channel || assigned_profile { - return Err(Error::MqttCommandError) + return Err(Error::MqttCommandError); } return Ok(MqttTopic::DefaultASF(channel)); } "Buffer/Append" => { if assigned_channel || assigned_profile { - return Err(Error::MqttCommandError) + return Err(Error::MqttCommandError); } return Ok(MqttTopic::AppendBytes); } "Buffer/Commit" => { if assigned_channel || assigned_profile { - return Err(Error::MqttCommandError) + return Err(Error::MqttCommandError); } return Ok(MqttTopic::CommitBuffer); } "RAM" => { if !assigned_channel || !assigned_profile { - return Err(Error::MqttCommandError) + return Err(Error::MqttCommandError); } return Ok(MqttTopic::RAM(channel, profile)); } @@ -819,7 +845,11 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { } } - fn parse_message<'a>(&mut self, topic: MqttTopic, message: &'a [u8]) -> IResult<&'a [u8], MqttCommand> { + fn parse_message<'a>( + &mut self, + topic: MqttTopic, + message: &'a [u8], + ) -> IResult<&'a [u8], MqttCommand> { match topic { MqttTopic::Reset => Ok((message, MqttCommand::Reset)), MqttTopic::Switch(ch) => switch_message(ch, message), @@ -830,15 +860,19 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { MqttTopic::ClockDivision => clock_division_message(message), MqttTopic::SystemClock(ch) => system_clock_message(ch, message), MqttTopic::Singletone(ch, prof) => singletone_message(ch, prof, message), - MqttTopic::SingletoneFrequency(ch, prof) => singletone_frequency_message(ch, prof, message), - MqttTopic::SingletoneAmplitude(ch, prof) => singletone_amplitude_message(ch, prof, message), + MqttTopic::SingletoneFrequency(ch, prof) => { + singletone_frequency_message(ch, prof, message) + } + MqttTopic::SingletoneAmplitude(ch, prof) => { + singletone_amplitude_message(ch, prof, message) + } MqttTopic::SingletonePhase(ch, prof) => singletone_phase_message(ch, prof, message), MqttTopic::Profile => profile_message(message), MqttTopic::Save => Ok((message, MqttCommand::Save)), MqttTopic::Load => Ok((message, MqttCommand::Load)), MqttTopic::DefaultFTW(ch) => default_frequency_message(ch, message), MqttTopic::DefaultASF(ch) => default_amplitude_message(ch, message), - MqttTopic::AppendBytes => unreachable!(), // This topic should not be parsed + MqttTopic::AppendBytes => unreachable!(), // This topic should not be parsed MqttTopic::CommitBuffer => commit_buffer_message(message), MqttTopic::RAM(ch, pr) => ram_message(ch, pr, message), } @@ -855,20 +889,30 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { MqttCommand::ClockFrequency(freq) => self.urukul.set_clock_frequency(freq), MqttCommand::ClockDivision(div) => self.urukul.set_clock_division(div), MqttCommand::SystemClock(ch, freq) => self.urukul.set_channel_sys_clk(ch, freq), - MqttCommand::Singletone(ch, prof, freq, ampl, deg) => self.urukul.set_channel_single_tone_profile(ch, prof, freq, ampl, deg), - MqttCommand::SingletoneFrequency(ch, prof, freq) => self.urukul.set_channel_single_tone_profile_frequency(ch, prof, freq), - MqttCommand::SingletoneAmplitude(ch, prof, ampl) => self.urukul.set_channel_single_tone_profile_amplitude(ch, prof, ampl), - MqttCommand::SingletonePhase(ch, prof, deg) => self.urukul.set_channel_single_tone_profile_phase(ch, prof, deg), + MqttCommand::Singletone(ch, prof, freq, ampl, deg) => self + .urukul + .set_channel_single_tone_profile(ch, prof, freq, ampl, deg), + MqttCommand::SingletoneFrequency(ch, prof, freq) => self + .urukul + .set_channel_single_tone_profile_frequency(ch, prof, freq), + MqttCommand::SingletoneAmplitude(ch, prof, ampl) => self + .urukul + .set_channel_single_tone_profile_amplitude(ch, prof, ampl), + MqttCommand::SingletonePhase(ch, prof, deg) => self + .urukul + .set_channel_single_tone_profile_phase(ch, prof, deg), MqttCommand::Profile(prof) => self.urukul.set_profile(prof), MqttCommand::Save => self.save_device(), MqttCommand::Load => self.load_device(), MqttCommand::DefaultFTW(ch, freq) => self.urukul.set_channel_default_ftw(ch, freq), MqttCommand::DefaultASF(ch, ampl) => self.urukul.set_channel_default_asf(ch, ampl), - MqttCommand::AppendBytes(_) => Ok(()), // The bytes were not parsed and pushed - MqttCommand::CommitBuffer(dest, start_addr, ch) => self.urukul.commit_ram_buffer_to_channel(ch, start_addr, dest), - MqttCommand::RAM(ch, pr, start_addr, end_addr, op_mode, ramp_rate) => { - self.urukul.set_channel_ram_profile(ch, pr, start_addr, end_addr, op_mode, ramp_rate) - } + MqttCommand::AppendBytes(_) => Ok(()), // The bytes were not parsed and pushed + MqttCommand::CommitBuffer(dest, start_addr, ch) => self + .urukul + .commit_ram_buffer_to_channel(ch, start_addr, dest), + MqttCommand::RAM(ch, pr, start_addr, end_addr, op_mode, ramp_rate) => self + .urukul + .set_channel_ram_profile(ch, pr, start_addr, end_addr, op_mode, ramp_rate), } } @@ -876,37 +920,38 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { Ok(( { let mut topic_string = String::from(self.name); - topic_string.push_str("/Feedback/Clock/Source") + topic_string + .push_str("/Feedback/Clock/Source") .map_err(|_| Error::StringOutOfSpace)?; topic_string }, - self.urukul.get_clock_source().map( - |src| match src { - UrukulClockSource::OSC => String::from("OSC"), - UrukulClockSource::MMCX => String::from("MMCX"), - UrukulClockSource::SMA => String::from("SMA") - } - )? + self.urukul.get_clock_source().map(|src| match src { + UrukulClockSource::OSC => String::from("OSC"), + UrukulClockSource::MMCX => String::from("MMCX"), + UrukulClockSource::SMA => String::from("SMA"), + })?, )) } - fn get_clock_frequency_message(&mut self) -> Result<(String, String), Error> { + fn get_clock_frequency_message(&mut self) -> Result<(String, String), Error> { Ok(( { let mut topic_string = String::from(self.name); - topic_string.push_str("/Feedback/Clock/Frequency") + topic_string + .push_str("/Feedback/Clock/Frequency") .map_err(|_| Error::StringOutOfSpace)?; topic_string }, { let mut freq_str = String::from( - self.float_buffer.format_finite( - self.urukul.get_clock_frequency() - ) + self.float_buffer + .format_finite(self.urukul.get_clock_frequency()), ); - freq_str.push_str(" Hz").map_err(|_| Error::StringOutOfSpace)?; freq_str - } + .push_str(" Hz") + .map_err(|_| Error::StringOutOfSpace)?; + freq_str + }, )) } @@ -914,99 +959,110 @@ impl<'s, SPI, E> MqttMux<'s, SPI> where SPI: Transfer { Ok(( { let mut topic_string = String::from(self.name); - topic_string.push_str("/Feedback/Clock/Division") + topic_string + .push_str("/Feedback/Clock/Division") .map_err(|_| Error::StringOutOfSpace)?; topic_string }, { - self.urukul.get_clock_division().map( - |src| match src { - 1 => String::from("1"), - 2 => String::from("2"), - 4 => String::from("4"), - _ => unreachable!() - } - )? - } + self.urukul.get_clock_division().map(|src| match src { + 1 => String::from("1"), + 2 => String::from("2"), + 4 => String::from("4"), + _ => unreachable!(), + })? + }, )) } - fn get_single_tone_frequency_message(&mut self, ch: u8, f_out: f64) -> Result<(String, String), Error> { + fn get_single_tone_frequency_message( + &mut self, + ch: u8, + f_out: f64, + ) -> Result<(String, String), Error> { Ok(( { let mut topic_string = String::from(self.name); - topic_string.push_str("/Feedback/Channel") + topic_string + .push_str("/Feedback/Channel") .map_err(|_| Error::StringOutOfSpace)?; - topic_string.push(char::from_digit(ch.into(), 10).unwrap()) + topic_string + .push(char::from_digit(ch.into(), 10).unwrap()) .map_err(|_| Error::StringOutOfSpace)?; - topic_string.push_str("/Singletone/Frequency") + topic_string + .push_str("/Singletone/Frequency") .map_err(|_| Error::StringOutOfSpace)?; topic_string }, { - let mut message_str = String::from( - self.float_buffer.format_finite(f_out) - ); - message_str.push_str(" Hz") + let mut message_str = String::from(self.float_buffer.format_finite(f_out)); + message_str + .push_str(" Hz") .map_err(|_| Error::StringOutOfSpace)?; message_str - } + }, )) } - fn get_single_tone_amplitude_message(&mut self, ch: u8, ampl: f64) -> Result<(String, String), Error> { + fn get_single_tone_amplitude_message( + &mut self, + ch: u8, + ampl: f64, + ) -> Result<(String, String), Error> { Ok(( { let mut topic_string = String::from(self.name); - topic_string.push_str("/Feedback/Channel") + topic_string + .push_str("/Feedback/Channel") .map_err(|_| Error::StringOutOfSpace)?; - topic_string.push(char::from_digit(ch.into(), 10).unwrap()) + topic_string + .push(char::from_digit(ch.into(), 10).unwrap()) .map_err(|_| Error::StringOutOfSpace)?; - topic_string.push_str("/Singletone/Amplitude") + topic_string + .push_str("/Singletone/Amplitude") .map_err(|_| Error::StringOutOfSpace)?; topic_string }, { - let message_str = String::from( - self.float_buffer.format_finite(ampl) - ); + let message_str = String::from(self.float_buffer.format_finite(ampl)); message_str - } + }, )) } - fn get_single_tone_phase_message(&mut self, ch: u8, phase: f64) -> Result<(String, String), Error> { + fn get_single_tone_phase_message( + &mut self, + ch: u8, + phase: f64, + ) -> Result<(String, String), Error> { Ok(( { let mut topic_string = String::from(self.name); - topic_string.push_str("/Feedback/Channel") + topic_string + .push_str("/Feedback/Channel") .map_err(|_| Error::StringOutOfSpace)?; - topic_string.push(char::from_digit(ch.into(), 10).unwrap()) + topic_string + .push(char::from_digit(ch.into(), 10).unwrap()) .map_err(|_| Error::StringOutOfSpace)?; - topic_string.push_str("/Singletone/Phase") + topic_string + .push_str("/Singletone/Phase") .map_err(|_| Error::StringOutOfSpace)?; topic_string }, { - let mut message_str = String::from( - self.float_buffer.format_finite(phase) - ); - message_str.push_str(" deg") + let mut message_str = String::from(self.float_buffer.format_finite(phase)); + message_str + .push_str(" deg") .map_err(|_| Error::StringOutOfSpace)?; message_str - } + }, )) } } // Read message parameter separator (optional comma and whitespace) fn message_separator(message: &[u8]) -> IResult<&[u8], ()> { - preceded( - opt( - tag(",") - ), - whitespace - )(message) + preceded(opt(tag(",")), whitespace)(message) } // Read whitespace @@ -1019,387 +1075,312 @@ fn read_frequency(message: &[u8]) -> IResult<&[u8], f64> { map( pair( double, - opt( - preceded( - whitespace, - alt(( - value(1.0, tag_no_case("hz")), - value(1_000.0, tag_no_case("khz")), - value(1_000_000.0, tag_no_case("mhz")), - value(1_000_000_000.0, tag_no_case("ghz")) - )) - ) - ) + opt(preceded( + whitespace, + alt(( + value(1.0, tag_no_case("hz")), + value(1_000.0, tag_no_case("khz")), + value(1_000_000.0, tag_no_case("mhz")), + value(1_000_000_000.0, tag_no_case("ghz")), + )), + )), ), - |(freq, unit): (f64, Option)| { - freq * unit.map_or(1.0, |mul| mul) - } + |(freq, unit): (f64, Option)| freq * unit.map_or(1.0, |mul| mul), )(message) } // Parser for Switch Command Message fn switch_message(channel: u8, message: &[u8]) -> IResult<&[u8], MqttCommand> { - all_consuming( - map( - alt(( - value(true, tag("on")), - value(false, tag("off")) - )), - |switch| MqttCommand::Switch(channel, switch) - ) - )(message) + all_consuming(map( + alt((value(true, tag("on")), value(false, tag("off")))), + |switch| MqttCommand::Switch(channel, switch), + ))(message) } // Parser for Attenuation Command Message fn attenuation_message(channel: u8, message: &[u8]) -> IResult<&[u8], MqttCommand> { - all_consuming( - map( - terminated( - float, - opt( - preceded( - whitespace, - tag_no_case("db") - ) - ) - ), - |att: f32| MqttCommand::Attenuation(channel, att) - ) - )(message) + all_consuming(map( + terminated(float, opt(preceded(whitespace, tag_no_case("db")))), + |att: f32| MqttCommand::Attenuation(channel, att), + ))(message) } // Parser for Clock Source Command Message fn clock_source_message(message: &[u8]) -> IResult<&[u8], MqttCommand> { - all_consuming( - alt(( - value(MqttCommand::ClockSource(UrukulClockSource::OSC), tag_no_case("OSC")), - value(MqttCommand::ClockSource(UrukulClockSource::MMCX), tag_no_case("MMCX")), - value(MqttCommand::ClockSource(UrukulClockSource::SMA), tag_no_case("SMA")) - )) - )(message) + all_consuming(alt(( + value( + MqttCommand::ClockSource(UrukulClockSource::OSC), + tag_no_case("OSC"), + ), + value( + MqttCommand::ClockSource(UrukulClockSource::MMCX), + tag_no_case("MMCX"), + ), + value( + MqttCommand::ClockSource(UrukulClockSource::SMA), + tag_no_case("SMA"), + ), + )))(message) } // Parser for Clock Frequency Command Message fn clock_frequency_message(message: &[u8]) -> IResult<&[u8], MqttCommand> { - all_consuming( - map( - read_frequency, - |freq: f64| MqttCommand::ClockFrequency(freq) - ) - )(message) + all_consuming(map(read_frequency, |freq: f64| { + MqttCommand::ClockFrequency(freq) + }))(message) } // Parser for Clock Division Command Message fn clock_division_message(message: &[u8]) -> IResult<&[u8], MqttCommand> { - all_consuming( - map( - digit1, - |div: &[u8]| MqttCommand::ClockDivision( - u8::from_str_radix( - core::str::from_utf8(div).unwrap(), - 10 - ).unwrap() - ) + all_consuming(map(digit1, |div: &[u8]| { + MqttCommand::ClockDivision( + u8::from_str_radix(core::str::from_utf8(div).unwrap(), 10).unwrap(), ) - )(message) + }))(message) } // Parser for one-command master clock setup message fn clock_message(message: &[u8]) -> IResult<&[u8], MqttCommand> { - all_consuming( - map( - permutation(( + all_consuming(map( + permutation(( + preceded( + tag_no_case("source:"), preceded( - tag_no_case("source:"), - preceded( - whitespace, - terminated( - alt(( - value(UrukulClockSource::OSC, tag_no_case("OSC")), - value(UrukulClockSource::MMCX, tag_no_case("MMCX")), - value(UrukulClockSource::SMA, tag_no_case("SMA")) - )), - message_separator - ) - ) + whitespace, + terminated( + alt(( + value(UrukulClockSource::OSC, tag_no_case("OSC")), + value(UrukulClockSource::MMCX, tag_no_case("MMCX")), + value(UrukulClockSource::SMA, tag_no_case("SMA")), + )), + message_separator, + ), ), + ), + preceded( + tag_no_case("frequency:"), + preceded(whitespace, terminated(read_frequency, message_separator)), + ), + preceded( + tag_no_case("division:"), preceded( - tag_no_case("frequency:"), - preceded( - whitespace, - terminated( - read_frequency, - message_separator - ) - ) + whitespace, + terminated( + map_res(digit1, |div: &[u8]| { + u8::from_str_radix(core::str::from_utf8(div).unwrap(), 10) + }), + message_separator, + ), ), - preceded( - tag_no_case("division:"), - preceded( - whitespace, - terminated( - map_res( - digit1, - |div: &[u8]| u8::from_str_radix(core::str::from_utf8(div).unwrap(), 10) - ), - message_separator - ) - ) - ) - )), - |(src, freq, div): (UrukulClockSource, f64, u8)| MqttCommand::Clock(src, freq, div) - ) - )(message) + ), + )), + |(src, freq, div): (UrukulClockSource, f64, u8)| MqttCommand::Clock(src, freq, div), + ))(message) } // Message parser for f_sys_clk of any channels fn system_clock_message(channel: u8, message: &[u8]) -> IResult<&[u8], MqttCommand> { - all_consuming( - map( - read_frequency, - |freq: f64| MqttCommand::SystemClock(channel, freq) - ) - )(message) + all_consuming(map(read_frequency, |freq: f64| { + MqttCommand::SystemClock(channel, freq) + }))(message) } // Parser for Singletone frequency Command Message -fn singletone_frequency_message(channel: u8, profile: u8, message: &[u8]) -> IResult<&[u8], MqttCommand> { - all_consuming( - map( - read_frequency, - |freq: f64| MqttCommand::SingletoneFrequency(channel, profile, freq) - ) - )(message) +fn singletone_frequency_message( + channel: u8, + profile: u8, + message: &[u8], +) -> IResult<&[u8], MqttCommand> { + all_consuming(map(read_frequency, |freq: f64| { + MqttCommand::SingletoneFrequency(channel, profile, freq) + }))(message) } // Parser for default frequency Command Message fn default_frequency_message(channel: u8, message: &[u8]) -> IResult<&[u8], MqttCommand> { - all_consuming( - map( - read_frequency, - |freq: f64| MqttCommand::DefaultFTW(channel, freq) - ) - )(message) + all_consuming(map(read_frequency, |freq: f64| { + MqttCommand::DefaultFTW(channel, freq) + }))(message) } // Parser for Singletone Amplitude Command Message -fn singletone_amplitude_message(channel: u8, profile: u8, message: &[u8]) -> IResult<&[u8], MqttCommand> { - all_consuming( - map( - double, - |ampl: f64| MqttCommand::SingletoneAmplitude(channel, profile, ampl) - ) - )(message) +fn singletone_amplitude_message( + channel: u8, + profile: u8, + message: &[u8], +) -> IResult<&[u8], MqttCommand> { + all_consuming(map(double, |ampl: f64| { + MqttCommand::SingletoneAmplitude(channel, profile, ampl) + }))(message) } // Parser for Default Amplitude Command Message fn default_amplitude_message(channel: u8, message: &[u8]) -> IResult<&[u8], MqttCommand> { - all_consuming( - map( - double, - |ampl: f64| MqttCommand::DefaultASF(channel, ampl) - ) - )(message) + all_consuming(map(double, |ampl: f64| { + MqttCommand::DefaultASF(channel, ampl) + }))(message) } // Parser for Phase Command Message -fn singletone_phase_message(channel: u8, profile: u8, message: &[u8]) -> IResult<&[u8], MqttCommand> { - all_consuming( - map( - terminated( - double, - opt( - preceded( - whitespace, - tag_no_case("deg") - ) - ) - ), - |deg: f64| MqttCommand::SingletonePhase(channel, profile, deg) - ) - )(message) +fn singletone_phase_message( + channel: u8, + profile: u8, + message: &[u8], +) -> IResult<&[u8], MqttCommand> { + all_consuming(map( + terminated(double, opt(preceded(whitespace, tag_no_case("deg")))), + |deg: f64| MqttCommand::SingletonePhase(channel, profile, deg), + ))(message) } // Parser for one-command singletone profile Command fn singletone_message(channel: u8, profile: u8, message: &[u8]) -> IResult<&[u8], MqttCommand> { - all_consuming( - map( - permutation(( + all_consuming(map( + permutation(( + preceded( + tag_no_case("frequency:"), + preceded(whitespace, terminated(read_frequency, message_separator)), + ), + preceded( + tag_no_case("amplitude:"), + preceded(whitespace, terminated(double, message_separator)), + ), + opt(preceded( + tag_no_case("phase:"), preceded( - tag_no_case("frequency:"), - preceded( - whitespace, - terminated( - read_frequency, - message_separator - ) - ) - ), - preceded( - tag_no_case("amplitude:"), - preceded( - whitespace, - terminated( - double, - message_separator - ) - ) - ), - opt( - preceded( - tag_no_case("phase:"), + whitespace, + terminated( + double, preceded( - whitespace, - terminated( - double, - preceded( - opt( - preceded( - whitespace, - tag_no_case("deg") - ) - ), - message_separator - ) - ) - ) - ) - ) + opt(preceded(whitespace, tag_no_case("deg"))), + message_separator, + ), + ), + ), )), - |(freq, ampl, phase): (f64, f64, Option)| MqttCommand::Singletone(channel, profile, freq, phase.unwrap_or(0.0), ampl) - ) - )(message) + )), + |(freq, ampl, phase): (f64, f64, Option)| { + MqttCommand::Singletone(channel, profile, freq, phase.unwrap_or(0.0), ampl) + }, + ))(message) } fn profile_message(message: &[u8]) -> IResult<&[u8], MqttCommand> { - all_consuming( - map( - digit1, - |num: &[u8]| { - MqttCommand::Profile( - u8::from_str_radix(core::str::from_utf8(num).unwrap(), 10).unwrap() - ) - } - ) - )(message) + all_consuming(map(digit1, |num: &[u8]| { + MqttCommand::Profile(u8::from_str_radix(core::str::from_utf8(num).unwrap(), 10).unwrap()) + }))(message) } fn commit_buffer_message(message: &[u8]) -> IResult<&[u8], MqttCommand> { - all_consuming( - map( - permutation(( + all_consuming(map( + permutation(( + preceded( + tag_no_case("dest:"), preceded( - tag_no_case("dest:"), - preceded( - whitespace, - terminated( - alt(( - value(RAMDestination::Frequency, tag_no_case("frequency")), - value(RAMDestination::Amplitude, tag_no_case("amplitude")), - value(RAMDestination::Phase, tag_no_case("phase")), - value(RAMDestination::Polar, tag_no_case("polar")), - )), - message_separator - ) - ) + whitespace, + terminated( + alt(( + value(RAMDestination::Frequency, tag_no_case("frequency")), + value(RAMDestination::Amplitude, tag_no_case("amplitude")), + value(RAMDestination::Phase, tag_no_case("phase")), + value(RAMDestination::Polar, tag_no_case("polar")), + )), + message_separator, + ), ), + ), + preceded( + tag_no_case("start:"), preceded( - tag_no_case("start:"), - preceded( - whitespace, - terminated( - map_res( - digit1, - |start_addr: &[u8]| u16::from_str_radix(core::str::from_utf8(start_addr).unwrap(), 10) - ), - message_separator - ) - ) + whitespace, + terminated( + map_res(digit1, |start_addr: &[u8]| { + u16::from_str_radix(core::str::from_utf8(start_addr).unwrap(), 10) + }), + message_separator, + ), ), + ), + preceded( + tag_no_case("ch:"), preceded( - tag_no_case("ch:"), - preceded( - whitespace, - terminated( - map_res( - digit1, - |ch: &[u8]| u8::from_str_radix(core::str::from_utf8(ch).unwrap(), 10) - ), - message_separator - ) - ) - ) - )), - |(dest, start_addr, ch): (RAMDestination, u16, u8)| { - MqttCommand::CommitBuffer(dest, start_addr, ch) - } - ) - )(message) + whitespace, + terminated( + map_res(digit1, |ch: &[u8]| { + u8::from_str_radix(core::str::from_utf8(ch).unwrap(), 10) + }), + message_separator, + ), + ), + ), + )), + |(dest, start_addr, ch): (RAMDestination, u16, u8)| { + MqttCommand::CommitBuffer(dest, start_addr, ch) + }, + ))(message) } fn ram_message(channel: u8, profile: u8, message: &[u8]) -> IResult<&[u8], MqttCommand> { - all_consuming( - map( - permutation(( + all_consuming(map( + permutation(( + preceded( + tag_no_case("start:"), preceded( - tag_no_case("start:"), - preceded( - whitespace, - terminated( - map_res( - digit1, - |ch: &[u8]| u16::from_str_radix(core::str::from_utf8(ch).unwrap(), 10) - ), - message_separator - ) - ) + whitespace, + terminated( + map_res(digit1, |ch: &[u8]| { + u16::from_str_radix(core::str::from_utf8(ch).unwrap(), 10) + }), + message_separator, + ), ), + ), + preceded( + tag_no_case("end:"), preceded( - tag_no_case("end:"), - preceded( - whitespace, - terminated( - map_res( - digit1, - |ch: &[u8]| u16::from_str_radix(core::str::from_utf8(ch).unwrap(), 10) - ), - message_separator - ) - ) + whitespace, + terminated( + map_res(digit1, |ch: &[u8]| { + u16::from_str_radix(core::str::from_utf8(ch).unwrap(), 10) + }), + message_separator, + ), ), + ), + preceded( + tag_no_case("op_mode:"), preceded( - tag_no_case("op_mode:"), - preceded( - whitespace, - terminated( - alt(( - value(RAMOperationMode::DirectSwitch, tag_no_case("DS")), - value(RAMOperationMode::RampUp, tag_no_case("RU")), - value(RAMOperationMode::BidirectionalRamp, tag_no_case("BDR")), - value(RAMOperationMode::ContinuousBidirectionalRamp, tag_no_case("CBDR")), - value(RAMOperationMode::ContinuousRecirculate, tag_no_case("CR")), - )), - message_separator - ) - ) - ), - preceded( - tag_no_case("ramp:"), - preceded( - whitespace, - terminated( - map_res( - digit1, - |ch: &[u8]| u16::from_str_radix(core::str::from_utf8(ch).unwrap(), 10) + whitespace, + terminated( + alt(( + value(RAMOperationMode::DirectSwitch, tag_no_case("DS")), + value(RAMOperationMode::RampUp, tag_no_case("RU")), + value(RAMOperationMode::BidirectionalRamp, tag_no_case("BDR")), + value( + RAMOperationMode::ContinuousBidirectionalRamp, + tag_no_case("CBDR"), ), - message_separator - ) - ) - ) - )), - |(start_addr, end_addr, op_mode, ramp_rate): (u16, u16, RAMOperationMode, u16)| { - MqttCommand::RAM(channel, profile, start_addr, end_addr, op_mode, ramp_rate) - } - ) - )(message) + value(RAMOperationMode::ContinuousRecirculate, tag_no_case("CR")), + )), + message_separator, + ), + ), + ), + preceded( + tag_no_case("ramp:"), + preceded( + whitespace, + terminated( + map_res(digit1, |ch: &[u8]| { + u16::from_str_radix(core::str::from_utf8(ch).unwrap(), 10) + }), + message_separator, + ), + ), + ), + )), + |(start_addr, end_addr, op_mode, ramp_rate): (u16, u16, RAMOperationMode, u16)| { + MqttCommand::RAM(channel, profile, start_addr, end_addr, op_mode, ramp_rate) + }, + ))(message) } diff --git a/src/spi_slave.rs b/src/spi_slave.rs index 8859b08..e7e7328 100644 --- a/src/spi_slave.rs +++ b/src/spi_slave.rs @@ -1,11 +1,8 @@ -use embedded_hal::{ - blocking::spi::Transfer, - digital::v2::OutputPin, -}; use crate::cpld::CPLD; use crate::urukul::Error; +use embedded_hal::{blocking::spi::Transfer, digital::v2::OutputPin}; -pub struct SPISlave<'a, SPI, CS0, CS1, CS2, GPIO> ( +pub struct SPISlave<'a, SPI, CS0, CS1, CS2, GPIO>( // SPI device to be multiplexed &'a CPLD, // Channel of SPI slave @@ -48,8 +45,12 @@ where { type Error = Error; - fn transfer<'w>(&mut self, words: &'w mut[u8]) -> Result<&'w [u8], Self::Error> { - let mut dev = self.0.data.try_borrow_mut().map_err(|_| Error::GetRefMutDataError)?; + fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { + let mut dev = self + .0 + .data + .try_borrow_mut() + .map_err(|_| Error::GetRefMutDataError)?; dev.select_chip(self.1).map_err(|_| Error::CSError)?; let result = dev.spi.transfer(words).map_err(Error::SPI)?; dev.select_chip(0).map_err(|_| Error::CSError)?; diff --git a/src/urukul.rs b/src/urukul.rs index 1878fee..cb9f4bc 100644 --- a/src/urukul.rs +++ b/src/urukul.rs @@ -1,15 +1,13 @@ extern crate embedded_hal; -use embedded_hal::{ - blocking::spi::Transfer, -}; +use embedded_hal::blocking::spi::Transfer; -use serde::{ Serialize, Deserialize }; +use serde::{Deserialize, Serialize}; -use crate::config_register::ConfigRegister; -use crate::config_register::CFGMask; -use crate::config_register::StatusMask; use crate::attenuator::Attenuator; -use crate::dds::{ DDS, RAMOperationMode, RAMDestination }; +use crate::config_register::CFGMask; +use crate::config_register::ConfigRegister; +use crate::config_register::StatusMask; +use crate::dds::{RAMDestination, RAMOperationMode, DDS}; /* * Enum for structuring error @@ -30,7 +28,7 @@ pub enum Error { MqttCommandError, VectorOutOfSpace, StringOutOfSpace, - WaitRetry, // Prompt driver to just wait and retry + WaitRetry, // Prompt driver to just wait and retry } impl Error { @@ -68,7 +66,15 @@ where * Master constructor for the entire Urukul device * Supply 7 SPI channels to Urukul and 4 reference clock frequencies */ - pub fn new(spi1: SPI, spi2: SPI, spi3: SPI, spi4: SPI, spi5: SPI, spi6: SPI, spi7: SPI) -> Self { + pub fn new( + spi1: SPI, + spi2: SPI, + spi3: SPI, + spi4: SPI, + spi5: SPI, + spi6: SPI, + spi7: SPI, + ) -> Self { // Construct Urukul Urukul { config_register: ConfigRegister::new(spi1), @@ -100,21 +106,21 @@ where self.config_register.set_configurations(&mut [ (CFGMask::RST, 1), (CFGMask::IO_RST, 1), - (CFGMask::IO_UPDATE, 0) + (CFGMask::IO_UPDATE, 0), ])?; // Set 0 to all fields on configuration register. self.config_register.set_configurations(&mut [ - (CFGMask::RF_SW, 0), - (CFGMask::LED, 0), - (CFGMask::PROFILE, 0), - (CFGMask::IO_UPDATE, 0), - (CFGMask::MASK_NU, 0), - (CFGMask::CLK_SEL0, 0), - (CFGMask::SYNC_SEL, 0), - (CFGMask::RST, 0), - (CFGMask::IO_RST, 0), - (CFGMask::CLK_SEL1, 0), - (CFGMask::DIV, 0), + (CFGMask::RF_SW, 0), + (CFGMask::LED, 0), + (CFGMask::PROFILE, 0), + (CFGMask::IO_UPDATE, 0), + (CFGMask::MASK_NU, 0), + (CFGMask::CLK_SEL0, 0), + (CFGMask::SYNC_SEL, 0), + (CFGMask::RST, 0), + (CFGMask::IO_RST, 0), + (CFGMask::CLK_SEL1, 0), + (CFGMask::DIV, 0), ])?; // Init all DDS chips. Configure SDIO as input only. for chip_no in 0..4 { @@ -145,12 +151,13 @@ where impl Urukul where - SPI: Transfer + SPI: Transfer, { - pub fn get_channel_switch_status(&mut self, channel: u32) -> Result> { if channel < 4 { - self.config_register.get_status(StatusMask::RF_SW).map(|val| (val & (1 << channel)) != 0) + self.config_register + .get_status(StatusMask::RF_SW) + .map(|val| (val & (1 << channel)) != 0) } else { Err(Error::ParameterError) } @@ -166,15 +173,20 @@ where prev & (!(1 << channel)) } }; - self.config_register.set_configurations(&mut [ - (CFGMask::RF_SW, next), - ]).map(|_| ()) + self.config_register + .set_configurations(&mut [(CFGMask::RF_SW, next)]) + .map(|_| ()) } else { Err(Error::ParameterError) } } - pub fn set_clock(&mut self, source: ClockSource, frequency: f64, division: u8) -> Result<(), Error> { + pub fn set_clock( + &mut self, + source: ClockSource, + frequency: f64, + division: u8, + ) -> Result<(), Error> { // Change clock source through configuration register self.set_clock_source(source)?; @@ -188,30 +200,29 @@ where pub fn get_clock_source(&mut self) -> Result> { match ( self.config_register.get_configuration(CFGMask::CLK_SEL0), - self.config_register.get_configuration(CFGMask::CLK_SEL1) + self.config_register.get_configuration(CFGMask::CLK_SEL1), ) { (0, 0) => Ok(ClockSource::OSC), (0, 1) => Ok(ClockSource::MMCX), (1, _) => Ok(ClockSource::SMA), - _ => Err(Error::ConfigRegisterError) + _ => Err(Error::ConfigRegisterError), } } pub fn set_clock_source(&mut self, source: ClockSource) -> Result<(), Error> { // Change clock source through configuration register match source { - ClockSource::OSC => self.config_register.set_configurations(&mut [ - (CFGMask::CLK_SEL0, 0), - (CFGMask::CLK_SEL1, 0), - ]), - ClockSource::MMCX => self.config_register.set_configurations(&mut [ - (CFGMask::CLK_SEL0, 0), - (CFGMask::CLK_SEL1, 1), - ]), - ClockSource::SMA => self.config_register.set_configurations(&mut [ - (CFGMask::CLK_SEL0, 1), - ]), - }.map(|_| ()) + ClockSource::OSC => self + .config_register + .set_configurations(&mut [(CFGMask::CLK_SEL0, 0), (CFGMask::CLK_SEL1, 0)]), + ClockSource::MMCX => self + .config_register + .set_configurations(&mut [(CFGMask::CLK_SEL0, 0), (CFGMask::CLK_SEL1, 1)]), + ClockSource::SMA => self + .config_register + .set_configurations(&mut [(CFGMask::CLK_SEL0, 1)]), + } + .map(|_| ()) } pub fn get_clock_frequency(&mut self) -> f64 { @@ -228,24 +239,24 @@ where pub fn get_clock_division(&mut self) -> Result> { match self.config_register.get_configuration(CFGMask::DIV) { - 0| 3 => Ok(4), + 0 | 3 => Ok(4), 1 => Ok(1), 2 => Ok(2), - _ => Err(Error::ConfigRegisterError) + _ => Err(Error::ConfigRegisterError), } } pub fn set_clock_division(&mut self, division: u8) -> Result<(), Error> { match division { - 1 => self.config_register.set_configurations(&mut [ - (CFGMask::DIV, 1), - ]), - 2 => self.config_register.set_configurations(&mut [ - (CFGMask::DIV, 2), - ]), - 4 => self.config_register.set_configurations(&mut [ - (CFGMask::DIV, 3), - ]), + 1 => self + .config_register + .set_configurations(&mut [(CFGMask::DIV, 1)]), + 2 => self + .config_register + .set_configurations(&mut [(CFGMask::DIV, 2)]), + 4 => self + .config_register + .set_configurations(&mut [(CFGMask::DIV, 3)]), _ => Err(Error::ParameterError), }?; @@ -276,11 +287,16 @@ where self.attenuator.get_channel_attenuation(channel) } - pub fn set_channel_attenuation(&mut self, channel: u8, attenuation: f32) -> Result<(), Error> { + pub fn set_channel_attenuation( + &mut self, + channel: u8, + attenuation: f32, + ) -> Result<(), Error> { if channel >= 4 || attenuation < 0.0 || attenuation > 31.5 { return Err(Error::ParameterError); } - self.attenuator.set_channel_attenuation(channel, attenuation) + self.attenuator + .set_channel_attenuation(channel, attenuation) } pub fn get_profile(&mut self) -> Result> { @@ -291,38 +307,70 @@ where if profile >= 8 { return Err(Error::ParameterError); } - self.config_register.set_configurations(&mut [ - (CFGMask::PROFILE, profile.into()) - ]).map(|_| ()) + self.config_register + .set_configurations(&mut [(CFGMask::PROFILE, profile.into())]) + .map(|_| ()) } - pub fn set_channel_single_tone_profile(&mut self, channel: u8, profile: u8, frequency: f64, phase: f64, amplitude: f64) -> Result<(), Error> { - if channel >= 4 || profile >= 8 || frequency < 0.0 || phase >= 360.0 || - phase < 0.0 || amplitude < 0.0 || amplitude > 1.0 { + pub fn set_channel_single_tone_profile( + &mut self, + channel: u8, + profile: u8, + frequency: f64, + phase: f64, + amplitude: f64, + ) -> Result<(), Error> { + if channel >= 4 + || profile >= 8 + || frequency < 0.0 + || phase >= 360.0 + || phase < 0.0 + || amplitude < 0.0 + || amplitude > 1.0 + { return Err(Error::ParameterError); } self.dds[usize::from(channel)].set_single_tone_profile(profile, frequency, phase, amplitude) } - - pub fn get_channel_single_tone_profile(&mut self, channel: u8, profile: u8) -> Result<(f64, f64, f64), Error> { + + pub fn get_channel_single_tone_profile( + &mut self, + channel: u8, + profile: u8, + ) -> Result<(f64, f64, f64), Error> { self.dds[usize::from(channel)].get_single_tone_profile(profile) } - pub fn set_channel_single_tone_profile_frequency(&mut self, channel: u8, profile: u8, frequency: f64)-> Result<(), Error> { + pub fn set_channel_single_tone_profile_frequency( + &mut self, + channel: u8, + profile: u8, + frequency: f64, + ) -> Result<(), Error> { if channel >= 4 || profile >= 8 || frequency < 0.0 { return Err(Error::ParameterError); } self.dds[usize::from(channel)].set_single_tone_profile_frequency(profile, frequency) } - pub fn set_channel_single_tone_profile_phase(&mut self, channel: u8, profile: u8, phase: f64)-> Result<(), Error> { + pub fn set_channel_single_tone_profile_phase( + &mut self, + channel: u8, + profile: u8, + phase: f64, + ) -> Result<(), Error> { if channel >= 4 || profile >= 8 || phase >= 360.0 || phase < 0.0 { return Err(Error::ParameterError); } self.dds[usize::from(channel)].set_single_tone_profile_phase(profile, phase) } - pub fn set_channel_single_tone_profile_amplitude(&mut self, channel: u8, profile: u8, amplitude: f64)-> Result<(), Error> { + pub fn set_channel_single_tone_profile_amplitude( + &mut self, + channel: u8, + profile: u8, + amplitude: f64, + ) -> Result<(), Error> { if channel >= 4 || profile >= 8 || amplitude < 0.0 || amplitude > 1.0 { return Err(Error::ParameterError); } @@ -330,18 +378,20 @@ where } pub fn append_dds_ram_buffer(&mut self, data: &[u8]) -> Result<(), Error> { - unsafe { - Ok(crate::dds::append_ram_byte(data)) - } + unsafe { Ok(crate::dds::append_ram_byte(data)) } } // Use profile 7 to write into the RAM - pub fn commit_ram_buffer_to_channel(&mut self, channel: u8, start_addr: u16, ram_dest: RAMDestination) -> Result<(), Error> { + pub fn commit_ram_buffer_to_channel( + &mut self, + channel: u8, + start_addr: u16, + ram_dest: RAMDestination, + ) -> Result<(), Error> { let profile = self.get_profile()?; self.set_profile(7)?; unsafe { - self.dds[usize::from(channel)] - .commit_ram_buffer(start_addr, ram_dest)?; + self.dds[usize::from(channel)].commit_ram_buffer(start_addr, ram_dest)?; } self.set_profile(profile) } @@ -350,7 +400,11 @@ where self.dds[usize::from(channel)].set_default_ftw(frequency) } - pub fn set_channel_default_asf(&mut self, channel: u8, amplitude_scale: f64) -> Result<(), Error> { + pub fn set_channel_default_asf( + &mut self, + channel: u8, + amplitude_scale: f64, + ) -> Result<(), Error> { self.dds[usize::from(channel)].set_default_asf(amplitude_scale) } @@ -362,14 +416,25 @@ where self.dds[usize::from(channel)].get_default_asf() } - pub fn set_channel_ram_profile(&mut self, channel: u8, profile: u8, start_addr: u16, - end_addr: u16, op_mode: RAMOperationMode, ramp_rate: u16 + pub fn set_channel_ram_profile( + &mut self, + channel: u8, + profile: u8, + start_addr: u16, + end_addr: u16, + op_mode: RAMOperationMode, + ramp_rate: u16, ) -> Result<(), Error> { - self.dds[usize::from(channel)] - .set_up_ram_profile(profile, start_addr, end_addr, true, false, op_mode, ramp_rate) + self.dds[usize::from(channel)].set_up_ram_profile( + profile, start_addr, end_addr, true, false, op_mode, ramp_rate, + ) } - pub fn get_channel_ram_profile(&mut self, channel: u8, profile: u8) -> Result<(u16, u16, u16, u8), Error> { + pub fn get_channel_ram_profile( + &mut self, + channel: u8, + profile: u8, + ) -> Result<(u16, u16, u16, u8), Error> { self.dds[usize::from(channel)].get_ram_profile(profile) } @@ -406,17 +471,28 @@ where // Note: If a channel is masked, io_update must be completed through configuration register (IO_UPDATE bit-field) // Implication: Deselect such channel if individual communication is needed. pub fn set_multi_channel_coverage(&mut self, channel: u8) -> Result<(), Error> { - self.config_register.set_configurations(&mut [ - (CFGMask::MASK_NU, channel.into()) - ]).map(|_| ()) + self.config_register + .set_configurations(&mut [(CFGMask::MASK_NU, channel.into())]) + .map(|_| ()) } // Difference from individual single tone setup function: // - Remove the need of passing channel // All selected channels must share the same f_sys_clk - pub fn set_multi_channel_single_tone_profile(&mut self, profile: u8, frequency: f64, phase: f64, amplitude: f64) -> Result<(), Error> { - if profile >= 8 || frequency < 0.0 || phase >= 360.0 || - phase < 0.0 || amplitude < 0.0 || amplitude > 1.0 { + pub fn set_multi_channel_single_tone_profile( + &mut self, + profile: u8, + frequency: f64, + phase: f64, + amplitude: f64, + ) -> Result<(), Error> { + if profile >= 8 + || frequency < 0.0 + || phase >= 360.0 + || phase < 0.0 + || amplitude < 0.0 + || amplitude > 1.0 + { return Err(Error::ParameterError); } // Check f_sys_clk of all selected channels @@ -434,18 +510,18 @@ where } } self.multi_dds.set_sys_clk_frequency(reported_f_sys_clk)?; - self.multi_dds.set_single_tone_profile(profile, frequency, phase, amplitude)?; + self.multi_dds + .set_single_tone_profile(profile, frequency, phase, amplitude)?; self.invoke_io_update() } // Generate a pulse for io_update bit in configuration register // This acts like io_update in CPLD struct, but for multi-dds channel fn invoke_io_update(&mut self) -> Result<(), Error> { - self.config_register.set_configurations(&mut [ - (CFGMask::IO_UPDATE, 1) - ])?; - self.config_register.set_configurations(&mut [ - (CFGMask::IO_UPDATE, 0) - ]).map(|_| ()) + self.config_register + .set_configurations(&mut [(CFGMask::IO_UPDATE, 1)])?; + self.config_register + .set_configurations(&mut [(CFGMask::IO_UPDATE, 0)]) + .map(|_| ()) } }