Compare commits
11 Commits
3ad7c417f6
...
7f06fc06fd
Author | SHA1 | Date |
---|---|---|
linuswck | 7f06fc06fd | |
linuswck | 67f9e65df8 | |
linuswck | 7d2e14ef2f | |
linuswck | e525a3f354 | |
linuswck | 8431e9f43d | |
linuswck | e9d5f4598a | |
linuswck | 1867935047 | |
linuswck | 99cf17f7e4 | |
linuswck | 048245f674 | |
linuswck | 0a01d299bc | |
linuswck | dbbd438e92 |
14
README.md
14
README.md
|
@ -41,7 +41,7 @@ gdb target/thumbv7em-none-eabihf/release/kirdy
|
|||
```
|
||||
|
||||
## Flashing
|
||||
There are several options for flashing kirdy. DFU requires only a USB-C cable or RJ45 cable, whereas OpenOCD needs a JTAG/SWD adapter.
|
||||
If the firmware to be flashed involves an update on the flash settings, it is required to erase the flash settings before flashing the new firmware to avoid unexpected hardware behavior. There are several options for flashing kirdy. DFU requires only a USB-C cable or RJ45 cable, whereas OpenOCD needs a JTAG/SWD adapter.
|
||||
|
||||
### dfu-util on Linux
|
||||
* Install the DFU USB tool (dfu-util).
|
||||
|
@ -64,7 +64,12 @@ On a Windows machine install [st.com](https://st.com) DfuSe USB device firmware
|
|||
- remove jumper
|
||||
- cycle power to leave DFU update mode
|
||||
|
||||
### Erasing Flash Settings
|
||||
### OpenOCD
|
||||
```shell
|
||||
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg -c "program target/thumbv7em-none-eabihf/debug/kirdy verify reset; exit"
|
||||
```
|
||||
|
||||
## Erasing Flash Settings
|
||||
The flash settings are stored in the last flash sector(ID: 11) of bank 0 of stm32f405. You can erase it with JTAG/SWD adapter or by putting the device in Dfu mode. You may find it useful if you have set network settings incorrectly.
|
||||
|
||||
With JTAG/SWD adapter connected, issue the following command:
|
||||
|
@ -78,8 +83,3 @@ With STM32 in DFU Mode, connect the USB Type C cable and then issue the followin
|
|||
```
|
||||
dfu-util -a 0 -s 0x080E0000:leave -D erase_flash_settings.bin
|
||||
```
|
||||
|
||||
### OpenOCD
|
||||
```shell
|
||||
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg -c "program target/thumbv7em-none-eabihf/debug/kirdy verify reset; exit"
|
||||
```
|
||||
|
|
|
@ -358,16 +358,16 @@ class Thermostat:
|
|||
"""
|
||||
return await self._send_cmd(TARGET_THERMOSTAT, "SetTecMaxV", max_v)
|
||||
|
||||
async def set_tec_max_i_pos(self, max_i_pos):
|
||||
async def set_tec_max_cooling_i(self, max_i_pos):
|
||||
"""
|
||||
Set Tec maximum positive output
|
||||
Set Tec maximum cooling current (Settable Range: 0.0 - 1.0)
|
||||
- max_i_pos: A
|
||||
"""
|
||||
return await self._send_cmd(TARGET_THERMOSTAT, "SetTecMaxIPos", max_i_pos)
|
||||
|
||||
async def set_tec_max_i_neg(self, max_i_neg):
|
||||
async def set_tec_max_heating_i(self, max_i_neg):
|
||||
"""
|
||||
Set Tec maximum negative output
|
||||
Set Tec maximum heating current (Settable Range: 0.0 - 1.0)
|
||||
- max_i_neg: A
|
||||
"""
|
||||
return await self._send_cmd(TARGET_THERMOSTAT, "SetTecMaxINeg", max_i_neg)
|
||||
|
@ -609,7 +609,7 @@ class Kirdy:
|
|||
line = await asyncio.shield(self._read_write(cmd))
|
||||
|
||||
async def end_session(self):
|
||||
"""End session to Thermostat if connected, cancel connection if connecting"""
|
||||
"""End session to Kirdy if connected, cancel connection if connecting"""
|
||||
if self._connecting_task is not None:
|
||||
self._connecting_task.cancel()
|
||||
|
||||
|
@ -625,7 +625,7 @@ class Kirdy:
|
|||
async def _read_response(self):
|
||||
try:
|
||||
response = await asyncio.wait_for(self._reader.read(1024), self.timeout)
|
||||
except TimeoutError:
|
||||
except asyncio.exceptions.TimeoutError:
|
||||
return {
|
||||
"msg_type": "Internal Timeout"
|
||||
}
|
||||
|
@ -645,12 +645,10 @@ class Kirdy:
|
|||
self._writer.write(bytes(json.dumps(cmd), "UTF-8"))
|
||||
await self._writer.drain()
|
||||
response = await self._read_response()
|
||||
try:
|
||||
if response["msg_type"] == "Acknowledge":
|
||||
return response
|
||||
except:
|
||||
retry += 1
|
||||
await asyncio.sleep(0.25)
|
||||
if response["msg_type"] == "Acknowledge":
|
||||
return response
|
||||
retry += 1
|
||||
await asyncio.sleep(0.1)
|
||||
raise NoAckRecv
|
||||
|
||||
async def _send_cmd_handler(self, target, cmd, data=None):
|
||||
|
@ -681,12 +679,10 @@ class Kirdy:
|
|||
self._writer.write(bytes(json.dumps(cmd_dict), "UTF-8"))
|
||||
await self._writer.drain()
|
||||
response = await self._read_response()
|
||||
try:
|
||||
if response["msg_type"] == "Acknowledge":
|
||||
return response
|
||||
except:
|
||||
retry += 1
|
||||
await asyncio.sleep(0.1)
|
||||
if response["msg_type"] == "Acknowledge":
|
||||
return response
|
||||
retry += 1
|
||||
await asyncio.sleep(0.1)
|
||||
raise NoAckRecv
|
||||
|
||||
async def report_mode(self):
|
||||
|
|
|
@ -278,8 +278,8 @@ async def main():
|
|||
await kirdy.thermostat.set_temp_mon_upper_limit(target_temperature + 20)
|
||||
await kirdy.thermostat.set_temp_mon_lower_limit(target_temperature - 20)
|
||||
|
||||
await kirdy.thermostat.set_tec_max_i_pos(output_step)
|
||||
await kirdy.thermostat.set_tec_max_i_neg(output_step)
|
||||
await kirdy.thermostat.set_tec_max_cooling_i(output_step)
|
||||
await kirdy.thermostat.set_tec_max_heating_i(output_step)
|
||||
|
||||
# The Polling Rate of Temperature Adc is equal to the PID Update Interval
|
||||
await kirdy.thermostat.config_temp_adc_filter("Sinc5Sinc1With50hz60HzRejection", "F16SPS")
|
||||
|
|
|
@ -33,7 +33,7 @@ impl State {
|
|||
let serial = SerialPort::new(bus);
|
||||
let dev = UsbDeviceBuilder::new(bus, UsbVidPid(0x16c0, 0x27dd))
|
||||
.manufacturer("M-Labs")
|
||||
.product("thermostat")
|
||||
.product("Kirdy")
|
||||
.device_release(0x20)
|
||||
.self_powered(true)
|
||||
.device_class(usbd_serial::USB_CLASS_CDC)
|
||||
|
|
|
@ -118,7 +118,7 @@ impl LdDrive{
|
|||
}
|
||||
|
||||
pub fn power_up(&mut self){
|
||||
let prev_i_set = LdCurrentOutCtrlTimer::get_target_i();
|
||||
let prev_i_set = self.settings.ld_drive_current;
|
||||
LdCurrentOutCtrlTimer::reset();
|
||||
let _ = self.ctrl.set_i(ElectricCurrent::new::<milliampere>(0.0), Settings::LD_DRIVE_TRANSIMPEDANCE, Settings::DAC_OUT_V_MAX);
|
||||
LdPwrExcProtector::pwr_on_and_arm_protection();
|
||||
|
@ -142,14 +142,14 @@ impl LdDrive{
|
|||
}
|
||||
|
||||
pub fn ld_set_i(&mut self, i: ElectricCurrent){
|
||||
LdCurrentOutCtrlTimer::set_target_i_and_listen_irq(i, self.settings.ld_drive_current);
|
||||
self.settings.ld_drive_current = i;
|
||||
LdCurrentOutCtrlTimer::set_target_i_and_listen_irq(i, self.ctrl.get_i_set());
|
||||
}
|
||||
|
||||
pub fn poll_and_update_output_current(&mut self) -> ElectricCurrent {
|
||||
match LdCurrentOutCtrlTimer::get_irq_status() {
|
||||
Some(i_set) => {
|
||||
let i_set = self.ctrl.set_i(i_set, Settings::LD_DRIVE_TRANSIMPEDANCE, Settings::DAC_OUT_V_MAX);
|
||||
self.settings.ld_drive_current = i_set;
|
||||
LdCurrentOutCtrlTimer::clear_alarm_and_resume_listening();
|
||||
i_set
|
||||
}
|
||||
|
@ -195,10 +195,15 @@ impl LdDrive{
|
|||
}
|
||||
|
||||
pub fn get_status_report(&mut self) -> StatusReport {
|
||||
let ld_i_set = if LdPwrExcProtector::get_status().pwr_engaged {
|
||||
self.ctrl.get_i_set()
|
||||
} else {
|
||||
ElectricCurrent::new::<ampere>(0.0)
|
||||
};
|
||||
StatusReport {
|
||||
pwr_on: LdPwrExcProtector::get_status().pwr_engaged,
|
||||
pwr_excursion: LdPwrExcProtector::get_status().pwr_excursion,
|
||||
ld_i_set: self.settings.ld_drive_current,
|
||||
ld_i_set: ld_i_set,
|
||||
pd_i: self.get_pd_i(),
|
||||
pd_pwr: self.get_pd_pwr(),
|
||||
term_status: self.get_term_status(),
|
||||
|
|
|
@ -8,7 +8,8 @@ use stm32f4xx_hal::{
|
|||
|
||||
use uom::si::{
|
||||
ratio::ratio,
|
||||
f32::{ElectricPotential, ElectricCurrent},
|
||||
f32::{ElectricPotential, ElectricCurrent},
|
||||
electric_current::ampere,
|
||||
};
|
||||
|
||||
use crate::laser_diode::max5719::{self, Dac};
|
||||
|
@ -49,12 +50,14 @@ type DacLoad = PB14<Output<PushPull>>;
|
|||
|
||||
pub struct LdCtrl{
|
||||
pub phy: LdCtrlPhy<Channel0>,
|
||||
i_set: ElectricCurrent,
|
||||
}
|
||||
|
||||
impl LdCtrl {
|
||||
pub fn new(phy_ch0: LdCtrlPhy<Channel0>) -> Self {
|
||||
LdCtrl {
|
||||
phy: phy_ch0,
|
||||
i_set: ElectricCurrent::new::<ampere>(0.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,6 +88,11 @@ impl LdCtrl {
|
|||
}
|
||||
|
||||
pub fn set_i(&mut self, current: ElectricCurrent, transimpedance: TransimpedanceUnit, dac_out_v_max: ElectricPotential) -> ElectricCurrent {
|
||||
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
|
||||
}
|
||||
|
||||
pub fn get_i_set(&mut self) -> ElectricCurrent{
|
||||
self.i_set
|
||||
}
|
||||
}
|
|
@ -63,13 +63,6 @@ impl LdCurrentOutCtrlTimer {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_target_i() -> ElectricCurrent {
|
||||
if let Some(ref mut ld_current_out_ctrl_timer ) = LdCurrentOutCtrlTimer::get() {
|
||||
return ld_current_out_ctrl_timer.target_i
|
||||
}
|
||||
ElectricCurrent::new::<ampere>(0.0)
|
||||
}
|
||||
|
||||
pub fn set_alarm() {
|
||||
if let Some(ref mut ld_current_out_ctrl_timer ) = LdCurrentOutCtrlTimer::get() {
|
||||
ld_current_out_ctrl_timer.timeout = true;
|
||||
|
|
53
src/main.rs
53
src/main.rs
|
@ -31,7 +31,6 @@ static mut ETH_DATA_BUFFER: [u8; 1024] = [0; 1024];
|
|||
|
||||
#[derive(Deserialize, Serialize, Clone, Copy, Debug)]
|
||||
pub struct DeviceSettings{
|
||||
report_readings: bool,
|
||||
ip_settings: IpSettings,
|
||||
}
|
||||
|
||||
|
@ -59,10 +58,11 @@ fn main() -> ! {
|
|||
let (mut wd, mut flash_store, mut laser, mut thermostat,) = bootup(core_perif, perif);
|
||||
|
||||
let mut device_settings = DeviceSettings {
|
||||
report_readings: false,
|
||||
ip_settings: IpSettings::default()
|
||||
};
|
||||
|
||||
let mut active_report: [bool; net::net::NUM_OF_SOCKETS] = [false; net::net::NUM_OF_SOCKETS];
|
||||
|
||||
let mut state = State::default();
|
||||
|
||||
loop {
|
||||
|
@ -133,12 +133,10 @@ fn main() -> ! {
|
|||
}
|
||||
State::MainLoop => {
|
||||
let mut eth_is_pending = false;
|
||||
let mut has_temp_reading = false;
|
||||
|
||||
laser.poll_and_update_output_current();
|
||||
|
||||
if thermostat.poll_adc() {
|
||||
has_temp_reading = true;
|
||||
thermostat.update_pid();
|
||||
if thermostat.get_temp_mon_status().over_temp_alarm {
|
||||
laser.power_down();
|
||||
|
@ -146,43 +144,42 @@ fn main() -> ! {
|
|||
thermostat.power_down();
|
||||
}
|
||||
|
||||
net::net::for_each(|mut socket| {
|
||||
if net::net::eth_is_socket_active(socket) {
|
||||
if device_settings.report_readings {
|
||||
net::net::for_each(|mut socket, id| {
|
||||
if net::net::eth_is_socket_active(socket) && net::net::eth_is_socket_connected(socket) {
|
||||
if active_report[id] {
|
||||
unsafe {
|
||||
net::cmd_handler::send_status_report(&mut ETH_DATA_BUFFER, &mut laser, &mut thermostat, &mut socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
active_report[id] = false;
|
||||
}
|
||||
});
|
||||
|
||||
thermostat.start_tec_readings_conversion();
|
||||
}
|
||||
net::net::for_each(|mut socket| {
|
||||
if net::net::eth_is_socket_active(socket) {
|
||||
cortex_m::interrupt::free(|cs|
|
||||
{
|
||||
eth_is_pending = net::net::is_pending(cs);
|
||||
}
|
||||
);
|
||||
|
||||
if eth_is_pending {
|
||||
cortex_m::interrupt::free(|cs|
|
||||
{
|
||||
eth_is_pending = net::net::is_pending(cs);
|
||||
net::net::clear_pending(cs);
|
||||
}
|
||||
);
|
||||
if eth_is_pending {
|
||||
net::net::for_each(|mut socket, id| {
|
||||
if net::net::eth_is_socket_active(socket) && net::net::eth_is_socket_connected(socket){
|
||||
unsafe{
|
||||
cortex_m::interrupt::free(|cs| {
|
||||
net::net::clear_pending(cs);
|
||||
});
|
||||
let bytes = net::net::eth_recv(&mut ETH_DATA_BUFFER, socket);
|
||||
if bytes != 0 {
|
||||
info!("Ts: {:?}", sys_timer::now());
|
||||
debug!("Number of bytes recv: {:?}", bytes);
|
||||
// State Transition
|
||||
net::cmd_handler::execute_cmd(&mut ETH_DATA_BUFFER, bytes, &mut socket, &mut laser, &mut thermostat, &mut state, &mut device_settings);
|
||||
net::cmd_handler::execute_cmd(&mut ETH_DATA_BUFFER, bytes, &mut socket, &mut laser, &mut thermostat, &mut state, &mut device_settings, &mut active_report[id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if has_temp_reading {
|
||||
thermostat.start_tec_readings_conversion();
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
};
|
||||
}
|
||||
State::SaveFlashSettings => {
|
||||
// State Transition
|
||||
|
@ -226,7 +223,7 @@ fn main() -> ! {
|
|||
wd.feed();
|
||||
laser.power_down();
|
||||
thermostat.power_down();
|
||||
net::net::for_each(|mut socket| {
|
||||
net::net::for_each(|mut socket, _| {
|
||||
if net::net::eth_is_socket_active(socket) {
|
||||
unsafe {
|
||||
net::cmd_handler::send_response(&mut ETH_DATA_BUFFER, net::cmd_handler::ResponseEnum::HardReset, None, &mut socket);
|
||||
|
@ -239,10 +236,10 @@ fn main() -> ! {
|
|||
laser.power_down();
|
||||
thermostat.power_down();
|
||||
let mut any_socket_alive = false;
|
||||
net::net::for_each(|socket| {
|
||||
net::net::for_each(|socket, _| {
|
||||
if net::net::eth_is_socket_active(socket) {
|
||||
net::net::eth_close_socket(socket);
|
||||
any_socket_alive = true;
|
||||
any_socket_alive = true;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -221,7 +221,7 @@ pub struct TecSetICmd {
|
|||
/// 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
|
||||
/// 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){
|
||||
pub fn execute_cmd(buffer: &mut [u8], buffer_size: usize, socket: &mut SocketHandle, laser: &mut LdDrive, thermostat: &mut Thermostat, state: &mut State, device_settings: &mut DeviceSettings, active_report: &mut bool){
|
||||
let mut cmd = TecSetICmd {
|
||||
json: TecSetICmdJson::default()
|
||||
};
|
||||
|
@ -266,7 +266,7 @@ pub fn execute_cmd(buffer: &mut [u8], buffer_size: usize, socket: &mut SocketHan
|
|||
match cmd.json.data_bool{
|
||||
Some(val) => {
|
||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||
device_settings.report_readings = val;
|
||||
*active_report = val;
|
||||
}
|
||||
None => {
|
||||
send_response(buffer, ResponseEnum::InvalidDatatype, Some(ERR_MSG_MISSING_DATA_BOOL), socket);
|
||||
|
|
|
@ -61,7 +61,7 @@ pub struct EthernetMgmtPins {
|
|||
}
|
||||
pub type EthInterface = Interface;
|
||||
|
||||
const NUM_OF_SOCKETS : usize = 4;
|
||||
pub const NUM_OF_SOCKETS : usize = 4;
|
||||
const TCP_BUFFER_SIZE: usize = 2048;
|
||||
static mut RX_RING: Option<[RxRingEntry; 8]> = None;
|
||||
static mut TX_RING: Option<[TxRingEntry; 2]> = None;
|
||||
|
@ -207,8 +207,11 @@ impl ServerHandle {
|
|||
self.link_was_up = self.phy.phy_link_up();
|
||||
}
|
||||
|
||||
pub fn recv(&mut self, buffer: &mut [u8], socket_handles: SocketHandle)-> Result<usize, smoltcp::socket::tcp::RecvError> {
|
||||
pub fn poll_iface(&mut self) {
|
||||
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> {
|
||||
let socket = self.socket_set.get_mut::<Socket>(socket_handles);
|
||||
|
||||
socket.recv_slice(buffer)
|
||||
|
@ -218,11 +221,14 @@ impl ServerHandle {
|
|||
let socket = self.socket_set.get_mut::<Socket>(socket_handles);
|
||||
if num_bytes > 0 {
|
||||
socket.send_slice(&buffer[..num_bytes]).ok();
|
||||
self.poll_iface();
|
||||
info!("Sent {} bytes.", num_bytes);
|
||||
}
|
||||
|
||||
// Send bytes out
|
||||
self.iface.poll(now_fn(), &mut &mut self.dma, &mut self.socket_set);
|
||||
}
|
||||
|
||||
pub fn is_socket_connected(&mut self, socket_handles: SocketHandle)->bool {
|
||||
let socket = self.socket_set.get_mut::<Socket>(socket_handles);
|
||||
socket.state() == State::Established
|
||||
}
|
||||
|
||||
pub fn poll_socket_status(&mut self, socket_handles: SocketHandle)-> bool {
|
||||
|
@ -357,6 +363,17 @@ pub fn eth_poll_and_update_link_speed() {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn eth_poll_iface() {
|
||||
unsafe {
|
||||
if let Some(ref mut server_handle ) = SERVER_HANDLE {
|
||||
server_handle.poll_iface();
|
||||
}
|
||||
else {
|
||||
panic!("eth_poll_packet is called before init");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eth_send(buffer: &mut [u8], num_bytes: usize, socket_handles: SocketHandle) {
|
||||
unsafe {
|
||||
if let Some(ref mut server_handle ) = SERVER_HANDLE {
|
||||
|
@ -385,6 +402,17 @@ pub fn eth_recv(buffer: &mut [u8], socket_handles: SocketHandle)-> usize{
|
|||
}
|
||||
}
|
||||
|
||||
pub fn eth_is_socket_connected(socket_handles: SocketHandle) -> bool {
|
||||
unsafe {
|
||||
if let Some(ref mut server_handle ) = SERVER_HANDLE {
|
||||
server_handle.is_socket_connected(socket_handles)
|
||||
}
|
||||
else {
|
||||
panic!("eth_is_socket_connected is called before init");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eth_is_socket_active(socket_handles: SocketHandle) -> bool {
|
||||
unsafe {
|
||||
if let Some(ref mut server_handle ) = SERVER_HANDLE {
|
||||
|
@ -407,11 +435,11 @@ pub fn eth_close_socket(socket_handles: SocketHandle) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn for_each<F: FnMut(SocketHandle)>(mut callback: F) {
|
||||
pub fn for_each<F: FnMut(SocketHandle, usize)>(mut callback: F) {
|
||||
unsafe {
|
||||
if let Some(ref mut server_handle ) = SERVER_HANDLE {
|
||||
for i in 0..NUM_OF_SOCKETS {
|
||||
callback(server_handle.socket_handles[i]);
|
||||
callback(server_handle.socket_handles[i], i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -426,10 +454,12 @@ pub fn for_each<F: FnMut(SocketHandle)>(mut callback: F) {
|
|||
fn ETH() {
|
||||
let interrupt_reason = stm32_eth::eth_interrupt_handler();
|
||||
cortex_m::interrupt::free(|cs| {
|
||||
*NET_PENDING.borrow(cs)
|
||||
.borrow_mut() = true;
|
||||
if interrupt_reason.rx {
|
||||
*NET_PENDING.borrow(cs)
|
||||
.borrow_mut() = true;
|
||||
eth_poll_iface();
|
||||
}
|
||||
});
|
||||
|
||||
debug!("Ethernet Interrupt{:?}", interrupt_reason);
|
||||
}
|
||||
|
||||
|
|
|
@ -218,7 +218,7 @@ impl MAX1968 {
|
|||
}
|
||||
|
||||
pub fn is_powered_on(&mut self) -> bool {
|
||||
self.phy.shdn.is_set_low()
|
||||
self.phy.shdn.is_set_high()
|
||||
}
|
||||
|
||||
pub fn power_down(&mut self) {
|
||||
|
|
|
@ -11,6 +11,7 @@ pub enum TempStatusEnum {
|
|||
OverTemp,
|
||||
Unstable,
|
||||
Stable,
|
||||
ConstantCurrentMode,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
||||
|
@ -56,7 +57,8 @@ impl Default for TempMon {
|
|||
#[derive(Default, PartialEq, Debug)]
|
||||
enum State {
|
||||
#[default]
|
||||
PidOff,
|
||||
PwrOff,
|
||||
ConstantCurrentMode,
|
||||
PidStartUp,
|
||||
PidStable,
|
||||
OverTempAlarm,
|
||||
|
@ -95,16 +97,38 @@ impl TempMon {
|
|||
self.state = State::default();
|
||||
}
|
||||
|
||||
pub fn update_status(&mut self, pid_engaged: bool, temp: ThermodynamicTemperature) {
|
||||
pub fn update_status(&mut self, pid_engaged: bool, pwr_on: bool, temp: ThermodynamicTemperature) {
|
||||
match self.state {
|
||||
State::PidOff => {
|
||||
State::PwrOff => {
|
||||
self.is_set_point_changed = false;
|
||||
self.status.status = TempStatusEnum::Off;
|
||||
self.count = 0;
|
||||
|
||||
// State Transition
|
||||
if pid_engaged {
|
||||
if pwr_on {
|
||||
if pid_engaged {
|
||||
self.state = State::PidStartUp;
|
||||
} else {
|
||||
self.state = State::ConstantCurrentMode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
State::ConstantCurrentMode => {
|
||||
let is_over_temp = temp > self.upper_limit || temp < self.lower_limit;
|
||||
self.status.status = TempStatusEnum::ConstantCurrentMode;
|
||||
|
||||
if is_over_temp {
|
||||
self.state = State::OverTempAlarm;
|
||||
self.status.status = TempStatusEnum::OverTemp;
|
||||
}
|
||||
else if !pwr_on {
|
||||
self.state = State::PwrOff;
|
||||
self.status.status = TempStatusEnum::Off;
|
||||
} else if pid_engaged {
|
||||
self.state = State::PidStartUp;
|
||||
self.status.status = TempStatusEnum::Unstable;
|
||||
self.is_set_point_changed = false;
|
||||
}
|
||||
}
|
||||
State::PidStartUp | State::PidStable => {
|
||||
|
@ -134,13 +158,20 @@ impl TempMon {
|
|||
}
|
||||
|
||||
// State Transition
|
||||
if self.status.status == TempStatusEnum::OverTemp {
|
||||
self.state = State::OverTempAlarm;
|
||||
} else if self.is_set_point_changed {
|
||||
self.is_set_point_changed = false;
|
||||
self.state = State::PidStartUp;
|
||||
} else if self.status.status == TempStatusEnum::Stable {
|
||||
self.state = State::PidStable;
|
||||
if !pwr_on {
|
||||
self.state = State::PwrOff;
|
||||
}
|
||||
else {
|
||||
if self.status.status == TempStatusEnum::OverTemp {
|
||||
self.state = State::OverTempAlarm;
|
||||
} else if self.is_set_point_changed {
|
||||
self.is_set_point_changed = false;
|
||||
self.state = State::PidStartUp;
|
||||
} else if self.status.status == TempStatusEnum::Stable {
|
||||
self.state = State::PidStable;
|
||||
} else if !pid_engaged {
|
||||
self.state = State::ConstantCurrentMode
|
||||
}
|
||||
}
|
||||
}
|
||||
State::OverTempAlarm => {
|
||||
|
|
|
@ -186,7 +186,7 @@ impl Thermostat{
|
|||
state.update(data);
|
||||
let pid_engaged = state.get_pid_engaged();
|
||||
let temp = self.get_temperature();
|
||||
self.temp_mon.update_status(pid_engaged, temp);
|
||||
self.temp_mon.update_status(pid_engaged, self.max1968.is_powered_on(), temp);
|
||||
debug!("state.get_pid_engaged(): {:?}", pid_engaged);
|
||||
debug!("Temperature: {:?} degree", temp.get::<degree_celsius>());
|
||||
data_rdy = true;
|
||||
|
|
Loading…
Reference in New Issue