parent
ded7dd7694
commit
b8241d1f27
5
build.rs
5
build.rs
|
@ -1,7 +1,4 @@
|
||||||
use std::env;
|
use std::{env, fs::File, io::Write, path::PathBuf};
|
||||||
use std::fs::File;
|
|
||||||
use std::io::Write;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Put the linker script somewhere the linker can find it
|
// Put the linker script somewhere the linker can find it
|
||||||
|
|
12
flake.lock
12
flake.lock
|
@ -3,11 +3,11 @@
|
||||||
"mozilla-overlay": {
|
"mozilla-overlay": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1695805681,
|
"lastModified": 1704373101,
|
||||||
"narHash": "sha256-1ElPLD8eFfnuIk0G52HGGpRtQZ4QPCjChRlEOfkZ5ro=",
|
"narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=",
|
||||||
"owner": "mozilla",
|
"owner": "mozilla",
|
||||||
"repo": "nixpkgs-mozilla",
|
"repo": "nixpkgs-mozilla",
|
||||||
"rev": "6eabade97bc28d707a8b9d82ad13ef143836736e",
|
"rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -18,11 +18,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1710951922,
|
"lastModified": 1713725259,
|
||||||
"narHash": "sha256-FOOBJ3DQenLpTNdxMHR2CpGZmYuctb92gF0lpiirZ30=",
|
"narHash": "sha256-9ZR/Rbx5/Z/JZf5ehVNMoz/s5xjpP0a22tL6qNvLt5E=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "f091af045dff8347d66d186a62d42aceff159456",
|
"rev": "a5e4bbcb4780c63c79c87d29ea409abf097de3f7",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
let
|
let
|
||||||
pkgs = import nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; };
|
pkgs = import nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; };
|
||||||
rustManifest = pkgs.fetchurl {
|
rustManifest = pkgs.fetchurl {
|
||||||
url = "https://static.rust-lang.org/dist/2024-03-21/channel-rust-stable.toml";
|
url = "https://static.rust-lang.org/dist/2024-03-21/channel-rust-nightly.toml";
|
||||||
sha256 = "faccaa01dda45fc2956bcfd4da0cf76e52104d3b1862ddd4eb7c4159a18e49cf";
|
sha256 = "1c7db6ab80d20682b5cc5bda7360c63311d7188c0c082902d3790820527cd4e0";
|
||||||
};
|
};
|
||||||
|
|
||||||
targets = [
|
targets = [
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
inherit targets;
|
inherit targets;
|
||||||
extensions = ["rust-src"];
|
extensions = ["rust-src"];
|
||||||
};
|
};
|
||||||
rust = rustChannelOfTargets "stable" null targets;
|
rust = rustChannelOfTargets "nightly" null targets;
|
||||||
rustPlatform = pkgs.recurseIntoAttrs (pkgs.makeRustPlatform {
|
rustPlatform = pkgs.recurseIntoAttrs (pkgs.makeRustPlatform {
|
||||||
rustc = rust;
|
rustc = rust;
|
||||||
cargo = rust;
|
cargo = rust;
|
||||||
|
|
|
@ -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
|
|
@ -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 fugit::ExtU32;
|
||||||
use log::{info, debug};
|
use log::{debug, info};
|
||||||
use stm32f4xx_hal::timer::TimerExt;
|
use stm32f4xx_hal::{pac::{CorePeripherals, Peripherals},
|
||||||
use stm32f4xx_hal::{
|
rcc::RccExt,
|
||||||
pac::{CorePeripherals, Peripherals},
|
time::MegaHertz,
|
||||||
rcc::RccExt,
|
timer::TimerExt,
|
||||||
time::MegaHertz,
|
watchdog::IndependentWatchdog};
|
||||||
watchdog::IndependentWatchdog,
|
use uom::si::{electric_current::{ampere, milliampere},
|
||||||
};
|
f32::ElectricCurrent};
|
||||||
use crate::DeviceSettings;
|
|
||||||
use uom::si::electric_current::milliampere;
|
use super::{gpio, sys_timer, usb};
|
||||||
use uom::si::{electric_current::ampere, f32::ElectricCurrent};
|
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"))]
|
#[cfg(not(feature = "semihosting"))]
|
||||||
const WATCHDOG_PERIOD: u32 = 4000;
|
const WATCHDOG_PERIOD: u32 = 4000;
|
||||||
|
@ -44,21 +40,22 @@ pub fn bootup(
|
||||||
|
|
||||||
sys_timer::setup(core_perif.SYST, clocks);
|
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(
|
let (mut hw_rev, eth_pins, eth_mgmt_pins, usb, current_source_phy, ad7172_phy, max1968_phy, pd_mon_phy) =
|
||||||
clocks,
|
gpio::setup(
|
||||||
perif.TIM4,
|
clocks,
|
||||||
perif.GPIOA,
|
perif.TIM4,
|
||||||
perif.GPIOB,
|
perif.GPIOA,
|
||||||
perif.GPIOC,
|
perif.GPIOB,
|
||||||
perif.GPIOD,
|
perif.GPIOC,
|
||||||
perif.GPIOE,
|
perif.GPIOD,
|
||||||
perif.SPI1,
|
perif.GPIOE,
|
||||||
perif.SPI2,
|
perif.SPI1,
|
||||||
perif.SPI3,
|
perif.SPI2,
|
||||||
perif.OTG_FS_GLOBAL,
|
perif.SPI3,
|
||||||
perif.OTG_FS_DEVICE,
|
perif.OTG_FS_GLOBAL,
|
||||||
perif.OTG_FS_PWRCLK,
|
perif.OTG_FS_DEVICE,
|
||||||
);
|
perif.OTG_FS_PWRCLK,
|
||||||
|
);
|
||||||
|
|
||||||
usb::State::setup(usb);
|
usb::State::setup(usb);
|
||||||
|
|
||||||
|
@ -84,7 +81,7 @@ pub fn bootup(
|
||||||
let flash_store = flash_store::store(perif.FLASH);
|
let flash_store = flash_store::store(perif.FLASH);
|
||||||
|
|
||||||
let mut ip_settings: IpSettings = IpSettings::default();
|
let mut ip_settings: IpSettings = IpSettings::default();
|
||||||
let device_settings : DeviceSettings;
|
let device_settings: DeviceSettings;
|
||||||
match flash_store.read_value("Device") {
|
match flash_store.read_value("Device") {
|
||||||
Ok(Some(config)) => {
|
Ok(Some(config)) => {
|
||||||
device_settings = config;
|
device_settings = config;
|
||||||
|
@ -107,7 +104,14 @@ pub fn bootup(
|
||||||
mmc: perif.ETHERNET_MMC,
|
mmc: perif.ETHERNET_MMC,
|
||||||
ptp: perif.ETHERNET_PTP,
|
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");
|
debug!("Setting Watchdog");
|
||||||
let mut wd = IndependentWatchdog::new(perif.IWDG);
|
let mut wd = IndependentWatchdog::new(perif.IWDG);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
use cortex_m_rt::pre_init;
|
use cortex_m_rt::pre_init;
|
||||||
use stm32f4xx_hal::pac::{RCC, SYSCFG};
|
use stm32f4xx_hal::pac::{RCC, SYSCFG};
|
||||||
use core::arch::asm;
|
|
||||||
|
|
||||||
const DFU_TRIG_MSG: u32 = 0xDECAFBAD;
|
const DFU_TRIG_MSG: u32 = 0xDECAFBAD;
|
||||||
|
|
||||||
|
@ -27,7 +28,7 @@ unsafe fn __pre_init() {
|
||||||
rcc.apb2enr.modify(|_, w| w.syscfgen().set_bit());
|
rcc.apb2enr.modify(|_, w| w.syscfgen().set_bit());
|
||||||
|
|
||||||
// Bypass BOOT pins and remap bootloader to 0x00000000
|
// Bypass BOOT pins and remap bootloader to 0x00000000
|
||||||
let syscfg = &*SYSCFG::ptr() ;
|
let syscfg = &*SYSCFG::ptr();
|
||||||
syscfg.memrm.write(|w| w.mem_mode().bits(0b01));
|
syscfg.memrm.write(|w| w.mem_mode().bits(0b01));
|
||||||
|
|
||||||
// Impose instruction and memory barriers
|
// Impose instruction and memory barriers
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use log::error;
|
use log::error;
|
||||||
use stm32f4xx_hal::{
|
|
||||||
flash::{Error, FlashExt},
|
|
||||||
pac::FLASH,
|
|
||||||
};
|
|
||||||
use sfkv::{Store, StoreBackend};
|
use sfkv::{Store, StoreBackend};
|
||||||
|
use stm32f4xx_hal::{flash::{Error, FlashExt},
|
||||||
|
pac::FLASH};
|
||||||
|
|
||||||
// Last flash sector is used to avoid overwriting the code in flash.
|
// Last flash sector is used to avoid overwriting the code in flash.
|
||||||
pub const FLASH_SECTOR: u8 = 11;
|
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> {
|
fn program(&mut self, offset: usize, payload: &[u8]) -> Result<(), Self::Error> {
|
||||||
self.flash.unlocked()
|
self.flash.unlocked().program(get_offset() + offset, payload.iter())
|
||||||
.program(get_offset() + offset, payload.iter())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn backup_space(&self) -> &'static mut [u8] {
|
fn backup_space(&self) -> &'static mut [u8] {
|
||||||
|
@ -53,8 +50,7 @@ pub fn store(flash: FLASH) -> FlashStore {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("corrupt store, erasing. error: {:?}", e);
|
error!("corrupt store, erasing. error: {:?}", e);
|
||||||
let _ = store.erase()
|
let _ = store.erase().map_err(|e| error!("flash erase failed: {:?}", e));
|
||||||
.map_err(|e| error!("flash erase failed: {:?}", e));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 stm32_eth::EthPins;
|
||||||
use stm32f4xx_hal::gpio::alt::otg_fs::{Dm, Dp};
|
use stm32f4xx_hal::{gpio::{alt::otg_fs::{Dm, Dp},
|
||||||
use stm32f4xx_hal::{
|
gpioa::*,
|
||||||
gpio::{gpioa::*, gpiob::*, gpioc::*, GpioExt, Input, Speed},
|
gpiob::*,
|
||||||
otg_fs::USB,
|
gpioc::*,
|
||||||
pac::{
|
GpioExt, Input, Speed},
|
||||||
GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, OTG_FS_DEVICE, OTG_FS_GLOBAL, OTG_FS_PWRCLK, SPI1, SPI2, SPI3,
|
otg_fs::USB,
|
||||||
TIM4,
|
pac::{GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, OTG_FS_DEVICE, OTG_FS_GLOBAL, OTG_FS_PWRCLK, SPI1, SPI2,
|
||||||
},
|
SPI3, TIM4},
|
||||||
rcc::Clocks,
|
rcc::Clocks,
|
||||||
spi::{NoMiso, Spi},
|
spi::{NoMiso, Spi},
|
||||||
timer::{Channel1, Channel2, Channel3, pwm::PwmExt}
|
timer::{pwm::PwmExt, Channel1, Channel2, Channel3}};
|
||||||
};
|
|
||||||
|
|
||||||
pub type EthernetPins =
|
use crate::{device::hw_rev::{HWRev, HwRevPins},
|
||||||
EthPins<PA1<Input>, PA7<Input>, PB11<Input>, PB12<Input>, PB13<Input>, PC4<Input>, PC5<Input>>;
|
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<PA1<Input>, PA7<Input>, PB11<Input>, PB12<Input>, PB13<Input>, PC4<Input>, PC5<Input>>;
|
||||||
|
|
||||||
pub fn setup(
|
pub fn setup(
|
||||||
clocks: Clocks,
|
clocks: Clocks,
|
||||||
|
@ -45,7 +43,7 @@ pub fn setup(
|
||||||
LdCtrlPhy<ld_ctrl::Channel0>,
|
LdCtrlPhy<ld_ctrl::Channel0>,
|
||||||
ad7172::AdcPhy,
|
ad7172::AdcPhy,
|
||||||
MAX1968Phy<max1968::Channel0>,
|
MAX1968Phy<max1968::Channel0>,
|
||||||
LdPwrExcProtectorPhy
|
LdPwrExcProtectorPhy,
|
||||||
) {
|
) {
|
||||||
let gpioa = gpioa.split();
|
let gpioa = gpioa.split();
|
||||||
let gpiob = gpiob.split();
|
let gpiob = gpiob.split();
|
||||||
|
@ -53,14 +51,12 @@ pub fn setup(
|
||||||
let gpiod = gpiod.split();
|
let gpiod = gpiod.split();
|
||||||
let gpioe = gpioe.split();
|
let gpioe = gpioe.split();
|
||||||
|
|
||||||
let mut hw_rev = HWRev::detect_hw_rev(
|
let mut hw_rev = HWRev::detect_hw_rev(HwRevPins {
|
||||||
HwRevPins {
|
h0: gpioe.pe8.into_input(),
|
||||||
h0: gpioe.pe8.into_input(),
|
h1: gpioe.pe9.into_input(),
|
||||||
h1: gpioe.pe9.into_input(),
|
h2: gpioe.pe10.into_input(),
|
||||||
h2: gpioe.pe10.into_input(),
|
h3: gpioe.pe11.into_input(),
|
||||||
h3: gpioe.pe11.into_input(),
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
hw_rev.startup_delay_before_gpio_init();
|
hw_rev.startup_delay_before_gpio_init();
|
||||||
|
|
||||||
|
@ -84,26 +80,24 @@ pub fn setup(
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut eth_mgmt_pins = EthernetMgmtPins {
|
let mut eth_mgmt_pins = EthernetMgmtPins {
|
||||||
mdio: gpioa.pa2.into_alternate::<11>(),
|
mdio: gpioa.pa2.into_alternate::<11>(),
|
||||||
mdc: gpioc.pc1.into_alternate::<11>(),
|
mdc: gpioc.pc1.into_alternate::<11>(),
|
||||||
};
|
};
|
||||||
eth_mgmt_pins.mdio.set_speed(Speed::VeryHigh);
|
eth_mgmt_pins.mdio.set_speed(Speed::VeryHigh);
|
||||||
eth_mgmt_pins.mdc.set_speed(Speed::VeryHigh);
|
eth_mgmt_pins.mdc.set_speed(Speed::VeryHigh);
|
||||||
|
|
||||||
let current_source_phy = LdCtrlPhy {
|
let current_source_phy = LdCtrlPhy {
|
||||||
dac: max5719::Dac::new(Spi::new(
|
dac: max5719::Dac::new(
|
||||||
spi2,
|
Spi::new(
|
||||||
(
|
spi2,
|
||||||
gpiob.pb10.into_alternate(),
|
(gpiob.pb10.into_alternate(), NoMiso::new(), gpiob.pb15.into_alternate()),
|
||||||
NoMiso::new(),
|
max5719::SPI_MODE,
|
||||||
gpiob.pb15.into_alternate(),
|
max5719::SPI_CLOCK_MHZ.convert(),
|
||||||
),
|
&clocks,
|
||||||
max5719::SPI_MODE,
|
|
||||||
max5719::SPI_CLOCK_MHZ.convert(),
|
|
||||||
&clocks,
|
|
||||||
), gpiod.pd8.into_push_pull_output(),
|
|
||||||
gpiob.pb14.into_push_pull_output(),
|
|
||||||
),
|
),
|
||||||
|
gpiod.pd8.into_push_pull_output(),
|
||||||
|
gpiob.pb14.into_push_pull_output(),
|
||||||
|
),
|
||||||
current_source_short_pin: gpioa.pa4.into_push_pull_output(),
|
current_source_short_pin: gpioa.pa4.into_push_pull_output(),
|
||||||
termination_status_pin: gpiod.pd7.internal_pull_up(true),
|
termination_status_pin: gpiod.pd7.internal_pull_up(true),
|
||||||
};
|
};
|
||||||
|
@ -118,18 +112,13 @@ pub fn setup(
|
||||||
Channel2::new(gpiob.pb7),
|
Channel2::new(gpiob.pb7),
|
||||||
Channel3::new(gpiob.pb8),
|
Channel3::new(gpiob.pb8),
|
||||||
);
|
);
|
||||||
let (max_i_neg0, max_v0, max_i_pos0) =
|
let (max_i_neg0, max_v0, max_i_pos0) = tim4.pwm_hz(pwm_chs, PWM_FREQ_KHZ.convert(), &clocks).split();
|
||||||
tim4.pwm_hz(pwm_chs, PWM_FREQ_KHZ.convert(), &clocks).split();
|
|
||||||
|
|
||||||
let max1968_phy = MAX1968Phy::new(MAX1968PinSet {
|
let max1968_phy = MAX1968Phy::new(MAX1968PinSet {
|
||||||
dac: ad5680::Dac::new(
|
dac: ad5680::Dac::new(
|
||||||
Spi::new(
|
Spi::new(
|
||||||
spi1,
|
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_MODE,
|
||||||
ad5680::SPI_CLOCK_MHZ.convert(),
|
ad5680::SPI_CLOCK_MHZ.convert(),
|
||||||
&clocks,
|
&clocks,
|
||||||
|
@ -147,7 +136,8 @@ pub fn setup(
|
||||||
});
|
});
|
||||||
|
|
||||||
let ad7172_phy = ad7172::Adc::new(
|
let ad7172_phy = ad7172::Adc::new(
|
||||||
Spi::new(spi3,
|
Spi::new(
|
||||||
|
spi3,
|
||||||
(
|
(
|
||||||
gpioc.pc10.into_alternate(),
|
gpioc.pc10.into_alternate(),
|
||||||
gpioc.pc11.into_alternate(),
|
gpioc.pc11.into_alternate(),
|
||||||
|
@ -155,10 +145,20 @@ pub fn setup(
|
||||||
),
|
),
|
||||||
ad7172::SPI_MODE,
|
ad7172::SPI_MODE,
|
||||||
ad7172::SPI_CLOCK_MHZ.convert(),
|
ad7172::SPI_CLOCK_MHZ.convert(),
|
||||||
&clocks
|
&clocks,
|
||||||
),
|
),
|
||||||
gpioa.pa15.into_push_pull_output(),
|
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,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 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<Input>,
|
pub h0: PE8<Input>,
|
||||||
pub h1: PE9<Input>,
|
pub h1: PE9<Input>,
|
||||||
pub h2: PE10<Input>,
|
pub h2: PE10<Input>,
|
||||||
|
@ -18,19 +19,21 @@ pub struct HWRev {
|
||||||
impl HWRev {
|
impl HWRev {
|
||||||
pub fn detect_hw_rev(hwrev_pins: HwRevPins) -> Self {
|
pub fn detect_hw_rev(hwrev_pins: HwRevPins) -> Self {
|
||||||
let (h0, h1, h2, h3) = (
|
let (h0, h1, h2, h3) = (
|
||||||
hwrev_pins.h0.is_high(), hwrev_pins.h1.is_high(),
|
hwrev_pins.h0.is_high(),
|
||||||
hwrev_pins.h2.is_high(), hwrev_pins.h3.is_high()
|
hwrev_pins.h1.is_high(),
|
||||||
|
hwrev_pins.h2.is_high(),
|
||||||
|
hwrev_pins.h3.is_high(),
|
||||||
);
|
);
|
||||||
match (h0, h1, h2, h3) {
|
match (h0, h1, h2, h3) {
|
||||||
(true, true, true, true) => HWRev { major: 0, minor: 3 },
|
(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
|
/// 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
|
/// 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 {
|
if self.major == 0 && self.minor == 3 {
|
||||||
sleep(5000);
|
sleep(5000);
|
||||||
}
|
}
|
||||||
|
@ -54,7 +57,7 @@ impl HWRev {
|
||||||
digest.update(&uid_data);
|
digest.update(&uid_data);
|
||||||
let crc24 = digest.finalize();
|
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 {
|
} else {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,15 @@ pub fn init_log() {
|
||||||
use super::usb;
|
use super::usb;
|
||||||
static USB_LOGGER: usb::Logger = usb::Logger;
|
static USB_LOGGER: usb::Logger = usb::Logger;
|
||||||
let _ = log::set_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")]
|
#[cfg(feature = "RTT")]
|
||||||
pub fn init_log() {
|
pub fn init_log() {
|
||||||
use super::rtt_logger;
|
|
||||||
use rtt_target::rtt_init_print;
|
use rtt_target::rtt_init_print;
|
||||||
|
|
||||||
|
use super::rtt_logger;
|
||||||
static RTT_LOGGER: rtt_logger::Logger = rtt_logger::Logger;
|
static RTT_LOGGER: rtt_logger::Logger = rtt_logger::Logger;
|
||||||
rtt_init_print!();
|
rtt_init_print!();
|
||||||
let _ = log::set_logger(&RTT_LOGGER);
|
let _ = log::set_logger(&RTT_LOGGER);
|
||||||
|
@ -18,8 +20,8 @@ pub fn init_log() {
|
||||||
|
|
||||||
#[cfg(feature = "semihosting")]
|
#[cfg(feature = "semihosting")]
|
||||||
pub fn init_log() {
|
pub fn init_log() {
|
||||||
use cortex_m_log::log::{init, Logger};
|
use cortex_m_log::{log::{init, Logger},
|
||||||
use cortex_m_log::printer::semihosting::{hio::HStdout, InterruptOk};
|
printer::semihosting::{hio::HStdout, InterruptOk}};
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
static mut LOGGER: Option<Logger<InterruptOk<HStdout>>> = None;
|
static mut LOGGER: Option<Logger<InterruptOk<HStdout>>> = None;
|
||||||
let logger = Logger {
|
let logger = Logger {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
pub mod boot;
|
pub mod boot;
|
||||||
|
pub mod dfu;
|
||||||
|
pub mod flash_store;
|
||||||
pub mod gpio;
|
pub mod gpio;
|
||||||
|
pub mod hw_rev;
|
||||||
pub mod log_setup;
|
pub mod log_setup;
|
||||||
pub mod rtt_logger;
|
pub mod rtt_logger;
|
||||||
pub mod sys_timer;
|
pub mod sys_timer;
|
||||||
pub mod usb;
|
pub mod usb;
|
||||||
pub mod flash_store;
|
|
||||||
pub mod hw_rev;
|
|
||||||
pub mod dfu;
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use core::cell::RefCell;
|
use core::{cell::RefCell, ops::Deref};
|
||||||
use core::ops::Deref;
|
|
||||||
use cortex_m::interrupt::Mutex;
|
use cortex_m::{interrupt::Mutex, peripheral::syst::SystClkSource};
|
||||||
use cortex_m::peripheral::syst::SystClkSource;
|
|
||||||
use cortex_m_rt::exception;
|
use cortex_m_rt::exception;
|
||||||
use stm32f4xx_hal::{pac::SYST, rcc::Clocks};
|
use stm32f4xx_hal::{pac::SYST, rcc::Clocks};
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
use core::{
|
use core::{fmt::{self, Write},
|
||||||
fmt::{self, Write},
|
mem::MaybeUninit};
|
||||||
mem::MaybeUninit,
|
|
||||||
};
|
|
||||||
use cortex_m::interrupt::free;
|
use cortex_m::interrupt::free;
|
||||||
use log::{Log, Metadata, Record};
|
use log::{Log, Metadata, Record};
|
||||||
use stm32f4xx_hal::{
|
use stm32f4xx_hal::{otg_fs::{UsbBus as Bus, USB},
|
||||||
otg_fs::{UsbBus as Bus, USB},
|
pac::{interrupt, Interrupt, NVIC}};
|
||||||
pac::{interrupt, Interrupt, NVIC},
|
use usb_device::{class_prelude::UsbBusAllocator,
|
||||||
};
|
descriptor::lang_id,
|
||||||
use usb_device::{
|
device::StringDescriptors,
|
||||||
descriptor::lang_id,
|
prelude::{UsbDevice, UsbDeviceBuilder, UsbVidPid}};
|
||||||
device::StringDescriptors,
|
|
||||||
class_prelude::UsbBusAllocator,
|
|
||||||
prelude::{UsbDevice, UsbDeviceBuilder, UsbVidPid},
|
|
||||||
};
|
|
||||||
use usbd_serial::SerialPort;
|
use usbd_serial::SerialPort;
|
||||||
|
|
||||||
static mut EP_MEMORY: [u32; 1024] = [0; 1024];
|
static mut EP_MEMORY: [u32; 1024] = [0; 1024];
|
||||||
|
@ -41,7 +36,8 @@ impl State {
|
||||||
.device_release(0x20)
|
.device_release(0x20)
|
||||||
.self_powered(true)
|
.self_powered(true)
|
||||||
.device_class(usbd_serial::USB_CLASS_CDC)
|
.device_class(usbd_serial::USB_CLASS_CDC)
|
||||||
.strings(&[str_descriptor]).unwrap()
|
.strings(&[str_descriptor])
|
||||||
|
.unwrap()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
free(|_| unsafe {
|
free(|_| unsafe {
|
||||||
|
|
|
@ -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 core::marker::PhantomData;
|
||||||
use crate::device::sys_timer::sleep;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use uom::si::{
|
use miniconf::Tree;
|
||||||
electric_current::milliampere,
|
use serde::{Deserialize, Serialize};
|
||||||
f32::{ElectricPotential, ElectricCurrent, Power},
|
use stm32f4xx_hal::{pac::{ADC3, TIM2},
|
||||||
};
|
timer::CounterUs};
|
||||||
use uom::{si::{ISQ, SI, Quantity}, typenum::*};
|
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
|
// Volt / Ampere
|
||||||
pub type TransimpedanceUnit = Quantity<ISQ<P2, P1, N3, N2, Z0, Z0, Z0>, SI<f32>, f32>;
|
pub type TransimpedanceUnit = Quantity<ISQ<P2, P1, N3, N2, Z0, Z0, Z0>, SI<f32>, f32>;
|
||||||
// Ampere / Volt
|
// Ampere / Volt
|
||||||
type TransconductanceUnit = Quantity<ISQ<N2, N1, P3, P2, Z0, Z0, Z0>, SI<f32>, f32>;
|
type TransconductanceUnit = Quantity<ISQ<N2, N1, P3, P2, Z0, Z0, Z0>, SI<f32>, f32>;
|
||||||
|
|
||||||
impl Settings{
|
impl Settings {
|
||||||
pub const LD_CURRENT_MAX: ElectricCurrent = ElectricCurrent {
|
pub const LD_CURRENT_MAX: ElectricCurrent = ElectricCurrent {
|
||||||
dimension: PhantomData,
|
dimension: PhantomData,
|
||||||
units: PhantomData,
|
units: PhantomData,
|
||||||
|
@ -83,31 +82,40 @@ pub struct StatusReport {
|
||||||
term_status: Impedance,
|
term_status: Impedance,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LdDrive{
|
pub struct LdDrive {
|
||||||
ctrl: LdCtrl,
|
ctrl: LdCtrl,
|
||||||
settings: Settings,
|
settings: Settings,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LdDrive{
|
impl LdDrive {
|
||||||
pub fn new(current_source: LdCtrl, pins_adc: ADC3, tim2: CounterUs<TIM2>, phy: ld_pwr_exc_protector::LdPwrExcProtectorPhy)-> Self {
|
pub fn new(
|
||||||
|
current_source: LdCtrl,
|
||||||
|
pins_adc: ADC3,
|
||||||
|
tim2: CounterUs<TIM2>,
|
||||||
|
phy: ld_pwr_exc_protector::LdPwrExcProtectorPhy,
|
||||||
|
) -> Self {
|
||||||
LdPwrExcProtector::setup(pins_adc, phy);
|
LdPwrExcProtector::setup(pins_adc, phy);
|
||||||
LdCurrentOutCtrlTimer::setup(tim2);
|
LdCurrentOutCtrlTimer::setup(tim2);
|
||||||
|
|
||||||
LdDrive {
|
LdDrive {
|
||||||
ctrl: current_source,
|
ctrl: current_source,
|
||||||
settings: Settings::default()
|
settings: Settings::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup(&mut self) {
|
pub fn setup(&mut self) {
|
||||||
LdPwrExcProtector::pwr_off();
|
LdPwrExcProtector::pwr_off();
|
||||||
self.ctrl.set_i(ElectricCurrent::new::<milliampere>(0.0), Settings::LD_DRIVE_TRANSIMPEDANCE, Settings::DAC_OUT_V_MAX);
|
self.ctrl.set_i(
|
||||||
|
ElectricCurrent::new::<milliampere>(0.0),
|
||||||
|
Settings::LD_DRIVE_TRANSIMPEDANCE,
|
||||||
|
Settings::DAC_OUT_V_MAX,
|
||||||
|
);
|
||||||
self.set_ld_drive_current_limit(Settings::LD_CURRENT_MAX);
|
self.set_ld_drive_current_limit(Settings::LD_CURRENT_MAX);
|
||||||
LdCurrentOutCtrlTimer::reset();
|
LdCurrentOutCtrlTimer::reset();
|
||||||
self.ld_short();
|
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);
|
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;
|
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;
|
let prev_i_set = self.settings.ld_drive_current;
|
||||||
LdCurrentOutCtrlTimer::reset();
|
LdCurrentOutCtrlTimer::reset();
|
||||||
let _ = self.ctrl.set_i(ElectricCurrent::new::<milliampere>(0.0), Settings::LD_DRIVE_TRANSIMPEDANCE, Settings::DAC_OUT_V_MAX);
|
let _ = self.ctrl.set_i(
|
||||||
|
ElectricCurrent::new::<milliampere>(0.0),
|
||||||
|
Settings::LD_DRIVE_TRANSIMPEDANCE,
|
||||||
|
Settings::DAC_OUT_V_MAX,
|
||||||
|
);
|
||||||
// Wait for the DAC to reset its voltage back to 0V
|
// Wait for the DAC to reset its voltage back to 0V
|
||||||
sleep(35);
|
sleep(35);
|
||||||
LdPwrExcProtector::pwr_on_and_arm_protection();
|
LdPwrExcProtector::pwr_on_and_arm_protection();
|
||||||
|
@ -134,7 +146,7 @@ impl LdDrive{
|
||||||
self.settings.pwr_on = true;
|
self.settings.pwr_on = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn power_down(&mut self){
|
pub fn power_down(&mut self) {
|
||||||
LdPwrExcProtector::pwr_off();
|
LdPwrExcProtector::pwr_off();
|
||||||
self.settings.pwr_on = false;
|
self.settings.pwr_on = false;
|
||||||
}
|
}
|
||||||
|
@ -144,10 +156,12 @@ impl LdDrive{
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_pd_pwr(&mut self) -> Power {
|
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);
|
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());
|
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 {
|
pub fn poll_and_update_output_current(&mut self) -> ElectricCurrent {
|
||||||
match LdCurrentOutCtrlTimer::get_irq_status() {
|
match LdCurrentOutCtrlTimer::get_irq_status() {
|
||||||
Some(i_set) => {
|
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();
|
LdCurrentOutCtrlTimer::clear_alarm_and_resume_listening();
|
||||||
i_set
|
i_set
|
||||||
}
|
}
|
||||||
None => {
|
None => ElectricCurrent::new::<ampere>(0.0),
|
||||||
ElectricCurrent::new::<ampere>(0.0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,26 +188,26 @@ impl LdDrive{
|
||||||
LdPwrExcProtector::clear_alarm_status();
|
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);
|
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);
|
self.settings.pd_mon_params.set_i_dark(i_dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_ld_power_limit(&mut self, pwr_limit: Power){
|
pub fn set_ld_power_limit(&mut self, pwr_limit: Power) {
|
||||||
LdPwrExcProtector::set_trigger_threshold_v(self.settings.pd_mon_params
|
LdPwrExcProtector::set_trigger_threshold_v(
|
||||||
.get_ld_i_from_ld_pwr(pwr_limit) / Settings::PD_MON_TRANSCONDUCTANCE
|
self.settings.pd_mon_params.get_ld_i_from_ld_pwr(pwr_limit) / Settings::PD_MON_TRANSCONDUCTANCE,
|
||||||
);
|
);
|
||||||
self.settings.ld_pwr_limit = pwr_limit;
|
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);
|
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;
|
self.settings.default_pwr_on = pwr_on;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,8 +235,14 @@ impl LdDrive{
|
||||||
let settings = self.settings;
|
let settings = self.settings;
|
||||||
LdSettingsSummary {
|
LdSettingsSummary {
|
||||||
default_pwr_on: self.settings.default_pwr_on,
|
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: LdSettingsSummaryField {
|
||||||
ld_drive_current_limit: LdSettingsSummaryField { value: settings.ld_drive_current_limit, max: Settings::LD_CURRENT_MAX},
|
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,
|
pd_mon_params: settings.pd_mon_params,
|
||||||
ld_pwr_limit: settings.ld_pwr_limit,
|
ld_pwr_limit: settings.ld_pwr_limit,
|
||||||
ld_terms_short: settings.ld_terms_short,
|
ld_terms_short: settings.ld_terms_short,
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use stm32f4xx_hal::{
|
use stm32f4xx_hal::{gpio::{gpioa::*, gpiob::*, gpiod::*, Input, Output, PushPull},
|
||||||
gpio::{gpioa::*, gpiob::*, gpiod::*, Input, Output, PushPull},
|
hal::{digital::{InputPin, OutputPin},
|
||||||
hal::{spi::SpiBus, digital::{OutputPin, InputPin}},
|
spi::SpiBus},
|
||||||
pac::SPI2,
|
pac::SPI2,
|
||||||
spi::Spi,
|
spi::Spi};
|
||||||
};
|
use uom::si::{electric_current::ampere,
|
||||||
|
f32::{ElectricCurrent, ElectricPotential},
|
||||||
|
ratio::ratio};
|
||||||
|
|
||||||
use uom::si::{
|
use crate::laser_diode::{laser_diode::TransimpedanceUnit,
|
||||||
ratio::ratio,
|
max5719::{self, Dac}};
|
||||||
f32::{ElectricPotential, ElectricCurrent},
|
|
||||||
electric_current::ampere,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::laser_diode::max5719::{self, Dac};
|
|
||||||
use crate::laser_diode::laser_diode::TransimpedanceUnit;
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug, Clone, Copy)]
|
#[derive(Deserialize, Serialize, Debug, Clone, Copy)]
|
||||||
pub enum Impedance {
|
pub enum Impedance {
|
||||||
|
@ -32,7 +28,7 @@ pub trait ChannelPins {
|
||||||
pub struct LdCtrlPhy<C: ChannelPins> {
|
pub struct LdCtrlPhy<C: ChannelPins> {
|
||||||
pub dac: Dac<C::Max5719Spi, C::Max5719Cs, C::Max5719Load>,
|
pub dac: Dac<C::Max5719Spi, C::Max5719Cs, C::Max5719Load>,
|
||||||
pub current_source_short_pin: C::CurrentSourceShort,
|
pub current_source_short_pin: C::CurrentSourceShort,
|
||||||
pub termination_status_pin: C::TerminationStatus
|
pub termination_status_pin: C::TerminationStatus,
|
||||||
}
|
}
|
||||||
pub struct Channel0;
|
pub struct Channel0;
|
||||||
|
|
||||||
|
@ -48,7 +44,7 @@ type DacSpi = Spi<SPI2>;
|
||||||
type DacCs = PD8<Output<PushPull>>;
|
type DacCs = PD8<Output<PushPull>>;
|
||||||
type DacLoad = PB14<Output<PushPull>>;
|
type DacLoad = PB14<Output<PushPull>>;
|
||||||
|
|
||||||
pub struct LdCtrl{
|
pub struct LdCtrl {
|
||||||
pub phy: LdCtrlPhy<Channel0>,
|
pub phy: LdCtrlPhy<Channel0>,
|
||||||
i_set: ElectricCurrent,
|
i_set: ElectricCurrent,
|
||||||
}
|
}
|
||||||
|
@ -57,7 +53,7 @@ impl LdCtrl {
|
||||||
pub fn new(phy_ch0: LdCtrlPhy<Channel0>) -> Self {
|
pub fn new(phy_ch0: LdCtrlPhy<Channel0>) -> Self {
|
||||||
LdCtrl {
|
LdCtrl {
|
||||||
phy: phy_ch0,
|
phy: phy_ch0,
|
||||||
i_set: ElectricCurrent::new::<ampere>(0.0)
|
i_set: ElectricCurrent::new::<ampere>(0.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,28 +67,31 @@ impl LdCtrl {
|
||||||
self.phy.current_source_short_pin.set_high();
|
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() {
|
if self.phy.termination_status_pin.is_high() {
|
||||||
Impedance::Is50Ohm
|
Impedance::Is50Ohm
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Impedance::Not50Ohm
|
Impedance::Not50Ohm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_dac(&mut self, voltage: ElectricPotential, dac_out_v_max: ElectricPotential) -> ElectricPotential {
|
pub fn set_dac(&mut self, voltage: ElectricPotential, dac_out_v_max: ElectricPotential) -> ElectricPotential {
|
||||||
let value = ((voltage / dac_out_v_max).get::<ratio>()
|
let value = ((voltage / dac_out_v_max).get::<ratio>() * (max5719::MAX_VALUE as f32)) as u32;
|
||||||
* (max5719::MAX_VALUE as f32)) as u32;
|
|
||||||
self.phy.dac.set(value).unwrap();
|
self.phy.dac.set(value).unwrap();
|
||||||
value as f32 * dac_out_v_max / max5719::MAX_VALUE as f32
|
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 = self.set_dac(current * transimpedance, dac_out_v_max) / transimpedance;
|
||||||
self.i_set
|
self.i_set
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_i_set(&mut self) -> ElectricCurrent{
|
pub fn get_i_set(&mut self) -> ElectricCurrent {
|
||||||
self.i_set
|
self.i_set
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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 core::marker::PhantomData;
|
||||||
|
|
||||||
|
use fugit::{KilohertzU32, TimerDurationU32};
|
||||||
use log::debug;
|
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 {
|
pub struct LdCurrentOutCtrlTimer {
|
||||||
target_i: ElectricCurrent,
|
target_i: ElectricCurrent,
|
||||||
|
@ -32,14 +33,12 @@ impl LdCurrentOutCtrlTimer {
|
||||||
cortex_m::peripheral::NVIC::unmask(Interrupt::TIM2);
|
cortex_m::peripheral::NVIC::unmask(Interrupt::TIM2);
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
LD_CURRENT_OUT_CTRL_TIMER = Some(
|
LD_CURRENT_OUT_CTRL_TIMER = Some(LdCurrentOutCtrlTimer {
|
||||||
LdCurrentOutCtrlTimer {
|
target_i: ElectricCurrent::new::<ampere>(0.0),
|
||||||
target_i: ElectricCurrent::new::<ampere>(0.0),
|
now_i: ElectricCurrent::new::<ampere>(0.0),
|
||||||
now_i: ElectricCurrent::new::<ampere>(0.0),
|
timer: tim2,
|
||||||
timer: tim2,
|
timeout: false,
|
||||||
timeout: false
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +47,7 @@ impl LdCurrentOutCtrlTimer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset() {
|
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::<ampere>(0.0);
|
ld_current_out_ctrl_timer.target_i = ElectricCurrent::new::<ampere>(0.0);
|
||||||
ld_current_out_ctrl_timer.now_i = ElectricCurrent::new::<ampere>(0.0);
|
ld_current_out_ctrl_timer.now_i = ElectricCurrent::new::<ampere>(0.0);
|
||||||
ld_current_out_ctrl_timer.timeout = false;
|
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) {
|
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(|_| {
|
cortex_m::interrupt::free(|_| {
|
||||||
ld_current_out_ctrl_timer.target_i = target;
|
ld_current_out_ctrl_timer.target_i = target;
|
||||||
ld_current_out_ctrl_timer.now_i = now;
|
ld_current_out_ctrl_timer.now_i = now;
|
||||||
ld_current_out_ctrl_timer.timer.listen(Event::Update);
|
ld_current_out_ctrl_timer.timer.listen(Event::Update);
|
||||||
}
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_alarm() {
|
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;
|
ld_current_out_ctrl_timer.timeout = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn clear_alarm_and_resume_listening() {
|
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.timeout = false;
|
||||||
ld_current_out_ctrl_timer.timer.listen(Event::Update);
|
ld_current_out_ctrl_timer.timer.listen(Event::Update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn get_irq_status() -> Option<ElectricCurrent> {
|
pub fn get_irq_status() -> Option<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() {
|
||||||
if ld_current_out_ctrl_timer.timeout {
|
if ld_current_out_ctrl_timer.timeout {
|
||||||
return Some(ld_current_out_ctrl_timer.now_i);
|
return Some(ld_current_out_ctrl_timer.now_i);
|
||||||
}
|
}
|
||||||
|
@ -88,37 +86,40 @@ impl LdCurrentOutCtrlTimer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_irq_flag() {
|
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() {
|
match ld_current_out_ctrl_timer.timer.wait() {
|
||||||
Ok(_) => {}
|
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 {
|
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;
|
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 {
|
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 {
|
return update;
|
||||||
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
|
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stop_listening() {
|
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);
|
ld_current_out_ctrl_timer.timer.unlisten(Event::Update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
fn TIM2(){
|
fn TIM2() {
|
||||||
if LdCurrentOutCtrlTimer::update_next_i_set() {
|
if LdCurrentOutCtrlTimer::update_next_i_set() {
|
||||||
LdCurrentOutCtrlTimer::set_alarm();
|
LdCurrentOutCtrlTimer::set_alarm();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,8 @@
|
||||||
use stm32f4xx_hal::pac;
|
use stm32f4xx_hal::{gpio::{gpioa::PA3, gpiod::PD9, Analog, Output, PushPull},
|
||||||
use stm32f4xx_hal::rcc::Enable;
|
interrupt, pac,
|
||||||
use stm32f4xx_hal::{
|
pac::{ADC3, NVIC},
|
||||||
pac::{ADC3, NVIC},
|
rcc::Enable};
|
||||||
gpio::{Analog, Output, PushPull, gpioa::PA3, gpiod::PD9},
|
use uom::si::{electric_potential::millivolt, f32::ElectricPotential, ratio::ratio};
|
||||||
interrupt,
|
|
||||||
};
|
|
||||||
use uom::si::{
|
|
||||||
electric_potential::millivolt,
|
|
||||||
f32::ElectricPotential,
|
|
||||||
ratio::ratio
|
|
||||||
};
|
|
||||||
|
|
||||||
// 12 bit Resolution
|
// 12 bit Resolution
|
||||||
const MAX_SAMPLE: u16 = 4095;
|
const MAX_SAMPLE: u16 = 4095;
|
||||||
|
@ -22,7 +15,7 @@ static mut LD_PWR_EXC_PROTECTOR: Option<LdPwrExcProtector> = None;
|
||||||
pub struct LdPwrExcProtectorPhy {
|
pub struct LdPwrExcProtectorPhy {
|
||||||
// To make sure Pd Mon Pin is configured to Analog mode
|
// To make sure Pd Mon Pin is configured to Analog mode
|
||||||
pub _pd_mon_ch0: PdMonAdcPinType,
|
pub _pd_mon_ch0: PdMonAdcPinType,
|
||||||
pub pwr_en_ch0: LdPwrEnPinType,
|
pub pwr_en_ch0: LdPwrEnPinType,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -55,7 +48,7 @@ impl LdPwrExcProtector {
|
||||||
/// ADC Analog Watchdog is configured to guard a single regular Adc channel on Pd Mon Pin.
|
/// 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.
|
/// ADC is configured to start continuous conversion without using DMA immediately.
|
||||||
/// Interrupt is disabled by default.
|
/// Interrupt is disabled by default.
|
||||||
pub fn setup(pac_adc: ADC3, mut phy: LdPwrExcProtectorPhy){
|
pub fn setup(pac_adc: ADC3, mut phy: LdPwrExcProtectorPhy) {
|
||||||
unsafe {
|
unsafe {
|
||||||
// All ADCs share the same reset interface.
|
// All ADCs share the same reset interface.
|
||||||
// NOTE(unsafe) this reference will only be used for atomic writes with no side effects.
|
// NOTE(unsafe) this reference will only be used for atomic writes with no side effects.
|
||||||
|
@ -72,34 +65,46 @@ impl LdPwrExcProtector {
|
||||||
pac_adc.sqr2.reset();
|
pac_adc.sqr2.reset();
|
||||||
pac_adc.sqr3.reset();
|
pac_adc.sqr3.reset();
|
||||||
|
|
||||||
pac_adc.cr1.write(|w| w
|
pac_adc.cr1.write(|w| {
|
||||||
// 12 Bit Resolution
|
w
|
||||||
.res().twelve_bit()
|
// 12 Bit Resolution
|
||||||
// Set Analog Watchdog to guard Single Regular Channel
|
.res()
|
||||||
.awden().enabled()
|
.twelve_bit()
|
||||||
.awdsgl().single_channel()
|
// Set Analog Watchdog to guard Single Regular Channel
|
||||||
.jawden().disabled()
|
.awden()
|
||||||
// Disable Analog Watchdog Interrupt
|
.enabled()
|
||||||
.awdie().disabled()
|
.awdsgl()
|
||||||
// Set Analog Watchdog to monitor Pd Mon Pin
|
.single_channel()
|
||||||
.awdch().variant(PD_MON_ADC_CH_ID)
|
.jawden()
|
||||||
);
|
.disabled()
|
||||||
pac_adc.cr2.write(|w| w
|
// Disable Analog Watchdog Interrupt
|
||||||
// Continous Conversion Mode
|
.awdie()
|
||||||
.cont().set_bit()
|
.disabled()
|
||||||
// Power up ADC
|
// Set Analog Watchdog to monitor Pd Mon Pin
|
||||||
.adon().set_bit()
|
.awdch()
|
||||||
// Set data alignment to the right
|
.variant(PD_MON_ADC_CH_ID)
|
||||||
.align().right()
|
});
|
||||||
// End of conversion selection: Each Sequence
|
pac_adc.cr2.write(|w| {
|
||||||
.eocs().each_sequence()
|
w
|
||||||
.exten().disabled()
|
// Continous Conversion Mode
|
||||||
.extsel().tim1cc1()
|
.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
|
// Set the Conversion Sequence to include Pd Mon Pin
|
||||||
pac_adc.sqr3.write(|w| w
|
pac_adc.sqr3.write(|w| w.sq1().variant(PD_MON_ADC_CH_ID));
|
||||||
.sq1().variant(PD_MON_ADC_CH_ID)
|
|
||||||
);
|
|
||||||
// Set all sampling channels to have fastest sampling interval
|
// Set all sampling channels to have fastest sampling interval
|
||||||
pac_adc.smpr1.reset();
|
pac_adc.smpr1.reset();
|
||||||
pac_adc.smpr2.reset();
|
pac_adc.smpr2.reset();
|
||||||
|
@ -110,21 +115,17 @@ impl LdPwrExcProtector {
|
||||||
pac_adc.ltr.write(|w| w.lt().variant(0));
|
pac_adc.ltr.write(|w| w.lt().variant(0));
|
||||||
|
|
||||||
// SWStart should only be set when ADON = 1. Otherwise no conversion is launched.
|
// SWStart should only be set when ADON = 1. Otherwise no conversion is launched.
|
||||||
pac_adc.cr2.modify(|_, w| w
|
pac_adc.cr2.modify(|_, w| w.swstart().set_bit());
|
||||||
.swstart().set_bit()
|
|
||||||
);
|
|
||||||
|
|
||||||
phy.pwr_en_ch0.set_low();
|
phy.pwr_en_ch0.set_low();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
LD_PWR_EXC_PROTECTOR = Some(
|
LD_PWR_EXC_PROTECTOR = Some(LdPwrExcProtector {
|
||||||
LdPwrExcProtector {
|
pac: pac_adc,
|
||||||
pac: pac_adc,
|
phy: phy,
|
||||||
phy: phy,
|
alarm_status: Status::default(),
|
||||||
alarm_status: Status::default(),
|
calibrated_vdda: 3300,
|
||||||
calibrated_vdda: 3300,
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,36 +133,39 @@ impl LdPwrExcProtector {
|
||||||
unsafe { LD_PWR_EXC_PROTECTOR.as_mut() }
|
unsafe { LD_PWR_EXC_PROTECTOR.as_mut() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_sample_to_volt(sample :u16) -> ElectricPotential {
|
fn convert_sample_to_volt(sample: u16) -> ElectricPotential {
|
||||||
if let Some(ref mut wdg ) = LdPwrExcProtector::get() {
|
if let Some(ref mut wdg) = LdPwrExcProtector::get() {
|
||||||
return ElectricPotential::new::<millivolt>(((u32::from(sample) * wdg.calibrated_vdda) / u32::from(MAX_SAMPLE)) as f32)
|
return ElectricPotential::new::<millivolt>(
|
||||||
|
((u32::from(sample) * wdg.calibrated_vdda) / u32::from(MAX_SAMPLE)) as f32,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
ElectricPotential::new::<millivolt>(0.0)
|
ElectricPotential::new::<millivolt>(0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_trigger_threshold_v(htr: ElectricPotential){
|
pub fn set_trigger_threshold_v(htr: ElectricPotential) {
|
||||||
if let Some(ref mut wdg ) = LdPwrExcProtector::get() {
|
if let Some(ref mut wdg) = LdPwrExcProtector::get() {
|
||||||
let code: u32 = ((htr / (ElectricPotential::new::<millivolt>(wdg.calibrated_vdda as f32))).get::<ratio>() * (MAX_SAMPLE as f32)) as u32;
|
let code: u32 = ((htr / (ElectricPotential::new::<millivolt>(wdg.calibrated_vdda as f32))).get::<ratio>()
|
||||||
wdg.pac.htr.write(|w| unsafe {w.bits(code)});
|
* (MAX_SAMPLE as f32)) as u32;
|
||||||
|
wdg.pac.htr.write(|w| unsafe { w.bits(code) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_calibrated_vdda(val: u32) {
|
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;
|
wdg.calibrated_vdda = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_status() -> Status {
|
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());
|
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()
|
Status::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pwr_on_and_arm_protection(){
|
pub fn pwr_on_and_arm_protection() {
|
||||||
if let Some(ref mut wdg ) = LdPwrExcProtector::get() {
|
if let Some(ref mut wdg) = LdPwrExcProtector::get() {
|
||||||
wdg.alarm_status = Status::default();
|
wdg.alarm_status = Status::default();
|
||||||
LdPwrExcProtector::pwr_on();
|
LdPwrExcProtector::pwr_on();
|
||||||
// Interrupt should be enabled after power on to tackle the following edge case:
|
// Interrupt should be enabled after power on to tackle the following edge case:
|
||||||
|
@ -170,53 +174,47 @@ impl LdPwrExcProtector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_alarm_status(){
|
pub fn clear_alarm_status() {
|
||||||
if let Some(ref mut wdg ) = LdPwrExcProtector::get() {
|
if let Some(ref mut wdg) = LdPwrExcProtector::get() {
|
||||||
wdg.alarm_status.pwr_excursion = false;
|
wdg.alarm_status.pwr_excursion = false;
|
||||||
wdg.alarm_status.v_tripped = ElectricPotential::new::<millivolt>(0.0);
|
wdg.alarm_status.v_tripped = ElectricPotential::new::<millivolt>(0.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enable_watchdog_interrupt(){
|
fn enable_watchdog_interrupt() {
|
||||||
if let Some(ref mut wdg ) = LdPwrExcProtector::get() {
|
if let Some(ref mut wdg) = LdPwrExcProtector::get() {
|
||||||
wdg.pac.cr1.modify(|_, w| w
|
wdg.pac.cr1.modify(|_, w| w.awdie().set_bit());
|
||||||
.awdie().set_bit()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disable_watchdog_interrupt(){
|
fn disable_watchdog_interrupt() {
|
||||||
if let Some(ref mut wdg ) = LdPwrExcProtector::get() {
|
if let Some(ref mut wdg) = LdPwrExcProtector::get() {
|
||||||
wdg.pac.cr1.modify(|_, w| w
|
wdg.pac.cr1.modify(|_, w| w.awdie().clear_bit());
|
||||||
.awdie().clear_bit()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_interrupt_bit(){
|
fn clear_interrupt_bit() {
|
||||||
if let Some(ref mut wdg ) = LdPwrExcProtector::get() {
|
if let Some(ref mut wdg) = LdPwrExcProtector::get() {
|
||||||
wdg.pac.sr.modify(|_, w| w
|
wdg.pac.sr.modify(|_, w| w.awd().clear_bit());
|
||||||
.awd().clear_bit()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pwr_on(){
|
fn pwr_on() {
|
||||||
if let Some(ref mut wdg ) = LdPwrExcProtector::get() {
|
if let Some(ref mut wdg) = LdPwrExcProtector::get() {
|
||||||
wdg.alarm_status.pwr_engaged = true;
|
wdg.alarm_status.pwr_engaged = true;
|
||||||
wdg.phy.pwr_en_ch0.set_high()
|
wdg.phy.pwr_en_ch0.set_high()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pwr_off(){
|
pub fn pwr_off() {
|
||||||
if let Some(ref mut wdg ) = LdPwrExcProtector::get() {
|
if let Some(ref mut wdg) = LdPwrExcProtector::get() {
|
||||||
wdg.alarm_status.pwr_engaged = false;
|
wdg.alarm_status.pwr_engaged = false;
|
||||||
wdg.phy.pwr_en_ch0.set_low()
|
wdg.phy.pwr_en_ch0.set_low()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pwr_excursion_handler(){
|
fn pwr_excursion_handler() {
|
||||||
if let Some(ref mut wdg ) = LdPwrExcProtector::get() {
|
if let Some(ref mut wdg) = LdPwrExcProtector::get() {
|
||||||
let sample = wdg.pac.dr.read().data().bits();
|
let sample = wdg.pac.dr.read().data().bits();
|
||||||
LdPwrExcProtector::pwr_off();
|
LdPwrExcProtector::pwr_off();
|
||||||
wdg.alarm_status.pwr_excursion = true;
|
wdg.alarm_status.pwr_excursion = true;
|
||||||
|
@ -226,12 +224,11 @@ impl LdPwrExcProtector {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
fn ADC(){
|
fn ADC() {
|
||||||
cortex_m::interrupt::free(|_| {
|
cortex_m::interrupt::free(|_| {
|
||||||
LdPwrExcProtector::pwr_excursion_handler();
|
LdPwrExcProtector::pwr_excursion_handler();
|
||||||
// Disable interrupt to avoid getting stuck in infinite loop
|
// Disable interrupt to avoid getting stuck in infinite loop
|
||||||
LdPwrExcProtector::disable_watchdog_interrupt();
|
LdPwrExcProtector::disable_watchdog_interrupt();
|
||||||
LdPwrExcProtector::clear_interrupt_bit();
|
LdPwrExcProtector::clear_interrupt_bit();
|
||||||
}
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
use crate::device::sys_timer::sleep;
|
|
||||||
use fugit::MegahertzU32;
|
use fugit::MegahertzU32;
|
||||||
use stm32f4xx_hal::{
|
use stm32f4xx_hal::{hal::{digital::OutputPin, spi::SpiBus},
|
||||||
hal::{spi::SpiBus, digital::OutputPin},
|
spi};
|
||||||
spi,
|
|
||||||
};
|
use crate::device::sys_timer::sleep;
|
||||||
|
|
||||||
pub const SPI_MODE: spi::Mode = spi::Mode {
|
pub const SPI_MODE: spi::Mode = spi::Mode {
|
||||||
polarity: spi::Polarity::IdleLow,
|
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 const MAX_VALUE: u32 = 0xFFFFF;
|
||||||
|
|
||||||
pub struct Dac<SPI: SpiBus<u8>, S1: OutputPin, S2:OutputPin> {
|
pub struct Dac<SPI: SpiBus<u8>, S1: OutputPin, S2: OutputPin> {
|
||||||
spi: SPI,
|
spi: SPI,
|
||||||
cs_n: S1,
|
cs_n: S1,
|
||||||
load_n: S2,
|
load_n: S2,
|
||||||
|
@ -25,7 +24,7 @@ impl<SPI: SpiBus<u8>, S1: OutputPin, S2: OutputPin> Dac<SPI, S1, S2> {
|
||||||
let _ = cs_n.set_high();
|
let _ = cs_n.set_high();
|
||||||
let _ = load_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> {
|
fn write(&mut self, buf: &mut [u8]) -> Result<(), SPI::Error> {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
pub mod ld_ctrl;
|
|
||||||
pub mod max5719;
|
|
||||||
pub mod laser_diode;
|
pub mod laser_diode;
|
||||||
pub mod pd_mon_params;
|
pub mod ld_ctrl;
|
||||||
pub mod ld_pwr_exc_protector;
|
|
||||||
pub mod ld_current_out_ctrl_timer;
|
pub mod ld_current_out_ctrl_timer;
|
||||||
|
pub mod ld_pwr_exc_protector;
|
||||||
|
pub mod max5719;
|
||||||
|
pub mod pd_mon_params;
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
use core::{f32::NAN, marker::PhantomData};
|
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 miniconf::Tree;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use uom::{si::{electric_current::microampere,
|
||||||
|
f32::{ElectricCurrent, Power},
|
||||||
|
Quantity, ISQ, SI},
|
||||||
|
typenum::*};
|
||||||
|
|
||||||
// Ampere / Watt
|
// Ampere / Watt
|
||||||
pub type ResponsitivityUnit = Quantity<ISQ<N2, N1, P3, P1, Z0, Z0, Z0>, SI<f32>, f32>;
|
pub type ResponsitivityUnit = Quantity<ISQ<N2, N1, P3, P1, Z0, Z0, Z0>, SI<f32>, f32>;
|
||||||
|
@ -42,7 +39,11 @@ impl Parameters {
|
||||||
impl Default for Parameters {
|
impl Default for Parameters {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Parameters {
|
Parameters {
|
||||||
responsitivity: ResponsitivityUnit {dimension: PhantomData, units: PhantomData, value: NAN},
|
responsitivity: ResponsitivityUnit {
|
||||||
|
dimension: PhantomData,
|
||||||
|
units: PhantomData,
|
||||||
|
value: NAN,
|
||||||
|
},
|
||||||
i_dark: ElectricCurrent::new::<microampere>(0.0),
|
i_dark: ElectricCurrent::new::<microampere>(0.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
60
src/main.rs
60
src/main.rs
|
@ -2,22 +2,24 @@
|
||||||
#![cfg_attr(not(test), no_std)]
|
#![cfg_attr(not(test), no_std)]
|
||||||
|
|
||||||
use cortex_m_rt::entry;
|
use cortex_m_rt::entry;
|
||||||
use log::{info, debug};
|
use log::{debug, info};
|
||||||
use stm32f4xx_hal::pac::{CorePeripherals, Peripherals};
|
use stm32f4xx_hal::pac::{CorePeripherals, Peripherals};
|
||||||
mod device;
|
mod device;
|
||||||
mod laser_diode;
|
mod laser_diode;
|
||||||
mod thermostat;
|
|
||||||
mod net;
|
mod net;
|
||||||
|
mod thermostat;
|
||||||
|
|
||||||
use core::ptr::addr_of_mut;
|
use core::ptr::addr_of_mut;
|
||||||
|
|
||||||
use device::{boot::bootup, log_setup, sys_timer};
|
use device::{boot::bootup, log_setup, sys_timer};
|
||||||
use crate::net::net::IpSettings;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use stm32f4xx_hal::pac::SCB;
|
use stm32f4xx_hal::pac::SCB;
|
||||||
|
|
||||||
// If RTT is used, print panic info through RTT
|
// If RTT is used, print panic info through RTT
|
||||||
#[cfg(all(feature = "RTT", not(test)))]
|
#[cfg(all(feature = "RTT", not(test)))]
|
||||||
use {core::panic::PanicInfo, rtt_target::rprintln};
|
use {core::panic::PanicInfo, rtt_target::rprintln};
|
||||||
|
|
||||||
|
use crate::net::net::IpSettings;
|
||||||
|
|
||||||
#[cfg(all(feature = "RTT", not(test)))]
|
#[cfg(all(feature = "RTT", not(test)))]
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &PanicInfo) -> ! {
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
|
@ -31,7 +33,7 @@ use panic_halt as _;
|
||||||
static mut ETH_DATA_BUFFER: [u8; 1024] = [0; 1024];
|
static mut ETH_DATA_BUFFER: [u8; 1024] = [0; 1024];
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Clone, Copy, Debug)]
|
#[derive(Deserialize, Serialize, Clone, Copy, Debug)]
|
||||||
pub struct DeviceSettings{
|
pub struct DeviceSettings {
|
||||||
ip_settings: IpSettings,
|
ip_settings: IpSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,22 +59,22 @@ fn main() -> ! {
|
||||||
let core_perif = CorePeripherals::take().unwrap();
|
let core_perif = CorePeripherals::take().unwrap();
|
||||||
let perif = Peripherals::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 {
|
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 active_report: [bool; net::net::NUM_OF_SOCKETS] = [false; net::net::NUM_OF_SOCKETS];
|
||||||
|
|
||||||
let mut state = State::default();
|
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 {
|
loop {
|
||||||
wd.feed();
|
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];
|
active_report = [false; net::net::NUM_OF_SOCKETS];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,31 +155,42 @@ fn main() -> ! {
|
||||||
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 net::net::eth_is_socket_active(socket) && net::net::eth_is_socket_connected(socket) {
|
||||||
if active_report[id] {
|
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;
|
active_report[id] = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
thermostat.start_tec_readings_conversion();
|
thermostat.start_tec_readings_conversion();
|
||||||
}
|
}
|
||||||
cortex_m::interrupt::free(|cs|
|
cortex_m::interrupt::free(|cs| {
|
||||||
{
|
eth_is_pending = net::net::is_pending(cs);
|
||||||
eth_is_pending = net::net::is_pending(cs);
|
net::net::clear_pending(cs);
|
||||||
net::net::clear_pending(cs);
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
if eth_is_pending {
|
if eth_is_pending {
|
||||||
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 net::net::eth_is_socket_active(socket) && net::net::eth_is_socket_connected(socket) {
|
||||||
let bytes = net::net::eth_recv(eth_data_buffer, socket);
|
let bytes = net::net::eth_recv(eth_data_buffer, socket);
|
||||||
if bytes != 0 {
|
if bytes != 0 {
|
||||||
info!("Ts: {:?}", sys_timer::now());
|
info!("Ts: {:?}", sys_timer::now());
|
||||||
debug!("Number of bytes recv: {:?}", bytes);
|
debug!("Number of bytes recv: {:?}", bytes);
|
||||||
// State Transition
|
// 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],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -232,7 +245,12 @@ fn main() -> ! {
|
||||||
thermostat.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) {
|
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,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,24 @@
|
||||||
use core::{fmt::Debug, marker::PhantomData};
|
use core::{fmt::Debug, marker::PhantomData};
|
||||||
|
|
||||||
|
use log::{debug, info};
|
||||||
use miniconf::{JsonCoreSlash, Tree};
|
use miniconf::{JsonCoreSlash, Tree};
|
||||||
use serde::{Deserialize, Serialize};
|
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 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)]
|
#[derive(Deserialize, Serialize, Copy, Clone, Default, Debug)]
|
||||||
pub enum ResponseEnum {
|
pub enum ResponseEnum {
|
||||||
|
@ -42,19 +40,19 @@ pub struct Response<'a> {
|
||||||
msg: Option<&'a str>,
|
msg: Option<&'a str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Response<'static>{
|
impl Default for Response<'static> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Response{
|
Response {
|
||||||
msg_type: ResponseEnum:: Reserved,
|
msg_type: ResponseEnum::Reserved,
|
||||||
msg: None,
|
msg: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
||||||
pub struct ResponseObj<'a>{
|
pub struct ResponseObj<'a> {
|
||||||
#[serde(borrow)]
|
#[serde(borrow)]
|
||||||
json: Response<'a>
|
json: Response<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Copy, Clone, Default, Debug)]
|
#[derive(Deserialize, Serialize, Copy, Clone, Default, Debug)]
|
||||||
|
@ -124,7 +122,7 @@ enum ThermostatCmdEnum {
|
||||||
SetShBeta,
|
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_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_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";
|
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";
|
const ERR_MSG_MISSING_SINC3FINEODR: &str = "Required field \"sinc3fineodr\" does not exist";
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Default, Tree)]
|
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Default, Tree)]
|
||||||
pub struct CmdJsonObj{
|
pub struct CmdJsonObj {
|
||||||
laser_diode_cmd: Option<LdCmdEnum>,
|
laser_diode_cmd: Option<LdCmdEnum>,
|
||||||
thermostat_cmd: Option<ThermostatCmdEnum>,
|
thermostat_cmd: Option<ThermostatCmdEnum>,
|
||||||
device_cmd: Option<DeviceCmd>,
|
device_cmd: Option<DeviceCmd>,
|
||||||
|
@ -146,7 +144,7 @@ pub struct CmdJsonObj{
|
||||||
}
|
}
|
||||||
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Default, Tree)]
|
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Default, Tree)]
|
||||||
pub struct Cmd {
|
pub struct Cmd {
|
||||||
json: CmdJsonObj
|
json: CmdJsonObj,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
||||||
|
@ -159,7 +157,7 @@ pub struct StatusReport {
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
||||||
pub struct StatusReportObj {
|
pub struct StatusReportObj {
|
||||||
json: StatusReport
|
json: StatusReport,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
||||||
|
@ -171,15 +169,15 @@ pub struct SettingsSummary {
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
||||||
pub struct SettingsSummaryObj {
|
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 {
|
let response = ResponseObj {
|
||||||
json: Response {
|
json: Response {
|
||||||
msg_type: msg_type,
|
msg_type: msg_type,
|
||||||
msg: msg,
|
msg: msg,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
debug!("{:?}", response.json);
|
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);
|
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 {
|
let settings_summary = SettingsSummaryObj {
|
||||||
json: SettingsSummary {
|
json: SettingsSummary {
|
||||||
msg_type: ResponseEnum::Settings,
|
msg_type: ResponseEnum::Settings,
|
||||||
laser: laser.get_settings_summary(),
|
laser: laser.get_settings_summary(),
|
||||||
thermostat: thermostat.get_settings_summary(),
|
thermostat: thermostat.get_settings_summary(),
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
let mut num_bytes = settings_summary.get_json("/json", buffer).unwrap();
|
let mut num_bytes = settings_summary.get_json("/json", buffer).unwrap();
|
||||||
buffer[num_bytes] = b'\n';
|
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);
|
net::eth_send(buffer, num_bytes, *socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn send_status_report(
|
||||||
pub fn send_status_report(buffer: &mut [u8], laser: &mut LdDrive, thermostat: &mut Thermostat, socket: &mut SocketHandle){
|
buffer: &mut [u8],
|
||||||
|
laser: &mut LdDrive,
|
||||||
|
thermostat: &mut Thermostat,
|
||||||
|
socket: &mut SocketHandle,
|
||||||
|
) {
|
||||||
let status_report = StatusReportObj {
|
let status_report = StatusReportObj {
|
||||||
json: StatusReport {
|
json: StatusReport {
|
||||||
ts: sys_timer::now(),
|
ts: sys_timer::now(),
|
||||||
msg_type: ResponseEnum::Report,
|
msg_type: ResponseEnum::Report,
|
||||||
laser: laser.get_status_report(),
|
laser: laser.get_status_report(),
|
||||||
thermostat: thermostat.get_status_report(),
|
thermostat: thermostat.get_status_report(),
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
let mut num_bytes = status_report.get_json("/json", buffer).unwrap();
|
let mut num_bytes = status_report.get_json("/json", buffer).unwrap();
|
||||||
buffer[num_bytes] = b'\n';
|
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
|
// Use a minimal struct for high speed cmd ctrl to reduce processing overhead
|
||||||
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Default, Tree)]
|
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Default, Tree)]
|
||||||
pub struct TecSetICmdJson {
|
pub struct TecSetICmdJson {
|
||||||
tec_set_i: f32
|
tec_set_i: f32,
|
||||||
}
|
}
|
||||||
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Default, Tree)]
|
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Default, Tree)]
|
||||||
pub struct TecSetICmd {
|
pub struct TecSetICmd {
|
||||||
json: TecSetICmdJson
|
json: TecSetICmdJson,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Miniconf is very slow in debug builds (~3-4ms of cmd decoding time).
|
/// Miniconf is very slow in debug builds (~3-4ms of cmd decoding time).
|
||||||
/// Make sure kirdy's firmware is flashed with release builds.
|
/// 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.
|
/// 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 {
|
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(_) => {
|
Ok(_) => {
|
||||||
thermostat.set_i(ElectricCurrent::new::<ampere>(cmd.json.tec_set_i));
|
thermostat.set_i(ElectricCurrent::new::<ampere>(cmd.json.tec_set_i));
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Err(_) => { /* Do Nothing */}
|
Err(_) => { /* Do Nothing */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut cmd = Cmd {
|
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(_) => {
|
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!("############ Thermostat Command Received {:?}", cmd.json.thermostat_cmd);
|
||||||
info!("############ Device Command Received {:?}", cmd.json.device_cmd);
|
info!("############ Device Command Received {:?}", cmd.json.device_cmd);
|
||||||
|
|
||||||
match cmd.json.device_cmd {
|
match cmd.json.device_cmd {
|
||||||
Some(DeviceCmd::SetIPSettings) => {
|
Some(DeviceCmd::SetIPSettings) => match cmd.json.ip_settings {
|
||||||
match cmd.json.ip_settings {
|
Some(val) => {
|
||||||
Some(val) => {
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
device_settings.ip_settings = val;
|
||||||
device_settings.ip_settings = val;
|
*state = State::SaveDeviceSettings;
|
||||||
*state = State::SaveDeviceSettings;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_IP_SETTINGS), socket);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
None => {
|
||||||
|
send_response(
|
||||||
|
buffer,
|
||||||
|
ResponseEnum::InvalidDatatype,
|
||||||
|
Some(ERR_MSG_MISSING_IP_SETTINGS),
|
||||||
|
socket,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
Some(DeviceCmd::Dfu) => {
|
Some(DeviceCmd::Dfu) => {
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -275,17 +297,20 @@ pub fn execute_cmd(buffer: &mut [u8], buffer_size: usize, socket: &mut SocketHan
|
||||||
}
|
}
|
||||||
*state = State::HardReset;
|
*state = State::HardReset;
|
||||||
}
|
}
|
||||||
Some(DeviceCmd::SetActiveReportMode) => {
|
Some(DeviceCmd::SetActiveReportMode) => match cmd.json.data_bool {
|
||||||
match cmd.json.data_bool{
|
Some(val) => {
|
||||||
Some(val) => {
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
*active_report = val;
|
||||||
*active_report = val;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_BOOL), socket);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
None => {
|
||||||
|
send_response(
|
||||||
|
buffer,
|
||||||
|
ResponseEnum::InvalidDatatype,
|
||||||
|
Some(ERR_MSG_MISSING_DATA_BOOL),
|
||||||
|
socket,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
Some(DeviceCmd::GetStatusReport) => {
|
Some(DeviceCmd::GetStatusReport) => {
|
||||||
send_status_report(buffer, laser, thermostat, socket);
|
send_status_report(buffer, laser, thermostat, socket);
|
||||||
}
|
}
|
||||||
|
@ -304,7 +329,7 @@ pub fn execute_cmd(buffer: &mut [u8], buffer_size: usize, socket: &mut SocketHan
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
*state = State::PrepareForHardReset;
|
*state = State::PrepareForHardReset;
|
||||||
}
|
}
|
||||||
None => { /* Do Nothing */}
|
None => { /* Do Nothing */ }
|
||||||
_ => {
|
_ => {
|
||||||
send_response(buffer, ResponseEnum::InvalidCmd, None, socket);
|
send_response(buffer, ResponseEnum::InvalidCmd, None, socket);
|
||||||
debug!("Unimplemented Command")
|
debug!("Unimplemented Command")
|
||||||
|
@ -312,18 +337,20 @@ pub fn execute_cmd(buffer: &mut [u8], buffer_size: usize, socket: &mut SocketHan
|
||||||
}
|
}
|
||||||
|
|
||||||
match cmd.json.laser_diode_cmd {
|
match cmd.json.laser_diode_cmd {
|
||||||
Some(LdCmdEnum::SetDefaultPowerOn) => {
|
Some(LdCmdEnum::SetDefaultPowerOn) => match cmd.json.data_bool {
|
||||||
match cmd.json.data_bool {
|
Some(val) => {
|
||||||
Some(val) => {
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
laser.set_default_pwr_on(val);
|
||||||
laser.set_default_pwr_on(val);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_BOOL), socket);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
None => {
|
||||||
}
|
send_response(
|
||||||
|
buffer,
|
||||||
|
ResponseEnum::InvalidDatatype,
|
||||||
|
Some(ERR_MSG_MISSING_DATA_BOOL),
|
||||||
|
socket,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
Some(LdCmdEnum::PowerUp) => {
|
Some(LdCmdEnum::PowerUp) => {
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
laser.power_up()
|
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);
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
laser.ld_open();
|
laser.ld_open();
|
||||||
}
|
}
|
||||||
Some(LdCmdEnum::SetI) => {
|
Some(LdCmdEnum::SetI) => match cmd.json.data_f32 {
|
||||||
match cmd.json.data_f32 {
|
Some(val) => {
|
||||||
Some(val) => {
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
laser.ld_set_i(ElectricCurrent::new::<ampere>(val));
|
||||||
laser.ld_set_i(ElectricCurrent::new::<ampere>(val));
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
None => {
|
||||||
Some(LdCmdEnum::SetISoftLimit) => {
|
send_response(
|
||||||
match cmd.json.data_f32 {
|
buffer,
|
||||||
Some(val) => {
|
ResponseEnum::InvalidDatatype,
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
Some(ERR_MSG_MISSING_DATA_F32),
|
||||||
laser.set_ld_drive_current_limit(ElectricCurrent::new::<ampere>(val))
|
socket,
|
||||||
}
|
);
|
||||||
None => {
|
|
||||||
send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Some(LdCmdEnum::SetPdResponsitivity) => {
|
Some(LdCmdEnum::SetISoftLimit) => match cmd.json.data_f32 {
|
||||||
match cmd.json.data_f32 {
|
Some(val) => {
|
||||||
Some(val) => {
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
laser.set_ld_drive_current_limit(ElectricCurrent::new::<ampere>(val))
|
||||||
laser.set_pd_responsitivity(ResponsitivityUnit {dimension: PhantomData, units: PhantomData, value: val})
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
None => {
|
||||||
Some(LdCmdEnum::SetPdDarkCurrent) => {
|
send_response(
|
||||||
match cmd.json.data_f32 {
|
buffer,
|
||||||
Some(val) => {
|
ResponseEnum::InvalidDatatype,
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
Some(ERR_MSG_MISSING_DATA_F32),
|
||||||
laser.set_pd_dark_current(ElectricCurrent::new::<ampere>(val))
|
socket,
|
||||||
}
|
);
|
||||||
None => {
|
|
||||||
send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Some(LdCmdEnum::SetLdPwrLimit) => {
|
Some(LdCmdEnum::SetPdResponsitivity) => match cmd.json.data_f32 {
|
||||||
match cmd.json.data_f32 {
|
Some(val) => {
|
||||||
Some(val) => {
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
laser.set_pd_responsitivity(ResponsitivityUnit {
|
||||||
laser.set_ld_power_limit(Power::new::<watt>(val))
|
dimension: PhantomData,
|
||||||
}
|
units: PhantomData,
|
||||||
None => {
|
value: val,
|
||||||
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::SetPdDarkCurrent) => match cmd.json.data_f32 {
|
||||||
|
Some(val) => {
|
||||||
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
|
laser.set_pd_dark_current(ElectricCurrent::new::<ampere>(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::<watt>(val))
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
send_response(
|
||||||
|
buffer,
|
||||||
|
ResponseEnum::InvalidDatatype,
|
||||||
|
Some(ERR_MSG_MISSING_DATA_F32),
|
||||||
|
socket,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
Some(LdCmdEnum::ClearAlarm) => {
|
Some(LdCmdEnum::ClearAlarm) => {
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
laser.pd_mon_clear_alarm()
|
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 {
|
match cmd.json.thermostat_cmd {
|
||||||
Some(ThermostatCmdEnum::SetDefaultPowerOn) => {
|
Some(ThermostatCmdEnum::SetDefaultPowerOn) => match cmd.json.data_bool {
|
||||||
match cmd.json.data_bool {
|
Some(val) => {
|
||||||
Some(val) => {
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
thermostat.set_default_pwr_on(val);
|
||||||
thermostat.set_default_pwr_on(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::PowerUp) => {
|
Some(ThermostatCmdEnum::PowerUp) => {
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
thermostat.power_up()
|
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);
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
thermostat.power_down()
|
thermostat.power_down()
|
||||||
}
|
}
|
||||||
Some(ThermostatCmdEnum::SetTecMaxV) => {
|
Some(ThermostatCmdEnum::SetTecMaxV) => match cmd.json.data_f32 {
|
||||||
match cmd.json.data_f32 {
|
Some(val) => {
|
||||||
Some(val) => {
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
thermostat.set_max_v(ElectricPotential::new::<volt>(val));
|
||||||
thermostat.set_max_v(ElectricPotential::new::<volt>(val));
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
None => {
|
||||||
Some(ThermostatCmdEnum::SetTecMaxIPos) => {
|
send_response(
|
||||||
match cmd.json.data_f32 {
|
buffer,
|
||||||
Some(val) => {
|
ResponseEnum::InvalidDatatype,
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
Some(ERR_MSG_MISSING_DATA_F32),
|
||||||
thermostat.set_max_i_pos(ElectricCurrent::new::<ampere>(val));
|
socket,
|
||||||
}
|
);
|
||||||
None => {
|
|
||||||
send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Some(ThermostatCmdEnum::SetTecMaxINeg) => {
|
Some(ThermostatCmdEnum::SetTecMaxIPos) => match cmd.json.data_f32 {
|
||||||
match cmd.json.data_f32 {
|
Some(val) => {
|
||||||
Some(val) => {
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
thermostat.set_max_i_pos(ElectricCurrent::new::<ampere>(val));
|
||||||
thermostat.set_max_i_pos(ElectricCurrent::new::<ampere>(val));
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
None => {
|
||||||
Some(ThermostatCmdEnum::SetTecIOut) => {
|
send_response(
|
||||||
match cmd.json.data_f32 {
|
buffer,
|
||||||
Some(val) => {
|
ResponseEnum::InvalidDatatype,
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
Some(ERR_MSG_MISSING_DATA_F32),
|
||||||
thermostat.set_i(ElectricCurrent::new::<ampere>(val));
|
socket,
|
||||||
}
|
);
|
||||||
None => {
|
|
||||||
send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Some(ThermostatCmdEnum::SetTemperatureSetpoint) => {
|
Some(ThermostatCmdEnum::SetTecMaxINeg) => match cmd.json.data_f32 {
|
||||||
match cmd.json.data_f32 {
|
Some(val) => {
|
||||||
Some(val) => {
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
thermostat.set_max_i_pos(ElectricCurrent::new::<ampere>(val));
|
||||||
thermostat.set_temperature_setpoint(ThermodynamicTemperature::new::<degree_celsius>(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::SetTecIOut) => match cmd.json.data_f32 {
|
||||||
|
Some(val) => {
|
||||||
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
|
thermostat.set_i(ElectricCurrent::new::<ampere>(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::<degree_celsius>(val));
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
send_response(
|
||||||
|
buffer,
|
||||||
|
ResponseEnum::InvalidDatatype,
|
||||||
|
Some(ERR_MSG_MISSING_DATA_F32),
|
||||||
|
socket,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
Some(ThermostatCmdEnum::SetPidEngage) => {
|
Some(ThermostatCmdEnum::SetPidEngage) => {
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
thermostat.set_pid_engaged(true);
|
thermostat.set_pid_engaged(true);
|
||||||
|
@ -489,179 +553,222 @@ pub fn execute_cmd(buffer: &mut [u8], buffer_size: usize, socket: &mut SocketHan
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
thermostat.set_pid_engaged(false);
|
thermostat.set_pid_engaged(false);
|
||||||
}
|
}
|
||||||
Some(ThermostatCmdEnum::SetPidKp) => {
|
Some(ThermostatCmdEnum::SetPidKp) => match cmd.json.data_f32 {
|
||||||
match cmd.json.data_f32 {
|
Some(val) => {
|
||||||
Some(val) => {
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
thermostat.set_pid(Kp, val);
|
||||||
thermostat.set_pid(Kp, val);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
None => {
|
||||||
Some(ThermostatCmdEnum::SetPidKi) => {
|
send_response(
|
||||||
match cmd.json.data_f32 {
|
buffer,
|
||||||
Some(val) => {
|
ResponseEnum::InvalidDatatype,
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
Some(ERR_MSG_MISSING_DATA_F32),
|
||||||
thermostat.set_pid(Ki, val);
|
socket,
|
||||||
}
|
);
|
||||||
None => {
|
|
||||||
send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Some(ThermostatCmdEnum::SetPidKd) => {
|
Some(ThermostatCmdEnum::SetPidKi) => match cmd.json.data_f32 {
|
||||||
match cmd.json.data_f32 {
|
Some(val) => {
|
||||||
Some(val) => {
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
thermostat.set_pid(Ki, val);
|
||||||
thermostat.set_pid(Kd, val);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
None => {
|
||||||
Some(ThermostatCmdEnum::SetPidOutMin) => {
|
send_response(
|
||||||
match cmd.json.data_f32 {
|
buffer,
|
||||||
Some(val) => {
|
ResponseEnum::InvalidDatatype,
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
Some(ERR_MSG_MISSING_DATA_F32),
|
||||||
thermostat.set_pid(Min, val);
|
socket,
|
||||||
}
|
);
|
||||||
None => {
|
|
||||||
send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Some(ThermostatCmdEnum::SetPidOutMax) => {
|
Some(ThermostatCmdEnum::SetPidKd) => match cmd.json.data_f32 {
|
||||||
match cmd.json.data_f32 {
|
Some(val) => {
|
||||||
Some(val) => {
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
thermostat.set_pid(Kd, val);
|
||||||
thermostat.set_pid(Max, 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::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) => {
|
Some(ThermostatCmdEnum::SetPidUpdateInterval) => {
|
||||||
send_response(buffer, ResponseEnum::InvalidCmd, None, socket);
|
send_response(buffer, ResponseEnum::InvalidCmd, None, socket);
|
||||||
debug!("Not supported Yet")
|
debug!("Not supported Yet")
|
||||||
}
|
}
|
||||||
Some(ThermostatCmdEnum::ConfigTempAdcFilter) => {
|
Some(ThermostatCmdEnum::ConfigTempAdcFilter) => match cmd.json.temp_adc_filter {
|
||||||
match cmd.json.temp_adc_filter {
|
Some(val) => match val.filter_type {
|
||||||
Some(val) => {
|
FilterType::Sinc5Sinc1With50hz60HzRejection => match val.sinc5sinc1postfilter {
|
||||||
match val.filter_type {
|
Some(val2) => {
|
||||||
FilterType::Sinc5Sinc1With50hz60HzRejection => {
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
match val.sinc5sinc1postfilter {
|
thermostat.set_temp_adc_sinc5_sinc1_with_postfilter(0, val2);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
None => {
|
||||||
None => {
|
send_response(
|
||||||
send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_TEMP_ADC_FILTER), socket);
|
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) => {
|
Some(ThermostatCmdEnum::SetTempMonUpperLimit) => match cmd.json.data_f32 {
|
||||||
match cmd.json.data_f32 {
|
Some(val) => {
|
||||||
Some(val) => {
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
thermostat.set_temp_mon_upper_limit(ThermodynamicTemperature::new::<degree_celsius>(val));
|
||||||
thermostat.set_temp_mon_upper_limit(ThermodynamicTemperature::new::<degree_celsius>(val));
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
None => {
|
||||||
Some(ThermostatCmdEnum::SetTempMonLowerLimit) => {
|
send_response(
|
||||||
match cmd.json.data_f32 {
|
buffer,
|
||||||
Some(val) => {
|
ResponseEnum::InvalidDatatype,
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
Some(ERR_MSG_MISSING_DATA_F32),
|
||||||
thermostat.set_temp_mon_lower_limit(ThermodynamicTemperature::new::<degree_celsius>(val));
|
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::<degree_celsius>(val));
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
send_response(
|
||||||
|
buffer,
|
||||||
|
ResponseEnum::InvalidDatatype,
|
||||||
|
Some(ERR_MSG_MISSING_DATA_F32),
|
||||||
|
socket,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
Some(ThermostatCmdEnum::ClearAlarm) => {
|
Some(ThermostatCmdEnum::ClearAlarm) => {
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
thermostat.clear_temp_mon_alarm();
|
thermostat.clear_temp_mon_alarm();
|
||||||
}
|
}
|
||||||
Some(ThermostatCmdEnum::SetShT0) => {
|
Some(ThermostatCmdEnum::SetShT0) => match cmd.json.data_f32 {
|
||||||
match cmd.json.data_f32 {
|
Some(val) => {
|
||||||
Some(val) => {
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
thermostat.set_sh_t0(ThermodynamicTemperature::new::<degree_celsius>(val));
|
||||||
thermostat.set_sh_t0(ThermodynamicTemperature::new::<degree_celsius>(val));
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
None => {
|
||||||
Some(ThermostatCmdEnum::SetShR0) => {
|
send_response(
|
||||||
match cmd.json.data_f32 {
|
buffer,
|
||||||
Some(val) => {
|
ResponseEnum::InvalidDatatype,
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
Some(ERR_MSG_MISSING_DATA_F32),
|
||||||
thermostat.set_sh_r0(ElectricalResistance::new::<ohm>(val));
|
socket,
|
||||||
}
|
);
|
||||||
None => {
|
|
||||||
send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_F32), socket);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Some(ThermostatCmdEnum::SetShBeta) => {
|
Some(ThermostatCmdEnum::SetShR0) => match cmd.json.data_f32 {
|
||||||
match cmd.json.data_f32 {
|
Some(val) => {
|
||||||
Some(val) => {
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
thermostat.set_sh_r0(ElectricalResistance::new::<ohm>(val));
|
||||||
thermostat.set_sh_beta(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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
None => { /* Do Nothing*/ }
|
None => { /* Do Nothing*/ }
|
||||||
_ => {
|
_ => {
|
||||||
send_response(buffer, ResponseEnum::InvalidCmd, None, socket);
|
send_response(buffer, ResponseEnum::InvalidCmd, None, socket);
|
||||||
|
@ -669,6 +776,7 @@ pub fn execute_cmd(buffer: &mut [u8], buffer_size: usize, socket: &mut SocketHan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
|
info!("cmd_recv: {:?}", buffer);
|
||||||
send_response(buffer, ResponseEnum::InvalidCmd, None, socket);
|
send_response(buffer, ResponseEnum::InvalidCmd, None, socket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
pub mod net;
|
|
||||||
pub mod cmd_handler;
|
pub mod cmd_handler;
|
||||||
|
pub mod net;
|
||||||
|
|
179
src/net/net.rs
179
src/net/net.rs
|
@ -1,25 +1,21 @@
|
||||||
use crate::device::sys_timer;
|
use core::{cell::RefCell,
|
||||||
use core::mem::{self, MaybeUninit};
|
mem::{self, MaybeUninit}};
|
||||||
use core::cell::RefCell;
|
|
||||||
use cortex_m::interrupt::{CriticalSection, Mutex};
|
use cortex_m::interrupt::{CriticalSection, Mutex};
|
||||||
use log::{debug, info};
|
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 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)]
|
#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
|
||||||
pub struct IpSettings {
|
pub struct IpSettings {
|
||||||
|
@ -35,7 +31,7 @@ impl Default for IpSettings {
|
||||||
addr: [192, 168, 1, 128],
|
addr: [192, 168, 1, 128],
|
||||||
port: 1337,
|
port: 1337,
|
||||||
prefix_len: 24,
|
prefix_len: 24,
|
||||||
gateway: [192, 168, 1, 1]
|
gateway: [192, 168, 1, 1],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,28 +49,28 @@ pub struct ServerHandle {
|
||||||
phy: EthernetPhy<EthernetMACWithMii<Pin<'A', 2, Alternate<11>>, Pin<'C', 1, Alternate<11>>>>,
|
phy: EthernetPhy<EthernetMACWithMii<Pin<'A', 2, Alternate<11>>, Pin<'C', 1, Alternate<11>>>>,
|
||||||
link_was_up: bool,
|
link_was_up: bool,
|
||||||
}
|
}
|
||||||
pub type EthernetPins =
|
pub type EthernetPins = EthPins<PA1<Input>, PA7<Input>, PB11<Input>, PB12<Input>, PB13<Input>, PC4<Input>, PC5<Input>>;
|
||||||
EthPins<PA1<Input>, PA7<Input>, PB11<Input>, PB12<Input>, PB13<Input>, PC4<Input>, PC5<Input>>;
|
|
||||||
pub struct EthernetMgmtPins {
|
pub struct EthernetMgmtPins {
|
||||||
pub mdio: PA2<Alternate<11>>,
|
pub mdio: PA2<Alternate<11>>,
|
||||||
pub mdc: PC1<Alternate<11>>,
|
pub mdc: PC1<Alternate<11>>,
|
||||||
}
|
}
|
||||||
pub type EthInterface = Interface;
|
pub type EthInterface = Interface;
|
||||||
|
|
||||||
pub const NUM_OF_SOCKETS : usize = 4;
|
pub const NUM_OF_SOCKETS: usize = 4;
|
||||||
const TCP_BUFFER_SIZE: usize = 2048;
|
const TCP_BUFFER_SIZE: usize = 4096;
|
||||||
static mut RX_RING: Option<[RxRingEntry; 8]> = None;
|
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;
|
static mut SOCKET_STORAGE: Option<[SocketStorage<'static>; NUM_OF_SOCKETS]> = None;
|
||||||
|
|
||||||
fn now_fn() -> smoltcp::time::Instant {
|
fn now_fn() -> smoltcp::time::Instant {
|
||||||
Instant::from_millis(i64::from(sys_timer::now()))
|
Instant::from_millis(i64::from(sys_timer::now()))
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut SERVER_HANDLE : Option<ServerHandle> = None;
|
static mut SERVER_HANDLE: Option<ServerHandle> = None;
|
||||||
|
|
||||||
impl ServerHandle {
|
impl ServerHandle {
|
||||||
pub fn new (eth_pins: EthernetPins,
|
pub fn new(
|
||||||
|
eth_pins: EthernetPins,
|
||||||
eth_mgmt_pins: EthernetMgmtPins,
|
eth_mgmt_pins: EthernetMgmtPins,
|
||||||
ethernet_parts_in: PartsIn,
|
ethernet_parts_in: PartsIn,
|
||||||
clocks: Clocks,
|
clocks: Clocks,
|
||||||
|
@ -85,23 +81,24 @@ impl ServerHandle {
|
||||||
let tx_ring = unsafe { TX_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 socket_storage = unsafe { SOCKET_STORAGE.get_or_insert([SocketStorage::EMPTY; NUM_OF_SOCKETS]) };
|
||||||
|
|
||||||
let Parts {
|
let Parts { mut dma, mac, .. } = stm32_eth::new_with_mii(
|
||||||
mut dma,
|
|
||||||
mac,
|
|
||||||
#[cfg(feature = "ptp")]
|
|
||||||
..
|
|
||||||
} = stm32_eth::new_with_mii(
|
|
||||||
ethernet_parts_in,
|
ethernet_parts_in,
|
||||||
&mut rx_ring[..],
|
&mut rx_ring[..],
|
||||||
&mut tx_ring[..],
|
&mut tx_ring[..],
|
||||||
clocks,
|
clocks,
|
||||||
eth_pins,
|
eth_pins,
|
||||||
eth_mgmt_pins.mdio,
|
eth_mgmt_pins.mdio,
|
||||||
eth_mgmt_pins.mdc
|
eth_mgmt_pins.mdc,
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let ip_init = IpCidr::Ipv4(Ipv4Cidr::new(
|
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,
|
ip_settings.prefix_len,
|
||||||
));
|
));
|
||||||
let socket_addr: (IpAddress, u16) = (
|
let socket_addr: (IpAddress, u16) = (
|
||||||
|
@ -116,7 +113,12 @@ impl ServerHandle {
|
||||||
|
|
||||||
let mut routes = smoltcp::iface::Routes::new();
|
let mut routes = smoltcp::iface::Routes::new();
|
||||||
routes
|
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();
|
.ok();
|
||||||
dma.enable_interrupt();
|
dma.enable_interrupt();
|
||||||
|
|
||||||
|
@ -134,20 +136,18 @@ impl ServerHandle {
|
||||||
let tcp_handles = {
|
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
|
// remind developers to create/remove tcp_handles accordingly after changing NUM_OF_SOCKETS
|
||||||
let mut tcp_handles: [MaybeUninit<SocketHandle>; 4]= unsafe {
|
let mut tcp_handles: [MaybeUninit<SocketHandle>; 4] = unsafe { MaybeUninit::uninit().assume_init() };
|
||||||
MaybeUninit::uninit().assume_init()
|
|
||||||
};
|
|
||||||
|
|
||||||
macro_rules! create_tcp_handle {
|
macro_rules! create_tcp_handle {
|
||||||
($rx_storage:ident, $tx_storage:ident, $handle:expr) => {
|
($rx_storage:ident, $tx_storage:ident, $handle:expr) => {
|
||||||
static mut $rx_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];
|
static mut $tx_storage: [u8; TCP_BUFFER_SIZE] = [0; TCP_BUFFER_SIZE];
|
||||||
unsafe {
|
unsafe {
|
||||||
let rx_buffer = SocketBuffer::new(&mut $rx_storage[..]);
|
let rx_buffer = SocketBuffer::new(&mut $rx_storage[..]);
|
||||||
let tx_buffer = SocketBuffer::new(&mut $tx_storage[..]);
|
let tx_buffer = SocketBuffer::new(&mut $tx_storage[..]);
|
||||||
$handle.write(socket_set.add(Socket::new(rx_buffer, tx_buffer)));
|
$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_STORAGE0, TX_STORAGE0, tcp_handles[0]);
|
||||||
create_tcp_handle!(RX_STORAGE1, TX_STORAGE1, tcp_handles[1]);
|
create_tcp_handle!(RX_STORAGE1, TX_STORAGE1, tcp_handles[1]);
|
||||||
|
@ -164,13 +164,14 @@ impl ServerHandle {
|
||||||
socket.set_nagle_enabled(false);
|
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) {
|
if let Ok(mut phy) = EthernetPhy::from_miim(mac, 0) {
|
||||||
info!(
|
info!("Resetting PHY as an extra step. Type: {}", phy.ident_string());
|
||||||
"Resetting PHY as an extra step. Type: {}",
|
|
||||||
phy.ident_string()
|
|
||||||
);
|
|
||||||
|
|
||||||
phy.phy_init();
|
phy.phy_init();
|
||||||
|
|
||||||
|
@ -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 !self.link_was_up & self.phy.phy_link_up() {
|
||||||
if let Some(speed) = self.phy.speed().map(|s| match s {
|
if let Some(speed) = self.phy.speed().map(|s| match s {
|
||||||
PhySpeed::HalfDuplexBase10T => Speed::HalfDuplexBase10T,
|
PhySpeed::HalfDuplexBase10T => Speed::HalfDuplexBase10T,
|
||||||
|
@ -213,10 +214,14 @@ impl ServerHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll_iface(&mut self) {
|
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<usize, smoltcp::socket::tcp::RecvError> {
|
pub fn recv(
|
||||||
|
&mut self,
|
||||||
|
buffer: &mut [u8],
|
||||||
|
socket_handles: SocketHandle,
|
||||||
|
) -> Result<usize, smoltcp::socket::tcp::RecvError> {
|
||||||
let socket = self.socket_set.get_mut::<Socket>(socket_handles);
|
let socket = self.socket_set.get_mut::<Socket>(socket_handles);
|
||||||
|
|
||||||
socket.recv_slice(buffer)
|
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>(socket_handles);
|
let socket = self.socket_set.get_mut::<Socket>(socket_handles);
|
||||||
socket.state() == State::Established
|
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>(socket_handles);
|
let socket = self.socket_set.get_mut::<Socket>(socket_handles);
|
||||||
if !socket.is_listening() && !socket.is_open() || socket.state() == State::CloseWait {
|
if !socket.is_listening() && !socket.is_open() || socket.state() == State::CloseWait {
|
||||||
socket.abort();
|
socket.abort();
|
||||||
|
@ -255,14 +260,9 @@ impl ServerHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use ieee802_3_miim::{
|
use ieee802_3_miim::{phy::{lan87xxa::{LAN8720A, LAN8742A},
|
||||||
phy::{
|
BarePhy, PhySpeed, KSZ8081R},
|
||||||
lan87xxa::{LAN8720A, LAN8742A},
|
Miim, Pause, Phy};
|
||||||
BarePhy, KSZ8081R,
|
|
||||||
PhySpeed
|
|
||||||
},
|
|
||||||
Miim, Pause, Phy,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// An ethernet PHY
|
/// An ethernet PHY
|
||||||
pub enum EthernetPhy<M: Miim> {
|
pub enum EthernetPhy<M: Miim> {
|
||||||
|
@ -359,7 +359,7 @@ impl<M: Miim> EthernetPhy<M> {
|
||||||
|
|
||||||
pub fn eth_poll_link_status_and_update_link_speed() -> bool {
|
pub fn eth_poll_link_status_and_update_link_speed() -> bool {
|
||||||
unsafe {
|
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();
|
let new_link_is_up = server_handle.update_link_speed();
|
||||||
if new_link_is_up {
|
if new_link_is_up {
|
||||||
info!("Resetting TCP Sockets");
|
info!("Resetting TCP Sockets");
|
||||||
|
@ -368,8 +368,7 @@ pub fn eth_poll_link_status_and_update_link_speed() -> bool {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return new_link_is_up;
|
return new_link_is_up;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
panic!("eth_poll_link_status_and_update_link_speed is called before init");
|
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() {
|
pub fn eth_poll_iface() {
|
||||||
unsafe {
|
unsafe {
|
||||||
if let Some(ref mut server_handle ) = SERVER_HANDLE {
|
if let Some(ref mut server_handle) = SERVER_HANDLE {
|
||||||
server_handle.poll_iface();
|
server_handle.poll_iface();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
panic!("eth_poll_packet is called before init");
|
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) {
|
pub fn eth_send(buffer: &mut [u8], num_bytes: usize, socket_handles: SocketHandle) {
|
||||||
unsafe {
|
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);
|
server_handle.send(buffer, num_bytes, socket_handles);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
panic!("eth_send is called before init");
|
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 {
|
unsafe {
|
||||||
if let Some(ref mut server_handle ) = SERVER_HANDLE {
|
if let Some(ref mut server_handle) = SERVER_HANDLE {
|
||||||
match server_handle.recv(buffer, socket_handles){
|
match server_handle.recv(buffer, socket_handles) {
|
||||||
Ok(recv_bytes) => {return recv_bytes}
|
Ok(recv_bytes) => return recv_bytes,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
debug!("TCP Recv Error: {}", err);
|
debug!("TCP Recv Error: {}", err);
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
panic!("eth_send is called before init");
|
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 {
|
pub fn eth_is_socket_connected(socket_handles: SocketHandle) -> bool {
|
||||||
unsafe {
|
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)
|
server_handle.is_socket_connected(socket_handles)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
panic!("eth_is_socket_connected is called before init");
|
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 {
|
pub fn eth_is_socket_active(socket_handles: SocketHandle) -> bool {
|
||||||
unsafe {
|
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)
|
server_handle.poll_socket_status(socket_handles)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
panic!("eth_is_socket_active is called before init");
|
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) {
|
pub fn eth_close_socket(socket_handles: SocketHandle) {
|
||||||
unsafe {
|
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)
|
server_handle.close_socket(socket_handles)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
panic!("eth_close_socket is called before init");
|
panic!("eth_close_socket is called before init");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -449,12 +442,11 @@ pub fn eth_close_socket(socket_handles: SocketHandle) {
|
||||||
|
|
||||||
pub fn for_each<F: FnMut(SocketHandle, usize)>(mut callback: F) {
|
pub fn for_each<F: FnMut(SocketHandle, usize)>(mut callback: F) {
|
||||||
unsafe {
|
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 {
|
for i in 0..NUM_OF_SOCKETS {
|
||||||
callback(server_handle.socket_handles[i], i);
|
callback(server_handle.socket_handles[i], i);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
panic!("eth_close_socket is called before init");
|
panic!("eth_close_socket is called before init");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -467,8 +459,7 @@ fn ETH() {
|
||||||
let interrupt_reason = stm32_eth::eth_interrupt_handler();
|
let interrupt_reason = stm32_eth::eth_interrupt_handler();
|
||||||
cortex_m::interrupt::free(|cs| {
|
cortex_m::interrupt::free(|cs| {
|
||||||
if interrupt_reason.rx {
|
if interrupt_reason.rx {
|
||||||
*NET_PENDING.borrow(cs)
|
*NET_PENDING.borrow(cs).borrow_mut() = true;
|
||||||
.borrow_mut() = true;
|
|
||||||
eth_poll_iface();
|
eth_poll_iface();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -477,13 +468,11 @@ fn ETH() {
|
||||||
|
|
||||||
/// Has an interrupt occurred since last call to `clear_pending()`?
|
/// Has an interrupt occurred since last call to `clear_pending()`?
|
||||||
pub fn is_pending(cs: &CriticalSection) -> bool {
|
pub fn is_pending(cs: &CriticalSection) -> bool {
|
||||||
*NET_PENDING.borrow(cs)
|
*NET_PENDING.borrow(cs).borrow()
|
||||||
.borrow()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clear the interrupt pending flag before polling the interface for
|
/// Clear the interrupt pending flag before polling the interface for
|
||||||
/// data.
|
/// data.
|
||||||
pub fn clear_pending(cs: &CriticalSection) {
|
pub fn clear_pending(cs: &CriticalSection) {
|
||||||
*NET_PENDING.borrow(cs)
|
*NET_PENDING.borrow(cs).borrow_mut() = false;
|
||||||
.borrow_mut() = false;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
use crate::device::sys_timer::sleep;
|
|
||||||
use fugit::MegahertzU32;
|
use fugit::MegahertzU32;
|
||||||
use stm32f4xx_hal::{
|
use stm32f4xx_hal::{hal::{digital::OutputPin, spi::SpiBus},
|
||||||
hal::{spi::SpiBus, digital::OutputPin},
|
spi};
|
||||||
spi,
|
|
||||||
};
|
use crate::device::sys_timer::sleep;
|
||||||
|
|
||||||
/// SPI Mode 1
|
/// SPI Mode 1
|
||||||
pub const SPI_MODE: spi::Mode = spi::Mode {
|
pub const SPI_MODE: spi::Mode = spi::Mode {
|
||||||
|
|
|
@ -1,22 +1,16 @@
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
use stm32f4xx_hal::
|
use stm32f4xx_hal::{gpio::{Output, PushPull, PA15},
|
||||||
{
|
hal::{digital::OutputPin, spi::SpiBus},
|
||||||
spi::Spi,
|
pac::SPI3,
|
||||||
pac::SPI3,
|
spi::Spi};
|
||||||
gpio::{PA15, Output, PushPull},
|
use uom::si::{electric_potential::volt, f32::ElectricPotential};
|
||||||
hal::{
|
|
||||||
spi::SpiBus,
|
use super::{checksum::{Checksum, ChecksumMode},
|
||||||
digital::OutputPin,
|
regs::{self, Register, RegisterData},
|
||||||
},
|
sinc3_fine_odr_closest, sinc3_fine_odr_output_rate, DigitalFilterOrder, FilterType, Input, Mode,
|
||||||
};
|
PostFilter, RefSource, SingleChODR};
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
/// AD7172-2 implementation
|
/// AD7172-2 implementation
|
||||||
///
|
///
|
||||||
|
@ -35,7 +29,8 @@ impl<SPI: SpiBus<u8, Error = E>, NSS: OutputPin, E: fmt::Debug> Adc<SPI, NSS> {
|
||||||
pub fn new(spi: SPI, mut nss: NSS) -> Result<Self, SPI::Error> {
|
pub fn new(spi: SPI, mut nss: NSS) -> Result<Self, SPI::Error> {
|
||||||
let _ = nss.set_high();
|
let _ = nss.set_high();
|
||||||
let mut adc = Adc {
|
let mut adc = Adc {
|
||||||
spi, nss,
|
spi,
|
||||||
|
nss,
|
||||||
checksum_mode: ChecksumMode::Off,
|
checksum_mode: ChecksumMode::Off,
|
||||||
};
|
};
|
||||||
adc.reset()?;
|
adc.reset()?;
|
||||||
|
@ -64,8 +59,7 @@ impl<SPI: SpiBus<u8, Error = E>, NSS: OutputPin, E: fmt::Debug> Adc<SPI, NSS> {
|
||||||
|
|
||||||
/// `0x00DX` for AD7172-2
|
/// `0x00DX` for AD7172-2
|
||||||
pub fn identify(&mut self) -> Result<u16, SPI::Error> {
|
pub fn identify(&mut self) -> Result<u16, SPI::Error> {
|
||||||
self.read_reg(®s::Id)
|
self.read_reg(®s::Id).map(|id| id.id())
|
||||||
.map(|id| id.id())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_checksum_mode(&mut self, mode: ChecksumMode) -> Result<(), SPI::Error> {
|
pub fn set_checksum_mode(&mut self, mode: ChecksumMode) -> Result<(), SPI::Error> {
|
||||||
|
@ -84,9 +78,7 @@ impl<SPI: SpiBus<u8, Error = E>, NSS: OutputPin, E: fmt::Debug> Adc<SPI, NSS> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup_channel(
|
pub fn setup_channel(&mut self, index: u8, in_pos: Input, in_neg: Input) -> Result<(), SPI::Error> {
|
||||||
&mut self, index: u8, in_pos: Input, in_neg: Input
|
|
||||||
) -> Result<(), SPI::Error> {
|
|
||||||
self.update_reg(®s::SetupCon { index }, |data| {
|
self.update_reg(®s::SetupCon { index }, |data| {
|
||||||
data.set_bipolar(false);
|
data.set_bipolar(false);
|
||||||
data.set_refbuf_pos(true);
|
data.set_refbuf_pos(true);
|
||||||
|
@ -127,29 +119,40 @@ impl<SPI: SpiBus<u8, Error = E>, NSS: OutputPin, E: fmt::Debug> Adc<SPI, NSS> {
|
||||||
pub fn get_filter_type_and_rate(&mut self, index: u8) -> Result<(FilterType, f32), SPI::Error> {
|
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 filter_type: FilterType = FilterType::Sinc5Sinc1With50hz60HzRejection;
|
||||||
let mut rate: f32 = -1.0;
|
let mut rate: f32 = -1.0;
|
||||||
self.read_reg(®s::FiltCon { index })
|
self.read_reg(®s::FiltCon { index }).map(|data| {
|
||||||
.map(|data| {
|
|
||||||
if data.sinc3_map() {
|
if data.sinc3_map() {
|
||||||
filter_type = FilterType::Sinc3WithFineODR;
|
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);
|
rate = sinc3_fine_odr_output_rate(odr);
|
||||||
} else if data.enh_filt_en() {
|
} else if data.enh_filt_en() {
|
||||||
filter_type = FilterType::Sinc5Sinc1With50hz60HzRejection;
|
filter_type = FilterType::Sinc5Sinc1With50hz60HzRejection;
|
||||||
match data.enh_filt().output_rate(){
|
match data.enh_filt().output_rate() {
|
||||||
Some(val) => { rate = val; }
|
Some(val) => {
|
||||||
None => { rate = -1.0; }
|
rate = val;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
rate = -1.0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} else if data.order() == DigitalFilterOrder::Sinc5Sinc1 {
|
} else if data.order() == DigitalFilterOrder::Sinc5Sinc1 {
|
||||||
filter_type = FilterType::Sinc5Sinc1;
|
filter_type = FilterType::Sinc5Sinc1;
|
||||||
match data.odr().output_rate(){
|
match data.odr().output_rate() {
|
||||||
Some(val) => { rate = val; }
|
Some(val) => {
|
||||||
None => { rate = -1.0; }
|
rate = val;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
rate = -1.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
filter_type = FilterType::Sinc3;
|
filter_type = FilterType::Sinc3;
|
||||||
match data.odr().output_rate(){
|
match data.odr().output_rate() {
|
||||||
Some(val) => { rate = val; }
|
Some(val) => {
|
||||||
None => { rate = -1.0; }
|
rate = val;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
rate = -1.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
@ -191,25 +194,19 @@ impl<SPI: SpiBus<u8, Error = E>, NSS: OutputPin, E: fmt::Debug> Adc<SPI, NSS> {
|
||||||
data.set_sinc3_map(true);
|
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_msb((sinc3_fine_odr_u16 >> 8 & 0xFF) as u8);
|
||||||
data.set_sinc3_map_fine_odr_lsb((sinc3_fine_odr_u16 & 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
|
/// Returns the channel the data is from
|
||||||
pub fn data_ready(&mut self) -> Result<Option<u8>, SPI::Error> {
|
pub fn data_ready(&mut self) -> Result<Option<u8>, SPI::Error> {
|
||||||
self.read_reg(®s::Status)
|
self.read_reg(®s::Status)
|
||||||
.map(|status| {
|
.map(|status| if status.ready() { Some(status.channel()) } else { None })
|
||||||
if status.ready() {
|
|
||||||
Some(status.channel())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get data
|
/// Get data
|
||||||
pub fn read_data(&mut self) -> Result<u32, SPI::Error> {
|
pub fn read_data(&mut self) -> Result<u32, SPI::Error> {
|
||||||
self.read_reg(®s::Data)
|
self.read_reg(®s::Data).map(|data| data.data())
|
||||||
.map(|data| data.data())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_reg<R: regs::Register>(&mut self, reg: &R) -> Result<R::Data, SPI::Error> {
|
fn read_reg<R: regs::Register>(&mut self, reg: &R) -> Result<R::Data, SPI::Error> {
|
||||||
|
@ -228,7 +225,12 @@ impl<SPI: SpiBus<u8, Error = E>, NSS: OutputPin, E: fmt::Debug> Adc<SPI, NSS> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Retry
|
// 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)
|
Ok(reg_data)
|
||||||
}
|
}
|
||||||
|
@ -254,7 +256,10 @@ impl<SPI: SpiBus<u8, Error = E>, NSS: OutputPin, E: fmt::Debug> Adc<SPI, NSS> {
|
||||||
if *readback_data == **reg_data {
|
if *readback_data == **reg_data {
|
||||||
return Ok(());
|
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<SPI: SpiBus<u8, Error = E>, NSS: OutputPin, E: fmt::Debug> Adc<SPI, NSS> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transfer<'w>(&mut self, addr: u8, reg_data: &'w mut [u8], checksum: Option<u8>) -> Result<Option<u8>, SPI::Error> {
|
fn transfer<'w>(
|
||||||
|
&mut self,
|
||||||
|
addr: u8,
|
||||||
|
reg_data: &'w mut [u8],
|
||||||
|
checksum: Option<u8>,
|
||||||
|
) -> Result<Option<u8>, SPI::Error> {
|
||||||
let mut addr_buf = [addr];
|
let mut addr_buf = [addr];
|
||||||
|
|
||||||
let _ = self.nss.set_low();
|
let _ = self.nss.set_low();
|
||||||
|
@ -287,8 +297,7 @@ impl<SPI: SpiBus<u8, Error = E>, NSS: OutputPin, E: fmt::Debug> Adc<SPI, NSS> {
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
};
|
};
|
||||||
let result = match (result, checksum) {
|
let result = match (result, checksum) {
|
||||||
(Ok(_), None) =>
|
(Ok(_), None) => Ok(None),
|
||||||
Ok(None),
|
|
||||||
(Ok(_), Some(checksum_out)) => {
|
(Ok(_), Some(checksum_out)) => {
|
||||||
let mut checksum_buf = [checksum_out; 1];
|
let mut checksum_buf = [checksum_out; 1];
|
||||||
match self.spi.transfer_in_place(&mut checksum_buf) {
|
match self.spi.transfer_in_place(&mut checksum_buf) {
|
||||||
|
@ -296,8 +305,7 @@ impl<SPI: SpiBus<u8, Error = E>, NSS: OutputPin, E: fmt::Debug> Adc<SPI, NSS> {
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Err(e), _) =>
|
(Err(e), _) => Err(e),
|
||||||
Err(e),
|
|
||||||
};
|
};
|
||||||
let _ = self.nss.set_high();
|
let _ = self.nss.set_high();
|
||||||
|
|
||||||
|
|
|
@ -29,13 +29,13 @@ impl Checksum {
|
||||||
|
|
||||||
fn feed_byte(&mut self, input: u8) {
|
fn feed_byte(&mut self, input: u8) {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
ChecksumMode::Off => {},
|
ChecksumMode::Off => {}
|
||||||
ChecksumMode::Xor => self.state ^= input,
|
ChecksumMode::Xor => self.state ^= input,
|
||||||
ChecksumMode::Crc => {
|
ChecksumMode::Crc => {
|
||||||
for i in 0..8 {
|
for i in 0..8 {
|
||||||
let input_mask = 0x80 >> i;
|
let input_mask = 0x80 >> i;
|
||||||
self.state = (self.state << 1) ^
|
self.state = (self.state << 1)
|
||||||
if ((self.state & 0x80) != 0) != ((input & input_mask) != 0) {
|
^ if ((self.state & 0x80) != 0) != ((input & input_mask) != 0) {
|
||||||
0x07 /* x8 + x2 + x + 1 */
|
0x07 /* x8 + x2 + x + 1 */
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
|
@ -54,7 +54,7 @@ impl Checksum {
|
||||||
pub fn result(&self) -> Option<u8> {
|
pub fn result(&self) -> Option<u8> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
ChecksumMode::Off => None,
|
ChecksumMode::Off => None,
|
||||||
_ => Some(self.state)
|
_ => Some(self.state),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use num_traits::float::Float;
|
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
use fugit::MegahertzU32;
|
use fugit::MegahertzU32;
|
||||||
|
use num_traits::float::Float;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use stm32f4xx_hal::spi;
|
use stm32f4xx_hal::spi;
|
||||||
|
|
||||||
pub mod regs;
|
|
||||||
mod checksum;
|
mod checksum;
|
||||||
|
pub mod regs;
|
||||||
pub use checksum::ChecksumMode;
|
pub use checksum::ChecksumMode;
|
||||||
mod adc;
|
mod adc;
|
||||||
pub use 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;
|
pub const MAX_VALUE: u32 = 0xFF_FFFF;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum Mode {
|
pub enum Mode {
|
||||||
|
@ -103,7 +103,8 @@ impl fmt::Display for Input {
|
||||||
RefPos => "ref+",
|
RefPos => "ref+",
|
||||||
RefNeg => "ref-",
|
RefNeg => "ref-",
|
||||||
_ => "<INVALID>",
|
_ => "<INVALID>",
|
||||||
}.fmt(fmt)
|
}
|
||||||
|
.fmt(fmt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +140,8 @@ impl fmt::Display for RefSource {
|
||||||
Internal => "internal",
|
Internal => "internal",
|
||||||
Avdd1MinusAvss => "avdd1-avss",
|
Avdd1MinusAvss => "avdd1-avss",
|
||||||
_ => "<INVALID>",
|
_ => "<INVALID>",
|
||||||
}.fmt(fmt)
|
}
|
||||||
|
.fmt(fmt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,9 +171,7 @@ impl PostFilter {
|
||||||
let mut best: Option<(f32, Self)> = None;
|
let mut best: Option<(f32, Self)> = None;
|
||||||
for value in Self::VALID_VALUES {
|
for value in Self::VALID_VALUES {
|
||||||
let error = (rate - value.output_rate().unwrap()).abs();
|
let error = (rate - value.output_rate().unwrap()).abs();
|
||||||
let better = best
|
let better = best.map(|(best_error, _)| error < best_error).unwrap_or(true);
|
||||||
.map(|(best_error, _)| error < best_error)
|
|
||||||
.unwrap_or(true);
|
|
||||||
if better {
|
if better {
|
||||||
best = Some((error, *value));
|
best = Some((error, *value));
|
||||||
}
|
}
|
||||||
|
@ -237,22 +237,22 @@ pub enum SingleChODR {
|
||||||
F31250_0SPS = 0b00101,
|
F31250_0SPS = 0b00101,
|
||||||
F15625_0SPS = 0b00110,
|
F15625_0SPS = 0b00110,
|
||||||
F10417_0SPS = 0b00111,
|
F10417_0SPS = 0b00111,
|
||||||
F5208_0SPS = 0b01000,
|
F5208_0SPS = 0b01000,
|
||||||
F2597_0SPS = 0b01001,
|
F2597_0SPS = 0b01001,
|
||||||
F1007_0SPS = 0b01010,
|
F1007_0SPS = 0b01010,
|
||||||
F503_8SPS = 0b01011,
|
F503_8SPS = 0b01011,
|
||||||
F381_0SPS = 0b01100,
|
F381_0SPS = 0b01100,
|
||||||
F200_3SPS = 0b01101,
|
F200_3SPS = 0b01101,
|
||||||
F100_2SPS = 0b01110,
|
F100_2SPS = 0b01110,
|
||||||
F59_52SPS = 0b01111,
|
F59_52SPS = 0b01111,
|
||||||
F49_68SPS = 0b10000,
|
F49_68SPS = 0b10000,
|
||||||
F20_01SPS = 0b10001,
|
F20_01SPS = 0b10001,
|
||||||
F16_63SPS = 0b10010,
|
F16_63SPS = 0b10010,
|
||||||
F10_0SPS = 0b10011,
|
F10_0SPS = 0b10011,
|
||||||
F5_0SPS = 0b10100,
|
F5_0SPS = 0b10100,
|
||||||
F2_5SPS = 0b10101,
|
F2_5SPS = 0b10101,
|
||||||
F1_25SPS = 0b10110,
|
F1_25SPS = 0b10110,
|
||||||
Invalid = 0b11111,
|
Invalid = 0b11111,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SingleChODR {
|
impl SingleChODR {
|
||||||
|
@ -281,9 +281,7 @@ impl SingleChODR {
|
||||||
let mut best: Option<(f32, Self)> = None;
|
let mut best: Option<(f32, Self)> = None;
|
||||||
for value in Self::VALID_VALUES {
|
for value in Self::VALID_VALUES {
|
||||||
let error = (rate - value.output_rate().unwrap()).abs();
|
let error = (rate - value.output_rate().unwrap()).abs();
|
||||||
let better = best
|
let better = best.map(|(best_error, _)| error < best_error).unwrap_or(true);
|
||||||
.map(|(best_error, _)| error < best_error)
|
|
||||||
.unwrap_or(true);
|
|
||||||
if better {
|
if better {
|
||||||
best = Some((error, *value));
|
best = Some((error, *value));
|
||||||
}
|
}
|
||||||
|
@ -348,5 +346,5 @@ pub fn sinc3_fine_odr_output_rate(odr: u16) -> f32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sinc3_fine_odr_closest(rate: f32) -> u16 {
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
use byteorder::{BigEndian, ByteOrder};
|
|
||||||
use bit_field::BitField;
|
use bit_field::BitField;
|
||||||
|
use byteorder::{BigEndian, ByteOrder};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -9,12 +10,12 @@ pub trait Register {
|
||||||
fn address(&self) -> u8;
|
fn address(&self) -> u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait RegisterData: Clone + Deref<Target=[u8]> + DerefMut {
|
pub trait RegisterData: Clone + Deref<Target = [u8]> + DerefMut {
|
||||||
fn empty() -> Self;
|
fn empty() -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! def_reg {
|
macro_rules! def_reg {
|
||||||
($Reg: ident, $reg: ident, $addr: expr, $size: expr) => {
|
($Reg:ident, $reg:ident, $addr:expr, $size:expr) => {
|
||||||
/// AD7172 register
|
/// AD7172 register
|
||||||
pub struct $Reg;
|
pub struct $Reg;
|
||||||
impl Register for $Reg {
|
impl Register for $Reg {
|
||||||
|
@ -48,8 +49,10 @@ macro_rules! def_reg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($Reg: ident, u8, $reg: ident, $addr: expr, $size: expr) => {
|
($Reg:ident,u8, $reg:ident, $addr:expr, $size:expr) => {
|
||||||
pub struct $Reg { pub index: u8, }
|
pub struct $Reg {
|
||||||
|
pub index: u8,
|
||||||
|
}
|
||||||
impl Register for $Reg {
|
impl Register for $Reg {
|
||||||
type Data = $reg::Data;
|
type Data = $reg::Data;
|
||||||
fn address(&self) -> u8 {
|
fn address(&self) -> u8 {
|
||||||
|
@ -76,18 +79,18 @@ macro_rules! def_reg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! reg_bit {
|
macro_rules! reg_bit {
|
||||||
($getter: ident, $byte: expr, $bit: expr, $doc: expr) => {
|
($getter:ident, $byte:expr, $bit:expr, $doc:expr) => {
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[doc = $doc]
|
#[doc = $doc]
|
||||||
pub fn $getter(&self) -> bool {
|
pub fn $getter(&self) -> bool {
|
||||||
self.0[$byte].get_bit($bit)
|
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)]
|
#[allow(unused)]
|
||||||
#[doc = $doc]
|
#[doc = $doc]
|
||||||
pub fn $getter(&self) -> bool {
|
pub fn $getter(&self) -> bool {
|
||||||
|
@ -102,14 +105,14 @@ macro_rules! reg_bit {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! reg_bits {
|
macro_rules! reg_bits {
|
||||||
($getter: ident, $byte: expr, $bits: expr, $doc: expr) => {
|
($getter:ident, $byte:expr, $bits:expr, $doc:expr) => {
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[doc = $doc]
|
#[doc = $doc]
|
||||||
pub fn $getter(&self) -> u8 {
|
pub fn $getter(&self) -> u8 {
|
||||||
self.0[$byte].get_bits($bits)
|
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)]
|
#[allow(unused)]
|
||||||
#[doc = $doc]
|
#[doc = $doc]
|
||||||
pub fn $getter(&self) -> u8 {
|
pub fn $getter(&self) -> u8 {
|
||||||
|
@ -121,14 +124,14 @@ macro_rules! reg_bits {
|
||||||
self.0[$byte].set_bits($bits, value);
|
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)]
|
#[allow(unused)]
|
||||||
#[doc = $doc]
|
#[doc = $doc]
|
||||||
pub fn $getter(&self) -> $ty {
|
pub fn $getter(&self) -> $ty {
|
||||||
self.0[$byte].get_bits($bits) as $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)]
|
#[allow(unused)]
|
||||||
#[doc = $doc]
|
#[doc = $doc]
|
||||||
pub fn $getter(&self) -> $ty {
|
pub fn $getter(&self) -> $ty {
|
||||||
|
@ -146,7 +149,7 @@ def_reg!(Status, status, 0x00, 1);
|
||||||
impl status::Data {
|
impl status::Data {
|
||||||
/// Is there new data to read?
|
/// Is there new data to read?
|
||||||
pub fn ready(&self) -> bool {
|
pub fn ready(&self) -> bool {
|
||||||
! self.not_ready()
|
!self.not_ready()
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_bit!(not_ready, 0, 7, "No data ready indicator");
|
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_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!(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!(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!(clockset, set_clocksel, 1, 2..=3, "Clock source");
|
||||||
reg_bits!(mode, set_mode, 1, 4..=6, Mode, "Operating mode");
|
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);
|
def_reg!(Data, data, 0x04, 3);
|
||||||
impl data::Data {
|
impl data::Data {
|
||||||
pub fn data(&self) -> u32 {
|
pub fn data(&self) -> u32 {
|
||||||
(u32::from(self.0[0]) << 16) |
|
(u32::from(self.0[0]) << 16) | (u32::from(self.0[1]) << 8) | u32::from(self.0[2])
|
||||||
(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
|
/// Which input is connected to positive input of this channel
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn a_in_pos(&self) -> Input {
|
pub fn a_in_pos(&self) -> Input {
|
||||||
((self.0[0].get_bits(0..=1) << 3) |
|
((self.0[0].get_bits(0..=1) << 3) | self.0[1].get_bits(5..=7)).into()
|
||||||
self.0[1].get_bits(5..=7)).into()
|
|
||||||
}
|
}
|
||||||
/// Set which input is connected to positive input of this channel
|
/// Set which input is connected to positive input of this channel
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
@ -210,39 +216,108 @@ impl channel::Data {
|
||||||
self.0[0].set_bits(0..=1, value >> 3);
|
self.0[0].set_bits(0..=1, value >> 3);
|
||||||
self.0[1].set_bits(5..=7, value & 0x7);
|
self.0[1].set_bits(5..=7, value & 0x7);
|
||||||
}
|
}
|
||||||
reg_bits!(a_in_neg, set_a_in_neg, 1, 0..=4, Input,
|
reg_bits!(
|
||||||
"Which input is connected to negative input of this channel");
|
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);
|
def_reg!(SetupCon, u8, setup_con, 0x20, 2);
|
||||||
impl setup_con::Data {
|
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_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!(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_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!(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_bit!(
|
||||||
reg_bits!(ref_sel, set_ref_sel, 1, 4..=5, RefSource, "Select reference source for conversion");
|
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);
|
def_reg!(FiltCon, u8, filt_con, 0x28, 2);
|
||||||
impl filt_con::Data {
|
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!(
|
||||||
reg_bit!(enh_filt_en, set_enh_filt_en, 0, 3, "Enable postfilters for enhanced 50Hz and 60Hz rejection");
|
sinc3_map,
|
||||||
reg_bits!(enh_filt, set_enh_filt, 0, 0..=2, PostFilter, "Select postfilters output data rate for enhanced 50Hz and 60Hz rejection");
|
set_sinc3_map,
|
||||||
reg_bits!(order, set_order, 1, 5..=6, DigitalFilterOrder, "order of the digital filter that processes the modulator data");
|
0,
|
||||||
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");
|
7,
|
||||||
reg_bits!(sinc3_map_fine_odr_msb, set_sinc3_map_fine_odr_msb, 0, 0..=6, "MSB Byte Sinc3 Fine Output Config");
|
"If set, Sinc3 Filter's notch frequency rejection position can be fine tuned with FiltCon[14:0]. Best to be \
|
||||||
reg_bits!(sinc3_map_fine_odr_lsb, set_sinc3_map_fine_odr_lsb, 1, 0..=7, "LSB Byte Sinc3 Fine Output Config");
|
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);
|
def_reg!(Offset, u8, offset, 0x30, 3);
|
||||||
impl offset::Data {
|
impl offset::Data {
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn offset(&self) -> u32 {
|
pub fn offset(&self) -> u32 {
|
||||||
(u32::from(self.0[0]) << 16) |
|
(u32::from(self.0[0]) << 16) | (u32::from(self.0[1]) << 8) | u32::from(self.0[2])
|
||||||
(u32::from(self.0[1]) << 8) |
|
|
||||||
u32::from(self.0[2])
|
|
||||||
}
|
}
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn set_offset(&mut self, value: u32) {
|
pub fn set_offset(&mut self, value: u32) {
|
||||||
|
@ -256,9 +331,7 @@ def_reg!(Gain, u8, gain, 0x38, 3);
|
||||||
impl gain::Data {
|
impl gain::Data {
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn gain(&self) -> u32 {
|
pub fn gain(&self) -> u32 {
|
||||||
(u32::from(self.0[0]) << 16) |
|
(u32::from(self.0[0]) << 16) | (u32::from(self.0[1]) << 8) | u32::from(self.0[2])
|
||||||
(u32::from(self.0[1]) << 8) |
|
|
||||||
u32::from(self.0[2])
|
|
||||||
}
|
}
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn set_gain(&mut self, value: u32) {
|
pub fn set_gain(&mut self, value: u32) {
|
||||||
|
|
|
@ -1,22 +1,18 @@
|
||||||
use crate::thermostat::ad5680;
|
|
||||||
use core::ptr::addr_of_mut;
|
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::{
|
use fugit::KilohertzU32;
|
||||||
electric_potential::millivolt,
|
use stm32f4xx_hal::{adc::{config::{self, AdcConfig},
|
||||||
f32::ElectricPotential,
|
Adc},
|
||||||
ratio::ratio,
|
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);
|
pub const PWM_FREQ_KHZ: KilohertzU32 = KilohertzU32::from_raw(20);
|
||||||
|
|
||||||
|
@ -115,8 +111,8 @@ impl<C: ChannelPins> MAX1968Phy<C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut ADC2_FIRST_BUFFER : [u16; 16] = [0; 16];
|
static mut ADC2_FIRST_BUFFER: [u16; 16] = [0; 16];
|
||||||
static mut ADC2_LOCAL_BUFFER : [u16; 16] = [0; 16];
|
static mut ADC2_LOCAL_BUFFER: [u16; 16] = [0; 16];
|
||||||
|
|
||||||
impl MAX1968 {
|
impl MAX1968 {
|
||||||
pub fn new(phy_ch0: MAX1968Phy<Channel0>, adc1: ADC1, adc2: ADC2, dma2: DMA2) -> Self {
|
pub fn new(phy_ch0: MAX1968Phy<Channel0>, adc1: ADC1, adc2: ADC2, dma2: DMA2) -> Self {
|
||||||
|
@ -137,7 +133,7 @@ impl MAX1968 {
|
||||||
vdda_mv = vdda_mv / 512 as u32;
|
vdda_mv = vdda_mv / 512 as u32;
|
||||||
pins_adc1.apply_config(adc_config.reference_voltage(vdda_mv));
|
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)
|
.clock(config::Clock::Pclk2_div_8)
|
||||||
.default_sample_time(config::SampleTime::Cycles_480)
|
.default_sample_time(config::SampleTime::Cycles_480)
|
||||||
.dma(config::Dma::Continuous)
|
.dma(config::Dma::Continuous)
|
||||||
|
@ -150,25 +146,79 @@ impl MAX1968 {
|
||||||
let mut pins_adc2 = Adc::adc2(adc2, false, adc_config);
|
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.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.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(
|
||||||
pins_adc2.configure_channel(&phy_ch0.vtec_pin, config::Sequence::Four, config::SampleTime::Cycles_480);
|
&phy_ch0.itec_pin,
|
||||||
pins_adc2.configure_channel(&phy_ch0.itec_pin, config::Sequence::Five, config::SampleTime::Cycles_480);
|
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.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(
|
||||||
pins_adc2.configure_channel(&phy_ch0.vtec_pin, config::Sequence::Eight, config::SampleTime::Cycles_480);
|
&phy_ch0.itec_pin,
|
||||||
pins_adc2.configure_channel(&phy_ch0.itec_pin, config::Sequence::Nine, config::SampleTime::Cycles_480);
|
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.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(
|
||||||
pins_adc2.configure_channel(&phy_ch0.vtec_pin, config::Sequence::Twelve, config::SampleTime::Cycles_480);
|
&phy_ch0.itec_pin,
|
||||||
pins_adc2.configure_channel(&phy_ch0.itec_pin, config::Sequence::Thirteen, config::SampleTime::Cycles_480);
|
config::Sequence::Eleven,
|
||||||
pins_adc2.configure_channel(&phy_ch0.vtec_pin, config::Sequence::Fourteen, config::SampleTime::Cycles_480);
|
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.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 = StreamsTuple::new(dma2);
|
||||||
let dma_adc : DMA_Transfer<Stream2<DMA2>, 1, Adc<ADC2>, PeripheralToMemory, &'static mut [u16; 16]>;
|
let dma_adc: DMA_Transfer<Stream2<DMA2>, 1, Adc<ADC2>, PeripheralToMemory, &'static mut [u16; 16]>;
|
||||||
unsafe {
|
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);
|
NVIC::unmask(interrupt::DMA2_STREAM2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,9 +231,11 @@ impl MAX1968 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dma_adc_start_conversion(&mut self){
|
pub fn dma_adc_start_conversion(&mut self) {
|
||||||
if unsafe {DMA_TRANSFER_COMPLETE} {
|
if unsafe { DMA_TRANSFER_COMPLETE } {
|
||||||
unsafe { DMA_TRANSFER_COMPLETE = false; }
|
unsafe {
|
||||||
|
DMA_TRANSFER_COMPLETE = false;
|
||||||
|
}
|
||||||
self.dma_adc.start(|adc| {
|
self.dma_adc.start(|adc| {
|
||||||
adc.clear_end_of_conversion_flag();
|
adc.clear_end_of_conversion_flag();
|
||||||
adc.start_conversion();
|
adc.start_conversion();
|
||||||
|
@ -195,7 +247,8 @@ impl MAX1968 {
|
||||||
if unsafe { DMA_TRANSFER_COMPLETE } {
|
if unsafe { DMA_TRANSFER_COMPLETE } {
|
||||||
let buffer: &[u16; 16];
|
let buffer: &[u16; 16];
|
||||||
unsafe {
|
unsafe {
|
||||||
(buffer, _) = self.dma_adc
|
(buffer, _) = self
|
||||||
|
.dma_adc
|
||||||
.next_transfer(addr_of_mut!(ADC2_LOCAL_BUFFER).as_mut().unwrap())
|
.next_transfer(addr_of_mut!(ADC2_LOCAL_BUFFER).as_mut().unwrap())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -240,10 +293,8 @@ impl MAX1968 {
|
||||||
self.phy.shdn.set_high();
|
self.phy.shdn.set_high();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn set_dac(&mut self, voltage: ElectricPotential, dac_out_v_max: ElectricPotential) -> ElectricPotential {
|
pub fn set_dac(&mut self, voltage: ElectricPotential, dac_out_v_max: ElectricPotential) -> ElectricPotential {
|
||||||
let value = ((voltage / dac_out_v_max).get::<ratio>()
|
let value = ((voltage / dac_out_v_max).get::<ratio>() * (ad5680::MAX_VALUE as f32)) as u32;
|
||||||
* (ad5680::MAX_VALUE as f32)) as u32;
|
|
||||||
self.phy.dac.set(value).unwrap();
|
self.phy.dac.set(value).unwrap();
|
||||||
voltage
|
voltage
|
||||||
}
|
}
|
||||||
|
@ -255,10 +306,10 @@ impl MAX1968 {
|
||||||
sample = match adc_read_target {
|
sample = match adc_read_target {
|
||||||
AdcReadTarget::VREF => {
|
AdcReadTarget::VREF => {
|
||||||
for _ in (0..avg_pt).rev() {
|
for _ in (0..avg_pt).rev() {
|
||||||
sample += self.pins_adc.convert(
|
sample += self
|
||||||
&self.phy.vref_pin,
|
.pins_adc
|
||||||
stm32f4xx_hal::adc::config::SampleTime::Cycles_480,
|
.convert(&self.phy.vref_pin, stm32f4xx_hal::adc::config::SampleTime::Cycles_480)
|
||||||
) as u32;
|
as u32;
|
||||||
}
|
}
|
||||||
sample / avg_pt as u32
|
sample / avg_pt as u32
|
||||||
}
|
}
|
||||||
|
@ -273,19 +324,19 @@ impl MAX1968 {
|
||||||
}
|
}
|
||||||
AdcReadTarget::ITec => {
|
AdcReadTarget::ITec => {
|
||||||
for _ in (0..avg_pt).rev() {
|
for _ in (0..avg_pt).rev() {
|
||||||
sample += self.pins_adc.convert(
|
sample += self
|
||||||
&self.phy.itec_pin,
|
.pins_adc
|
||||||
stm32f4xx_hal::adc::config::SampleTime::Cycles_480,
|
.convert(&self.phy.itec_pin, stm32f4xx_hal::adc::config::SampleTime::Cycles_480)
|
||||||
) as u32;
|
as u32;
|
||||||
}
|
}
|
||||||
sample / avg_pt as u32
|
sample / avg_pt as u32
|
||||||
}
|
}
|
||||||
AdcReadTarget::VTec => {
|
AdcReadTarget::VTec => {
|
||||||
for _ in (0..avg_pt).rev() {
|
for _ in (0..avg_pt).rev() {
|
||||||
sample += self.pins_adc.convert(
|
sample += self
|
||||||
&self.phy.vtec_pin,
|
.pins_adc
|
||||||
stm32f4xx_hal::adc::config::SampleTime::Cycles_480,
|
.convert(&self.phy.vtec_pin, stm32f4xx_hal::adc::config::SampleTime::Cycles_480)
|
||||||
) as u32;
|
as u32;
|
||||||
}
|
}
|
||||||
sample / avg_pt as u32
|
sample / avg_pt as u32
|
||||||
}
|
}
|
||||||
|
@ -307,7 +358,6 @@ impl MAX1968 {
|
||||||
max_value = self.phy.max_v.get_max_duty();
|
max_value = self.phy.max_v.get_max_duty();
|
||||||
value = duty_cycle_value(duty, max_duty, max_value);
|
value = duty_cycle_value(duty, max_duty, max_value);
|
||||||
self.phy.max_v.set_duty(value);
|
self.phy.max_v.set_duty(value);
|
||||||
|
|
||||||
}
|
}
|
||||||
PwmPinsEnum::MaxPosI => {
|
PwmPinsEnum::MaxPosI => {
|
||||||
self.phy.max_i_pos.enable();
|
self.phy.max_i_pos.enable();
|
||||||
|
@ -324,22 +374,24 @@ impl MAX1968 {
|
||||||
}
|
}
|
||||||
return (value as f64) / (max_value as f64);
|
return (value as f64) / (max_value as f64);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
fn DMA2_STREAM2(){
|
fn DMA2_STREAM2() {
|
||||||
cortex_m::interrupt::free(|_| {
|
cortex_m::interrupt::free(|_| {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Clear all DMA2_STREAM2 interrupt flags
|
// Clear all DMA2_STREAM2 interrupt flags
|
||||||
Peripherals::steal().DMA2.lifcr.write(|w| w
|
Peripherals::steal().DMA2.lifcr.write(|w| {
|
||||||
.ctcif2().set_bit()
|
w.ctcif2()
|
||||||
.cdmeif2().set_bit()
|
.set_bit()
|
||||||
.chtif2().set_bit()
|
.cdmeif2()
|
||||||
.cteif2().set_bit()
|
.set_bit()
|
||||||
);
|
.chtif2()
|
||||||
DMA_TRANSFER_COMPLETE = true;
|
.set_bit()
|
||||||
}
|
.cteif2()
|
||||||
|
.set_bit()
|
||||||
|
});
|
||||||
|
DMA_TRANSFER_COMPLETE = true;
|
||||||
}
|
}
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
pub mod ad5680;
|
pub mod ad5680;
|
||||||
pub mod max1968;
|
|
||||||
pub mod thermostat;
|
|
||||||
pub mod ad7172;
|
pub mod ad7172;
|
||||||
pub mod steinhart_hart;
|
pub mod max1968;
|
||||||
pub mod pid_state;
|
pub mod pid_state;
|
||||||
|
pub mod steinhart_hart;
|
||||||
pub mod temp_mon;
|
pub mod temp_mon;
|
||||||
|
pub mod thermostat;
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
use miniconf::Tree;
|
use miniconf::Tree;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use uom::si::{
|
use uom::si::{electric_potential::volt,
|
||||||
electric_potential::volt, electrical_resistance::ohm, f32::{
|
electrical_resistance::ohm,
|
||||||
ElectricPotential, ElectricalResistance, ThermodynamicTemperature
|
f32::{ElectricPotential, ElectricalResistance, ThermodynamicTemperature},
|
||||||
}, thermodynamic_temperature::degree_celsius
|
thermodynamic_temperature::degree_celsius};
|
||||||
};
|
|
||||||
use crate::thermostat::{
|
use crate::thermostat::{ad7172, steinhart_hart as sh};
|
||||||
ad7172,
|
|
||||||
steinhart_hart as sh,
|
|
||||||
};
|
|
||||||
const R_INNER: f32 = 2.0 * 5100.0;
|
const R_INNER: f32 = 2.0 * 5100.0;
|
||||||
const VREF_SENS: f32 = 3.3 / 2.0;
|
const VREF_SENS: f32 = 3.3 / 2.0;
|
||||||
|
|
||||||
|
@ -41,13 +38,12 @@ impl Default for Parameters {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Controller {
|
pub struct Controller {
|
||||||
pub parameters: Parameters,
|
pub parameters: Parameters,
|
||||||
u1 : f64,
|
u1: f64,
|
||||||
x1 : f64,
|
x1: f64,
|
||||||
x2 : f64,
|
x2: f64,
|
||||||
pub y1 : f64,
|
pub y1: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct PidState {
|
pub struct PidState {
|
||||||
adc_data: Option<u32>,
|
adc_data: Option<u32>,
|
||||||
adc_calibration: ad7172::ChannelCalibration,
|
adc_calibration: ad7172::ChannelCalibration,
|
||||||
|
@ -67,10 +63,10 @@ impl Default for PidState {
|
||||||
sh: sh::Parameters::default(),
|
sh: sh::Parameters::default(),
|
||||||
controller: Controller {
|
controller: Controller {
|
||||||
parameters: Parameters::default(),
|
parameters: Parameters::default(),
|
||||||
u1 : 0.0,
|
u1: 0.0,
|
||||||
x1 : 0.0,
|
x1: 0.0,
|
||||||
x2 : 0.0,
|
x2: 0.0,
|
||||||
y1 : 0.0,
|
y1: 0.0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,10 +102,13 @@ impl PidState {
|
||||||
let input = self.get_temperature()?.get::<degree_celsius>();
|
let input = self.get_temperature()?.get::<degree_celsius>();
|
||||||
let setpoint = self.set_point.get::<degree_celsius>();
|
let setpoint = self.set_point.get::<degree_celsius>();
|
||||||
let mut output: f64 = self.controller.y1 - setpoint as f64 * f64::from(self.controller.parameters.ki)
|
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)
|
+ input as f64
|
||||||
- self.controller.x1 * f64::from(self.controller.parameters.kp + 2.0 * self.controller.parameters.kd)
|
* f64::from(
|
||||||
+ self.controller.x2 * f64::from(self.controller.parameters.kd)
|
self.controller.parameters.kp + self.controller.parameters.ki + self.controller.parameters.kd,
|
||||||
+ f64::from(self.controller.parameters.kp) * (setpoint as f64 - self.controller.u1);
|
)
|
||||||
|
- 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() {
|
if output < self.controller.parameters.output_min.into() {
|
||||||
output = self.controller.parameters.output_min.into();
|
output = self.controller.parameters.output_min.into();
|
||||||
}
|
}
|
||||||
|
@ -142,11 +141,11 @@ impl PidState {
|
||||||
Some(temperature)
|
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;
|
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 {
|
match param {
|
||||||
PidSettings::Kp => {
|
PidSettings::Kp => {
|
||||||
self.controller.parameters.kp = val;
|
self.controller.parameters.kp = val;
|
||||||
|
@ -166,14 +165,14 @@ impl PidState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset_pid_state(&mut self){
|
pub fn reset_pid_state(&mut self) {
|
||||||
self.controller.u1 = 0.0;
|
self.controller.u1 = 0.0;
|
||||||
self.controller.x1 = 0.0;
|
self.controller.x1 = 0.0;
|
||||||
self.controller.x2 = 0.0;
|
self.controller.x2 = 0.0;
|
||||||
self.controller.y1 = 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;
|
self.set_point = temperature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,23 +180,23 @@ impl PidState {
|
||||||
self.set_point
|
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
|
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
|
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
|
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;
|
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;
|
self.pid_engaged = pid_engaged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
|
use miniconf::Tree;
|
||||||
use num_traits::float::Float;
|
use num_traits::float::Float;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use uom::si::{
|
use uom::si::{electrical_resistance::ohm,
|
||||||
f32::{
|
f32::{ElectricalResistance, ThermodynamicTemperature},
|
||||||
ElectricalResistance,
|
ratio::ratio,
|
||||||
ThermodynamicTemperature,
|
thermodynamic_temperature::{degree_celsius, kelvin}};
|
||||||
},
|
|
||||||
electrical_resistance::ohm,
|
|
||||||
ratio::ratio,
|
|
||||||
thermodynamic_temperature::{degree_celsius, kelvin},
|
|
||||||
};
|
|
||||||
use miniconf::Tree;
|
|
||||||
|
|
||||||
/// Steinhart-Hart equation parameters
|
/// Steinhart-Hart equation parameters
|
||||||
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use miniconf::Tree;
|
use miniconf::Tree;
|
||||||
use uom::si::{
|
|
||||||
f32::ThermodynamicTemperature, thermodynamic_temperature::degree_celsius
|
|
||||||
};
|
|
||||||
use num_traits::Float;
|
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)]
|
#[derive(PartialEq, Deserialize, Serialize, Copy, Clone, Default, Debug)]
|
||||||
pub enum TempStatusEnum {
|
pub enum TempStatusEnum {
|
||||||
#[default]
|
#[default]
|
||||||
|
@ -44,7 +42,7 @@ impl Default for TempMon {
|
||||||
set_point: ThermodynamicTemperature::new::<degree_celsius>(0.0),
|
set_point: ThermodynamicTemperature::new::<degree_celsius>(0.0),
|
||||||
status: TempStatus {
|
status: TempStatus {
|
||||||
status: TempStatusEnum::Off,
|
status: TempStatusEnum::Off,
|
||||||
over_temp_alarm: false
|
over_temp_alarm: false,
|
||||||
},
|
},
|
||||||
state: State::default(),
|
state: State::default(),
|
||||||
count: 0,
|
count: 0,
|
||||||
|
@ -121,8 +119,7 @@ impl TempMon {
|
||||||
if is_over_temp {
|
if is_over_temp {
|
||||||
self.state = State::OverTempAlarm;
|
self.state = State::OverTempAlarm;
|
||||||
self.status.status = TempStatusEnum::OverTemp;
|
self.status.status = TempStatusEnum::OverTemp;
|
||||||
}
|
} else if !pwr_on {
|
||||||
else if !pwr_on {
|
|
||||||
self.state = State::PwrOff;
|
self.state = State::PwrOff;
|
||||||
self.status.status = TempStatusEnum::Off;
|
self.status.status = TempStatusEnum::Off;
|
||||||
} else if pid_engaged {
|
} else if pid_engaged {
|
||||||
|
@ -160,8 +157,7 @@ impl TempMon {
|
||||||
// State Transition
|
// State Transition
|
||||||
if !pwr_on {
|
if !pwr_on {
|
||||||
self.state = State::PwrOff;
|
self.state = State::PwrOff;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if self.status.status == TempStatusEnum::OverTemp {
|
if self.status.status == TempStatusEnum::OverTemp {
|
||||||
self.state = State::OverTempAlarm;
|
self.state = State::OverTempAlarm;
|
||||||
} else if self.is_set_point_changed {
|
} else if self.is_set_point_changed {
|
||||||
|
|
|
@ -1,25 +1,23 @@
|
||||||
use core::f32::NAN;
|
use core::{f32::NAN, marker::PhantomData};
|
||||||
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 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 {
|
pub const R_SENSE: ElectricalResistance = ElectricalResistance {
|
||||||
dimension: PhantomData,
|
dimension: PhantomData,
|
||||||
|
@ -28,7 +26,7 @@ pub const R_SENSE: ElectricalResistance = ElectricalResistance {
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Default, Tree)]
|
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Default, Tree)]
|
||||||
pub struct TempAdcFilter{
|
pub struct TempAdcFilter {
|
||||||
pub filter_type: FilterType,
|
pub filter_type: FilterType,
|
||||||
pub sinc5sinc1odr: Option<SingleChODR>,
|
pub sinc5sinc1odr: Option<SingleChODR>,
|
||||||
pub sinc3odr: Option<SingleChODR>,
|
pub sinc3odr: Option<SingleChODR>,
|
||||||
|
@ -37,7 +35,6 @@ pub struct TempAdcFilter{
|
||||||
pub rate: Option<f32>,
|
pub rate: Option<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Clone, Copy, Debug, Tree)]
|
#[derive(Deserialize, Serialize, Clone, Copy, Debug, Tree)]
|
||||||
pub struct TecSettings {
|
pub struct TecSettings {
|
||||||
pub default_pwr_on: bool,
|
pub default_pwr_on: bool,
|
||||||
|
@ -49,7 +46,7 @@ pub struct TecSettings {
|
||||||
pub vref: ElectricPotential,
|
pub vref: ElectricPotential,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TecSettings{
|
impl TecSettings {
|
||||||
pub const DAC_OUT_V_MAX: ElectricPotential = ElectricPotential {
|
pub const DAC_OUT_V_MAX: ElectricPotential = ElectricPotential {
|
||||||
dimension: PhantomData,
|
dimension: PhantomData,
|
||||||
units: PhantomData,
|
units: PhantomData,
|
||||||
|
@ -64,7 +61,7 @@ impl TecSettings{
|
||||||
// Kirdy Design Specs:
|
// Kirdy Design Specs:
|
||||||
// MaxV = 5.0V
|
// MaxV = 5.0V
|
||||||
// MAX Current = +- 1.0A
|
// MAX Current = +- 1.0A
|
||||||
const MAX_I_SET : ElectricCurrent = ElectricCurrent {
|
const MAX_I_SET: ElectricCurrent = ElectricCurrent {
|
||||||
dimension: PhantomData,
|
dimension: PhantomData,
|
||||||
units: PhantomData,
|
units: PhantomData,
|
||||||
value: 1.0,
|
value: 1.0,
|
||||||
|
@ -79,7 +76,8 @@ impl TecSettings{
|
||||||
units: PhantomData,
|
units: PhantomData,
|
||||||
value: 5.0,
|
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 {
|
const MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE: ElectricCurrent = ElectricCurrent {
|
||||||
dimension: PhantomData,
|
dimension: PhantomData,
|
||||||
units: PhantomData,
|
units: PhantomData,
|
||||||
|
@ -96,8 +94,10 @@ impl TecSettings{
|
||||||
value: 1.0,
|
value: 1.0,
|
||||||
};
|
};
|
||||||
// .get::<ratio>() is not implemented for const
|
// .get::<ratio>() 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_POS_DUTY_MAX: 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;
|
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 {
|
impl Default for TecSettings {
|
||||||
|
@ -134,9 +134,9 @@ pub struct ThermostatSettingsSummary {
|
||||||
thermistor_params: ThermistorParams,
|
thermistor_params: ThermistorParams,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Thermostat{
|
impl Thermostat {
|
||||||
pub fn new (max1968: MAX1968, ad7172: ad7172::AdcPhy) -> Self {
|
pub fn new(max1968: MAX1968, ad7172: ad7172::AdcPhy) -> Self {
|
||||||
Thermostat{
|
Thermostat {
|
||||||
max1968: max1968,
|
max1968: max1968,
|
||||||
ad7172: ad7172,
|
ad7172: ad7172,
|
||||||
tec_settings: TecSettings::default(),
|
tec_settings: TecSettings::default(),
|
||||||
|
@ -144,16 +144,16 @@ impl Thermostat{
|
||||||
temp_mon: TempMon::default(),
|
temp_mon: TempMon::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn setup(&mut self){
|
pub fn setup(&mut self) {
|
||||||
self.tec_setup();
|
self.tec_setup();
|
||||||
let t_adc_ch0_cal = self.t_adc_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
|
/// start_tec_readings_conversion() should not be called before the current
|
||||||
/// DMA request is serviced or the conversion process will be restarted
|
/// DMA request is serviced or the conversion process will be restarted
|
||||||
/// Thus, no new readings is available when you call get_tec_readings() fn
|
/// 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();
|
self.max1968.dma_adc_start_conversion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,24 +169,26 @@ impl Thermostat{
|
||||||
self.set_max_i_neg(self.tec_settings.max_i_neg_set);
|
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.set_sync_enable(false).unwrap();
|
||||||
self.ad7172.setup_channel(0, ad7172::Input::Ain0, ad7172::Input::Ain1).unwrap();
|
self.ad7172
|
||||||
let adc_calibration0 = self.ad7172.get_calibration(0)
|
.setup_channel(0, ad7172::Input::Ain0, ad7172::Input::Ain1)
|
||||||
.expect("adc_calibration0");
|
.unwrap();
|
||||||
|
let adc_calibration0 = self.ad7172.get_calibration(0).expect("adc_calibration0");
|
||||||
self.ad7172.start_continuous_conversion().unwrap();
|
self.ad7172.start_continuous_conversion().unwrap();
|
||||||
adc_calibration0
|
adc_calibration0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll_adc(&mut self) -> bool {
|
pub fn poll_adc(&mut self) -> bool {
|
||||||
let mut data_rdy = false;
|
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 data = self.ad7172.read_data().unwrap();
|
||||||
let state: &mut PidState = &mut self.pid_ctrl_ch0;
|
let state: &mut PidState = &mut self.pid_ctrl_ch0;
|
||||||
state.update(data);
|
state.update(data);
|
||||||
let pid_engaged = state.get_pid_engaged();
|
let pid_engaged = state.get_pid_engaged();
|
||||||
let temp = self.get_temperature();
|
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!("state.get_pid_engaged(): {:?}", pid_engaged);
|
||||||
debug!("Temperature: {:?} degree", temp.get::<degree_celsius>());
|
debug!("Temperature: {:?} degree", temp.get::<degree_celsius>());
|
||||||
data_rdy = true;
|
data_rdy = true;
|
||||||
|
@ -201,9 +203,12 @@ impl Thermostat{
|
||||||
match state.update_pid() {
|
match state.update_pid() {
|
||||||
Some(pid_output) => {
|
Some(pid_output) => {
|
||||||
self.set_i(ElectricCurrent::new::<ampere>(pid_output as f32));
|
self.set_i(ElectricCurrent::new::<ampere>(pid_output as f32));
|
||||||
debug!("Temperature Set Point: {:?} degree", self.pid_ctrl_ch0.get_pid_setpoint().get::<degree_celsius>());
|
debug!(
|
||||||
|
"Temperature Set Point: {:?} degree",
|
||||||
|
self.pid_ctrl_ch0.get_pid_setpoint().get::<degree_celsius>()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
None => { }
|
None => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,22 +217,22 @@ impl Thermostat{
|
||||||
self.temp_mon.get_status()
|
self.temp_mon.get_status()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn power_up(&mut self){
|
pub fn power_up(&mut self) {
|
||||||
self.max1968.power_up();
|
self.max1968.power_up();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn power_down(&mut self){
|
pub fn power_down(&mut self) {
|
||||||
self.max1968.power_down();
|
self.max1968.power_down();
|
||||||
self.pid_ctrl_ch0.reset_pid_state();
|
self.pid_ctrl_ch0.reset_pid_state();
|
||||||
self.set_i(ElectricCurrent::new::<ampere>(0.0));
|
self.set_i(ElectricCurrent::new::<ampere>(0.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_center_pt(&mut self, value: ElectricPotential){
|
fn set_center_pt(&mut self, value: ElectricPotential) {
|
||||||
self.tec_settings.center_pt = value;
|
self.tec_settings.center_pt = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_default_pwr_on(&mut self, pwr_on: bool) {
|
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 {
|
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 {
|
pub fn set_max_v(&mut self, max_v: ElectricPotential) -> ElectricPotential {
|
||||||
let duty = (max_v / TecSettings::MAX_V_DUTY_TO_CURRENT_RATE).get::<ratio>();
|
let duty = (max_v / TecSettings::MAX_V_DUTY_TO_CURRENT_RATE).get::<ratio>();
|
||||||
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 = duty as f32 * TecSettings::MAX_V_DUTY_TO_CURRENT_RATE;
|
||||||
self.tec_settings.max_v_set
|
self.tec_settings.max_v_set
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_max_i_pos(&mut self, max_i_pos: ElectricCurrent) -> ElectricCurrent {
|
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::<ratio>();
|
let duty = (max_i_pos / TecSettings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE).get::<ratio>();
|
||||||
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 = duty as f32 * TecSettings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE;
|
||||||
self.tec_settings.max_i_pos_set
|
self.tec_settings.max_i_pos_set
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_max_i_neg(&mut self, max_i_neg: ElectricCurrent) -> ElectricCurrent {
|
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::<ratio>();
|
let duty = (max_i_neg / TecSettings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE).get::<ratio>();
|
||||||
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 = duty as f32 * TecSettings::MAX_I_POS_NEG_DUTY_TO_CURRENT_RATE;
|
||||||
self.tec_settings.max_i_neg_set
|
self.tec_settings.max_i_neg_set
|
||||||
}
|
}
|
||||||
|
@ -282,7 +293,10 @@ impl Thermostat{
|
||||||
pub fn get_tec_readings(&mut self) -> (ElectricPotential, ElectricCurrent) {
|
pub fn get_tec_readings(&mut self) -> (ElectricPotential, ElectricCurrent) {
|
||||||
let vref = self.tec_settings.vref;
|
let vref = self.tec_settings.vref;
|
||||||
let (vtec, itec) = self.max1968.get_tec_readings();
|
let (vtec, itec) = self.max1968.get_tec_readings();
|
||||||
((vtec - TecSettings::TEC_VSEC_BIAS_V) * 4.0, (itec - vref) / ElectricalResistance::new::<ohm>(0.4))
|
(
|
||||||
|
(vtec - TecSettings::TEC_VSEC_BIAS_V) * 4.0,
|
||||||
|
(itec - vref) / ElectricalResistance::new::<ohm>(0.4),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calibrates the DAC output to match vref of the MAX driver to reduce zero-current offset of the MAX driver output.
|
/// Calibrates the DAC output to match vref of the MAX driver to reduce zero-current offset of the MAX driver output.
|
||||||
|
@ -307,7 +321,7 @@ impl Thermostat{
|
||||||
let target_voltage = self.max1968.adc_read(AdcReadTarget::VREF, 512);
|
let target_voltage = self.max1968.adc_read(AdcReadTarget::VREF, 512);
|
||||||
let mut start_value = 1;
|
let mut start_value = 1;
|
||||||
let mut best_error = ElectricPotential::new::<volt>(100.0);
|
let mut best_error = ElectricPotential::new::<volt>(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;
|
let mut prev_value = start_value;
|
||||||
for value in (start_value..=ad5680::MAX_VALUE).step_by(1 << step) {
|
for value in (start_value..=ad5680::MAX_VALUE).step_by(1 << step) {
|
||||||
self.max1968.phy.dac.set(value).unwrap();
|
self.max1968.phy.dac.set(value).unwrap();
|
||||||
|
@ -335,7 +349,7 @@ impl Thermostat{
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_pid_engaged(&mut self) -> bool {
|
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 {
|
pub fn get_status_report(&mut self) -> StatusReport {
|
||||||
|
@ -343,9 +357,7 @@ impl Thermostat{
|
||||||
let temperature: Option<f32>;
|
let temperature: Option<f32>;
|
||||||
|
|
||||||
match self.pid_ctrl_ch0.get_temperature() {
|
match self.pid_ctrl_ch0.get_temperature() {
|
||||||
Some(val) => {
|
Some(val) => temperature = Some(val.get::<degree_celsius>()),
|
||||||
temperature = Some(val.get::<degree_celsius>())
|
|
||||||
}
|
|
||||||
None => {
|
None => {
|
||||||
temperature = None;
|
temperature = None;
|
||||||
}
|
}
|
||||||
|
@ -364,10 +376,8 @@ impl Thermostat{
|
||||||
|
|
||||||
pub fn get_temperature(&mut self) -> ThermodynamicTemperature {
|
pub fn get_temperature(&mut self) -> ThermodynamicTemperature {
|
||||||
match self.pid_ctrl_ch0.get_temperature() {
|
match self.pid_ctrl_ch0.get_temperature() {
|
||||||
Some(val) => {
|
Some(val) => val,
|
||||||
val
|
None => ThermodynamicTemperature::new::<degree_celsius>(NAN),
|
||||||
}
|
|
||||||
None => { ThermodynamicTemperature::new::<degree_celsius>(NAN) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,26 +392,34 @@ impl Thermostat{
|
||||||
r0: sh.r0,
|
r0: sh.r0,
|
||||||
b: sh.b,
|
b: sh.b,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_steinhart_hart(&mut self, sh: ThermistorParams) {
|
fn apply_steinhart_hart(&mut self, sh: ThermistorParams) {
|
||||||
self.pid_ctrl_ch0.apply_sh(
|
self.pid_ctrl_ch0.apply_sh(Sh_Params {
|
||||||
Sh_Params {
|
t0: ThermodynamicTemperature::new::<degree_celsius>(sh.t0),
|
||||||
t0: ThermodynamicTemperature::new::<degree_celsius>(sh.t0),
|
r0: sh.r0,
|
||||||
r0: sh.r0,
|
b: sh.b,
|
||||||
b: sh.b,
|
})
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn get_tec_settings(&mut self) -> TecSettingSummary {
|
fn get_tec_settings(&mut self) -> TecSettingSummary {
|
||||||
TecSettingSummary {
|
TecSettingSummary {
|
||||||
i_set: TecSettingsSummaryField { value: self.tec_settings.i_set, max: TecSettings::MAX_I_SET },
|
i_set: TecSettingsSummaryField {
|
||||||
max_v: TecSettingsSummaryField { value: self.tec_settings.max_v_set, max: TecSettings::MAX_V_MAX },
|
value: self.tec_settings.i_set,
|
||||||
max_i_pos: TecSettingsSummaryField { value: self.tec_settings.max_i_pos_set, max: TecSettings::MAX_I_POS_CURRENT },
|
max: TecSettings::MAX_I_SET,
|
||||||
max_i_neg: TecSettingsSummaryField { value: self.tec_settings.max_i_neg_set, max: TecSettings::MAX_I_NEG_CURRENT },
|
},
|
||||||
|
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()
|
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);
|
self.pid_ctrl_ch0.set_pid_params(param, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,14 +444,18 @@ impl Thermostat{
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_temperature_setpoint(&mut self, t: ThermodynamicTemperature) {
|
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.pid_ctrl_ch0.set_pid_setpoint(t);
|
||||||
self.temp_mon.set_setpoint(t);
|
self.temp_mon.set_setpoint(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_temp_mon_settings(&mut self, settings: TempMonSettings){
|
pub fn apply_temp_mon_settings(&mut self, settings: TempMonSettings) {
|
||||||
self.temp_mon.set_upper_limit(ThermodynamicTemperature::new::<degree_celsius>(settings.upper_limit));
|
self.temp_mon
|
||||||
self.temp_mon.set_lower_limit(ThermodynamicTemperature::new::<degree_celsius>(settings.lower_limit));
|
.set_upper_limit(ThermodynamicTemperature::new::<degree_celsius>(settings.upper_limit));
|
||||||
|
self.temp_mon
|
||||||
|
.set_lower_limit(ThermodynamicTemperature::new::<degree_celsius>(settings.lower_limit));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_temp_mon_upper_limit(&mut self, t: ThermodynamicTemperature) {
|
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) {
|
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) {
|
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::<degree_celsius>(),
|
temperature_setpoint: self.pid_ctrl_ch0.get_pid_setpoint().get::<degree_celsius>(),
|
||||||
tec_settings: self.get_tec_settings(),
|
tec_settings: self.get_tec_settings(),
|
||||||
pid_params: self.get_pid_settings(),
|
pid_params: self.get_pid_settings(),
|
||||||
temp_adc_settings: TempAdcFilter{
|
temp_adc_settings: TempAdcFilter {
|
||||||
filter_type : temp_adc_filter_type,
|
filter_type: temp_adc_filter_type,
|
||||||
sinc5sinc1odr : None,
|
sinc5sinc1odr: None,
|
||||||
sinc3odr : None,
|
sinc3odr: None,
|
||||||
sinc5sinc1postfilter : None,
|
sinc5sinc1postfilter: None,
|
||||||
sinc3fineodr : None,
|
sinc3fineodr: None,
|
||||||
rate : Some(update_rate),
|
rate: Some(update_rate),
|
||||||
},
|
},
|
||||||
temp_mon_settings: self.get_temp_mon_settings(),
|
temp_mon_settings: self.get_temp_mon_settings(),
|
||||||
thermistor_params: self.get_steinhart_hart(),
|
thermistor_params: self.get_steinhart_hart(),
|
||||||
|
@ -510,22 +534,14 @@ impl Thermostat{
|
||||||
self.apply_temp_mon_settings(settings.temp_mon_settings);
|
self.apply_temp_mon_settings(settings.temp_mon_settings);
|
||||||
|
|
||||||
match settings.temp_adc_settings.rate {
|
match settings.temp_adc_settings.rate {
|
||||||
Some(rate) => {
|
Some(rate) => match settings.temp_adc_settings.filter_type {
|
||||||
match settings.temp_adc_settings.filter_type {
|
FilterType::Sinc3 => self.set_temp_adc_sinc3_filter(0, SingleChODR::closest(rate).unwrap()),
|
||||||
FilterType::Sinc3 => {
|
FilterType::Sinc5Sinc1 => self.set_temp_adc_sinc5_sinc1_filter(0, SingleChODR::closest(rate).unwrap()),
|
||||||
self.set_temp_adc_sinc3_filter(0, SingleChODR::closest(rate).unwrap())
|
FilterType::Sinc3WithFineODR => self.set_temp_adc_sinc3_fine_filter(0, rate),
|
||||||
}
|
FilterType::Sinc5Sinc1With50hz60HzRejection => {
|
||||||
FilterType::Sinc5Sinc1 => {
|
self.set_temp_adc_sinc5_sinc1_with_postfilter(0, PostFilter::closest(rate).unwrap())
|
||||||
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 => {
|
None => {
|
||||||
debug!(" Temperature ADC Settings is not found");
|
debug!(" Temperature ADC Settings is not found");
|
||||||
}
|
}
|
||||||
|
@ -533,7 +549,9 @@ impl Thermostat{
|
||||||
|
|
||||||
self.set_pid_engaged(settings.pid_engaged);
|
self.set_pid_engaged(settings.pid_engaged);
|
||||||
self.pid_ctrl_ch0.apply_pid_params(settings.pid_params);
|
self.pid_ctrl_ch0.apply_pid_params(settings.pid_params);
|
||||||
self.set_temperature_setpoint(ThermodynamicTemperature::new::<degree_celsius>(settings.temperature_setpoint));
|
self.set_temperature_setpoint(ThermodynamicTemperature::new::<degree_celsius>(
|
||||||
|
settings.temperature_setpoint,
|
||||||
|
));
|
||||||
if !settings.pid_engaged {
|
if !settings.pid_engaged {
|
||||||
self.set_i(settings.tec_settings.i_set.value);
|
self.set_i(settings.tec_settings.i_set.value);
|
||||||
}
|
}
|
||||||
|
@ -575,5 +593,5 @@ pub struct TecSettingSummary {
|
||||||
pub struct ThermistorParams {
|
pub struct ThermistorParams {
|
||||||
t0: f32,
|
t0: f32,
|
||||||
r0: ElectricalResistance,
|
r0: ElectricalResistance,
|
||||||
b: f32
|
b: f32,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue