diff --git a/.cargo/config b/.cargo/config.toml similarity index 100% rename from .cargo/config rename to .cargo/config.toml diff --git a/build.rs b/build.rs index 98f603e..97d2806 100644 --- a/build.rs +++ b/build.rs @@ -1,7 +1,4 @@ -use std::env; -use std::fs::File; -use std::io::Write; -use std::path::PathBuf; +use std::{env, fs::File, io::Write, path::PathBuf}; fn main() { // Put the linker script somewhere the linker can find it diff --git a/flake.lock b/flake.lock index a9b126c..40a4336 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "mozilla-overlay": { "flake": false, "locked": { - "lastModified": 1695805681, - "narHash": "sha256-1ElPLD8eFfnuIk0G52HGGpRtQZ4QPCjChRlEOfkZ5ro=", + "lastModified": 1704373101, + "narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=", "owner": "mozilla", "repo": "nixpkgs-mozilla", - "rev": "6eabade97bc28d707a8b9d82ad13ef143836736e", + "rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2", "type": "github" }, "original": { @@ -18,11 +18,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1710951922, - "narHash": "sha256-FOOBJ3DQenLpTNdxMHR2CpGZmYuctb92gF0lpiirZ30=", + "lastModified": 1713725259, + "narHash": "sha256-9ZR/Rbx5/Z/JZf5ehVNMoz/s5xjpP0a22tL6qNvLt5E=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "f091af045dff8347d66d186a62d42aceff159456", + "rev": "a5e4bbcb4780c63c79c87d29ea409abf097de3f7", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 49896bd..3e3877c 100644 --- a/flake.nix +++ b/flake.nix @@ -8,8 +8,8 @@ let pkgs = import nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; }; rustManifest = pkgs.fetchurl { - url = "https://static.rust-lang.org/dist/2024-03-21/channel-rust-stable.toml"; - sha256 = "faccaa01dda45fc2956bcfd4da0cf76e52104d3b1862ddd4eb7c4159a18e49cf"; + url = "https://static.rust-lang.org/dist/2024-03-21/channel-rust-nightly.toml"; + sha256 = "1c7db6ab80d20682b5cc5bda7360c63311d7188c0c082902d3790820527cd4e0"; }; targets = [ @@ -22,7 +22,7 @@ inherit targets; extensions = ["rust-src"]; }; - rust = rustChannelOfTargets "stable" null targets; + rust = rustChannelOfTargets "nightly" null targets; rustPlatform = pkgs.recurseIntoAttrs (pkgs.makeRustPlatform { rustc = rust; cargo = rust; diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..8e12cc7 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,64 @@ +max_width = 120 +hard_tabs = false +tab_spaces = 4 +newline_style = "Auto" +use_small_heuristics = "Default" +indent_style = "Block" +wrap_comments = false +format_code_in_doc_comments = false +comment_width = 100 +normalize_comments = false +normalize_doc_attributes = false +format_strings = true +format_macro_matchers = true +format_macro_bodies = true +empty_item_single_line = true +struct_lit_single_line = true +fn_single_line = false +where_single_line = true +imports_indent = "Visual" +imports_layout = "Mixed" +imports_granularity="Crate" +group_imports = "StdExternalCrate" +reorder_imports = true +reorder_modules = true +reorder_impl_items = false +type_punctuation_density = "Wide" +space_before_colon = false +space_after_colon = true +spaces_around_ranges = false +binop_separator = "Front" +remove_nested_parens = true +combine_control_expr = true +overflow_delimited_expr = false +struct_field_align_threshold = 0 +enum_discrim_align_threshold = 0 +match_arm_blocks = true +match_arm_leading_pipes = "Never" +force_multiline_blocks = false +fn_params_layout = "Tall" +brace_style = "SameLineWhere" +control_brace_style = "AlwaysSameLine" +trailing_semicolon = true +trailing_comma = "Vertical" +match_block_trailing_comma = false +blank_lines_upper_bound = 1 +blank_lines_lower_bound = 0 +edition = "2018" +version = "Two" +inline_attribute_width = 0 +merge_derives = true +use_try_shorthand = false +use_field_init_shorthand = false +force_explicit_abi = true +condense_wildcard_suffixes = false +color = "Auto" +unstable_features = false +disable_all_formatting = false +skip_children = false +hide_parse_errors = false +error_on_line_overflow = false +error_on_unformatted = false +ignore = [] +emit_mode = "Files" +make_backup = false \ No newline at end of file diff --git a/src/device/boot.rs b/src/device/boot.rs index b01d20e..33dd3d7 100644 --- a/src/device/boot.rs +++ b/src/device/boot.rs @@ -1,23 +1,19 @@ -use super::{gpio, sys_timer, usb}; -use crate::device::flash_store::{self, FlashStore}; -use crate::laser_diode::ld_ctrl::{*}; -use crate::laser_diode::laser_diode::LdDrive; -use crate::thermostat::max1968::MAX1968; -use crate::thermostat::thermostat::Thermostat; -use crate::net::net::{IpSettings, ServerHandle}; -use stm32_eth; use fugit::ExtU32; -use log::{info, debug}; -use stm32f4xx_hal::timer::TimerExt; -use stm32f4xx_hal::{ - pac::{CorePeripherals, Peripherals}, - rcc::RccExt, - time::MegaHertz, - watchdog::IndependentWatchdog, -}; -use crate::DeviceSettings; -use uom::si::electric_current::milliampere; -use uom::si::{electric_current::ampere, f32::ElectricCurrent}; +use log::{debug, info}; +use stm32f4xx_hal::{pac::{CorePeripherals, Peripherals}, + rcc::RccExt, + time::MegaHertz, + timer::TimerExt, + watchdog::IndependentWatchdog}; +use uom::si::{electric_current::{ampere, milliampere}, + f32::ElectricCurrent}; + +use super::{gpio, sys_timer, usb}; +use crate::{device::flash_store::{self, FlashStore}, + laser_diode::{laser_diode::LdDrive, ld_ctrl::*}, + net::net::{IpSettings, ServerHandle}, + thermostat::{max1968::MAX1968, thermostat::Thermostat}, + DeviceSettings}; #[cfg(not(feature = "semihosting"))] const WATCHDOG_PERIOD: u32 = 4000; @@ -44,21 +40,22 @@ pub fn bootup( sys_timer::setup(core_perif.SYST, clocks); - let (mut hw_rev, eth_pins, eth_mgmt_pins, usb, current_source_phy, ad7172_phy, max1968_phy, pd_mon_phy) = gpio::setup( - clocks, - perif.TIM4, - perif.GPIOA, - perif.GPIOB, - perif.GPIOC, - perif.GPIOD, - perif.GPIOE, - perif.SPI1, - perif.SPI2, - perif.SPI3, - perif.OTG_FS_GLOBAL, - perif.OTG_FS_DEVICE, - perif.OTG_FS_PWRCLK, - ); + let (mut hw_rev, eth_pins, eth_mgmt_pins, usb, current_source_phy, ad7172_phy, max1968_phy, pd_mon_phy) = + gpio::setup( + clocks, + perif.TIM4, + perif.GPIOA, + perif.GPIOB, + perif.GPIOC, + perif.GPIOD, + perif.GPIOE, + perif.SPI1, + perif.SPI2, + perif.SPI3, + perif.OTG_FS_GLOBAL, + perif.OTG_FS_DEVICE, + perif.OTG_FS_PWRCLK, + ); usb::State::setup(usb); @@ -79,12 +76,12 @@ pub fn bootup( laser.set_pd_i_limit(ElectricCurrent::new::(2.5)); laser.set_pd_mon_calibrated_vdda(thermostat.get_calibrated_vdda()); laser.power_up(); - + debug!("Setting up Internal Flash Driver"); let flash_store = flash_store::store(perif.FLASH); let mut ip_settings: IpSettings = IpSettings::default(); - let device_settings : DeviceSettings; + let device_settings: DeviceSettings; match flash_store.read_value("Device") { Ok(Some(config)) => { device_settings = config; @@ -107,7 +104,14 @@ pub fn bootup( mmc: perif.ETHERNET_MMC, ptp: perif.ETHERNET_PTP, }; - ServerHandle::new(eth_pins, eth_mgmt_pins, ethernet_parts_in, clocks, mac_addr, ip_settings); + ServerHandle::new( + eth_pins, + eth_mgmt_pins, + ethernet_parts_in, + clocks, + mac_addr, + ip_settings, + ); debug!("Setting Watchdog"); let mut wd = IndependentWatchdog::new(perif.IWDG); diff --git a/src/device/dfu.rs b/src/device/dfu.rs index 47fa53f..2951aa6 100644 --- a/src/device/dfu.rs +++ b/src/device/dfu.rs @@ -1,6 +1,7 @@ +use core::arch::asm; + use cortex_m_rt::pre_init; use stm32f4xx_hal::pac::{RCC, SYSCFG}; -use core::arch::asm; const DFU_TRIG_MSG: u32 = 0xDECAFBAD; @@ -14,7 +15,7 @@ pub unsafe fn set_dfu_trigger() { } /// Called by reset handler in lib.rs immediately after reset. -/// This function should not be called outside of reset handler as +/// This function should not be called outside of reset handler as /// bootloader expects MCU to be in reset state when called. #[cfg(target_arch = "arm")] #[pre_init] @@ -27,13 +28,13 @@ unsafe fn __pre_init() { rcc.apb2enr.modify(|_, w| w.syscfgen().set_bit()); // Bypass BOOT pins and remap bootloader to 0x00000000 - let syscfg = &*SYSCFG::ptr() ; - syscfg.memrm.write(|w| w.mem_mode().bits(0b01)); + let syscfg = &*SYSCFG::ptr(); + syscfg.memrm.write(|w| w.mem_mode().bits(0b01)); // Impose instruction and memory barriers cortex_m::asm::isb(); cortex_m::asm::dsb(); - + asm!( // Set stack pointer to bootloader location "LDR R0, =0x1FFF0000", diff --git a/src/device/flash_store.rs b/src/device/flash_store.rs index 4570e53..0130f7d 100644 --- a/src/device/flash_store.rs +++ b/src/device/flash_store.rs @@ -1,9 +1,7 @@ use log::error; -use stm32f4xx_hal::{ - flash::{Error, FlashExt}, - pac::FLASH, -}; use sfkv::{Store, StoreBackend}; +use stm32f4xx_hal::{flash::{Error, FlashExt}, + pac::FLASH}; // Last flash sector is used to avoid overwriting the code in flash. pub const FLASH_SECTOR: u8 = 11; @@ -34,8 +32,7 @@ impl StoreBackend for FlashBackend { } fn program(&mut self, offset: usize, payload: &[u8]) -> Result<(), Self::Error> { - self.flash.unlocked() - .program(get_offset() + offset, payload.iter()) + self.flash.unlocked().program(get_offset() + offset, payload.iter()) } fn backup_space(&self) -> &'static mut [u8] { @@ -53,8 +50,7 @@ pub fn store(flash: FLASH) -> FlashStore { Ok(_) => {} Err(e) => { error!("corrupt store, erasing. error: {:?}", e); - let _ = store.erase() - .map_err(|e| error!("flash erase failed: {:?}", e)); + let _ = store.erase().map_err(|e| error!("flash erase failed: {:?}", e)); } } diff --git a/src/device/gpio.rs b/src/device/gpio.rs index ad24481..726c78d 100644 --- a/src/device/gpio.rs +++ b/src/device/gpio.rs @@ -1,27 +1,25 @@ -use crate::laser_diode::ld_ctrl::{self, LdCtrlPhy}; -use crate::laser_diode::max5719; -use crate::laser_diode::ld_pwr_exc_protector::LdPwrExcProtectorPhy; -use crate::thermostat::ad5680; -use crate::thermostat::max1968::{self, MAX1968PinSet, MAX1968Phy, PWM_FREQ_KHZ}; -use crate::thermostat::ad7172; -use crate::net::net::EthernetMgmtPins; -use crate::device::hw_rev::{HWRev, HwRevPins}; use stm32_eth::EthPins; -use stm32f4xx_hal::gpio::alt::otg_fs::{Dm, Dp}; -use stm32f4xx_hal::{ - gpio::{gpioa::*, gpiob::*, gpioc::*, GpioExt, Input, Speed}, - otg_fs::USB, - pac::{ - GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, OTG_FS_DEVICE, OTG_FS_GLOBAL, OTG_FS_PWRCLK, SPI1, SPI2, SPI3, - TIM4, - }, - rcc::Clocks, - spi::{NoMiso, Spi}, - timer::{Channel1, Channel2, Channel3, pwm::PwmExt} -}; +use stm32f4xx_hal::{gpio::{alt::otg_fs::{Dm, Dp}, + gpioa::*, + gpiob::*, + gpioc::*, + GpioExt, Input, Speed}, + otg_fs::USB, + pac::{GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, OTG_FS_DEVICE, OTG_FS_GLOBAL, OTG_FS_PWRCLK, SPI1, SPI2, + SPI3, TIM4}, + rcc::Clocks, + spi::{NoMiso, Spi}, + timer::{pwm::PwmExt, Channel1, Channel2, Channel3}}; -pub type EthernetPins = - EthPins, PA7, PB11, PB12, PB13, PC4, PC5>; +use crate::{device::hw_rev::{HWRev, HwRevPins}, + laser_diode::{ld_ctrl::{self, LdCtrlPhy}, + ld_pwr_exc_protector::LdPwrExcProtectorPhy, + max5719}, + net::net::EthernetMgmtPins, + thermostat::{ad5680, ad7172, + max1968::{self, MAX1968Phy, MAX1968PinSet, PWM_FREQ_KHZ}}}; + +pub type EthernetPins = EthPins, PA7, PB11, PB12, PB13, PC4, PC5>; pub fn setup( clocks: Clocks, @@ -45,7 +43,7 @@ pub fn setup( LdCtrlPhy, ad7172::AdcPhy, MAX1968Phy, - LdPwrExcProtectorPhy + LdPwrExcProtectorPhy, ) { let gpioa = gpioa.split(); let gpiob = gpiob.split(); @@ -53,14 +51,12 @@ pub fn setup( let gpiod = gpiod.split(); let gpioe = gpioe.split(); - let mut hw_rev = HWRev::detect_hw_rev( - HwRevPins { - h0: gpioe.pe8.into_input(), - h1: gpioe.pe9.into_input(), - h2: gpioe.pe10.into_input(), - h3: gpioe.pe11.into_input(), - } - ); + let mut hw_rev = HWRev::detect_hw_rev(HwRevPins { + h0: gpioe.pe8.into_input(), + h1: gpioe.pe9.into_input(), + h2: gpioe.pe10.into_input(), + h3: gpioe.pe11.into_input(), + }); hw_rev.startup_delay_before_gpio_init(); @@ -82,28 +78,26 @@ pub fn setup( rx_d0: gpioc.pc4, rx_d1: gpioc.pc5, }; - + let mut eth_mgmt_pins = EthernetMgmtPins { - mdio: gpioa.pa2.into_alternate::<11>(), + mdio: gpioa.pa2.into_alternate::<11>(), mdc: gpioc.pc1.into_alternate::<11>(), }; eth_mgmt_pins.mdio.set_speed(Speed::VeryHigh); eth_mgmt_pins.mdc.set_speed(Speed::VeryHigh); let current_source_phy = LdCtrlPhy { - dac: max5719::Dac::new(Spi::new( - spi2, - ( - gpiob.pb10.into_alternate(), - NoMiso::new(), - gpiob.pb15.into_alternate(), - ), - max5719::SPI_MODE, - max5719::SPI_CLOCK_MHZ.convert(), - &clocks, - ), gpiod.pd8.into_push_pull_output(), - gpiob.pb14.into_push_pull_output(), + dac: max5719::Dac::new( + Spi::new( + spi2, + (gpiob.pb10.into_alternate(), NoMiso::new(), gpiob.pb15.into_alternate()), + max5719::SPI_MODE, + max5719::SPI_CLOCK_MHZ.convert(), + &clocks, ), + gpiod.pd8.into_push_pull_output(), + gpiob.pb14.into_push_pull_output(), + ), current_source_short_pin: gpioa.pa4.into_push_pull_output(), termination_status_pin: gpiod.pd7.internal_pull_up(true), }; @@ -118,18 +112,13 @@ pub fn setup( Channel2::new(gpiob.pb7), Channel3::new(gpiob.pb8), ); - let (max_i_neg0, max_v0, max_i_pos0) = - tim4.pwm_hz(pwm_chs, PWM_FREQ_KHZ.convert(), &clocks).split(); + let (max_i_neg0, max_v0, max_i_pos0) = tim4.pwm_hz(pwm_chs, PWM_FREQ_KHZ.convert(), &clocks).split(); let max1968_phy = MAX1968Phy::new(MAX1968PinSet { dac: ad5680::Dac::new( Spi::new( spi1, - ( - gpiob.pb3.into_alternate(), - NoMiso::new(), - gpiob.pb5.into_alternate(), - ), + (gpiob.pb3.into_alternate(), NoMiso::new(), gpiob.pb5.into_alternate()), ad5680::SPI_MODE, ad5680::SPI_CLOCK_MHZ.convert(), &clocks, @@ -147,7 +136,8 @@ pub fn setup( }); let ad7172_phy = ad7172::Adc::new( - Spi::new(spi3, + Spi::new( + spi3, ( gpioc.pc10.into_alternate(), gpioc.pc11.into_alternate(), @@ -155,10 +145,20 @@ pub fn setup( ), ad7172::SPI_MODE, ad7172::SPI_CLOCK_MHZ.convert(), - &clocks + &clocks, ), gpioa.pa15.into_push_pull_output(), - ).unwrap(); + ) + .unwrap(); - (hw_rev, eth_pins, eth_mgmt_pins, usb, current_source_phy, ad7172_phy, max1968_phy, pd_mon_phy) + ( + hw_rev, + eth_pins, + eth_mgmt_pins, + usb, + current_source_phy, + ad7172_phy, + max1968_phy, + pd_mon_phy, + ) } diff --git a/src/device/hw_rev.rs b/src/device/hw_rev.rs index f5aa2d0..ac835e6 100644 --- a/src/device/hw_rev.rs +++ b/src/device/hw_rev.rs @@ -1,9 +1,10 @@ -use stm32f4xx_hal::gpio::{Input, PE10, PE11, PE8, PE9}; -use crate::device::sys_timer::sleep; -use stm32f4xx_hal::signature; use crc::{Crc, CRC_24_BLE}; +use stm32f4xx_hal::{gpio::{Input, PE10, PE11, PE8, PE9}, + signature}; -pub struct HwRevPins{ +use crate::device::sys_timer::sleep; + +pub struct HwRevPins { pub h0: PE8, pub h1: PE9, pub h2: PE10, @@ -18,19 +19,21 @@ pub struct HWRev { impl HWRev { pub fn detect_hw_rev(hwrev_pins: HwRevPins) -> Self { let (h0, h1, h2, h3) = ( - hwrev_pins.h0.is_high(), hwrev_pins.h1.is_high(), - hwrev_pins.h2.is_high(), hwrev_pins.h3.is_high() + hwrev_pins.h0.is_high(), + hwrev_pins.h1.is_high(), + hwrev_pins.h2.is_high(), + hwrev_pins.h3.is_high(), ); match (h0, h1, h2, h3) { (true, true, true, true) => HWRev { major: 0, minor: 3 }, - (_, _, _, _) => HWRev { major: 0, minor: 0 } + (_, _, _, _) => HWRev { major: 0, minor: 0 }, } } /// On Rev0_3, during power up, digital power rails are stabilized way before analog power rails - /// This causes improper initialization on any peripherals requiring calibrations + /// This causes improper initialization on any peripherals requiring calibrations /// See Issue #32 on Kirdy Hw Repo - pub fn startup_delay_before_gpio_init(&mut self){ + pub fn startup_delay_before_gpio_init(&mut self) { if self.major == 0 && self.minor == 3 { sleep(5000); } @@ -54,7 +57,7 @@ impl HWRev { digest.update(&uid_data); let crc24 = digest.finalize(); - [ 0x02, 0xE0, 0xD5, (crc24 >> 16) as u8, (crc24 >> 8) as u8, (crc24 as u8)] + [0x02, 0xE0, 0xD5, (crc24 >> 16) as u8, (crc24 >> 8) as u8, (crc24 as u8)] } else { unimplemented!() } diff --git a/src/device/log_setup.rs b/src/device/log_setup.rs index 54a896c..ccef0ec 100644 --- a/src/device/log_setup.rs +++ b/src/device/log_setup.rs @@ -3,13 +3,15 @@ pub fn init_log() { use super::usb; static USB_LOGGER: usb::Logger = usb::Logger; let _ = log::set_logger(&USB_LOGGER); - log::set_max_level(log::LevelFilter::Debug); + // log::set_max_level(log::LevelFilter::Debug); + log::set_max_level(log::LevelFilter::Trace); } #[cfg(feature = "RTT")] pub fn init_log() { - use super::rtt_logger; use rtt_target::rtt_init_print; + + use super::rtt_logger; static RTT_LOGGER: rtt_logger::Logger = rtt_logger::Logger; rtt_init_print!(); let _ = log::set_logger(&RTT_LOGGER); @@ -18,8 +20,8 @@ pub fn init_log() { #[cfg(feature = "semihosting")] pub fn init_log() { - use cortex_m_log::log::{init, Logger}; - use cortex_m_log::printer::semihosting::{hio::HStdout, InterruptOk}; + use cortex_m_log::{log::{init, Logger}, + printer::semihosting::{hio::HStdout, InterruptOk}}; use log::LevelFilter; static mut LOGGER: Option>> = None; let logger = Logger { diff --git a/src/device/mod.rs b/src/device/mod.rs index d7132d5..b8c3222 100644 --- a/src/device/mod.rs +++ b/src/device/mod.rs @@ -1,9 +1,9 @@ pub mod boot; +pub mod dfu; +pub mod flash_store; pub mod gpio; +pub mod hw_rev; pub mod log_setup; pub mod rtt_logger; pub mod sys_timer; pub mod usb; -pub mod flash_store; -pub mod hw_rev; -pub mod dfu; diff --git a/src/device/sys_timer.rs b/src/device/sys_timer.rs index 04abbf3..e4568ca 100644 --- a/src/device/sys_timer.rs +++ b/src/device/sys_timer.rs @@ -1,7 +1,6 @@ -use core::cell::RefCell; -use core::ops::Deref; -use cortex_m::interrupt::Mutex; -use cortex_m::peripheral::syst::SystClkSource; +use core::{cell::RefCell, ops::Deref}; + +use cortex_m::{interrupt::Mutex, peripheral::syst::SystClkSource}; use cortex_m_rt::exception; use stm32f4xx_hal::{pac::SYST, rcc::Clocks}; diff --git a/src/device/usb.rs b/src/device/usb.rs index f5fdcae..e89e6f5 100644 --- a/src/device/usb.rs +++ b/src/device/usb.rs @@ -1,19 +1,14 @@ -use core::{ - fmt::{self, Write}, - mem::MaybeUninit, -}; +use core::{fmt::{self, Write}, + mem::MaybeUninit}; + use cortex_m::interrupt::free; use log::{Log, Metadata, Record}; -use stm32f4xx_hal::{ - otg_fs::{UsbBus as Bus, USB}, - pac::{interrupt, Interrupt, NVIC}, -}; -use usb_device::{ - descriptor::lang_id, - device::StringDescriptors, - class_prelude::UsbBusAllocator, - prelude::{UsbDevice, UsbDeviceBuilder, UsbVidPid}, -}; +use stm32f4xx_hal::{otg_fs::{UsbBus as Bus, USB}, + pac::{interrupt, Interrupt, NVIC}}; +use usb_device::{class_prelude::UsbBusAllocator, + descriptor::lang_id, + device::StringDescriptors, + prelude::{UsbDevice, UsbDeviceBuilder, UsbVidPid}}; use usbd_serial::SerialPort; static mut EP_MEMORY: [u32; 1024] = [0; 1024]; @@ -41,7 +36,8 @@ impl State { .device_release(0x20) .self_powered(true) .device_class(usbd_serial::USB_CLASS_CDC) - .strings(&[str_descriptor]).unwrap() + .strings(&[str_descriptor]) + .unwrap() .build(); free(|_| unsafe { diff --git a/src/laser_diode/laser_diode.rs b/src/laser_diode/laser_diode.rs index 1282778..81a64ca 100644 --- a/src/laser_diode/laser_diode.rs +++ b/src/laser_diode/laser_diode.rs @@ -1,28 +1,27 @@ -use miniconf::Tree; -use stm32f4xx_hal::timer::CounterUs; -use stm32f4xx_hal::pac::{ADC3, TIM2}; -use uom::si::electric_current::ampere; -use uom::si::power::milliwatt; -use crate::laser_diode::ld_ctrl::{LdCtrl, Impedance}; -use crate::laser_diode::ld_pwr_exc_protector::{LdPwrExcProtector, self}; -use crate::laser_diode::pd_mon_params; -use crate::laser_diode::ld_current_out_ctrl_timer::LdCurrentOutCtrlTimer; use core::marker::PhantomData; -use crate::device::sys_timer::sleep; -use serde::{Deserialize, Serialize}; -use uom::si::{ - electric_current::milliampere, - f32::{ElectricPotential, ElectricCurrent, Power}, -}; -use uom::{si::{ISQ, SI, Quantity}, typenum::*}; +use miniconf::Tree; +use serde::{Deserialize, Serialize}; +use stm32f4xx_hal::{pac::{ADC3, TIM2}, + timer::CounterUs}; +use uom::{si::{electric_current::{ampere, milliampere}, + f32::{ElectricCurrent, ElectricPotential, Power}, + power::milliwatt, + Quantity, ISQ, SI}, + typenum::*}; + +use crate::{device::sys_timer::sleep, + laser_diode::{ld_ctrl::{Impedance, LdCtrl}, + ld_current_out_ctrl_timer::LdCurrentOutCtrlTimer, + ld_pwr_exc_protector::{self, LdPwrExcProtector}, + pd_mon_params}}; // Volt / Ampere pub type TransimpedanceUnit = Quantity, SI, f32>; // Ampere / Volt type TransconductanceUnit = Quantity, SI, f32>; -impl Settings{ +impl Settings { pub const LD_CURRENT_MAX: ElectricCurrent = ElectricCurrent { dimension: PhantomData, units: PhantomData, @@ -83,31 +82,40 @@ pub struct StatusReport { term_status: Impedance, } -pub struct LdDrive{ +pub struct LdDrive { ctrl: LdCtrl, settings: Settings, } -impl LdDrive{ - pub fn new(current_source: LdCtrl, pins_adc: ADC3, tim2: CounterUs, phy: ld_pwr_exc_protector::LdPwrExcProtectorPhy)-> Self { +impl LdDrive { + pub fn new( + current_source: LdCtrl, + pins_adc: ADC3, + tim2: CounterUs, + phy: ld_pwr_exc_protector::LdPwrExcProtectorPhy, + ) -> Self { LdPwrExcProtector::setup(pins_adc, phy); LdCurrentOutCtrlTimer::setup(tim2); - + LdDrive { ctrl: current_source, - settings: Settings::default() + settings: Settings::default(), } } pub fn setup(&mut self) { LdPwrExcProtector::pwr_off(); - self.ctrl.set_i(ElectricCurrent::new::(0.0), Settings::LD_DRIVE_TRANSIMPEDANCE, Settings::DAC_OUT_V_MAX); + self.ctrl.set_i( + ElectricCurrent::new::(0.0), + Settings::LD_DRIVE_TRANSIMPEDANCE, + Settings::DAC_OUT_V_MAX, + ); self.set_ld_drive_current_limit(Settings::LD_CURRENT_MAX); LdCurrentOutCtrlTimer::reset(); self.ld_short(); } - pub fn set_ld_drive_current_limit(&mut self, i_limit: ElectricCurrent){ + pub fn set_ld_drive_current_limit(&mut self, i_limit: ElectricCurrent) { self.settings.ld_drive_current_limit = i_limit.min(Settings::LD_CURRENT_MAX); } @@ -121,10 +129,14 @@ impl LdDrive{ self.settings.ld_terms_short = false; } - pub fn power_up(&mut self){ + pub fn power_up(&mut self) { let prev_i_set = self.settings.ld_drive_current; - LdCurrentOutCtrlTimer::reset(); - let _ = self.ctrl.set_i(ElectricCurrent::new::(0.0), Settings::LD_DRIVE_TRANSIMPEDANCE, Settings::DAC_OUT_V_MAX); + LdCurrentOutCtrlTimer::reset(); + let _ = self.ctrl.set_i( + ElectricCurrent::new::(0.0), + Settings::LD_DRIVE_TRANSIMPEDANCE, + Settings::DAC_OUT_V_MAX, + ); // Wait for the DAC to reset its voltage back to 0V sleep(35); LdPwrExcProtector::pwr_on_and_arm_protection(); @@ -134,7 +146,7 @@ impl LdDrive{ self.settings.pwr_on = true; } - pub fn power_down(&mut self){ + pub fn power_down(&mut self) { LdPwrExcProtector::pwr_off(); self.settings.pwr_on = false; } @@ -144,10 +156,12 @@ impl LdDrive{ } pub fn get_pd_pwr(&mut self) -> Power { - self.settings.pd_mon_params.get_ld_pwr_from_ld_i(LdPwrExcProtector::get_status().v * Settings::PD_MON_TRANSCONDUCTANCE) + self.settings + .pd_mon_params + .get_ld_pwr_from_ld_i(LdPwrExcProtector::get_status().v * Settings::PD_MON_TRANSCONDUCTANCE) } - pub fn ld_set_i(&mut self, i: ElectricCurrent){ + pub fn ld_set_i(&mut self, i: ElectricCurrent) { self.settings.ld_drive_current = i.min(self.settings.ld_drive_current_limit); LdCurrentOutCtrlTimer::set_target_i_and_listen_irq(self.settings.ld_drive_current, self.ctrl.get_i_set()); } @@ -155,13 +169,13 @@ impl LdDrive{ pub fn poll_and_update_output_current(&mut self) -> ElectricCurrent { match LdCurrentOutCtrlTimer::get_irq_status() { Some(i_set) => { - let i_set = self.ctrl.set_i(i_set, Settings::LD_DRIVE_TRANSIMPEDANCE, Settings::DAC_OUT_V_MAX); + let i_set = self + .ctrl + .set_i(i_set, Settings::LD_DRIVE_TRANSIMPEDANCE, Settings::DAC_OUT_V_MAX); LdCurrentOutCtrlTimer::clear_alarm_and_resume_listening(); i_set } - None => { - ElectricCurrent::new::(0.0) - } + None => ElectricCurrent::new::(0.0), } } @@ -174,26 +188,26 @@ impl LdDrive{ LdPwrExcProtector::clear_alarm_status(); } - pub fn set_pd_responsitivity(&mut self, responsitivity: pd_mon_params::ResponsitivityUnit){ + pub fn set_pd_responsitivity(&mut self, responsitivity: pd_mon_params::ResponsitivityUnit) { self.settings.pd_mon_params.set(responsitivity); } - pub fn set_pd_dark_current(&mut self, i_dark: ElectricCurrent){ + pub fn set_pd_dark_current(&mut self, i_dark: ElectricCurrent) { self.settings.pd_mon_params.set_i_dark(i_dark); } - pub fn set_ld_power_limit(&mut self, pwr_limit: Power){ - LdPwrExcProtector::set_trigger_threshold_v(self.settings.pd_mon_params - .get_ld_i_from_ld_pwr(pwr_limit) / Settings::PD_MON_TRANSCONDUCTANCE + pub fn set_ld_power_limit(&mut self, pwr_limit: Power) { + LdPwrExcProtector::set_trigger_threshold_v( + self.settings.pd_mon_params.get_ld_i_from_ld_pwr(pwr_limit) / Settings::PD_MON_TRANSCONDUCTANCE, ); self.settings.ld_pwr_limit = pwr_limit; } - pub fn set_pd_i_limit(&mut self, i: ElectricCurrent){ + pub fn set_pd_i_limit(&mut self, i: ElectricCurrent) { LdPwrExcProtector::set_trigger_threshold_v(i / Settings::PD_MON_TRANSCONDUCTANCE); } - pub fn set_default_pwr_on(&mut self, pwr_on: bool){ + pub fn set_default_pwr_on(&mut self, pwr_on: bool) { self.settings.default_pwr_on = pwr_on; } @@ -221,8 +235,14 @@ impl LdDrive{ let settings = self.settings; LdSettingsSummary { default_pwr_on: self.settings.default_pwr_on, - ld_drive_current: LdSettingsSummaryField { value: settings.ld_drive_current, max: Settings::LD_CURRENT_MAX}, - ld_drive_current_limit: LdSettingsSummaryField { value: settings.ld_drive_current_limit, max: Settings::LD_CURRENT_MAX}, + ld_drive_current: LdSettingsSummaryField { + value: settings.ld_drive_current, + max: Settings::LD_CURRENT_MAX, + }, + ld_drive_current_limit: LdSettingsSummaryField { + value: settings.ld_drive_current_limit, + max: Settings::LD_CURRENT_MAX, + }, pd_mon_params: settings.pd_mon_params, ld_pwr_limit: settings.ld_pwr_limit, ld_terms_short: settings.ld_terms_short, diff --git a/src/laser_diode/ld_ctrl.rs b/src/laser_diode/ld_ctrl.rs index 2c54dec..788a5e6 100644 --- a/src/laser_diode/ld_ctrl.rs +++ b/src/laser_diode/ld_ctrl.rs @@ -1,19 +1,15 @@ use serde::{Deserialize, Serialize}; -use stm32f4xx_hal::{ - gpio::{gpioa::*, gpiob::*, gpiod::*, Input, Output, PushPull}, - hal::{spi::SpiBus, digital::{OutputPin, InputPin}}, - pac::SPI2, - spi::Spi, -}; +use stm32f4xx_hal::{gpio::{gpioa::*, gpiob::*, gpiod::*, Input, Output, PushPull}, + hal::{digital::{InputPin, OutputPin}, + spi::SpiBus}, + pac::SPI2, + spi::Spi}; +use uom::si::{electric_current::ampere, + f32::{ElectricCurrent, ElectricPotential}, + ratio::ratio}; -use uom::si::{ - ratio::ratio, - f32::{ElectricPotential, ElectricCurrent}, - electric_current::ampere, -}; - -use crate::laser_diode::max5719::{self, Dac}; -use crate::laser_diode::laser_diode::TransimpedanceUnit; +use crate::laser_diode::{laser_diode::TransimpedanceUnit, + max5719::{self, Dac}}; #[derive(Deserialize, Serialize, Debug, Clone, Copy)] pub enum Impedance { @@ -32,7 +28,7 @@ pub trait ChannelPins { pub struct LdCtrlPhy { pub dac: Dac, pub current_source_short_pin: C::CurrentSourceShort, - pub termination_status_pin: C::TerminationStatus + pub termination_status_pin: C::TerminationStatus, } pub struct Channel0; @@ -48,7 +44,7 @@ type DacSpi = Spi; type DacCs = PD8>; type DacLoad = PB14>; -pub struct LdCtrl{ +pub struct LdCtrl { pub phy: LdCtrlPhy, i_set: ElectricCurrent, } @@ -57,7 +53,7 @@ impl LdCtrl { pub fn new(phy_ch0: LdCtrlPhy) -> Self { LdCtrl { phy: phy_ch0, - i_set: ElectricCurrent::new::(0.0) + i_set: ElectricCurrent::new::(0.0), } } @@ -71,28 +67,31 @@ impl LdCtrl { self.phy.current_source_short_pin.set_high(); } - pub fn get_lf_mod_in_impedance(&mut self)-> Impedance { + pub fn get_lf_mod_in_impedance(&mut self) -> Impedance { if self.phy.termination_status_pin.is_high() { Impedance::Is50Ohm - } - else { + } else { Impedance::Not50Ohm } } pub fn set_dac(&mut self, voltage: ElectricPotential, dac_out_v_max: ElectricPotential) -> ElectricPotential { - let value = ((voltage / dac_out_v_max).get::() - * (max5719::MAX_VALUE as f32)) as u32; + let value = ((voltage / dac_out_v_max).get::() * (max5719::MAX_VALUE as f32)) as u32; self.phy.dac.set(value).unwrap(); value as f32 * dac_out_v_max / max5719::MAX_VALUE as f32 } - pub fn set_i(&mut self, current: ElectricCurrent, transimpedance: TransimpedanceUnit, dac_out_v_max: ElectricPotential) -> ElectricCurrent { + pub fn set_i( + &mut self, + current: ElectricCurrent, + transimpedance: TransimpedanceUnit, + dac_out_v_max: ElectricPotential, + ) -> ElectricCurrent { self.i_set = self.set_dac(current * transimpedance, dac_out_v_max) / transimpedance; self.i_set } - pub fn get_i_set(&mut self) -> ElectricCurrent{ + pub fn get_i_set(&mut self) -> ElectricCurrent { self.i_set } -} \ No newline at end of file +} diff --git a/src/laser_diode/ld_current_out_ctrl_timer.rs b/src/laser_diode/ld_current_out_ctrl_timer.rs index c4143eb..7986cc2 100644 --- a/src/laser_diode/ld_current_out_ctrl_timer.rs +++ b/src/laser_diode/ld_current_out_ctrl_timer.rs @@ -1,10 +1,11 @@ -use stm32f4xx_hal::timer::{Event, Counter}; -use stm32f4xx_hal::pac::{interrupt, Interrupt, TIM2}; -use stm32f4xx_hal::Listen; -use uom::si::{f32::ElectricCurrent, electric_current::ampere}; -use fugit::{TimerDurationU32, KilohertzU32}; use core::marker::PhantomData; + +use fugit::{KilohertzU32, TimerDurationU32}; use log::debug; +use stm32f4xx_hal::{pac::{interrupt, Interrupt, TIM2}, + timer::{Counter, Event}, + Listen}; +use uom::si::{electric_current::ampere, f32::ElectricCurrent}; pub struct LdCurrentOutCtrlTimer { target_i: ElectricCurrent, @@ -32,14 +33,12 @@ impl LdCurrentOutCtrlTimer { cortex_m::peripheral::NVIC::unmask(Interrupt::TIM2); } unsafe { - LD_CURRENT_OUT_CTRL_TIMER = Some( - LdCurrentOutCtrlTimer { - target_i: ElectricCurrent::new::(0.0), - now_i: ElectricCurrent::new::(0.0), - timer: tim2, - timeout: false - } - ); + LD_CURRENT_OUT_CTRL_TIMER = Some(LdCurrentOutCtrlTimer { + target_i: ElectricCurrent::new::(0.0), + now_i: ElectricCurrent::new::(0.0), + timer: tim2, + timeout: false, + }); } } @@ -48,7 +47,7 @@ impl LdCurrentOutCtrlTimer { } pub fn reset() { - if let Some(ref mut ld_current_out_ctrl_timer ) = LdCurrentOutCtrlTimer::get() { + if let Some(ref mut ld_current_out_ctrl_timer) = LdCurrentOutCtrlTimer::get() { ld_current_out_ctrl_timer.target_i = ElectricCurrent::new::(0.0); ld_current_out_ctrl_timer.now_i = ElectricCurrent::new::(0.0); ld_current_out_ctrl_timer.timeout = false; @@ -57,29 +56,28 @@ impl LdCurrentOutCtrlTimer { } pub fn set_target_i_and_listen_irq(target: ElectricCurrent, now: ElectricCurrent) { - if let Some(ref mut ld_current_out_ctrl_timer ) = LdCurrentOutCtrlTimer::get() { + if let Some(ref mut ld_current_out_ctrl_timer) = LdCurrentOutCtrlTimer::get() { cortex_m::interrupt::free(|_| { - ld_current_out_ctrl_timer.target_i = target; - ld_current_out_ctrl_timer.now_i = now; - ld_current_out_ctrl_timer.timer.listen(Event::Update); - } - ) + ld_current_out_ctrl_timer.target_i = target; + ld_current_out_ctrl_timer.now_i = now; + ld_current_out_ctrl_timer.timer.listen(Event::Update); + }) } } pub fn set_alarm() { - if let Some(ref mut ld_current_out_ctrl_timer ) = LdCurrentOutCtrlTimer::get() { + if let Some(ref mut ld_current_out_ctrl_timer) = LdCurrentOutCtrlTimer::get() { ld_current_out_ctrl_timer.timeout = true; } } pub fn clear_alarm_and_resume_listening() { - if let Some(ref mut ld_current_out_ctrl_timer ) = LdCurrentOutCtrlTimer::get() { + if let Some(ref mut ld_current_out_ctrl_timer) = LdCurrentOutCtrlTimer::get() { ld_current_out_ctrl_timer.timeout = false; ld_current_out_ctrl_timer.timer.listen(Event::Update); } } pub fn get_irq_status() -> Option { - if let Some(ref mut ld_current_out_ctrl_timer ) = LdCurrentOutCtrlTimer::get() { + if let Some(ref mut ld_current_out_ctrl_timer) = LdCurrentOutCtrlTimer::get() { if ld_current_out_ctrl_timer.timeout { return Some(ld_current_out_ctrl_timer.now_i); } @@ -88,37 +86,40 @@ impl LdCurrentOutCtrlTimer { } pub fn clear_irq_flag() { - if let Some(ref mut ld_current_out_ctrl_timer ) = LdCurrentOutCtrlTimer::get() { + if let Some(ref mut ld_current_out_ctrl_timer) = LdCurrentOutCtrlTimer::get() { match ld_current_out_ctrl_timer.timer.wait() { Ok(_) => {} - Err(_) => {debug!("LD CTRL TIMER Interrupt is not present when clear_irq_flag() is called")} + Err(_) => { + debug!("LD CTRL TIMER Interrupt is not present when clear_irq_flag() is called") + } } } } pub fn update_next_i_set() -> bool { - if let Some(ref mut ld_current_out_ctrl_timer ) = LdCurrentOutCtrlTimer::get() { + if let Some(ref mut ld_current_out_ctrl_timer) = LdCurrentOutCtrlTimer::get() { let update = ld_current_out_ctrl_timer.now_i != ld_current_out_ctrl_timer.target_i; if ld_current_out_ctrl_timer.target_i > ld_current_out_ctrl_timer.now_i { - ld_current_out_ctrl_timer.now_i = (ld_current_out_ctrl_timer.now_i + LdCurrentOutCtrlTimer::STEP_SIZE).min(ld_current_out_ctrl_timer.target_i); + ld_current_out_ctrl_timer.now_i = (ld_current_out_ctrl_timer.now_i + LdCurrentOutCtrlTimer::STEP_SIZE) + .min(ld_current_out_ctrl_timer.target_i); + } else { + ld_current_out_ctrl_timer.now_i = (ld_current_out_ctrl_timer.now_i - LdCurrentOutCtrlTimer::STEP_SIZE) + .max(ld_current_out_ctrl_timer.target_i); } - else { - ld_current_out_ctrl_timer.now_i = (ld_current_out_ctrl_timer.now_i - LdCurrentOutCtrlTimer::STEP_SIZE).max(ld_current_out_ctrl_timer.target_i); - } - return update + return update; } false } pub fn stop_listening() { - if let Some(ref mut ld_current_out_ctrl_timer ) = LdCurrentOutCtrlTimer::get() { + if let Some(ref mut ld_current_out_ctrl_timer) = LdCurrentOutCtrlTimer::get() { ld_current_out_ctrl_timer.timer.unlisten(Event::Update); } } } #[interrupt] -fn TIM2(){ +fn TIM2() { if LdCurrentOutCtrlTimer::update_next_i_set() { LdCurrentOutCtrlTimer::set_alarm(); } diff --git a/src/laser_diode/ld_pwr_exc_protector.rs b/src/laser_diode/ld_pwr_exc_protector.rs index 72f990e..9586a39 100644 --- a/src/laser_diode/ld_pwr_exc_protector.rs +++ b/src/laser_diode/ld_pwr_exc_protector.rs @@ -1,15 +1,8 @@ -use stm32f4xx_hal::pac; -use stm32f4xx_hal::rcc::Enable; -use stm32f4xx_hal::{ - pac::{ADC3, NVIC}, - gpio::{Analog, Output, PushPull, gpioa::PA3, gpiod::PD9}, - interrupt, -}; -use uom::si::{ - electric_potential::millivolt, - f32::ElectricPotential, - ratio::ratio -}; +use stm32f4xx_hal::{gpio::{gpioa::PA3, gpiod::PD9, Analog, Output, PushPull}, + interrupt, pac, + pac::{ADC3, NVIC}, + rcc::Enable}; +use uom::si::{electric_potential::millivolt, f32::ElectricPotential, ratio::ratio}; // 12 bit Resolution const MAX_SAMPLE: u16 = 4095; @@ -21,8 +14,8 @@ static mut LD_PWR_EXC_PROTECTOR: Option = None; pub struct LdPwrExcProtectorPhy { // To make sure Pd Mon Pin is configured to Analog mode - pub _pd_mon_ch0: PdMonAdcPinType, - pub pwr_en_ch0: LdPwrEnPinType, + pub _pd_mon_ch0: PdMonAdcPinType, + pub pwr_en_ch0: LdPwrEnPinType, } #[derive(Clone)] @@ -48,14 +41,14 @@ pub struct LdPwrExcProtector { pac: ADC3, phy: LdPwrExcProtectorPhy, alarm_status: Status, - calibrated_vdda: u32, + calibrated_vdda: u32, } impl LdPwrExcProtector { /// ADC Analog Watchdog is configured to guard a single regular Adc channel on Pd Mon Pin. /// ADC is configured to start continuous conversion without using DMA immediately. /// Interrupt is disabled by default. - pub fn setup(pac_adc: ADC3, mut phy: LdPwrExcProtectorPhy){ + pub fn setup(pac_adc: ADC3, mut phy: LdPwrExcProtectorPhy) { unsafe { // All ADCs share the same reset interface. // NOTE(unsafe) this reference will only be used for atomic writes with no side effects. @@ -71,60 +64,68 @@ impl LdPwrExcProtector { pac_adc.sqr1.reset(); pac_adc.sqr2.reset(); pac_adc.sqr3.reset(); - - pac_adc.cr1.write(|w| w - // 12 Bit Resolution - .res().twelve_bit() - // Set Analog Watchdog to guard Single Regular Channel - .awden().enabled() - .awdsgl().single_channel() - .jawden().disabled() - // Disable Analog Watchdog Interrupt - .awdie().disabled() - // Set Analog Watchdog to monitor Pd Mon Pin - .awdch().variant(PD_MON_ADC_CH_ID) - ); - pac_adc.cr2.write(|w| w - // Continous Conversion Mode - .cont().set_bit() - // Power up ADC - .adon().set_bit() - // Set data alignment to the right - .align().right() - // End of conversion selection: Each Sequence - .eocs().each_sequence() - .exten().disabled() - .extsel().tim1cc1() - ); + + pac_adc.cr1.write(|w| { + w + // 12 Bit Resolution + .res() + .twelve_bit() + // Set Analog Watchdog to guard Single Regular Channel + .awden() + .enabled() + .awdsgl() + .single_channel() + .jawden() + .disabled() + // Disable Analog Watchdog Interrupt + .awdie() + .disabled() + // Set Analog Watchdog to monitor Pd Mon Pin + .awdch() + .variant(PD_MON_ADC_CH_ID) + }); + pac_adc.cr2.write(|w| { + w + // Continous Conversion Mode + .cont() + .set_bit() + // Power up ADC + .adon() + .set_bit() + // Set data alignment to the right + .align() + .right() + // End of conversion selection: Each Sequence + .eocs() + .each_sequence() + .exten() + .disabled() + .extsel() + .tim1cc1() + }); // Set the Conversion Sequence to include Pd Mon Pin - pac_adc.sqr3.write(|w| w - .sq1().variant(PD_MON_ADC_CH_ID) - ); + pac_adc.sqr3.write(|w| w.sq1().variant(PD_MON_ADC_CH_ID)); // Set all sampling channels to have fastest sampling interval pac_adc.smpr1.reset(); pac_adc.smpr2.reset(); - + // Set the higher threshold to be max value initially pac_adc.htr.write(|w| w.ht().variant(MAX_SAMPLE)); // Set the lower threshold to be min value initially pac_adc.ltr.write(|w| w.lt().variant(0)); // SWStart should only be set when ADON = 1. Otherwise no conversion is launched. - pac_adc.cr2.modify(|_, w| w - .swstart().set_bit() - ); + pac_adc.cr2.modify(|_, w| w.swstart().set_bit()); phy.pwr_en_ch0.set_low(); unsafe { - LD_PWR_EXC_PROTECTOR = Some( - LdPwrExcProtector { - pac: pac_adc, - phy: phy, - alarm_status: Status::default(), - calibrated_vdda: 3300, - } - ); + LD_PWR_EXC_PROTECTOR = Some(LdPwrExcProtector { + pac: pac_adc, + phy: phy, + alarm_status: Status::default(), + calibrated_vdda: 3300, + }); } } @@ -132,36 +133,39 @@ impl LdPwrExcProtector { unsafe { LD_PWR_EXC_PROTECTOR.as_mut() } } - fn convert_sample_to_volt(sample :u16) -> ElectricPotential { - if let Some(ref mut wdg ) = LdPwrExcProtector::get() { - return ElectricPotential::new::(((u32::from(sample) * wdg.calibrated_vdda) / u32::from(MAX_SAMPLE)) as f32) + fn convert_sample_to_volt(sample: u16) -> ElectricPotential { + if let Some(ref mut wdg) = LdPwrExcProtector::get() { + return ElectricPotential::new::( + ((u32::from(sample) * wdg.calibrated_vdda) / u32::from(MAX_SAMPLE)) as f32, + ); } ElectricPotential::new::(0.0) } - pub fn set_trigger_threshold_v(htr: ElectricPotential){ - if let Some(ref mut wdg ) = LdPwrExcProtector::get() { - let code: u32 = ((htr / (ElectricPotential::new::(wdg.calibrated_vdda as f32))).get::() * (MAX_SAMPLE as f32)) as u32; - wdg.pac.htr.write(|w| unsafe {w.bits(code)}); + pub fn set_trigger_threshold_v(htr: ElectricPotential) { + if let Some(ref mut wdg) = LdPwrExcProtector::get() { + let code: u32 = ((htr / (ElectricPotential::new::(wdg.calibrated_vdda as f32))).get::() + * (MAX_SAMPLE as f32)) as u32; + wdg.pac.htr.write(|w| unsafe { w.bits(code) }); } } pub fn set_calibrated_vdda(val: u32) { - if let Some(ref mut wdg ) = LdPwrExcProtector::get() { + if let Some(ref mut wdg) = LdPwrExcProtector::get() { wdg.calibrated_vdda = val; } } pub fn get_status() -> Status { - if let Some(ref mut wdg ) = LdPwrExcProtector::get() { + if let Some(ref mut wdg) = LdPwrExcProtector::get() { wdg.alarm_status.v = LdPwrExcProtector::convert_sample_to_volt(wdg.pac.dr.read().data().bits()); - return wdg.alarm_status.clone() + return wdg.alarm_status.clone(); } Status::default() } - pub fn pwr_on_and_arm_protection(){ - if let Some(ref mut wdg ) = LdPwrExcProtector::get() { + pub fn pwr_on_and_arm_protection() { + if let Some(ref mut wdg) = LdPwrExcProtector::get() { wdg.alarm_status = Status::default(); LdPwrExcProtector::pwr_on(); // Interrupt should be enabled after power on to tackle the following edge case: @@ -170,53 +174,47 @@ impl LdPwrExcProtector { } } - pub fn clear_alarm_status(){ - if let Some(ref mut wdg ) = LdPwrExcProtector::get() { + pub fn clear_alarm_status() { + if let Some(ref mut wdg) = LdPwrExcProtector::get() { wdg.alarm_status.pwr_excursion = false; wdg.alarm_status.v_tripped = ElectricPotential::new::(0.0); } } - fn enable_watchdog_interrupt(){ - if let Some(ref mut wdg ) = LdPwrExcProtector::get() { - wdg.pac.cr1.modify(|_, w| w - .awdie().set_bit() - ); + fn enable_watchdog_interrupt() { + if let Some(ref mut wdg) = LdPwrExcProtector::get() { + wdg.pac.cr1.modify(|_, w| w.awdie().set_bit()); } } - fn disable_watchdog_interrupt(){ - if let Some(ref mut wdg ) = LdPwrExcProtector::get() { - wdg.pac.cr1.modify(|_, w| w - .awdie().clear_bit() - ); + fn disable_watchdog_interrupt() { + if let Some(ref mut wdg) = LdPwrExcProtector::get() { + wdg.pac.cr1.modify(|_, w| w.awdie().clear_bit()); } } - fn clear_interrupt_bit(){ - if let Some(ref mut wdg ) = LdPwrExcProtector::get() { - wdg.pac.sr.modify(|_, w| w - .awd().clear_bit() - ); + fn clear_interrupt_bit() { + if let Some(ref mut wdg) = LdPwrExcProtector::get() { + wdg.pac.sr.modify(|_, w| w.awd().clear_bit()); } } - fn pwr_on(){ - if let Some(ref mut wdg ) = LdPwrExcProtector::get() { + fn pwr_on() { + if let Some(ref mut wdg) = LdPwrExcProtector::get() { wdg.alarm_status.pwr_engaged = true; wdg.phy.pwr_en_ch0.set_high() } } - pub fn pwr_off(){ - if let Some(ref mut wdg ) = LdPwrExcProtector::get() { + pub fn pwr_off() { + if let Some(ref mut wdg) = LdPwrExcProtector::get() { wdg.alarm_status.pwr_engaged = false; wdg.phy.pwr_en_ch0.set_low() } } - fn pwr_excursion_handler(){ - if let Some(ref mut wdg ) = LdPwrExcProtector::get() { + fn pwr_excursion_handler() { + if let Some(ref mut wdg) = LdPwrExcProtector::get() { let sample = wdg.pac.dr.read().data().bits(); LdPwrExcProtector::pwr_off(); wdg.alarm_status.pwr_excursion = true; @@ -226,12 +224,11 @@ impl LdPwrExcProtector { } #[interrupt] -fn ADC(){ +fn ADC() { cortex_m::interrupt::free(|_| { - LdPwrExcProtector::pwr_excursion_handler(); - // Disable interrupt to avoid getting stuck in infinite loop - LdPwrExcProtector::disable_watchdog_interrupt(); - LdPwrExcProtector::clear_interrupt_bit(); - } - ) + LdPwrExcProtector::pwr_excursion_handler(); + // Disable interrupt to avoid getting stuck in infinite loop + LdPwrExcProtector::disable_watchdog_interrupt(); + LdPwrExcProtector::clear_interrupt_bit(); + }) } diff --git a/src/laser_diode/max5719.rs b/src/laser_diode/max5719.rs index d3345fa..cadd6cd 100644 --- a/src/laser_diode/max5719.rs +++ b/src/laser_diode/max5719.rs @@ -1,9 +1,8 @@ -use crate::device::sys_timer::sleep; use fugit::MegahertzU32; -use stm32f4xx_hal::{ - hal::{spi::SpiBus, digital::OutputPin}, - spi, -}; +use stm32f4xx_hal::{hal::{digital::OutputPin, spi::SpiBus}, + spi}; + +use crate::device::sys_timer::sleep; pub const SPI_MODE: spi::Mode = spi::Mode { polarity: spi::Polarity::IdleLow, @@ -14,7 +13,7 @@ pub const SPI_CLOCK_MHZ: MegahertzU32 = MegahertzU32::from_raw(21); pub const MAX_VALUE: u32 = 0xFFFFF; -pub struct Dac, S1: OutputPin, S2:OutputPin> { +pub struct Dac, S1: OutputPin, S2: OutputPin> { spi: SPI, cs_n: S1, load_n: S2, @@ -25,7 +24,7 @@ impl, S1: OutputPin, S2: OutputPin> Dac { let _ = cs_n.set_high(); let _ = load_n.set_high(); - Dac { spi, cs_n, load_n} + Dac { spi, cs_n, load_n } } fn write(&mut self, buf: &mut [u8]) -> Result<(), SPI::Error> { diff --git a/src/laser_diode/mod.rs b/src/laser_diode/mod.rs index 80e17aa..1d634b2 100644 --- a/src/laser_diode/mod.rs +++ b/src/laser_diode/mod.rs @@ -1,6 +1,6 @@ -pub mod ld_ctrl; -pub mod max5719; pub mod laser_diode; -pub mod pd_mon_params; -pub mod ld_pwr_exc_protector; +pub mod ld_ctrl; pub mod ld_current_out_ctrl_timer; +pub mod ld_pwr_exc_protector; +pub mod max5719; +pub mod pd_mon_params; diff --git a/src/laser_diode/pd_mon_params.rs b/src/laser_diode/pd_mon_params.rs index 2d10581..3d576e6 100644 --- a/src/laser_diode/pd_mon_params.rs +++ b/src/laser_diode/pd_mon_params.rs @@ -1,17 +1,14 @@ use core::{f32::NAN, marker::PhantomData}; -use serde::{Deserialize, Serialize}; -use uom::si::{ - f32::{ - ElectricCurrent, - Power - }, - electric_current::microampere, -}; -use uom::{si::{ISQ, SI, Quantity}, typenum::*}; + use miniconf::Tree; +use serde::{Deserialize, Serialize}; +use uom::{si::{electric_current::microampere, + f32::{ElectricCurrent, Power}, + Quantity, ISQ, SI}, + typenum::*}; // Ampere / Watt -pub type ResponsitivityUnit = Quantity, SI, f32>; +pub type ResponsitivityUnit = Quantity, SI, f32>; #[derive(Deserialize, Serialize, Clone, Copy, Debug, PartialEq, Tree)] pub struct Parameters { @@ -42,7 +39,11 @@ impl Parameters { impl Default for Parameters { fn default() -> Self { Parameters { - responsitivity: ResponsitivityUnit {dimension: PhantomData, units: PhantomData, value: NAN}, + responsitivity: ResponsitivityUnit { + dimension: PhantomData, + units: PhantomData, + value: NAN, + }, i_dark: ElectricCurrent::new::(0.0), } } diff --git a/src/main.rs b/src/main.rs index c6b09ea..bf445d3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,22 +2,24 @@ #![cfg_attr(not(test), no_std)] use cortex_m_rt::entry; -use log::{info, debug}; +use log::{debug, info}; use stm32f4xx_hal::pac::{CorePeripherals, Peripherals}; mod device; mod laser_diode; -mod thermostat; mod net; +mod thermostat; use core::ptr::addr_of_mut; + use device::{boot::bootup, log_setup, sys_timer}; -use crate::net::net::IpSettings; use serde::{Deserialize, Serialize}; use stm32f4xx_hal::pac::SCB; - // If RTT is used, print panic info through RTT #[cfg(all(feature = "RTT", not(test)))] use {core::panic::PanicInfo, rtt_target::rprintln}; + +use crate::net::net::IpSettings; + #[cfg(all(feature = "RTT", not(test)))] #[panic_handler] fn panic(info: &PanicInfo) -> ! { @@ -31,7 +33,7 @@ use panic_halt as _; static mut ETH_DATA_BUFFER: [u8; 1024] = [0; 1024]; #[derive(Deserialize, Serialize, Clone, Copy, Debug)] -pub struct DeviceSettings{ +pub struct DeviceSettings { ip_settings: IpSettings, } @@ -57,22 +59,22 @@ fn main() -> ! { let core_perif = CorePeripherals::take().unwrap(); let perif = Peripherals::take().unwrap(); - let (mut wd, mut flash_store, mut laser, mut thermostat,) = bootup(core_perif, perif); + let (mut wd, mut flash_store, mut laser, mut thermostat) = bootup(core_perif, perif); let mut device_settings = DeviceSettings { - ip_settings: IpSettings::default() + ip_settings: IpSettings::default(), }; let mut active_report: [bool; net::net::NUM_OF_SOCKETS] = [false; net::net::NUM_OF_SOCKETS]; let mut state = State::default(); - let eth_data_buffer = unsafe { addr_of_mut!(ETH_DATA_BUFFER).as_mut().unwrap()}; - + let eth_data_buffer = unsafe { addr_of_mut!(ETH_DATA_BUFFER).as_mut().unwrap() }; + loop { wd.feed(); - if !net::net::eth_poll_link_status_and_update_link_speed() { + if net::net::eth_poll_link_status_and_update_link_speed() { active_report = [false; net::net::NUM_OF_SOCKETS]; } @@ -97,7 +99,7 @@ fn main() -> ! { continue; } } - + wd.feed(); let laser_settings: laser_diode::laser_diode::LdSettingsSummary; match flash_store.read_value(CONFIG_KEY[1]) { @@ -139,9 +141,9 @@ fn main() -> ! { } State::MainLoop => { let mut eth_is_pending = false; - + laser.poll_and_update_output_current(); - + if thermostat.poll_adc() { thermostat.update_pid(); if thermostat.get_temp_mon_status().over_temp_alarm { @@ -150,34 +152,45 @@ fn main() -> ! { thermostat.power_down(); } - net::net::for_each(|mut socket, id| { + net::net::for_each(|mut socket, id| { if net::net::eth_is_socket_active(socket) && net::net::eth_is_socket_connected(socket) { if active_report[id] { - net::cmd_handler::send_status_report(eth_data_buffer, &mut laser, &mut thermostat, &mut socket); + net::cmd_handler::send_status_report( + eth_data_buffer, + &mut laser, + &mut thermostat, + &mut socket, + ); } - } - else { + } else { active_report[id] = false; } }); thermostat.start_tec_readings_conversion(); } - cortex_m::interrupt::free(|cs| - { - eth_is_pending = net::net::is_pending(cs); - net::net::clear_pending(cs); - } - ); + cortex_m::interrupt::free(|cs| { + eth_is_pending = net::net::is_pending(cs); + net::net::clear_pending(cs); + }); if eth_is_pending { - net::net::for_each(|mut socket, id| { - if net::net::eth_is_socket_active(socket) && net::net::eth_is_socket_connected(socket){ + net::net::for_each(|mut socket, id| { + if net::net::eth_is_socket_active(socket) && net::net::eth_is_socket_connected(socket) { let bytes = net::net::eth_recv(eth_data_buffer, socket); if bytes != 0 { info!("Ts: {:?}", sys_timer::now()); debug!("Number of bytes recv: {:?}", bytes); // State Transition - net::cmd_handler::execute_cmd(eth_data_buffer, bytes, &mut socket, &mut laser, &mut thermostat, &mut state, &mut device_settings, &mut active_report[id]); + net::cmd_handler::execute_cmd( + eth_data_buffer, + bytes, + &mut socket, + &mut laser, + &mut thermostat, + &mut state, + &mut device_settings, + &mut active_report[id], + ); } } }) @@ -230,9 +243,14 @@ fn main() -> ! { wd.feed(); laser.power_down(); thermostat.power_down(); - net::net::for_each(|mut socket, _| { + net::net::for_each(|mut socket, _| { if net::net::eth_is_socket_active(socket) { - net::cmd_handler::send_response(eth_data_buffer, net::cmd_handler::ResponseEnum::HardReset, None, &mut socket); + net::cmd_handler::send_response( + eth_data_buffer, + net::cmd_handler::ResponseEnum::HardReset, + None, + &mut socket, + ); } }); } @@ -241,18 +259,18 @@ fn main() -> ! { laser.power_down(); thermostat.power_down(); let mut any_socket_alive = false; - net::net::for_each(|socket, _| { + net::net::for_each(|socket, _| { if net::net::eth_is_socket_active(socket) { net::net::eth_close_socket(socket); any_socket_alive = true; } }); - + // Must let loop run for one more cycle to poll server for RST to be sent, // this makes sure system does not reset right after socket.abort() is called. if !any_socket_alive { SCB::sys_reset(); - } + } } } } diff --git a/src/net/cmd_handler.rs b/src/net/cmd_handler.rs index c08401b..455a59b 100644 --- a/src/net/cmd_handler.rs +++ b/src/net/cmd_handler.rs @@ -1,26 +1,24 @@ use core::{fmt::Debug, marker::PhantomData}; + +use log::{debug, info}; use miniconf::{JsonCoreSlash, Tree}; use serde::{Deserialize, Serialize}; -use uom::si::{ - electric_current::{ampere, ElectricCurrent}, - electric_potential::{volt, ElectricPotential}, - electrical_resistance::{ohm, ElectricalResistance}, - power::{watt, Power}, - thermodynamic_temperature::{degree_celsius, ThermodynamicTemperature} -}; -use crate::{laser_diode::{laser_diode::{ - LdDrive, LdSettingsSummary, StatusReport as LdStatusReport}, - pd_mon_params::ResponsitivityUnit - }, - net::net, - thermostat::{ad7172::FilterType, thermostat::{StatusReport as TecStatusReport, TempAdcFilter}} -}; -use crate::thermostat::thermostat::{Thermostat, ThermostatSettingsSummary}; -use crate::thermostat::pid_state::PidSettings::*; -use crate::device::{dfu, sys_timer}; -use log::{info, debug}; -use crate::{DeviceSettings, State, IpSettings}; use smoltcp::iface::SocketHandle; +use uom::si::{electric_current::{ampere, ElectricCurrent}, + electric_potential::{volt, ElectricPotential}, + electrical_resistance::{ohm, ElectricalResistance}, + power::{watt, Power}, + thermodynamic_temperature::{degree_celsius, ThermodynamicTemperature}}; + +use crate::{device::{dfu, sys_timer}, + laser_diode::{laser_diode::{LdDrive, LdSettingsSummary, StatusReport as LdStatusReport}, + pd_mon_params::ResponsitivityUnit}, + net::net, + thermostat::{ad7172::FilterType, + pid_state::PidSettings::*, + thermostat::{StatusReport as TecStatusReport, TempAdcFilter, Thermostat, + ThermostatSettingsSummary}}, + DeviceSettings, IpSettings, State}; #[derive(Deserialize, Serialize, Copy, Clone, Default, Debug)] pub enum ResponseEnum { @@ -42,19 +40,19 @@ pub struct Response<'a> { msg: Option<&'a str>, } -impl Default for Response<'static>{ +impl Default for Response<'static> { fn default() -> Self { - Response{ - msg_type: ResponseEnum:: Reserved, + Response { + msg_type: ResponseEnum::Reserved, msg: None, } } } #[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)] -pub struct ResponseObj<'a>{ +pub struct ResponseObj<'a> { #[serde(borrow)] - json: Response<'a> + json: Response<'a>, } #[derive(Deserialize, Serialize, Copy, Clone, Default, Debug)] @@ -124,7 +122,7 @@ enum ThermostatCmdEnum { SetShBeta, } -const ERR_MSG_MISSING_DATA_F32 : &str = "Required field \"data_f32\" does not exist"; +const ERR_MSG_MISSING_DATA_F32: &str = "Required field \"data_f32\" does not exist"; const ERR_MSG_MISSING_DATA_BOOL: &str = "Required field \"bool\" does not exist"; const ERR_MSG_MISSING_IP_SETTINGS: &str = "Required field \"ip_settings\" does not exist"; const ERR_MSG_MISSING_TEMP_ADC_FILTER: &str = "Required field \"temp_adc_filter\" does not exist"; @@ -134,7 +132,7 @@ const ERR_MSG_MISSING_POSTFILTER: &str = "Required field \"PostFilter\" does not const ERR_MSG_MISSING_SINC3FINEODR: &str = "Required field \"sinc3fineodr\" does not exist"; #[derive(Deserialize, Serialize, Copy, Clone, Debug, Default, Tree)] -pub struct CmdJsonObj{ +pub struct CmdJsonObj { laser_diode_cmd: Option, thermostat_cmd: Option, device_cmd: Option, @@ -146,7 +144,7 @@ pub struct CmdJsonObj{ } #[derive(Deserialize, Serialize, Copy, Clone, Debug, Default, Tree)] pub struct Cmd { - json: CmdJsonObj + json: CmdJsonObj, } #[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)] @@ -159,7 +157,7 @@ pub struct StatusReport { #[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)] pub struct StatusReportObj { - json: StatusReport + json: StatusReport, } #[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)] @@ -171,15 +169,15 @@ pub struct SettingsSummary { #[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)] pub struct SettingsSummaryObj { - json: SettingsSummary + json: SettingsSummary, } -pub fn send_response(buffer: &mut [u8], msg_type: ResponseEnum, msg: MsgType, socket: &mut SocketHandle){ +pub fn send_response(buffer: &mut [u8], msg_type: ResponseEnum, msg: MsgType, socket: &mut SocketHandle) { let response = ResponseObj { json: Response { msg_type: msg_type, msg: msg, - } + }, }; debug!("{:?}", response.json); @@ -189,13 +187,18 @@ pub fn send_response(buffer: &mut [u8], msg_type: ResponseEnum, msg: MsgType, so net::eth_send(buffer, num_bytes, *socket); } -pub fn send_settings_summary(buffer: &mut [u8], laser: &mut LdDrive, thermostat: &mut Thermostat, socket: &mut SocketHandle){ +pub fn send_settings_summary( + buffer: &mut [u8], + laser: &mut LdDrive, + thermostat: &mut Thermostat, + socket: &mut SocketHandle, +) { let settings_summary = SettingsSummaryObj { json: SettingsSummary { msg_type: ResponseEnum::Settings, laser: laser.get_settings_summary(), thermostat: thermostat.get_settings_summary(), - } + }, }; let mut num_bytes = settings_summary.get_json("/json", buffer).unwrap(); buffer[num_bytes] = b'\n'; @@ -203,15 +206,19 @@ pub fn send_settings_summary(buffer: &mut [u8], laser: &mut LdDrive, thermostat: net::eth_send(buffer, num_bytes, *socket); } - -pub fn send_status_report(buffer: &mut [u8], laser: &mut LdDrive, thermostat: &mut Thermostat, socket: &mut SocketHandle){ +pub fn send_status_report( + buffer: &mut [u8], + laser: &mut LdDrive, + thermostat: &mut Thermostat, + socket: &mut SocketHandle, +) { let status_report = StatusReportObj { json: StatusReport { ts: sys_timer::now(), msg_type: ResponseEnum::Report, laser: laser.get_status_report(), thermostat: thermostat.get_status_report(), - } + }, }; let mut num_bytes = status_report.get_json("/json", buffer).unwrap(); buffer[num_bytes] = b'\n'; @@ -222,52 +229,67 @@ pub fn send_status_report(buffer: &mut [u8], laser: &mut LdDrive, thermostat: &m // Use a minimal struct for high speed cmd ctrl to reduce processing overhead #[derive(Deserialize, Serialize, Copy, Clone, Debug, Default, Tree)] pub struct TecSetICmdJson { - tec_set_i: f32 + tec_set_i: f32, } #[derive(Deserialize, Serialize, Copy, Clone, Debug, Default, Tree)] pub struct TecSetICmd { - json: TecSetICmdJson + json: TecSetICmdJson, } /// Miniconf is very slow in debug builds (~3-4ms of cmd decoding time). /// Make sure kirdy's firmware is flashed with release builds. -/// The received message must contain only one json cmd. TCP client should set TCP_NODELAY or equivalent flag in its TCP Socket +/// The received message must contain only one json cmd. TCP client should set TCP_NODELAY or equivalent flag in its TCP Socket /// Settings to avoid unwanted buffering on TX Data and minimize TX latency. -pub fn execute_cmd(buffer: &mut [u8], buffer_size: usize, socket: &mut SocketHandle, laser: &mut LdDrive, thermostat: &mut Thermostat, state: &mut State, device_settings: &mut DeviceSettings, active_report: &mut bool){ +pub fn execute_cmd( + buffer: &mut [u8], + buffer_size: usize, + socket: &mut SocketHandle, + laser: &mut LdDrive, + thermostat: &mut Thermostat, + state: &mut State, + device_settings: &mut DeviceSettings, + active_report: &mut bool, +) { let mut cmd = TecSetICmd { - json: TecSetICmdJson::default() + json: TecSetICmdJson::default(), }; - match cmd.set_json("/json", &buffer[0..buffer_size]){ + match cmd.set_json("/json", &buffer[0..buffer_size]) { Ok(_) => { thermostat.set_i(ElectricCurrent::new::(cmd.json.tec_set_i)); send_response(buffer, ResponseEnum::Acknowledge, None, socket); return; } - Err(_) => { /* Do Nothing */} + Err(_) => { /* Do Nothing */ } } let mut cmd = Cmd { - json: CmdJsonObj::default() + json: CmdJsonObj::default(), }; - match cmd.set_json("/json", &buffer[0..buffer_size]){ + match cmd.set_json("/json", &buffer[0..buffer_size]) { Ok(_) => { - info!("############ Laser Diode Command Received {:?}", cmd.json.laser_diode_cmd); + info!( + "############ Laser Diode Command Received {:?}", + cmd.json.laser_diode_cmd + ); info!("############ Thermostat Command Received {:?}", cmd.json.thermostat_cmd); info!("############ Device Command Received {:?}", cmd.json.device_cmd); match cmd.json.device_cmd { - Some(DeviceCmd::SetIPSettings) => { - match cmd.json.ip_settings { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - device_settings.ip_settings = val; - *state = State::SaveDeviceSettings; - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_IP_SETTINGS), socket); - } + Some(DeviceCmd::SetIPSettings) => match cmd.json.ip_settings { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + device_settings.ip_settings = val; + *state = State::SaveDeviceSettings; } - } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_IP_SETTINGS), + socket, + ); + } + }, Some(DeviceCmd::Dfu) => { send_response(buffer, ResponseEnum::Acknowledge, None, socket); unsafe { @@ -275,17 +297,20 @@ pub fn execute_cmd(buffer: &mut [u8], buffer_size: usize, socket: &mut SocketHan } *state = State::HardReset; } - Some(DeviceCmd::SetActiveReportMode) => { - match cmd.json.data_bool{ - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - *active_report = val; - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_BOOL), socket); - } + Some(DeviceCmd::SetActiveReportMode) => match cmd.json.data_bool { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + *active_report = val; } - } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_BOOL), + socket, + ); + } + }, Some(DeviceCmd::GetStatusReport) => { send_status_report(buffer, laser, thermostat, socket); } @@ -304,26 +329,28 @@ pub fn execute_cmd(buffer: &mut [u8], buffer_size: usize, socket: &mut SocketHan send_response(buffer, ResponseEnum::Acknowledge, None, socket); *state = State::PrepareForHardReset; } - None => { /* Do Nothing */} + None => { /* Do Nothing */ } _ => { send_response(buffer, ResponseEnum::InvalidCmd, None, socket); - debug!("Unimplemented Command") + debug!("Unimplemented Command") } - } + } match cmd.json.laser_diode_cmd { - Some(LdCmdEnum::SetDefaultPowerOn) => { - match cmd.json.data_bool { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - laser.set_default_pwr_on(val); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_BOOL), socket); - } + Some(LdCmdEnum::SetDefaultPowerOn) => match cmd.json.data_bool { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + laser.set_default_pwr_on(val); } - - } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_BOOL), + socket, + ); + } + }, Some(LdCmdEnum::PowerUp) => { send_response(buffer, ResponseEnum::Acknowledge, None, socket); laser.power_up() @@ -340,61 +367,80 @@ pub fn execute_cmd(buffer: &mut [u8], buffer_size: usize, socket: &mut SocketHan send_response(buffer, ResponseEnum::Acknowledge, None, socket); laser.ld_open(); } - Some(LdCmdEnum::SetI) => { - match cmd.json.data_f32 { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - laser.ld_set_i(ElectricCurrent::new::(val)); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + Some(LdCmdEnum::SetI) => match cmd.json.data_f32 { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + laser.ld_set_i(ElectricCurrent::new::(val)); } - } - Some(LdCmdEnum::SetISoftLimit) => { - match cmd.json.data_f32 { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - laser.set_ld_drive_current_limit(ElectricCurrent::new::(val)) - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); } - } - Some(LdCmdEnum::SetPdResponsitivity) => { - match cmd.json.data_f32 { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - laser.set_pd_responsitivity(ResponsitivityUnit {dimension: PhantomData, units: PhantomData, value: val}) - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + }, + Some(LdCmdEnum::SetISoftLimit) => match cmd.json.data_f32 { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + laser.set_ld_drive_current_limit(ElectricCurrent::new::(val)) } - } - Some(LdCmdEnum::SetPdDarkCurrent) => { - match cmd.json.data_f32 { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - laser.set_pd_dark_current(ElectricCurrent::new::(val)) - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); } - } - Some(LdCmdEnum::SetLdPwrLimit) => { - match cmd.json.data_f32 { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - laser.set_ld_power_limit(Power::new::(val)) - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + }, + Some(LdCmdEnum::SetPdResponsitivity) => match cmd.json.data_f32 { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + laser.set_pd_responsitivity(ResponsitivityUnit { + dimension: PhantomData, + units: PhantomData, + value: val, + }) } - } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); + } + }, + Some(LdCmdEnum::SetPdDarkCurrent) => match cmd.json.data_f32 { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + laser.set_pd_dark_current(ElectricCurrent::new::(val)) + } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); + } + }, + Some(LdCmdEnum::SetLdPwrLimit) => match cmd.json.data_f32 { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + laser.set_ld_power_limit(Power::new::(val)) + } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); + } + }, Some(LdCmdEnum::ClearAlarm) => { send_response(buffer, ResponseEnum::Acknowledge, None, socket); laser.pd_mon_clear_alarm() @@ -407,17 +453,20 @@ pub fn execute_cmd(buffer: &mut [u8], buffer_size: usize, socket: &mut SocketHan } match cmd.json.thermostat_cmd { - Some(ThermostatCmdEnum::SetDefaultPowerOn) => { - match cmd.json.data_bool { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - thermostat.set_default_pwr_on(val); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + Some(ThermostatCmdEnum::SetDefaultPowerOn) => match cmd.json.data_bool { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + thermostat.set_default_pwr_on(val); } - } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); + } + }, Some(ThermostatCmdEnum::PowerUp) => { send_response(buffer, ResponseEnum::Acknowledge, None, socket); thermostat.power_up() @@ -426,61 +475,76 @@ pub fn execute_cmd(buffer: &mut [u8], buffer_size: usize, socket: &mut SocketHan send_response(buffer, ResponseEnum::Acknowledge, None, socket); thermostat.power_down() } - Some(ThermostatCmdEnum::SetTecMaxV) => { - match cmd.json.data_f32 { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - thermostat.set_max_v(ElectricPotential::new::(val)); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + Some(ThermostatCmdEnum::SetTecMaxV) => match cmd.json.data_f32 { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + thermostat.set_max_v(ElectricPotential::new::(val)); } - } - Some(ThermostatCmdEnum::SetTecMaxIPos) => { - match cmd.json.data_f32 { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - thermostat.set_max_i_pos(ElectricCurrent::new::(val)); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); } - } - Some(ThermostatCmdEnum::SetTecMaxINeg) => { - match cmd.json.data_f32 { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - thermostat.set_max_i_pos(ElectricCurrent::new::(val)); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + }, + Some(ThermostatCmdEnum::SetTecMaxIPos) => match cmd.json.data_f32 { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + thermostat.set_max_i_pos(ElectricCurrent::new::(val)); } - } - Some(ThermostatCmdEnum::SetTecIOut) => { - match cmd.json.data_f32 { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - thermostat.set_i(ElectricCurrent::new::(val)); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); } - } - Some(ThermostatCmdEnum::SetTemperatureSetpoint) => { - match cmd.json.data_f32 { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - thermostat.set_temperature_setpoint(ThermodynamicTemperature::new::(val)); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + }, + Some(ThermostatCmdEnum::SetTecMaxINeg) => match cmd.json.data_f32 { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + thermostat.set_max_i_pos(ElectricCurrent::new::(val)); } - } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); + } + }, + Some(ThermostatCmdEnum::SetTecIOut) => match cmd.json.data_f32 { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + thermostat.set_i(ElectricCurrent::new::(val)); + } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); + } + }, + Some(ThermostatCmdEnum::SetTemperatureSetpoint) => match cmd.json.data_f32 { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + thermostat.set_temperature_setpoint(ThermodynamicTemperature::new::(val)); + } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); + } + }, Some(ThermostatCmdEnum::SetPidEngage) => { send_response(buffer, ResponseEnum::Acknowledge, None, socket); thermostat.set_pid_engaged(true); @@ -489,186 +553,230 @@ pub fn execute_cmd(buffer: &mut [u8], buffer_size: usize, socket: &mut SocketHan send_response(buffer, ResponseEnum::Acknowledge, None, socket); thermostat.set_pid_engaged(false); } - Some(ThermostatCmdEnum::SetPidKp) => { - match cmd.json.data_f32 { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - thermostat.set_pid(Kp, val); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + Some(ThermostatCmdEnum::SetPidKp) => match cmd.json.data_f32 { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + thermostat.set_pid(Kp, val); } - } - Some(ThermostatCmdEnum::SetPidKi) => { - match cmd.json.data_f32 { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - thermostat.set_pid(Ki, val); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); } - } - Some(ThermostatCmdEnum::SetPidKd) => { - match cmd.json.data_f32 { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - thermostat.set_pid(Kd, val); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + }, + Some(ThermostatCmdEnum::SetPidKi) => match cmd.json.data_f32 { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + thermostat.set_pid(Ki, val); } - } - Some(ThermostatCmdEnum::SetPidOutMin) => { - match cmd.json.data_f32 { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - thermostat.set_pid(Min, val); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); } - } - Some(ThermostatCmdEnum::SetPidOutMax) => { - match cmd.json.data_f32 { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - thermostat.set_pid(Max, val); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + }, + Some(ThermostatCmdEnum::SetPidKd) => match cmd.json.data_f32 { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + thermostat.set_pid(Kd, val); } - } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); + } + }, + Some(ThermostatCmdEnum::SetPidOutMin) => match cmd.json.data_f32 { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + thermostat.set_pid(Min, val); + } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); + } + }, + Some(ThermostatCmdEnum::SetPidOutMax) => match cmd.json.data_f32 { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + thermostat.set_pid(Max, val); + } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); + } + }, Some(ThermostatCmdEnum::SetPidUpdateInterval) => { send_response(buffer, ResponseEnum::InvalidCmd, None, socket); debug!("Not supported Yet") } - Some(ThermostatCmdEnum::ConfigTempAdcFilter) => { - match cmd.json.temp_adc_filter { - Some(val) => { - match val.filter_type { - FilterType::Sinc5Sinc1With50hz60HzRejection => { - match val.sinc5sinc1postfilter { - Some(val2) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - thermostat.set_temp_adc_sinc5_sinc1_with_postfilter(0, val2); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_POSTFILTER), socket); - } - } - } - FilterType::Sinc5Sinc1 => { - match val.sinc5sinc1odr { - Some(val2) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - thermostat.set_temp_adc_sinc5_sinc1_filter(0, val2); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_SINC5SINC1ODR), socket); - } - } - } - FilterType::Sinc3WithFineODR => { - match val.sinc3fineodr { - Some(val2) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - thermostat.set_temp_adc_sinc3_fine_filter(0, val2); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_SINC3FINEODR), socket); - } - } - } - FilterType::Sinc3 => { - match val.sinc3odr { - Some(val2) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - thermostat.set_temp_adc_sinc3_filter(0, val2); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_SINC3ODR), socket); - } - } - } + Some(ThermostatCmdEnum::ConfigTempAdcFilter) => match cmd.json.temp_adc_filter { + Some(val) => match val.filter_type { + FilterType::Sinc5Sinc1With50hz60HzRejection => match val.sinc5sinc1postfilter { + Some(val2) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + thermostat.set_temp_adc_sinc5_sinc1_with_postfilter(0, val2); } - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_TEMP_ADC_FILTER), socket); - } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_POSTFILTER), + socket, + ); + } + }, + FilterType::Sinc5Sinc1 => match val.sinc5sinc1odr { + Some(val2) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + thermostat.set_temp_adc_sinc5_sinc1_filter(0, val2); + } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_SINC5SINC1ODR), + socket, + ); + } + }, + FilterType::Sinc3WithFineODR => match val.sinc3fineodr { + Some(val2) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + thermostat.set_temp_adc_sinc3_fine_filter(0, val2); + } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_SINC3FINEODR), + socket, + ); + } + }, + FilterType::Sinc3 => match val.sinc3odr { + Some(val2) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + thermostat.set_temp_adc_sinc3_filter(0, val2); + } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_SINC3ODR), + socket, + ); + } + }, + }, + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_TEMP_ADC_FILTER), + socket, + ); } - } - Some(ThermostatCmdEnum::SetTempMonUpperLimit) => { - match cmd.json.data_f32 { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - thermostat.set_temp_mon_upper_limit(ThermodynamicTemperature::new::(val)); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + }, + Some(ThermostatCmdEnum::SetTempMonUpperLimit) => match cmd.json.data_f32 { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + thermostat.set_temp_mon_upper_limit(ThermodynamicTemperature::new::(val)); } - } - Some(ThermostatCmdEnum::SetTempMonLowerLimit) => { - match cmd.json.data_f32 { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - thermostat.set_temp_mon_lower_limit(ThermodynamicTemperature::new::(val)); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); } - } + }, + Some(ThermostatCmdEnum::SetTempMonLowerLimit) => match cmd.json.data_f32 { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + thermostat.set_temp_mon_lower_limit(ThermodynamicTemperature::new::(val)); + } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); + } + }, Some(ThermostatCmdEnum::ClearAlarm) => { send_response(buffer, ResponseEnum::Acknowledge, None, socket); thermostat.clear_temp_mon_alarm(); } - Some(ThermostatCmdEnum::SetShT0) => { - match cmd.json.data_f32 { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - thermostat.set_sh_t0(ThermodynamicTemperature::new::(val)); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + Some(ThermostatCmdEnum::SetShT0) => match cmd.json.data_f32 { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + thermostat.set_sh_t0(ThermodynamicTemperature::new::(val)); } - } - Some(ThermostatCmdEnum::SetShR0) => { - match cmd.json.data_f32 { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - thermostat.set_sh_r0(ElectricalResistance::new::(val)); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); } - } - Some(ThermostatCmdEnum::SetShBeta) => { - match cmd.json.data_f32 { - Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - thermostat.set_sh_beta(val); - } - None => { - send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket); - } + }, + Some(ThermostatCmdEnum::SetShR0) => match cmd.json.data_f32 { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + thermostat.set_sh_r0(ElectricalResistance::new::(val)); } - } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); + } + }, + Some(ThermostatCmdEnum::SetShBeta) => match cmd.json.data_f32 { + Some(val) => { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + thermostat.set_sh_beta(val); + } + None => { + send_response( + buffer, + ResponseEnum::InvalidDatatype, + Some(ERR_MSG_MISSING_DATA_F32), + socket, + ); + } + }, None => { /* Do Nothing*/ } - _ => { + _ => { send_response(buffer, ResponseEnum::InvalidCmd, None, socket); } } } Err(_) => { + info!("cmd_recv: {:?}", buffer); send_response(buffer, ResponseEnum::InvalidCmd, None, socket); } } diff --git a/src/net/mod.rs b/src/net/mod.rs index 0f1b79c..b25ba38 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -1,2 +1,2 @@ +pub mod cmd_handler; pub mod net; -pub mod cmd_handler; \ No newline at end of file diff --git a/src/net/net.rs b/src/net/net.rs index 4d60287..c34bbbe 100644 --- a/src/net/net.rs +++ b/src/net/net.rs @@ -1,25 +1,21 @@ -use crate::device::sys_timer; -use core::mem::{self, MaybeUninit}; -use core::cell::RefCell; +use core::{cell::RefCell, + mem::{self, MaybeUninit}}; + use cortex_m::interrupt::{CriticalSection, Mutex}; use log::{debug, info}; -use smoltcp::{ - iface::{ - self, Interface, SocketHandle, SocketSet, SocketStorage - }, socket::tcp::{Socket, SocketBuffer, State}, time::{Instant, Duration}, wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv4Cidr} -}; -use stm32_eth::{ - Parts, EthPins, PartsIn, - mac::{Speed, EthernetMACWithMii}, - dma::{ - TxRingEntry, RxRingEntry, EthernetDMA - }}; -use stm32f4xx_hal::{ - gpio::{gpioa::*, gpiob::*, gpioc::*, Alternate, Input, Pin}, - rcc::Clocks, - interrupt, -}; use serde::{Deserialize, Serialize}; +use smoltcp::{iface::{self, Interface, SocketHandle, SocketSet, SocketStorage}, + socket::tcp::{Socket, SocketBuffer, State}, + time::{Duration, Instant}, + wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv4Cidr}}; +use stm32_eth::{dma::{EthernetDMA, RxRingEntry, TxRingEntry}, + mac::{EthernetMACWithMii, Speed}, + EthPins, Parts, PartsIn}; +use stm32f4xx_hal::{gpio::{gpioa::*, gpiob::*, gpioc::*, Alternate, Input, Pin}, + interrupt, + rcc::Clocks}; + +use crate::device::sys_timer; #[derive(Debug, Clone, Copy, Deserialize, Serialize)] pub struct IpSettings { @@ -35,7 +31,7 @@ impl Default for IpSettings { addr: [192, 168, 1, 128], port: 1337, prefix_len: 24, - gateway: [192, 168, 1, 1] + gateway: [192, 168, 1, 1], } } } @@ -53,55 +49,56 @@ pub struct ServerHandle { phy: EthernetPhy>, Pin<'C', 1, Alternate<11>>>>, link_was_up: bool, } -pub type EthernetPins = - EthPins, PA7, PB11, PB12, PB13, PC4, PC5>; +pub type EthernetPins = EthPins, PA7, PB11, PB12, PB13, PC4, PC5>; pub struct EthernetMgmtPins { pub mdio: PA2>, pub mdc: PC1>, } pub type EthInterface = Interface; -pub const NUM_OF_SOCKETS : usize = 4; -const TCP_BUFFER_SIZE: usize = 2048; +pub const NUM_OF_SOCKETS: usize = 4; +const TCP_BUFFER_SIZE: usize = 4096; static mut RX_RING: Option<[RxRingEntry; 8]> = None; -static mut TX_RING: Option<[TxRingEntry; 2]> = None; +static mut TX_RING: Option<[TxRingEntry; 8]> = None; static mut SOCKET_STORAGE: Option<[SocketStorage<'static>; NUM_OF_SOCKETS]> = None; fn now_fn() -> smoltcp::time::Instant { Instant::from_millis(i64::from(sys_timer::now())) } -static mut SERVER_HANDLE : Option = None; +static mut SERVER_HANDLE: Option = None; impl ServerHandle { - pub fn new (eth_pins: EthernetPins, + pub fn new( + eth_pins: EthernetPins, eth_mgmt_pins: EthernetMgmtPins, ethernet_parts_in: PartsIn, clocks: Clocks, mac_addr: [u8; 6], ip_settings: IpSettings, - ) { + ) { let rx_ring = unsafe { RX_RING.get_or_insert(Default::default()) }; let tx_ring = unsafe { TX_RING.get_or_insert(Default::default()) }; let socket_storage = unsafe { SOCKET_STORAGE.get_or_insert([SocketStorage::EMPTY; NUM_OF_SOCKETS]) }; - let Parts { - mut dma, - mac, - #[cfg(feature = "ptp")] - .. - } = stm32_eth::new_with_mii( + let Parts { mut dma, mac, .. } = stm32_eth::new_with_mii( ethernet_parts_in, &mut rx_ring[..], &mut tx_ring[..], clocks, eth_pins, eth_mgmt_pins.mdio, - eth_mgmt_pins.mdc - ).unwrap(); + eth_mgmt_pins.mdc, + ) + .unwrap(); let ip_init = IpCidr::Ipv4(Ipv4Cidr::new( - Ipv4Address::new(ip_settings.addr[0], ip_settings.addr[1], ip_settings.addr[2], ip_settings.addr[3]), + Ipv4Address::new( + ip_settings.addr[0], + ip_settings.addr[1], + ip_settings.addr[2], + ip_settings.addr[3], + ), ip_settings.prefix_len, )); let socket_addr: (IpAddress, u16) = ( @@ -116,7 +113,12 @@ impl ServerHandle { let mut routes = smoltcp::iface::Routes::new(); routes - .add_default_ipv4_route(Ipv4Address::new(ip_settings.gateway[0], ip_settings.gateway[1], ip_settings.gateway[2], ip_settings.gateway[3])) + .add_default_ipv4_route(Ipv4Address::new( + ip_settings.gateway[0], + ip_settings.gateway[1], + ip_settings.gateway[2], + ip_settings.gateway[3], + )) .ok(); dma.enable_interrupt(); @@ -132,22 +134,20 @@ impl ServerHandle { let mut socket_set = SocketSet::new(&mut socket_storage[..]); let tcp_handles = { - // Do not use NUM_OF_SOCKETS to define array size to + // Do not use NUM_OF_SOCKETS to define array size to // remind developers to create/remove tcp_handles accordingly after changing NUM_OF_SOCKETS - let mut tcp_handles: [MaybeUninit; 4]= unsafe { - MaybeUninit::uninit().assume_init() - }; + let mut tcp_handles: [MaybeUninit; 4] = unsafe { MaybeUninit::uninit().assume_init() }; macro_rules! create_tcp_handle { ($rx_storage:ident, $tx_storage:ident, $handle:expr) => { - static mut $rx_storage : [u8; TCP_BUFFER_SIZE] = [0; TCP_BUFFER_SIZE]; - static mut $tx_storage : [u8; TCP_BUFFER_SIZE] = [0; TCP_BUFFER_SIZE]; + static mut $rx_storage: [u8; TCP_BUFFER_SIZE] = [0; TCP_BUFFER_SIZE]; + static mut $tx_storage: [u8; TCP_BUFFER_SIZE] = [0; TCP_BUFFER_SIZE]; unsafe { let rx_buffer = SocketBuffer::new(&mut $rx_storage[..]); let tx_buffer = SocketBuffer::new(&mut $tx_storage[..]); $handle.write(socket_set.add(Socket::new(rx_buffer, tx_buffer))); } - } + }; } create_tcp_handle!(RX_STORAGE0, TX_STORAGE0, tcp_handles[0]); create_tcp_handle!(RX_STORAGE1, TX_STORAGE1, tcp_handles[1]); @@ -156,24 +156,25 @@ impl ServerHandle { unsafe { mem::transmute::<_, [SocketHandle; 4]>(tcp_handles) } }; - + for i in 0..NUM_OF_SOCKETS { let socket = socket_set.get_mut::(tcp_handles[i]); socket.listen(socket_addr).ok(); socket.set_keep_alive(Some(Duration::from_secs(1))); socket.set_nagle_enabled(false); } - - iface.poll(Instant::from_millis(i64::from(sys_timer::now())), &mut &mut dma, &mut socket_set); - + + iface.poll( + Instant::from_millis(i64::from(sys_timer::now())), + &mut &mut dma, + &mut socket_set, + ); + if let Ok(mut phy) = EthernetPhy::from_miim(mac, 0) { - info!( - "Resetting PHY as an extra step. Type: {}", - phy.ident_string() - ); + info!("Resetting PHY as an extra step. Type: {}", phy.ident_string()); phy.phy_init(); - + let server = ServerHandle { socket_handles: tcp_handles, socket_set: socket_set, @@ -183,7 +184,7 @@ impl ServerHandle { phy: phy, link_was_up: false, }; - + unsafe { SERVER_HANDLE = Some(server); } @@ -192,7 +193,7 @@ impl ServerHandle { } } - pub fn update_link_speed(&mut self)-> bool { + pub fn update_link_speed(&mut self) -> bool { if !self.link_was_up & self.phy.phy_link_up() { if let Some(speed) = self.phy.speed().map(|s| match s { PhySpeed::HalfDuplexBase10T => Speed::HalfDuplexBase10T, @@ -213,10 +214,14 @@ impl ServerHandle { } pub fn poll_iface(&mut self) { - self.iface.poll(now_fn(), &mut &mut self.dma, &mut self.socket_set); + self.iface.poll(now_fn(), &mut &mut self.dma, &mut self.socket_set); } - pub fn recv(&mut self, buffer: &mut [u8], socket_handles: SocketHandle)-> Result { + pub fn recv( + &mut self, + buffer: &mut [u8], + socket_handles: SocketHandle, + ) -> Result { let socket = self.socket_set.get_mut::(socket_handles); socket.recv_slice(buffer) @@ -231,12 +236,12 @@ impl ServerHandle { } } - pub fn is_socket_connected(&mut self, socket_handles: SocketHandle)->bool { + pub fn is_socket_connected(&mut self, socket_handles: SocketHandle) -> bool { let socket = self.socket_set.get_mut::(socket_handles); socket.state() == State::Established } - pub fn poll_socket_status(&mut self, socket_handles: SocketHandle)-> bool { + pub fn poll_socket_status(&mut self, socket_handles: SocketHandle) -> bool { let socket = self.socket_set.get_mut::(socket_handles); if !socket.is_listening() && !socket.is_open() || socket.state() == State::CloseWait { socket.abort(); @@ -255,14 +260,9 @@ impl ServerHandle { } } -use ieee802_3_miim::{ - phy::{ - lan87xxa::{LAN8720A, LAN8742A}, - BarePhy, KSZ8081R, - PhySpeed - }, - Miim, Pause, Phy, -}; +use ieee802_3_miim::{phy::{lan87xxa::{LAN8720A, LAN8742A}, + BarePhy, PhySpeed, KSZ8081R}, + Miim, Pause, Phy}; /// An ethernet PHY pub enum EthernetPhy { @@ -359,7 +359,7 @@ impl EthernetPhy { pub fn eth_poll_link_status_and_update_link_speed() -> bool { unsafe { - if let Some(ref mut server_handle ) = SERVER_HANDLE { + if let Some(ref mut server_handle) = SERVER_HANDLE { let new_link_is_up = server_handle.update_link_speed(); if new_link_is_up { info!("Resetting TCP Sockets"); @@ -368,8 +368,7 @@ pub fn eth_poll_link_status_and_update_link_speed() -> bool { }); } return new_link_is_up; - } - else { + } else { panic!("eth_poll_link_status_and_update_link_speed is called before init"); } } @@ -377,10 +376,9 @@ pub fn eth_poll_link_status_and_update_link_speed() -> bool { pub fn eth_poll_iface() { unsafe { - if let Some(ref mut server_handle ) = SERVER_HANDLE { + if let Some(ref mut server_handle) = SERVER_HANDLE { server_handle.poll_iface(); - } - else { + } else { panic!("eth_poll_packet is called before init"); } } @@ -388,27 +386,25 @@ pub fn eth_poll_iface() { pub fn eth_send(buffer: &mut [u8], num_bytes: usize, socket_handles: SocketHandle) { unsafe { - if let Some(ref mut server_handle ) = SERVER_HANDLE { + if let Some(ref mut server_handle) = SERVER_HANDLE { server_handle.send(buffer, num_bytes, socket_handles); - } - else { + } else { panic!("eth_send is called before init"); } } } -pub fn eth_recv(buffer: &mut [u8], socket_handles: SocketHandle)-> usize{ +pub fn eth_recv(buffer: &mut [u8], socket_handles: SocketHandle) -> usize { unsafe { - if let Some(ref mut server_handle ) = SERVER_HANDLE { - match server_handle.recv(buffer, socket_handles){ - Ok(recv_bytes) => {return recv_bytes} + if let Some(ref mut server_handle) = SERVER_HANDLE { + match server_handle.recv(buffer, socket_handles) { + Ok(recv_bytes) => return recv_bytes, Err(err) => { debug!("TCP Recv Error: {}", err); - return 0 + return 0; } }; - } - else { + } else { panic!("eth_send is called before init"); } } @@ -416,10 +412,9 @@ pub fn eth_recv(buffer: &mut [u8], socket_handles: SocketHandle)-> usize{ pub fn eth_is_socket_connected(socket_handles: SocketHandle) -> bool { unsafe { - if let Some(ref mut server_handle ) = SERVER_HANDLE { + if let Some(ref mut server_handle) = SERVER_HANDLE { server_handle.is_socket_connected(socket_handles) - } - else { + } else { panic!("eth_is_socket_connected is called before init"); } } @@ -427,10 +422,9 @@ pub fn eth_is_socket_connected(socket_handles: SocketHandle) -> bool { pub fn eth_is_socket_active(socket_handles: SocketHandle) -> bool { unsafe { - if let Some(ref mut server_handle ) = SERVER_HANDLE { + if let Some(ref mut server_handle) = SERVER_HANDLE { server_handle.poll_socket_status(socket_handles) - } - else { + } else { panic!("eth_is_socket_active is called before init"); } } @@ -438,10 +432,9 @@ pub fn eth_is_socket_active(socket_handles: SocketHandle) -> bool { pub fn eth_close_socket(socket_handles: SocketHandle) { unsafe { - if let Some(ref mut server_handle ) = SERVER_HANDLE { + if let Some(ref mut server_handle) = SERVER_HANDLE { server_handle.close_socket(socket_handles) - } - else { + } else { panic!("eth_close_socket is called before init"); } } @@ -449,12 +442,11 @@ pub fn eth_close_socket(socket_handles: SocketHandle) { pub fn for_each(mut callback: F) { unsafe { - if let Some(ref mut server_handle ) = SERVER_HANDLE { + if let Some(ref mut server_handle) = SERVER_HANDLE { for i in 0..NUM_OF_SOCKETS { callback(server_handle.socket_handles[i], i); } - } - else { + } else { panic!("eth_close_socket is called before init"); } } @@ -467,8 +459,7 @@ fn ETH() { let interrupt_reason = stm32_eth::eth_interrupt_handler(); cortex_m::interrupt::free(|cs| { if interrupt_reason.rx { - *NET_PENDING.borrow(cs) - .borrow_mut() = true; + *NET_PENDING.borrow(cs).borrow_mut() = true; eth_poll_iface(); } }); @@ -477,13 +468,11 @@ fn ETH() { /// Has an interrupt occurred since last call to `clear_pending()`? pub fn is_pending(cs: &CriticalSection) -> bool { - *NET_PENDING.borrow(cs) - .borrow() + *NET_PENDING.borrow(cs).borrow() } /// Clear the interrupt pending flag before polling the interface for /// data. pub fn clear_pending(cs: &CriticalSection) { - *NET_PENDING.borrow(cs) - .borrow_mut() = false; + *NET_PENDING.borrow(cs).borrow_mut() = false; } diff --git a/src/thermostat/ad5680.rs b/src/thermostat/ad5680.rs index 3788c80..8e3ec69 100644 --- a/src/thermostat/ad5680.rs +++ b/src/thermostat/ad5680.rs @@ -1,9 +1,8 @@ -use crate::device::sys_timer::sleep; use fugit::MegahertzU32; -use stm32f4xx_hal::{ - hal::{spi::SpiBus, digital::OutputPin}, - spi, -}; +use stm32f4xx_hal::{hal::{digital::OutputPin, spi::SpiBus}, + spi}; + +use crate::device::sys_timer::sleep; /// SPI Mode 1 pub const SPI_MODE: spi::Mode = spi::Mode { diff --git a/src/thermostat/ad7172/adc.rs b/src/thermostat/ad7172/adc.rs index 80f83fc..3730129 100644 --- a/src/thermostat/ad7172/adc.rs +++ b/src/thermostat/ad7172/adc.rs @@ -1,22 +1,16 @@ use core::fmt; + use log::{info, warn}; -use stm32f4xx_hal:: - { - spi::Spi, - pac::SPI3, - gpio::{PA15, Output, PushPull}, - hal::{ - spi::SpiBus, - digital::OutputPin, - }, -}; -use uom::si::{ - f32::ElectricPotential, - electric_potential::volt, -}; -use super::{ - checksum::{Checksum, ChecksumMode}, regs::{self, Register, RegisterData}, sinc3_fine_odr_closest, sinc3_fine_odr_output_rate, DigitalFilterOrder, FilterType, Input, Mode, PostFilter, RefSource, SingleChODR -}; +use stm32f4xx_hal::{gpio::{Output, PushPull, PA15}, + hal::{digital::OutputPin, spi::SpiBus}, + pac::SPI3, + spi::Spi}; +use uom::si::{electric_potential::volt, f32::ElectricPotential}; + +use super::{checksum::{Checksum, ChecksumMode}, + regs::{self, Register, RegisterData}, + sinc3_fine_odr_closest, sinc3_fine_odr_output_rate, DigitalFilterOrder, FilterType, Input, Mode, + PostFilter, RefSource, SingleChODR}; /// AD7172-2 implementation /// @@ -35,7 +29,8 @@ impl, NSS: OutputPin, E: fmt::Debug> Adc { pub fn new(spi: SPI, mut nss: NSS) -> Result { let _ = nss.set_high(); let mut adc = Adc { - spi, nss, + spi, + nss, checksum_mode: ChecksumMode::Off, }; adc.reset()?; @@ -64,8 +59,7 @@ impl, NSS: OutputPin, E: fmt::Debug> Adc { /// `0x00DX` for AD7172-2 pub fn identify(&mut self) -> Result { - self.read_reg(®s::Id) - .map(|id| id.id()) + self.read_reg(®s::Id).map(|id| id.id()) } pub fn set_checksum_mode(&mut self, mode: ChecksumMode) -> Result<(), SPI::Error> { @@ -84,9 +78,7 @@ impl, NSS: OutputPin, E: fmt::Debug> Adc { }) } - pub fn setup_channel( - &mut self, index: u8, in_pos: Input, in_neg: Input - ) -> Result<(), SPI::Error> { + pub fn setup_channel(&mut self, index: u8, in_pos: Input, in_neg: Input) -> Result<(), SPI::Error> { self.update_reg(®s::SetupCon { index }, |data| { data.set_bipolar(false); data.set_refbuf_pos(true); @@ -127,29 +119,40 @@ impl, NSS: OutputPin, E: fmt::Debug> Adc { pub fn get_filter_type_and_rate(&mut self, index: u8) -> Result<(FilterType, f32), SPI::Error> { let mut filter_type: FilterType = FilterType::Sinc5Sinc1With50hz60HzRejection; let mut rate: f32 = -1.0; - self.read_reg(®s::FiltCon { index }) - .map(|data| { + self.read_reg(®s::FiltCon { index }).map(|data| { if data.sinc3_map() { filter_type = FilterType::Sinc3WithFineODR; - let odr : u16 = (data.sinc3_map_fine_odr_msb() as u16) << 8 | data.sinc3_map_fine_odr_lsb() as u16; + let odr: u16 = (data.sinc3_map_fine_odr_msb() as u16) << 8 | data.sinc3_map_fine_odr_lsb() as u16; rate = sinc3_fine_odr_output_rate(odr); } else if data.enh_filt_en() { filter_type = FilterType::Sinc5Sinc1With50hz60HzRejection; - match data.enh_filt().output_rate(){ - Some(val) => { rate = val; } - None => { rate = -1.0; } + match data.enh_filt().output_rate() { + Some(val) => { + rate = val; + } + None => { + rate = -1.0; + } }; } else if data.order() == DigitalFilterOrder::Sinc5Sinc1 { filter_type = FilterType::Sinc5Sinc1; - match data.odr().output_rate(){ - Some(val) => { rate = val; } - None => { rate = -1.0; } + match data.odr().output_rate() { + Some(val) => { + rate = val; + } + None => { + rate = -1.0; + } } } else { filter_type = FilterType::Sinc3; - match data.odr().output_rate(){ - Some(val) => { rate = val; } - None => { rate = -1.0; } + match data.odr().output_rate() { + Some(val) => { + rate = val; + } + None => { + rate = -1.0; + } } } })?; @@ -186,30 +189,24 @@ impl, NSS: OutputPin, E: fmt::Debug> Adc { pub fn set_sinc3_fine_filter(&mut self, index: u8, rate: f32) -> Result { let sinc3_fine_odr_u16 = sinc3_fine_odr_closest(rate); - + self.update_reg(®s::FiltCon { index }, |data| { data.set_sinc3_map(true); data.set_sinc3_map_fine_odr_msb((sinc3_fine_odr_u16 >> 8 & 0xFF) as u8); data.set_sinc3_map_fine_odr_lsb((sinc3_fine_odr_u16 & 0xFF) as u8); - }).map(|_| sinc3_fine_odr_output_rate(sinc3_fine_odr_u16)) + }) + .map(|_| sinc3_fine_odr_output_rate(sinc3_fine_odr_u16)) } /// Returns the channel the data is from pub fn data_ready(&mut self) -> Result, SPI::Error> { self.read_reg(®s::Status) - .map(|status| { - if status.ready() { - Some(status.channel()) - } else { - None - } - }) + .map(|status| if status.ready() { Some(status.channel()) } else { None }) } /// Get data pub fn read_data(&mut self) -> Result { - self.read_reg(®s::Data) - .map(|data| data.data()) + self.read_reg(®s::Data).map(|data| data.data()) } fn read_reg(&mut self, reg: &R) -> Result { @@ -228,7 +225,12 @@ impl, NSS: OutputPin, E: fmt::Debug> Adc { break; } // Retry - warn!("read_reg {:02X}: checksum error: {:?}!={:?}, retrying", reg.address(), checksum_expected, checksum_in); + warn!( + "read_reg {:02X}: checksum error: {:?}!={:?}, retrying", + reg.address(), + checksum_expected, + checksum_in + ); } Ok(reg_data) } @@ -254,7 +256,10 @@ impl, NSS: OutputPin, E: fmt::Debug> Adc { if *readback_data == **reg_data { return Ok(()); } - warn!("write_reg {:02X}: readback error, {:?}!={:?}, retrying", address, &*readback_data, &**reg_data); + warn!( + "write_reg {:02X}: readback error, {:?}!={:?}, retrying", + address, &*readback_data, &**reg_data + ); } } @@ -278,7 +283,12 @@ impl, NSS: OutputPin, E: fmt::Debug> Adc { Ok(()) } - fn transfer<'w>(&mut self, addr: u8, reg_data: &'w mut [u8], checksum: Option) -> Result, SPI::Error> { + fn transfer<'w>( + &mut self, + addr: u8, + reg_data: &'w mut [u8], + checksum: Option, + ) -> Result, SPI::Error> { let mut addr_buf = [addr]; let _ = self.nss.set_low(); @@ -287,8 +297,7 @@ impl, NSS: OutputPin, E: fmt::Debug> Adc { Err(e) => Err(e), }; let result = match (result, checksum) { - (Ok(_), None) => - Ok(None), + (Ok(_), None) => Ok(None), (Ok(_), Some(checksum_out)) => { let mut checksum_buf = [checksum_out; 1]; match self.spi.transfer_in_place(&mut checksum_buf) { @@ -296,8 +305,7 @@ impl, NSS: OutputPin, E: fmt::Debug> Adc { Err(e) => Err(e), } } - (Err(e), _) => - Err(e), + (Err(e), _) => Err(e), }; let _ = self.nss.set_high(); diff --git a/src/thermostat/ad7172/checksum.rs b/src/thermostat/ad7172/checksum.rs index 496eb7c..9efe7b9 100644 --- a/src/thermostat/ad7172/checksum.rs +++ b/src/thermostat/ad7172/checksum.rs @@ -29,13 +29,13 @@ impl Checksum { fn feed_byte(&mut self, input: u8) { match self.mode { - ChecksumMode::Off => {}, + ChecksumMode::Off => {} ChecksumMode::Xor => self.state ^= input, ChecksumMode::Crc => { for i in 0..8 { let input_mask = 0x80 >> i; - self.state = (self.state << 1) ^ - if ((self.state & 0x80) != 0) != ((input & input_mask) != 0) { + self.state = (self.state << 1) + ^ if ((self.state & 0x80) != 0) != ((input & input_mask) != 0) { 0x07 /* x8 + x2 + x + 1 */ } else { 0 @@ -54,7 +54,7 @@ impl Checksum { pub fn result(&self) -> Option { match self.mode { ChecksumMode::Off => None, - _ => Some(self.state) + _ => Some(self.state), } } } diff --git a/src/thermostat/ad7172/mod.rs b/src/thermostat/ad7172/mod.rs index f12e608..c7f00cc 100644 --- a/src/thermostat/ad7172/mod.rs +++ b/src/thermostat/ad7172/mod.rs @@ -1,11 +1,12 @@ use core::fmt; -use num_traits::float::Float; -use serde::{Serialize, Deserialize}; + use fugit::MegahertzU32; +use num_traits::float::Float; +use serde::{Deserialize, Serialize}; use stm32f4xx_hal::spi; -pub mod regs; mod checksum; +pub mod regs; pub use checksum::ChecksumMode; mod adc; pub use adc::*; @@ -20,7 +21,6 @@ pub const SPI_CLOCK_MHZ: MegahertzU32 = MegahertzU32::from_raw(21); pub const MAX_VALUE: u32 = 0xFF_FFFF; - #[derive(Clone, Copy, Debug)] #[repr(u8)] pub enum Mode { @@ -103,7 +103,8 @@ impl fmt::Display for Input { RefPos => "ref+", RefNeg => "ref-", _ => "", - }.fmt(fmt) + } + .fmt(fmt) } } @@ -139,7 +140,8 @@ impl fmt::Display for RefSource { Internal => "internal", Avdd1MinusAvss => "avdd1-avss", _ => "", - }.fmt(fmt) + } + .fmt(fmt) } } @@ -169,9 +171,7 @@ impl PostFilter { let mut best: Option<(f32, Self)> = None; for value in Self::VALID_VALUES { let error = (rate - value.output_rate().unwrap()).abs(); - let better = best - .map(|(best_error, _)| error < best_error) - .unwrap_or(true); + let better = best.map(|(best_error, _)| error < best_error).unwrap_or(true); if better { best = Some((error, *value)); } @@ -237,22 +237,22 @@ pub enum SingleChODR { F31250_0SPS = 0b00101, F15625_0SPS = 0b00110, F10417_0SPS = 0b00111, - F5208_0SPS = 0b01000, - F2597_0SPS = 0b01001, - F1007_0SPS = 0b01010, - F503_8SPS = 0b01011, - F381_0SPS = 0b01100, - F200_3SPS = 0b01101, - F100_2SPS = 0b01110, - F59_52SPS = 0b01111, - F49_68SPS = 0b10000, - F20_01SPS = 0b10001, - F16_63SPS = 0b10010, - F10_0SPS = 0b10011, - F5_0SPS = 0b10100, - F2_5SPS = 0b10101, - F1_25SPS = 0b10110, - Invalid = 0b11111, + F5208_0SPS = 0b01000, + F2597_0SPS = 0b01001, + F1007_0SPS = 0b01010, + F503_8SPS = 0b01011, + F381_0SPS = 0b01100, + F200_3SPS = 0b01101, + F100_2SPS = 0b01110, + F59_52SPS = 0b01111, + F49_68SPS = 0b10000, + F20_01SPS = 0b10001, + F16_63SPS = 0b10010, + F10_0SPS = 0b10011, + F5_0SPS = 0b10100, + F2_5SPS = 0b10101, + F1_25SPS = 0b10110, + Invalid = 0b11111, } impl SingleChODR { @@ -281,9 +281,7 @@ impl SingleChODR { let mut best: Option<(f32, Self)> = None; for value in Self::VALID_VALUES { let error = (rate - value.output_rate().unwrap()).abs(); - let better = best - .map(|(best_error, _)| error < best_error) - .unwrap_or(true); + let better = best.map(|(best_error, _)| error < best_error).unwrap_or(true); if better { best = Some((error, *value)); } @@ -334,7 +332,7 @@ impl From for SingleChODR { 0b10000 => SingleChODR::F49_68SPS, 0b10001 => SingleChODR::F20_01SPS, 0b10010 => SingleChODR::F16_63SPS, - 0b10011 => SingleChODR::F10_0SPS, + 0b10011 => SingleChODR::F10_0SPS, 0b10100 => SingleChODR::F5_0SPS, 0b10101 => SingleChODR::F2_5SPS, 0b10110 => SingleChODR::F1_25SPS, @@ -344,9 +342,9 @@ impl From for SingleChODR { } pub fn sinc3_fine_odr_output_rate(odr: u16) -> f32 { - 1.0 * 1e6 / (32.0 * odr as f32) + 1.0 * 1e6 / (32.0 * odr as f32) } pub fn sinc3_fine_odr_closest(rate: f32) -> u16 { - (1.0e6 / ( 32.0 * rate )).max(1.0 as f32).min(0x7FFF as f32) as u16 + (1.0e6 / (32.0 * rate)).max(1.0 as f32).min(0x7FFF as f32) as u16 } diff --git a/src/thermostat/ad7172/regs.rs b/src/thermostat/ad7172/regs.rs index b992ab1..8f2d88c 100644 --- a/src/thermostat/ad7172/regs.rs +++ b/src/thermostat/ad7172/regs.rs @@ -1,6 +1,7 @@ use core::ops::{Deref, DerefMut}; -use byteorder::{BigEndian, ByteOrder}; + use bit_field::BitField; +use byteorder::{BigEndian, ByteOrder}; use super::*; @@ -9,12 +10,12 @@ pub trait Register { fn address(&self) -> u8; } -pub trait RegisterData: Clone + Deref + DerefMut { +pub trait RegisterData: Clone + Deref + DerefMut { fn empty() -> Self; } macro_rules! def_reg { - ($Reg: ident, $reg: ident, $addr: expr, $size: expr) => { + ($Reg:ident, $reg:ident, $addr:expr, $size:expr) => { /// AD7172 register pub struct $Reg; impl Register for $Reg { @@ -48,8 +49,10 @@ macro_rules! def_reg { } } }; - ($Reg: ident, u8, $reg: ident, $addr: expr, $size: expr) => { - pub struct $Reg { pub index: u8, } + ($Reg:ident,u8, $reg:ident, $addr:expr, $size:expr) => { + pub struct $Reg { + pub index: u8, + } impl Register for $Reg { type Data = $reg::Data; fn address(&self) -> u8 { @@ -76,18 +79,18 @@ macro_rules! def_reg { } } } - } + }; } macro_rules! reg_bit { - ($getter: ident, $byte: expr, $bit: expr, $doc: expr) => { + ($getter:ident, $byte:expr, $bit:expr, $doc:expr) => { #[allow(unused)] #[doc = $doc] pub fn $getter(&self) -> bool { self.0[$byte].get_bit($bit) } }; - ($getter: ident, $setter: ident, $byte: expr, $bit: expr, $doc: expr) => { + ($getter:ident, $setter:ident, $byte:expr, $bit:expr, $doc:expr) => { #[allow(unused)] #[doc = $doc] pub fn $getter(&self) -> bool { @@ -102,14 +105,14 @@ macro_rules! reg_bit { } macro_rules! reg_bits { - ($getter: ident, $byte: expr, $bits: expr, $doc: expr) => { + ($getter:ident, $byte:expr, $bits:expr, $doc:expr) => { #[allow(unused)] #[doc = $doc] pub fn $getter(&self) -> u8 { self.0[$byte].get_bits($bits) } }; - ($getter: ident, $setter: ident, $byte: expr, $bits: expr, $doc: expr) => { + ($getter:ident, $setter:ident, $byte:expr, $bits:expr, $doc:expr) => { #[allow(unused)] #[doc = $doc] pub fn $getter(&self) -> u8 { @@ -121,14 +124,14 @@ macro_rules! reg_bits { self.0[$byte].set_bits($bits, value); } }; - ($getter: ident, $byte: expr, $bits: expr, $ty: ty, $doc: expr) => { + ($getter:ident, $byte:expr, $bits:expr, $ty:ty, $doc:expr) => { #[allow(unused)] #[doc = $doc] pub fn $getter(&self) -> $ty { self.0[$byte].get_bits($bits) as $ty } }; - ($getter: ident, $setter: ident, $byte: expr, $bits: expr, $ty: ty, $doc: expr) => { + ($getter:ident, $setter:ident, $byte:expr, $bits:expr, $ty:ty, $doc:expr) => { #[allow(unused)] #[doc = $doc] pub fn $getter(&self) -> $ty { @@ -146,7 +149,7 @@ def_reg!(Status, status, 0x00, 1); impl status::Data { /// Is there new data to read? pub fn ready(&self) -> bool { - ! self.not_ready() + !self.not_ready() } reg_bit!(not_ready, 0, 7, "No data ready indicator"); @@ -161,7 +164,13 @@ impl adc_mode::Data { reg_bits!(delay, set_delay, 0, 0..=2, "Delay after channel switch"); reg_bit!(sing_cyc, set_sing_cyc, 0, 5, "Can only used with single channel"); reg_bit!(hide_delay, set_hide_delay, 0, 6, "Hide delay"); - reg_bit!(ref_en, set_ref_en, 0, 7, "Enable internal reference, output buffered 2.5 V to REFOUT"); + reg_bit!( + ref_en, + set_ref_en, + 0, + 7, + "Enable internal reference, output buffered 2.5 V to REFOUT" + ); reg_bits!(clockset, set_clocksel, 1, 2..=3, "Clock source"); reg_bits!(mode, set_mode, 1, 4..=6, Mode, "Operating mode"); } @@ -174,9 +183,7 @@ impl if_mode::Data { def_reg!(Data, data, 0x04, 3); impl data::Data { pub fn data(&self) -> u32 { - (u32::from(self.0[0]) << 16) | - (u32::from(self.0[1]) << 8) | - u32::from(self.0[2]) + (u32::from(self.0[0]) << 16) | (u32::from(self.0[1]) << 8) | u32::from(self.0[2]) } } @@ -200,8 +207,7 @@ impl channel::Data { /// Which input is connected to positive input of this channel #[allow(unused)] pub fn a_in_pos(&self) -> Input { - ((self.0[0].get_bits(0..=1) << 3) | - self.0[1].get_bits(5..=7)).into() + ((self.0[0].get_bits(0..=1) << 3) | self.0[1].get_bits(5..=7)).into() } /// Set which input is connected to positive input of this channel #[allow(unused)] @@ -210,39 +216,108 @@ impl channel::Data { self.0[0].set_bits(0..=1, value >> 3); self.0[1].set_bits(5..=7, value & 0x7); } - reg_bits!(a_in_neg, set_a_in_neg, 1, 0..=4, Input, - "Which input is connected to negative input of this channel"); + reg_bits!( + a_in_neg, + set_a_in_neg, + 1, + 0..=4, + Input, + "Which input is connected to negative input of this channel" + ); } def_reg!(SetupCon, u8, setup_con, 0x20, 2); impl setup_con::Data { - reg_bit!(bipolar, set_bipolar, 0, 4, "Unipolar (`false`) or bipolar (`true`) coded output"); + reg_bit!( + bipolar, + set_bipolar, + 0, + 4, + "Unipolar (`false`) or bipolar (`true`) coded output" + ); reg_bit!(refbuf_pos, set_refbuf_pos, 0, 3, "Enable REF+ input buffer"); reg_bit!(refbuf_neg, set_refbuf_neg, 0, 2, "Enable REF- input buffer"); reg_bit!(ainbuf_pos, set_ainbuf_pos, 0, 1, "Enable AIN+ input buffer"); reg_bit!(ainbuf_neg, set_ainbuf_neg, 0, 0, "Enable AIN- input buffer"); - reg_bit!(burnout_en, 1, 7, "enables a 10 µA current source on the positive analog input selected and a 10 µA current sink on the negative analog input selected"); - reg_bits!(ref_sel, set_ref_sel, 1, 4..=5, RefSource, "Select reference source for conversion"); + reg_bit!( + burnout_en, + 1, + 7, + "enables a 10 µA current source on the positive analog input selected and a 10 µA current sink on the \ + negative analog input selected" + ); + reg_bits!( + ref_sel, + set_ref_sel, + 1, + 4..=5, + RefSource, + "Select reference source for conversion" + ); } def_reg!(FiltCon, u8, filt_con, 0x28, 2); impl filt_con::Data { - reg_bit!(sinc3_map, set_sinc3_map, 0, 7, "If set, Sinc3 Filter's notch frequency rejection position can be fine tuned with FiltCon[14:0]. Best to be used with Single Channel Enabled"); - reg_bit!(enh_filt_en, set_enh_filt_en, 0, 3, "Enable postfilters for enhanced 50Hz and 60Hz rejection"); - reg_bits!(enh_filt, set_enh_filt, 0, 0..=2, PostFilter, "Select postfilters output data rate for enhanced 50Hz and 60Hz rejection"); - reg_bits!(order, set_order, 1, 5..=6, DigitalFilterOrder, "order of the digital filter that processes the modulator data"); - reg_bits!(odr, set_odr, 1, 0..=4, SingleChODR, "Output data rate for normal Sin5c + Sinc1 and Sinc3 filter with SING_CYC = 0 and Single Channel Enabled"); - reg_bits!(sinc3_map_fine_odr_msb, set_sinc3_map_fine_odr_msb, 0, 0..=6, "MSB Byte Sinc3 Fine Output Config"); - reg_bits!(sinc3_map_fine_odr_lsb, set_sinc3_map_fine_odr_lsb, 1, 0..=7, "LSB Byte Sinc3 Fine Output Config"); + reg_bit!( + sinc3_map, + set_sinc3_map, + 0, + 7, + "If set, Sinc3 Filter's notch frequency rejection position can be fine tuned with FiltCon[14:0]. Best to be \ + used with Single Channel Enabled" + ); + reg_bit!( + enh_filt_en, + set_enh_filt_en, + 0, + 3, + "Enable postfilters for enhanced 50Hz and 60Hz rejection" + ); + reg_bits!( + enh_filt, + set_enh_filt, + 0, + 0..=2, + PostFilter, + "Select postfilters output data rate for enhanced 50Hz and 60Hz rejection" + ); + reg_bits!( + order, + set_order, + 1, + 5..=6, + DigitalFilterOrder, + "order of the digital filter that processes the modulator data" + ); + reg_bits!( + odr, + set_odr, + 1, + 0..=4, + SingleChODR, + "Output data rate for normal Sin5c + Sinc1 and Sinc3 filter with SING_CYC = 0 and Single Channel Enabled" + ); + reg_bits!( + sinc3_map_fine_odr_msb, + set_sinc3_map_fine_odr_msb, + 0, + 0..=6, + "MSB Byte Sinc3 Fine Output Config" + ); + reg_bits!( + sinc3_map_fine_odr_lsb, + set_sinc3_map_fine_odr_lsb, + 1, + 0..=7, + "LSB Byte Sinc3 Fine Output Config" + ); } def_reg!(Offset, u8, offset, 0x30, 3); impl offset::Data { #[allow(unused)] pub fn offset(&self) -> u32 { - (u32::from(self.0[0]) << 16) | - (u32::from(self.0[1]) << 8) | - u32::from(self.0[2]) + (u32::from(self.0[0]) << 16) | (u32::from(self.0[1]) << 8) | u32::from(self.0[2]) } #[allow(unused)] pub fn set_offset(&mut self, value: u32) { @@ -256,9 +331,7 @@ def_reg!(Gain, u8, gain, 0x38, 3); impl gain::Data { #[allow(unused)] pub fn gain(&self) -> u32 { - (u32::from(self.0[0]) << 16) | - (u32::from(self.0[1]) << 8) | - u32::from(self.0[2]) + (u32::from(self.0[0]) << 16) | (u32::from(self.0[1]) << 8) | u32::from(self.0[2]) } #[allow(unused)] pub fn set_gain(&mut self, value: u32) { diff --git a/src/thermostat/max1968.rs b/src/thermostat/max1968.rs index 13fe147..bb5a466 100644 --- a/src/thermostat/max1968.rs +++ b/src/thermostat/max1968.rs @@ -1,22 +1,18 @@ -use crate::thermostat::ad5680; use core::ptr::addr_of_mut; -use fugit::KilohertzU32; -use stm32f4xx_hal::{ - adc::{config::{self, AdcConfig}, Adc}, - dma::{config::DmaConfig, PeripheralToMemory, Stream2, StreamsTuple, Transfer as DMA_Transfer}, - gpio::{gpioa::*, gpiob::*, gpioc::*, Analog, Output, PushPull}, - hal::{self, spi::SpiBus, digital::OutputPin}, - pac::{ADC1, ADC2, DMA2, SPI1, TIM4, Peripherals, NVIC}, - spi::Spi, - timer::pwm::PwmChannel, - interrupt -}; -use uom::si::{ - electric_potential::millivolt, - f32::ElectricPotential, - ratio::ratio, -}; +use fugit::KilohertzU32; +use stm32f4xx_hal::{adc::{config::{self, AdcConfig}, + Adc}, + dma::{config::DmaConfig, PeripheralToMemory, Stream2, StreamsTuple, Transfer as DMA_Transfer}, + gpio::{gpioa::*, gpiob::*, gpioc::*, Analog, Output, PushPull}, + hal::{digital::OutputPin, spi::SpiBus}, + interrupt, + pac::{Peripherals, ADC1, ADC2, DMA2, NVIC, SPI1, TIM4}, + spi::Spi, + timer::pwm::PwmChannel}; +use uom::si::{electric_potential::millivolt, f32::ElectricPotential, ratio::ratio}; + +use crate::thermostat::ad5680; pub const PWM_FREQ_KHZ: KilohertzU32 = KilohertzU32::from_raw(20); @@ -115,8 +111,8 @@ impl MAX1968Phy { } } -static mut ADC2_FIRST_BUFFER : [u16; 16] = [0; 16]; -static mut ADC2_LOCAL_BUFFER : [u16; 16] = [0; 16]; +static mut ADC2_FIRST_BUFFER: [u16; 16] = [0; 16]; +static mut ADC2_LOCAL_BUFFER: [u16; 16] = [0; 16]; impl MAX1968 { pub fn new(phy_ch0: MAX1968Phy, adc1: ADC1, adc2: ADC2, dma2: DMA2) -> Self { @@ -125,7 +121,7 @@ impl MAX1968 { .default_sample_time(config::SampleTime::Cycles_480); // Do not set reset RCCs as it causes other ADCs' clock to be disabled let mut pins_adc1 = Adc::adc1(adc1, false, adc_config); - + // adc1.calibrate() fn only read REFINT once to assign the calibration value. // It does not take the STM32F4's ADC Precision Limitation into account. // AN4073: ADC Reading Dispersion can be reduced through Averaging @@ -137,7 +133,7 @@ impl MAX1968 { vdda_mv = vdda_mv / 512 as u32; pins_adc1.apply_config(adc_config.reference_voltage(vdda_mv)); - let adc_config = AdcConfig::default() + let adc_config = AdcConfig::default() .clock(config::Clock::Pclk2_div_8) .default_sample_time(config::SampleTime::Cycles_480) .dma(config::Dma::Continuous) @@ -150,25 +146,79 @@ impl MAX1968 { let mut pins_adc2 = Adc::adc2(adc2, false, adc_config); pins_adc2.configure_channel(&phy_ch0.itec_pin, config::Sequence::One, config::SampleTime::Cycles_480); pins_adc2.configure_channel(&phy_ch0.vtec_pin, config::Sequence::Two, config::SampleTime::Cycles_480); - pins_adc2.configure_channel(&phy_ch0.itec_pin, config::Sequence::Three, config::SampleTime::Cycles_480); - pins_adc2.configure_channel(&phy_ch0.vtec_pin, config::Sequence::Four, config::SampleTime::Cycles_480); - pins_adc2.configure_channel(&phy_ch0.itec_pin, config::Sequence::Five, config::SampleTime::Cycles_480); + pins_adc2.configure_channel( + &phy_ch0.itec_pin, + config::Sequence::Three, + config::SampleTime::Cycles_480, + ); + pins_adc2.configure_channel( + &phy_ch0.vtec_pin, + config::Sequence::Four, + config::SampleTime::Cycles_480, + ); + pins_adc2.configure_channel( + &phy_ch0.itec_pin, + config::Sequence::Five, + config::SampleTime::Cycles_480, + ); pins_adc2.configure_channel(&phy_ch0.vtec_pin, config::Sequence::Six, config::SampleTime::Cycles_480); - pins_adc2.configure_channel(&phy_ch0.itec_pin, config::Sequence::Seven, config::SampleTime::Cycles_480); - pins_adc2.configure_channel(&phy_ch0.vtec_pin, config::Sequence::Eight, config::SampleTime::Cycles_480); - pins_adc2.configure_channel(&phy_ch0.itec_pin, config::Sequence::Nine, config::SampleTime::Cycles_480); + pins_adc2.configure_channel( + &phy_ch0.itec_pin, + config::Sequence::Seven, + config::SampleTime::Cycles_480, + ); + pins_adc2.configure_channel( + &phy_ch0.vtec_pin, + config::Sequence::Eight, + config::SampleTime::Cycles_480, + ); + pins_adc2.configure_channel( + &phy_ch0.itec_pin, + config::Sequence::Nine, + config::SampleTime::Cycles_480, + ); pins_adc2.configure_channel(&phy_ch0.vtec_pin, config::Sequence::Ten, config::SampleTime::Cycles_480); - pins_adc2.configure_channel(&phy_ch0.itec_pin, config::Sequence::Eleven, config::SampleTime::Cycles_480); - pins_adc2.configure_channel(&phy_ch0.vtec_pin, config::Sequence::Twelve, config::SampleTime::Cycles_480); - pins_adc2.configure_channel(&phy_ch0.itec_pin, config::Sequence::Thirteen, config::SampleTime::Cycles_480); - pins_adc2.configure_channel(&phy_ch0.vtec_pin, config::Sequence::Fourteen, config::SampleTime::Cycles_480); - pins_adc2.configure_channel(&phy_ch0.itec_pin, config::Sequence::Fifteen, config::SampleTime::Cycles_480); - pins_adc2.configure_channel(&phy_ch0.vtec_pin, config::Sequence::Sixteen, config::SampleTime::Cycles_480); + pins_adc2.configure_channel( + &phy_ch0.itec_pin, + config::Sequence::Eleven, + config::SampleTime::Cycles_480, + ); + pins_adc2.configure_channel( + &phy_ch0.vtec_pin, + config::Sequence::Twelve, + config::SampleTime::Cycles_480, + ); + pins_adc2.configure_channel( + &phy_ch0.itec_pin, + config::Sequence::Thirteen, + config::SampleTime::Cycles_480, + ); + pins_adc2.configure_channel( + &phy_ch0.vtec_pin, + config::Sequence::Fourteen, + config::SampleTime::Cycles_480, + ); + pins_adc2.configure_channel( + &phy_ch0.itec_pin, + config::Sequence::Fifteen, + config::SampleTime::Cycles_480, + ); + pins_adc2.configure_channel( + &phy_ch0.vtec_pin, + config::Sequence::Sixteen, + config::SampleTime::Cycles_480, + ); let dma = StreamsTuple::new(dma2); - let dma_adc : DMA_Transfer, 1, Adc, PeripheralToMemory, &'static mut [u16; 16]>; + let dma_adc: DMA_Transfer, 1, Adc, PeripheralToMemory, &'static mut [u16; 16]>; unsafe { - dma_adc = DMA_Transfer::init_peripheral_to_memory(dma.2, pins_adc2, addr_of_mut!(ADC2_FIRST_BUFFER).as_mut().unwrap(), None, dma_config); + dma_adc = DMA_Transfer::init_peripheral_to_memory( + dma.2, + pins_adc2, + addr_of_mut!(ADC2_FIRST_BUFFER).as_mut().unwrap(), + None, + dma_config, + ); NVIC::unmask(interrupt::DMA2_STREAM2); } @@ -176,30 +226,33 @@ impl MAX1968 { phy: phy_ch0, pins_adc: pins_adc1, dma_adc: dma_adc, - prev_vtec_volt: ElectricPotential::new::(0.0), - prev_itec_volt: ElectricPotential::new::(0.0), + prev_vtec_volt: ElectricPotential::new::(0.0), + prev_itec_volt: ElectricPotential::new::(0.0), } } - pub fn dma_adc_start_conversion(&mut self){ - if unsafe {DMA_TRANSFER_COMPLETE} { - unsafe { DMA_TRANSFER_COMPLETE = false; } - self.dma_adc.start(|adc| { + pub fn dma_adc_start_conversion(&mut self) { + if unsafe { DMA_TRANSFER_COMPLETE } { + unsafe { + DMA_TRANSFER_COMPLETE = false; + } + self.dma_adc.start(|adc| { adc.clear_end_of_conversion_flag(); adc.start_conversion(); }); - } + } } pub fn get_tec_readings(&mut self) -> (ElectricPotential, ElectricPotential) { if unsafe { DMA_TRANSFER_COMPLETE } { let buffer: &[u16; 16]; unsafe { - (buffer, _) = self.dma_adc + (buffer, _) = self + .dma_adc .next_transfer(addr_of_mut!(ADC2_LOCAL_BUFFER).as_mut().unwrap()) .unwrap(); } - + let sample_to_millivolts = self.dma_adc.peripheral().make_sample_to_millivolts(); let mut itec: u16 = 0; for data in buffer.into_iter().step_by(2) { @@ -240,10 +293,8 @@ impl MAX1968 { self.phy.shdn.set_high(); } - pub fn set_dac(&mut self, voltage: ElectricPotential, dac_out_v_max: ElectricPotential) -> ElectricPotential { - let value = ((voltage / dac_out_v_max).get::() - * (ad5680::MAX_VALUE as f32)) as u32; + let value = ((voltage / dac_out_v_max).get::() * (ad5680::MAX_VALUE as f32)) as u32; self.phy.dac.set(value).unwrap(); voltage } @@ -255,10 +306,10 @@ impl MAX1968 { sample = match adc_read_target { AdcReadTarget::VREF => { for _ in (0..avg_pt).rev() { - sample += self.pins_adc.convert( - &self.phy.vref_pin, - stm32f4xx_hal::adc::config::SampleTime::Cycles_480, - ) as u32; + sample += self + .pins_adc + .convert(&self.phy.vref_pin, stm32f4xx_hal::adc::config::SampleTime::Cycles_480) + as u32; } sample / avg_pt as u32 } @@ -273,19 +324,19 @@ impl MAX1968 { } AdcReadTarget::ITec => { for _ in (0..avg_pt).rev() { - sample += self.pins_adc.convert( - &self.phy.itec_pin, - stm32f4xx_hal::adc::config::SampleTime::Cycles_480, - ) as u32; + sample += self + .pins_adc + .convert(&self.phy.itec_pin, stm32f4xx_hal::adc::config::SampleTime::Cycles_480) + as u32; } sample / avg_pt as u32 } AdcReadTarget::VTec => { for _ in (0..avg_pt).rev() { - sample += self.pins_adc.convert( - &self.phy.vtec_pin, - stm32f4xx_hal::adc::config::SampleTime::Cycles_480, - ) as u32; + sample += self + .pins_adc + .convert(&self.phy.vtec_pin, stm32f4xx_hal::adc::config::SampleTime::Cycles_480) + as u32; } sample / avg_pt as u32 } @@ -307,7 +358,6 @@ impl MAX1968 { max_value = self.phy.max_v.get_max_duty(); value = duty_cycle_value(duty, max_duty, max_value); self.phy.max_v.set_duty(value); - } PwmPinsEnum::MaxPosI => { self.phy.max_i_pos.enable(); @@ -324,22 +374,24 @@ impl MAX1968 { } return (value as f64) / (max_value as f64); } - } #[interrupt] -fn DMA2_STREAM2(){ +fn DMA2_STREAM2() { cortex_m::interrupt::free(|_| { - unsafe { - // Clear all DMA2_STREAM2 interrupt flags - Peripherals::steal().DMA2.lifcr.write(|w| w - .ctcif2().set_bit() - .cdmeif2().set_bit() - .chtif2().set_bit() - .cteif2().set_bit() - ); - DMA_TRANSFER_COMPLETE = true; - } + unsafe { + // Clear all DMA2_STREAM2 interrupt flags + Peripherals::steal().DMA2.lifcr.write(|w| { + w.ctcif2() + .set_bit() + .cdmeif2() + .set_bit() + .chtif2() + .set_bit() + .cteif2() + .set_bit() + }); + DMA_TRANSFER_COMPLETE = true; } - ) + }) } diff --git a/src/thermostat/mod.rs b/src/thermostat/mod.rs index d506f91..06457f3 100644 --- a/src/thermostat/mod.rs +++ b/src/thermostat/mod.rs @@ -1,7 +1,7 @@ pub mod ad5680; -pub mod max1968; -pub mod thermostat; pub mod ad7172; -pub mod steinhart_hart; +pub mod max1968; pub mod pid_state; +pub mod steinhart_hart; pub mod temp_mon; +pub mod thermostat; diff --git a/src/thermostat/pid_state.rs b/src/thermostat/pid_state.rs index 2846678..5319b3c 100644 --- a/src/thermostat/pid_state.rs +++ b/src/thermostat/pid_state.rs @@ -1,14 +1,11 @@ use miniconf::Tree; use serde::{Deserialize, Serialize}; -use uom::si::{ - electric_potential::volt, electrical_resistance::ohm, f32::{ - ElectricPotential, ElectricalResistance, ThermodynamicTemperature - }, thermodynamic_temperature::degree_celsius -}; -use crate::thermostat::{ - ad7172, - steinhart_hart as sh, -}; +use uom::si::{electric_potential::volt, + electrical_resistance::ohm, + f32::{ElectricPotential, ElectricalResistance, ThermodynamicTemperature}, + thermodynamic_temperature::degree_celsius}; + +use crate::thermostat::{ad7172, steinhart_hart as sh}; const R_INNER: f32 = 2.0 * 5100.0; const VREF_SENS: f32 = 3.3 / 2.0; @@ -41,13 +38,12 @@ impl Default for Parameters { #[derive(Clone)] pub struct Controller { pub parameters: Parameters, - u1 : f64, - x1 : f64, - x2 : f64, - pub y1 : f64, + u1: f64, + x1: f64, + x2: f64, + pub y1: f64, } - pub struct PidState { adc_data: Option, adc_calibration: ad7172::ChannelCalibration, @@ -67,10 +63,10 @@ impl Default for PidState { sh: sh::Parameters::default(), controller: Controller { parameters: Parameters::default(), - u1 : 0.0, - x1 : 0.0, - x2 : 0.0, - y1 : 0.0, + u1: 0.0, + x1: 0.0, + x2: 0.0, + y1: 0.0, }, } } @@ -96,7 +92,7 @@ impl PidState { // Based on https://hackmd.io/IACbwcOTSt6Adj3_F9bKuw PID implementation // Input x(t), target u(t), output y(t) - // y0' = y1 - ki * u0 + // y0' = y1 - ki * u0 // + x0 * (kp + ki + kd) // - x1 * (kp + 2kd) // + x2 * kd @@ -106,10 +102,13 @@ impl PidState { let input = self.get_temperature()?.get::(); let setpoint = self.set_point.get::(); let mut output: f64 = self.controller.y1 - setpoint as f64 * f64::from(self.controller.parameters.ki) - + input as f64 * f64::from(self.controller.parameters.kp + self.controller.parameters.ki + self.controller.parameters.kd) - - self.controller.x1 * f64::from(self.controller.parameters.kp + 2.0 * self.controller.parameters.kd) - + self.controller.x2 * f64::from(self.controller.parameters.kd) - + f64::from(self.controller.parameters.kp) * (setpoint as f64 - self.controller.u1); + + input as f64 + * f64::from( + self.controller.parameters.kp + self.controller.parameters.ki + self.controller.parameters.kd, + ) + - self.controller.x1 * f64::from(self.controller.parameters.kp + 2.0 * self.controller.parameters.kd) + + self.controller.x2 * f64::from(self.controller.parameters.kd) + + f64::from(self.controller.parameters.kp) * (setpoint as f64 - self.controller.u1); if output < self.controller.parameters.output_min.into() { output = self.controller.parameters.output_min.into(); } @@ -119,7 +118,7 @@ impl PidState { self.controller.x2 = self.controller.x1; self.controller.x1 = input as f64; self.controller.u1 = setpoint as f64; - self.controller.y1 = output; + self.controller.y1 = output; Some(output) } @@ -142,38 +141,38 @@ impl PidState { Some(temperature) } - pub fn apply_pid_params(&mut self, pid_params: Parameters){ + pub fn apply_pid_params(&mut self, pid_params: Parameters) { self.controller.parameters = pid_params; } - pub fn set_pid_params(&mut self, param: PidSettings, val: f32){ + pub fn set_pid_params(&mut self, param: PidSettings, val: f32) { match param { - PidSettings::Kp => { + PidSettings::Kp => { self.controller.parameters.kp = val; } - PidSettings::Ki => { + PidSettings::Ki => { self.controller.parameters.ki = val; } - PidSettings::Kd => { + PidSettings::Kd => { self.controller.parameters.kd = val; } - PidSettings::Min => { + PidSettings::Min => { self.controller.parameters.output_min = val; } - PidSettings::Max => { + PidSettings::Max => { self.controller.parameters.output_max = val; } } } - pub fn reset_pid_state(&mut self){ + pub fn reset_pid_state(&mut self) { self.controller.u1 = 0.0; self.controller.x1 = 0.0; self.controller.x2 = 0.0; self.controller.y1 = 0.0; } - pub fn set_pid_setpoint(&mut self, temperature: ThermodynamicTemperature){ + pub fn set_pid_setpoint(&mut self, temperature: ThermodynamicTemperature) { self.set_point = temperature; } @@ -181,23 +180,23 @@ impl PidState { self.set_point } - pub fn set_sh_t0(&mut self, t0: ThermodynamicTemperature){ + pub fn set_sh_t0(&mut self, t0: ThermodynamicTemperature) { self.sh.t0 = t0 } - pub fn set_sh_r0(&mut self, r0: ElectricalResistance){ + pub fn set_sh_r0(&mut self, r0: ElectricalResistance) { self.sh.r0 = r0 } - pub fn set_sh_beta(&mut self, beta: f32){ + pub fn set_sh_beta(&mut self, beta: f32) { self.sh.b = beta } - pub fn set_adc_calibration(&mut self, adc_cal: ad7172::ChannelCalibration){ + pub fn set_adc_calibration(&mut self, adc_cal: ad7172::ChannelCalibration) { self.adc_calibration = adc_cal; } - pub fn set_pid_engaged(&mut self, pid_engaged: bool){ + pub fn set_pid_engaged(&mut self, pid_engaged: bool) { self.pid_engaged = pid_engaged; } diff --git a/src/thermostat/steinhart_hart.rs b/src/thermostat/steinhart_hart.rs index d6298a2..60d6a9d 100644 --- a/src/thermostat/steinhart_hart.rs +++ b/src/thermostat/steinhart_hart.rs @@ -1,15 +1,10 @@ +use miniconf::Tree; use num_traits::float::Float; use serde::{Deserialize, Serialize}; -use uom::si::{ - f32::{ - ElectricalResistance, - ThermodynamicTemperature, - }, - electrical_resistance::ohm, - ratio::ratio, - thermodynamic_temperature::{degree_celsius, kelvin}, -}; -use miniconf::Tree; +use uom::si::{electrical_resistance::ohm, + f32::{ElectricalResistance, ThermodynamicTemperature}, + ratio::ratio, + thermodynamic_temperature::{degree_celsius, kelvin}}; /// Steinhart-Hart equation parameters #[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)] diff --git a/src/thermostat/temp_mon.rs b/src/thermostat/temp_mon.rs index 99b4685..8992e7e 100644 --- a/src/thermostat/temp_mon.rs +++ b/src/thermostat/temp_mon.rs @@ -1,9 +1,7 @@ -use serde::{Deserialize, Serialize}; use miniconf::Tree; -use uom::si::{ - f32::ThermodynamicTemperature, thermodynamic_temperature::degree_celsius -}; use num_traits::Float; +use serde::{Deserialize, Serialize}; +use uom::si::{f32::ThermodynamicTemperature, thermodynamic_temperature::degree_celsius}; #[derive(PartialEq, Deserialize, Serialize, Copy, Clone, Default, Debug)] pub enum TempStatusEnum { #[default] @@ -44,7 +42,7 @@ impl Default for TempMon { set_point: ThermodynamicTemperature::new::(0.0), status: TempStatus { status: TempStatusEnum::Off, - over_temp_alarm: false + over_temp_alarm: false, }, state: State::default(), count: 0, @@ -117,12 +115,11 @@ impl TempMon { State::ConstantCurrentMode => { let is_over_temp = temp > self.upper_limit || temp < self.lower_limit; self.status.status = TempStatusEnum::ConstantCurrentMode; - + if is_over_temp { self.state = State::OverTempAlarm; self.status.status = TempStatusEnum::OverTemp; - } - else if !pwr_on { + } else if !pwr_on { self.state = State::PwrOff; self.status.status = TempStatusEnum::Off; } else if pid_engaged { @@ -138,7 +135,7 @@ impl TempMon { } else { is_over_temp = (temp.value - self.set_point.value).abs() > 0.5; } - + let is_within_spec: bool = (temp.value - self.set_point.value).abs() < 0.001; if is_over_temp { if self.count > TempMon::OVER_TEMP_COUNT_LIMIT { @@ -160,8 +157,7 @@ impl TempMon { // State Transition if !pwr_on { self.state = State::PwrOff; - } - else { + } else { if self.status.status == TempStatusEnum::OverTemp { self.state = State::OverTempAlarm; } else if self.is_set_point_changed { diff --git a/src/thermostat/thermostat.rs b/src/thermostat/thermostat.rs index d6d6440..90a7db8 100644 --- a/src/thermostat/thermostat.rs +++ b/src/thermostat/thermostat.rs @@ -1,25 +1,23 @@ -use core::f32::NAN; -use core::marker::PhantomData; -use crate::sys_timer; -use crate::thermostat::ad5680; -use crate::thermostat::max1968::{MAX1968, AdcReadTarget, PwmPinsEnum}; -use crate::thermostat::ad7172::{self, FilterType, PostFilter, SingleChODR}; -use crate::thermostat::pid_state::{PidState, PidSettings, Parameters as PidParams}; -use crate::thermostat::temp_mon::{TempMon, TempStatus, TempMonSettings}; -use crate::thermostat::steinhart_hart::Parameters as Sh_Params; -use serde::{Deserialize, Serialize}; -use log::debug; -use uom::si::{ - electric_current::ampere, - electric_potential::volt, - electrical_resistance::ohm, - thermodynamic_temperature::degree_celsius, - f32::{ThermodynamicTemperature, ElectricCurrent, ElectricPotential, ElectricalResistance}, - ratio::ratio, -}; -use miniconf::Tree; +use core::{f32::NAN, marker::PhantomData}; -use super::pid_state; +use log::debug; +use miniconf::Tree; +use serde::{Deserialize, Serialize}; +use uom::si::{electric_current::ampere, + electric_potential::volt, + electrical_resistance::ohm, + f32::{ElectricCurrent, ElectricPotential, ElectricalResistance, ThermodynamicTemperature}, + ratio::ratio, + thermodynamic_temperature::degree_celsius}; + +use crate::{sys_timer, + thermostat::{ad5680, + ad7172::{self, FilterType, PostFilter, SingleChODR}, + max1968::{AdcReadTarget, PwmPinsEnum, MAX1968}, + pid_state, + pid_state::{Parameters as PidParams, PidSettings, PidState}, + steinhart_hart::Parameters as Sh_Params, + temp_mon::{TempMon, TempMonSettings, TempStatus}}}; pub const R_SENSE: ElectricalResistance = ElectricalResistance { dimension: PhantomData, @@ -28,7 +26,7 @@ pub const R_SENSE: ElectricalResistance = ElectricalResistance { }; #[derive(Deserialize, Serialize, Copy, Clone, Debug, Default, Tree)] -pub struct TempAdcFilter{ +pub struct TempAdcFilter { pub filter_type: FilterType, pub sinc5sinc1odr: Option, pub sinc3odr: Option, @@ -37,7 +35,6 @@ pub struct TempAdcFilter{ pub rate: Option, } - #[derive(Deserialize, Serialize, Clone, Copy, Debug, Tree)] pub struct TecSettings { pub default_pwr_on: bool, @@ -49,7 +46,7 @@ pub struct TecSettings { pub vref: ElectricPotential, } -impl TecSettings{ +impl TecSettings { pub const DAC_OUT_V_MAX: ElectricPotential = ElectricPotential { dimension: PhantomData, units: PhantomData, @@ -60,11 +57,11 @@ impl TecSettings{ units: PhantomData, value: 1.65, }; - + // Kirdy Design Specs: // MaxV = 5.0V // MAX Current = +- 1.0A - const MAX_I_SET : ElectricCurrent = ElectricCurrent { + const MAX_I_SET: ElectricCurrent = ElectricCurrent { dimension: PhantomData, units: PhantomData, value: 1.0, @@ -79,7 +76,8 @@ impl TecSettings{ units: PhantomData, value: 5.0, }; - const MAX_V_DUTY_MAX: f64 = TecSettings::MAX_V_MAX.value as f64 / TecSettings::MAX_V_DUTY_TO_CURRENT_RATE.value as f64; + const MAX_V_DUTY_MAX: f64 = + TecSettings::MAX_V_MAX.value as f64 / TecSettings::MAX_V_DUTY_TO_CURRENT_RATE.value as f64; const MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE: ElectricCurrent = ElectricCurrent { dimension: PhantomData, units: PhantomData, @@ -96,8 +94,10 @@ impl TecSettings{ value: 1.0, }; // .get::() is not implemented for const - const MAX_I_POS_DUTY_MAX: f64 = TecSettings::MAX_I_POS_CURRENT.value as f64 / TecSettings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE.value as f64; - const MAX_I_NEG_DUTY_MAX: f64 = TecSettings::MAX_I_NEG_CURRENT.value as f64 / TecSettings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE.value as f64; + const MAX_I_POS_DUTY_MAX: f64 = + TecSettings::MAX_I_POS_CURRENT.value as f64 / TecSettings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE.value as f64; + const MAX_I_NEG_DUTY_MAX: f64 = + TecSettings::MAX_I_NEG_CURRENT.value as f64 / TecSettings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE.value as f64; } impl Default for TecSettings { @@ -134,9 +134,9 @@ pub struct ThermostatSettingsSummary { thermistor_params: ThermistorParams, } -impl Thermostat{ - pub fn new (max1968: MAX1968, ad7172: ad7172::AdcPhy) -> Self { - Thermostat{ +impl Thermostat { + pub fn new(max1968: MAX1968, ad7172: ad7172::AdcPhy) -> Self { + Thermostat { max1968: max1968, ad7172: ad7172, tec_settings: TecSettings::default(), @@ -144,16 +144,16 @@ impl Thermostat{ temp_mon: TempMon::default(), } } - pub fn setup(&mut self){ + pub fn setup(&mut self) { self.tec_setup(); let t_adc_ch0_cal = self.t_adc_setup(); - self.pid_ctrl_ch0.set_adc_calibration(t_adc_ch0_cal) ; + self.pid_ctrl_ch0.set_adc_calibration(t_adc_ch0_cal); } /// start_tec_readings_conversion() should not be called before the current /// DMA request is serviced or the conversion process will be restarted /// Thus, no new readings is available when you call get_tec_readings() fn - pub fn start_tec_readings_conversion(&mut self){ + pub fn start_tec_readings_conversion(&mut self) { self.max1968.dma_adc_start_conversion(); } @@ -169,24 +169,26 @@ impl Thermostat{ self.set_max_i_neg(self.tec_settings.max_i_neg_set); } - fn t_adc_setup(&mut self)->ad7172::ChannelCalibration{ + fn t_adc_setup(&mut self) -> ad7172::ChannelCalibration { self.ad7172.set_sync_enable(false).unwrap(); - self.ad7172.setup_channel(0, ad7172::Input::Ain0, ad7172::Input::Ain1).unwrap(); - let adc_calibration0 = self.ad7172.get_calibration(0) - .expect("adc_calibration0"); + self.ad7172 + .setup_channel(0, ad7172::Input::Ain0, ad7172::Input::Ain1) + .unwrap(); + let adc_calibration0 = self.ad7172.get_calibration(0).expect("adc_calibration0"); self.ad7172.start_continuous_conversion().unwrap(); adc_calibration0 } pub fn poll_adc(&mut self) -> bool { let mut data_rdy = false; - self.ad7172.data_ready().unwrap().map(|_ch| { + self.ad7172.data_ready().unwrap().map(|_ch| { let data = self.ad7172.read_data().unwrap(); let state: &mut PidState = &mut self.pid_ctrl_ch0; state.update(data); let pid_engaged = state.get_pid_engaged(); let temp = self.get_temperature(); - self.temp_mon.update_status(pid_engaged, self.max1968.is_powered_on(), temp); + self.temp_mon + .update_status(pid_engaged, self.max1968.is_powered_on(), temp); debug!("state.get_pid_engaged(): {:?}", pid_engaged); debug!("Temperature: {:?} degree", temp.get::()); data_rdy = true; @@ -201,9 +203,12 @@ impl Thermostat{ match state.update_pid() { Some(pid_output) => { self.set_i(ElectricCurrent::new::(pid_output as f32)); - debug!("Temperature Set Point: {:?} degree", self.pid_ctrl_ch0.get_pid_setpoint().get::()); + debug!( + "Temperature Set Point: {:?} degree", + self.pid_ctrl_ch0.get_pid_setpoint().get::() + ); } - None => { } + None => {} } } } @@ -212,22 +217,22 @@ impl Thermostat{ self.temp_mon.get_status() } - pub fn power_up(&mut self){ + pub fn power_up(&mut self) { self.max1968.power_up(); } - pub fn power_down(&mut self){ + pub fn power_down(&mut self) { self.max1968.power_down(); self.pid_ctrl_ch0.reset_pid_state(); self.set_i(ElectricCurrent::new::(0.0)); } - fn set_center_pt(&mut self, value: ElectricPotential){ + fn set_center_pt(&mut self, value: ElectricPotential) { self.tec_settings.center_pt = value; } pub fn set_default_pwr_on(&mut self, pwr_on: bool) { - self.tec_settings.default_pwr_on = pwr_on; + self.tec_settings.default_pwr_on = pwr_on; } pub fn set_i(&mut self, i_tec: ElectricCurrent) -> ElectricCurrent { @@ -239,21 +244,27 @@ impl Thermostat{ pub fn set_max_v(&mut self, max_v: ElectricPotential) -> ElectricPotential { let duty = (max_v / TecSettings::MAX_V_DUTY_TO_CURRENT_RATE).get::(); - let duty = self.max1968.set_pwm(PwmPinsEnum::MaxV, duty as f64, TecSettings::MAX_V_DUTY_MAX); + let duty = self + .max1968 + .set_pwm(PwmPinsEnum::MaxV, duty as f64, TecSettings::MAX_V_DUTY_MAX); self.tec_settings.max_v_set = duty as f32 * TecSettings::MAX_V_DUTY_TO_CURRENT_RATE; self.tec_settings.max_v_set } pub fn set_max_i_pos(&mut self, max_i_pos: ElectricCurrent) -> ElectricCurrent { let duty = (max_i_pos / TecSettings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE).get::(); - let duty = self.max1968.set_pwm(PwmPinsEnum::MaxPosI, duty as f64, TecSettings::MAX_I_POS_DUTY_MAX); + let duty = self + .max1968 + .set_pwm(PwmPinsEnum::MaxPosI, duty as f64, TecSettings::MAX_I_POS_DUTY_MAX); self.tec_settings.max_i_pos_set = duty as f32 * TecSettings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE; self.tec_settings.max_i_pos_set } pub fn set_max_i_neg(&mut self, max_i_neg: ElectricCurrent) -> ElectricCurrent { let duty = (max_i_neg / TecSettings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE).get::(); - let duty = self.max1968.set_pwm(PwmPinsEnum::MaxNegI, duty as f64, TecSettings::MAX_I_NEG_DUTY_MAX); + let duty = self + .max1968 + .set_pwm(PwmPinsEnum::MaxNegI, duty as f64, TecSettings::MAX_I_NEG_DUTY_MAX); self.tec_settings.max_i_neg_set = duty as f32 * TecSettings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE; self.tec_settings.max_i_neg_set } @@ -282,32 +293,35 @@ impl Thermostat{ pub fn get_tec_readings(&mut self) -> (ElectricPotential, ElectricCurrent) { let vref = self.tec_settings.vref; let (vtec, itec) = self.max1968.get_tec_readings(); - ((vtec - TecSettings::TEC_VSEC_BIAS_V) * 4.0, (itec - vref) / ElectricalResistance::new::(0.4)) + ( + (vtec - TecSettings::TEC_VSEC_BIAS_V) * 4.0, + (itec - vref) / ElectricalResistance::new::(0.4), + ) } /// Calibrates the DAC output to match vref of the MAX driver to reduce zero-current offset of the MAX driver output. /// /// The thermostat DAC applies a control voltage signal to the CTLI pin of MAX driver chip to control its output current. /// The CTLI input signal is centered around VREF of the MAX chip. Applying VREF to CTLI sets the output current to 0. - /// + /// /// This calibration routine measures the VREF voltage and the DAC output with the STM32 ADC, and uses a breadth-first - /// search to find the DAC setting that will produce a DAC output voltage closest to VREF. This DAC output voltage will - /// be stored and used in subsequent i_set routines to bias the current control signal to the measured VREF, reducing + /// search to find the DAC setting that will produce a DAC output voltage closest to VREF. This DAC output voltage will + /// be stored and used in subsequent i_set routines to bias the current control signal to the measured VREF, reducing /// the offset error of the current control signal. /// /// The input offset of the STM32 ADC is eliminated by using the same ADC for the measurements, and by only using the /// difference in VREF and DAC output for the calibration. - /// - /// This routine should be called only once after boot, repeated reading of the vref signal and changing of the stored + /// + /// This routine should be called only once after boot, repeated reading of the vref signal and changing of the stored /// VREF measurement can introduce significant noise at the current output, degrading the stabilily performance of the - /// thermostat. + /// thermostat. pub fn calibrate_dac_value(&mut self) { const DAC_BIT: u32 = 18; const ADC_BIT: u32 = 12; let target_voltage = self.max1968.adc_read(AdcReadTarget::VREF, 512); let mut start_value = 1; let mut best_error = ElectricPotential::new::(100.0); - for step in (DAC_BIT-ADC_BIT-1..DAC_BIT).rev() { + for step in (DAC_BIT - ADC_BIT - 1..DAC_BIT).rev() { let mut prev_value = start_value; for value in (start_value..=ad5680::MAX_VALUE).step_by(1 << step) { self.max1968.phy.dac.set(value).unwrap(); @@ -329,13 +343,13 @@ impl Thermostat{ } self.tec_settings.vref = target_voltage; } - + pub fn set_pid_engaged(&mut self, val: bool) { self.pid_ctrl_ch0.set_pid_engaged(val); } fn get_pid_engaged(&mut self) -> bool { - self.pid_ctrl_ch0.get_pid_engaged() + self.pid_ctrl_ch0.get_pid_engaged() } pub fn get_status_report(&mut self) -> StatusReport { @@ -343,14 +357,12 @@ impl Thermostat{ let temperature: Option; match self.pid_ctrl_ch0.get_temperature() { - Some(val) => { - temperature = Some(val.get::()) - } + Some(val) => temperature = Some(val.get::()), None => { temperature = None; } } - + StatusReport { pwr_on: self.max1968.is_powered_on(), pid_engaged: self.get_pid_engaged(), @@ -364,10 +376,8 @@ impl Thermostat{ pub fn get_temperature(&mut self) -> ThermodynamicTemperature { match self.pid_ctrl_ch0.get_temperature() { - Some(val) => { - val - } - None => { ThermodynamicTemperature::new::(NAN) } + Some(val) => val, + None => ThermodynamicTemperature::new::(NAN), } } @@ -382,26 +392,34 @@ impl Thermostat{ r0: sh.r0, b: sh.b, } - } fn apply_steinhart_hart(&mut self, sh: ThermistorParams) { - self.pid_ctrl_ch0.apply_sh( - Sh_Params { - t0: ThermodynamicTemperature::new::(sh.t0), - r0: sh.r0, - b: sh.b, - } - ) + self.pid_ctrl_ch0.apply_sh(Sh_Params { + t0: ThermodynamicTemperature::new::(sh.t0), + r0: sh.r0, + b: sh.b, + }) } - fn get_tec_settings(&mut self) -> TecSettingSummary { TecSettingSummary { - i_set: TecSettingsSummaryField { value: self.tec_settings.i_set, max: TecSettings::MAX_I_SET }, - max_v: TecSettingsSummaryField { value: self.tec_settings.max_v_set, max: TecSettings::MAX_V_MAX }, - max_i_pos: TecSettingsSummaryField { value: self.tec_settings.max_i_pos_set, max: TecSettings::MAX_I_POS_CURRENT }, - max_i_neg: TecSettingsSummaryField { value: self.tec_settings.max_i_neg_set, max: TecSettings::MAX_I_NEG_CURRENT }, + i_set: TecSettingsSummaryField { + value: self.tec_settings.i_set, + max: TecSettings::MAX_I_SET, + }, + max_v: TecSettingsSummaryField { + value: self.tec_settings.max_v_set, + max: TecSettings::MAX_V_MAX, + }, + max_i_pos: TecSettingsSummaryField { + value: self.tec_settings.max_i_pos_set, + max: TecSettings::MAX_I_POS_CURRENT, + }, + max_i_neg: TecSettingsSummaryField { + value: self.tec_settings.max_i_neg_set, + max: TecSettings::MAX_I_NEG_CURRENT, + }, } } @@ -409,7 +427,7 @@ impl Thermostat{ self.max1968.get_calibrated_vdda() } - pub fn set_pid(&mut self, param: PidSettings, val: f32){ + pub fn set_pid(&mut self, param: PidSettings, val: f32) { self.pid_ctrl_ch0.set_pid_params(param, val); } @@ -426,14 +444,18 @@ impl Thermostat{ } pub fn set_temperature_setpoint(&mut self, t: ThermodynamicTemperature) { - let t = t.min(self.temp_mon.get_upper_limit()).max(self.temp_mon.get_lower_limit()); + let t = t + .min(self.temp_mon.get_upper_limit()) + .max(self.temp_mon.get_lower_limit()); self.pid_ctrl_ch0.set_pid_setpoint(t); self.temp_mon.set_setpoint(t); } - pub fn apply_temp_mon_settings(&mut self, settings: TempMonSettings){ - self.temp_mon.set_upper_limit(ThermodynamicTemperature::new::(settings.upper_limit)); - self.temp_mon.set_lower_limit(ThermodynamicTemperature::new::(settings.lower_limit)); + pub fn apply_temp_mon_settings(&mut self, settings: TempMonSettings) { + self.temp_mon + .set_upper_limit(ThermodynamicTemperature::new::(settings.upper_limit)); + self.temp_mon + .set_lower_limit(ThermodynamicTemperature::new::(settings.lower_limit)); } pub fn set_temp_mon_upper_limit(&mut self, t: ThermodynamicTemperature) { @@ -453,7 +475,9 @@ impl Thermostat{ } pub fn set_temp_adc_sinc5_sinc1_with_postfilter(&mut self, index: u8, odr: ad7172::PostFilter) { - self.ad7172.set_sinc5_sinc1_with_50hz_60hz_rejection(index, odr).unwrap(); + self.ad7172 + .set_sinc5_sinc1_with_50hz_60hz_rejection(index, odr) + .unwrap(); } pub fn set_temp_adc_sinc3_fine_filter(&mut self, index: u8, rate: f32) { @@ -487,13 +511,13 @@ impl Thermostat{ temperature_setpoint: self.pid_ctrl_ch0.get_pid_setpoint().get::(), tec_settings: self.get_tec_settings(), pid_params: self.get_pid_settings(), - temp_adc_settings: TempAdcFilter{ - filter_type : temp_adc_filter_type, - sinc5sinc1odr : None, - sinc3odr : None, - sinc5sinc1postfilter : None, - sinc3fineodr : None, - rate : Some(update_rate), + temp_adc_settings: TempAdcFilter { + filter_type: temp_adc_filter_type, + sinc5sinc1odr: None, + sinc3odr: None, + sinc5sinc1postfilter: None, + sinc3fineodr: None, + rate: Some(update_rate), }, temp_mon_settings: self.get_temp_mon_settings(), thermistor_params: self.get_steinhart_hart(), @@ -505,27 +529,19 @@ impl Thermostat{ self.set_max_i_neg(settings.tec_settings.max_i_neg.value); self.set_max_i_pos(settings.tec_settings.max_i_pos.value); self.set_max_v(settings.tec_settings.max_v.value); - + self.apply_steinhart_hart(settings.thermistor_params); self.apply_temp_mon_settings(settings.temp_mon_settings); - + match settings.temp_adc_settings.rate { - Some(rate) => { - match settings.temp_adc_settings.filter_type { - FilterType::Sinc3 => { - self.set_temp_adc_sinc3_filter(0, SingleChODR::closest(rate).unwrap()) - } - FilterType::Sinc5Sinc1 => { - self.set_temp_adc_sinc5_sinc1_filter(0, SingleChODR::closest(rate).unwrap()) - } - FilterType::Sinc3WithFineODR => { - self.set_temp_adc_sinc3_fine_filter(0, rate) - } - FilterType::Sinc5Sinc1With50hz60HzRejection => { - self.set_temp_adc_sinc5_sinc1_with_postfilter(0, PostFilter::closest(rate).unwrap()) - } + Some(rate) => match settings.temp_adc_settings.filter_type { + FilterType::Sinc3 => self.set_temp_adc_sinc3_filter(0, SingleChODR::closest(rate).unwrap()), + FilterType::Sinc5Sinc1 => self.set_temp_adc_sinc5_sinc1_filter(0, SingleChODR::closest(rate).unwrap()), + FilterType::Sinc3WithFineODR => self.set_temp_adc_sinc3_fine_filter(0, rate), + FilterType::Sinc5Sinc1With50hz60HzRejection => { + self.set_temp_adc_sinc5_sinc1_with_postfilter(0, PostFilter::closest(rate).unwrap()) } - } + }, None => { debug!(" Temperature ADC Settings is not found"); } @@ -533,7 +549,9 @@ impl Thermostat{ self.set_pid_engaged(settings.pid_engaged); self.pid_ctrl_ch0.apply_pid_params(settings.pid_params); - self.set_temperature_setpoint(ThermodynamicTemperature::new::(settings.temperature_setpoint)); + self.set_temperature_setpoint(ThermodynamicTemperature::new::( + settings.temperature_setpoint, + )); if !settings.pid_engaged { self.set_i(settings.tec_settings.i_set.value); } @@ -575,5 +593,5 @@ pub struct TecSettingSummary { pub struct ThermistorParams { t0: f32, r0: ElectricalResistance, - b: f32 + b: f32, }