From d2af9307670fb6c3996b86e341004e53a07c0d2f Mon Sep 17 00:00:00 2001 From: Jack Rubacha Date: Fri, 6 Sep 2024 22:49:36 -0400 Subject: [PATCH] hehehe cerberus in rust --- Cargo.toml | 1 + cerberus/Cargo.toml | 1 + cerberus/src/can_handler.rs | 4 +- cerberus/src/dti.rs | 30 +++ cerberus/src/fault.rs | 21 +- cerberus/src/lib.rs | 13 +- cerberus/src/main.rs | 81 ++++++- cerberus/src/monitor.rs | 273 ++++++++++++++++++++++++ cerberus/src/state_machine.rs | 85 ++++++++ crates/pca9539-ner/Cargo.toml | 4 +- crates/pca9539-ner/src/lib.rs | 116 +++++----- msb-fw-rs/src/can_handler.rs | 6 +- rustc-ice-2024-09-06T23_26_24-47544.txt | 66 ++++++ 13 files changed, 633 insertions(+), 68 deletions(-) create mode 100644 cerberus/src/dti.rs create mode 100644 cerberus/src/monitor.rs create mode 100644 cerberus/src/state_machine.rs create mode 100644 rustc-ice-2024-09-06T23_26_24-47544.txt diff --git a/Cargo.toml b/Cargo.toml index 87e554d..ce89ec9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ heapless = { version = "0.8", default-features = false } static_cell = "2.1.0" chrono = { version = "^0.4", default-features = false} embedded-hal-async = {version = "1.0.0", features = ["defmt-03"] } +bitfield = "^0.13.2" [patch.crates-io] diff --git a/cerberus/Cargo.toml b/cerberus/Cargo.toml index a837a7f..5c41df0 100644 --- a/cerberus/Cargo.toml +++ b/cerberus/Cargo.toml @@ -17,4 +17,5 @@ embassy-futures.workspace = true heapless.workspace = true panic-probe.workspace = true static_cell.workspace = true +bitfield.workspace = true pca9539-ner = { version = "0.1.0", path = "../crates/pca9539-ner" } \ No newline at end of file diff --git a/cerberus/src/can_handler.rs b/cerberus/src/can_handler.rs index 560836a..d56b586 100644 --- a/cerberus/src/can_handler.rs +++ b/cerberus/src/can_handler.rs @@ -35,7 +35,9 @@ pub async fn can_handler( match select(recv.receive(), can.read()).await { select::Either::First(frame) => { trace!("Sending frame: {}", frame); - can.write(&frame).await; + if let Some(_) = can.write(&frame).await.dequeued_frame() { + warn!("Dequeing can frames!"); + } } select::Either::Second(res) => match res { Ok(got) => match got.frame.header().id() { diff --git a/cerberus/src/dti.rs b/cerberus/src/dti.rs new file mode 100644 index 0000000..7ec159a --- /dev/null +++ b/cerberus/src/dti.rs @@ -0,0 +1,30 @@ +use core::{f32::consts::PI, sync::atomic::AtomicI32}; + +use embassy_stm32::can::Frame; +use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal}; + +#[embassy_executor::task] +pub async fn dti_handler( + recved: &'static Signal, + speed: &'static AtomicI32, +) { + loop { + let frame = recved.wait().await; + match frame.id() { + embassy_stm32::can::Id::Standard(id) => match id.as_raw() { + 0x416 => { + // TODO fat chance this works + let erpm = ((frame.data()[0] as i32) << 24u32) + + ((frame.data()[1] as i32) << 16) + + ((frame.data()[2] as i32) << 8u32) + + (frame.data()[3] as i32); + let mph = (erpm / 10) as f32 / (47.0 / 13.0) * 60.0 * (16.0 / 63360.0) * PI; + // TODO add precision + speed.store(mph as i32, core::sync::atomic::Ordering::Release); + } + _ => (), + }, + embassy_stm32::can::Id::Extended(_) => (), + } + } +} diff --git a/cerberus/src/fault.rs b/cerberus/src/fault.rs index 725f892..86b46a0 100644 --- a/cerberus/src/fault.rs +++ b/cerberus/src/fault.rs @@ -6,14 +6,15 @@ use embassy_sync::{ channel::Sender, signal::Signal, }; -use embassy_time::Timer; +use embassy_time::{Duration, Instant, Timer}; -use crate::FaultCode; +use crate::{FaultCode, FaultSeverity, FunctionalType, StateTransition}; #[embassy_executor::task] pub async fn fault_handler( can_send: Sender<'static, ThreadModeRawMutex, Frame, 25>, fault: &'static Signal, + state_send: &'static Signal, ) { let mut last_fault = FaultCode::FaultsClear; @@ -21,19 +22,31 @@ pub async fn fault_handler( let mut fault_bits: [u8; 5] = [0u8; 5]; + let mut last_fault_time = Instant::now(); + loop { last_fault = match select(fault.wait(), Timer::after_millis(250)).await { embassy_futures::select::Either::First(event) => { match event.get_severity() { crate::FaultSeverity::Defcon1 | crate::FaultSeverity::Defcon2 - | crate::FaultSeverity::Defcon3 => todo!("Fault"), + | crate::FaultSeverity::Defcon3 => { + state_send.signal(StateTransition::Functional(FunctionalType::FAULTED)); + last_fault_time = Instant::now(); + } crate::FaultSeverity::Defcon4 => warn!("Non critical fault!"), crate::FaultSeverity::Defcon5 => debug!("Faults clear!"), } event } - embassy_futures::select::Either::Second(_) => last_fault, + embassy_futures::select::Either::Second(_) => { + if last_fault.get_severity() as u8 <= FaultSeverity::Defcon3 as u8 + && Instant::now() - last_fault_time > Duration::from_secs(5) + { + state_send.signal(StateTransition::Functional(FunctionalType::READY)) + } + FaultCode::FaultsClear + } }; fault_bits[3..4].copy_from_slice(&(last_fault.get_severity() as u8).to_be_bytes()); diff --git a/cerberus/src/lib.rs b/cerberus/src/lib.rs index 3bb4f10..3ce69d1 100644 --- a/cerberus/src/lib.rs +++ b/cerberus/src/lib.rs @@ -2,14 +2,17 @@ pub mod bms; pub mod can_handler; +pub mod dti; pub mod fault; +pub mod monitor; +pub mod state_machine; pub type SharedI2c = embassy_sync::mutex::Mutex< embassy_sync::blocking_mutex::raw::NoopRawMutex, embassy_stm32::i2c::I2c<'static, embassy_stm32::mode::Async>, >; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq, Eq)] pub enum FunctionalType { READY, /* F means functional */ @@ -39,6 +42,7 @@ pub enum StateTransition { // TODO: this is a breaking change and is also ugly and non-exhuastive in terms of IDs // However it is centralized which is better than the C impl +#[repr(u8)] pub enum FaultSeverity { Defcon1 = 1, Defcon2 = 2, @@ -61,3 +65,10 @@ impl FaultCode { } } } + +pub enum PduCommand { + WritePump(bool), + WriteBrakelight(bool), + WriteFault(bool), + SoundRtds, +} diff --git a/cerberus/src/main.rs b/cerberus/src/main.rs index 8a10bd0..143daf3 100644 --- a/cerberus/src/main.rs +++ b/cerberus/src/main.rs @@ -1,9 +1,15 @@ #![no_std] #![no_main] -use core::fmt::Write; +use core::{ + fmt::Write, + sync::atomic::{AtomicBool, AtomicI32, AtomicU32}, +}; -use cerberus::{bms, can_handler, fault, FaultCode, SharedI2c, StateTransition}; +use cerberus::{ + bms, can_handler, dti, fault, monitor, state_machine, FaultCode, PduCommand, SharedI2c, + StateTransition, +}; use cortex_m::{peripheral::SCB, singleton}; use cortex_m_rt::{exception, ExceptionFrame}; use defmt::{info, unwrap, warn}; @@ -12,6 +18,7 @@ use embassy_stm32::{ adc::{Adc, SampleTime, Sequence}, bind_interrupts, can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}, + exti::ExtiInput, i2c::{self, I2c}, peripherals::CAN1, time::Hertz, @@ -57,10 +64,18 @@ bind_interrupts!(struct IrqsI2c2 { }); static CAN_CHANNEL: Channel = Channel::new(); +static PDU_COMMAND: Channel = Channel::new(); static CURRENT_STATE: Signal = Signal::new(); static FAULT: Signal = Signal::new(); +// true=TS ON +static TSMS_SENSE: AtomicBool = AtomicBool::new(false); +// true=brakes engaged +static BRAKE_STATE: AtomicBool = AtomicBool::new(false); + +static DTI_MPH: AtomicI32 = AtomicI32::new(0); + static BMS_CALLBACK: Signal = Signal::new(); static DTI_CALLBACK: Signal = Signal::new(); @@ -83,8 +98,15 @@ async fn main(spawner: Spawner) -> ! { if let Err(err) = spawner.spawn(bms::bms_handler(&BMS_CALLBACK, &FAULT)) { warn!("Could not spawn BMS task: {}", err); } + if let Err(err) = spawner.spawn(dti::dti_handler(&DTI_CALLBACK, &DTI_MPH)) { + warn!("Could not spawn DTI task: {}", err); + } - if let Err(err) = spawner.spawn(fault::fault_handler(CAN_CHANNEL.sender(), &FAULT)) { + if let Err(err) = spawner.spawn(fault::fault_handler( + CAN_CHANNEL.sender(), + &FAULT, + &CURRENT_STATE, + )) { warn!("Could not spawn fault task: {}", err); } @@ -113,17 +135,28 @@ async fn main(spawner: Spawner) -> ! { i2c::Config::default(), ); let i2c_bus_2 = I2C_BUS_2.init(Mutex::new(i2c_2)); + if let Err(err) = spawner.spawn(monitor::ctrl_expander_handler( + CAN_CHANNEL.sender(), + PDU_COMMAND.receiver(), + i2c_bus_2, + &TSMS_SENSE, + )) { + warn!("Could not spawn ctrl expander task: {}", err); + } - const ADC_BUF_SIZE: usize = 1024; - + const ADC1_BUF_SIZE: usize = 40; let adc1 = Adc::new(p.ADC1); - let adc_data_1 = singleton!(ADCDAT : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]) + let adc_data_1 = singleton!(ADCDAT : [u16; ADC1_BUF_SIZE] = [0u16; ADC1_BUF_SIZE]) .expect("Could not init adc buffer"); let mut adc1 = adc1.into_ring_buffered(p.DMA2_CH4, adc_data_1); - adc1.set_sample_sequence(Sequence::One, &mut p.PB0, SampleTime::CYCLES112); // + adc1.set_sample_sequence(Sequence::One, &mut p.PB0, SampleTime::CYCLES112); // LV sense + if let Err(err) = spawner.spawn(monitor::lv_sense_handler(adc1, CAN_CHANNEL.sender())) { + warn!("Could not spawn LV sense task: {}", err); + } + const ADC3_BUF_SIZE: usize = 120; let adc3 = Adc::new(p.ADC3); - let adc_data_3 = singleton!(ADCDAT : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]) + let adc_data_3 = singleton!(ADCDAT : [u16; ADC3_BUF_SIZE] = [0u16; ADC3_BUF_SIZE]) .expect("Could not init adc buffer"); let mut adc3 = adc3.into_ring_buffered(p.DMA2_CH0, adc_data_3); adc3.set_sample_sequence(Sequence::One, &mut p.PA0, SampleTime::CYCLES112); // @@ -131,6 +164,28 @@ async fn main(spawner: Spawner) -> ! { adc3.set_sample_sequence(Sequence::One, &mut p.PA2, SampleTime::CYCLES112); // adc3.set_sample_sequence(Sequence::One, &mut p.PA3, SampleTime::CYCLES112); // + let button1 = ExtiInput::new(p.PA4, p.EXTI4, embassy_stm32::gpio::Pull::Up); + let button2 = ExtiInput::new(p.PA5, p.EXTI5, embassy_stm32::gpio::Pull::Up); + let button3 = ExtiInput::new(p.PA6, p.EXTI6, embassy_stm32::gpio::Pull::Up); + let button4 = ExtiInput::new(p.PA7, p.EXTI7, embassy_stm32::gpio::Pull::Up); + //let button5 = ExtiInput::new(p.PC4, p.EXTI4, embassy_stm32::gpio::Pull::Up); + //let button6 = ExtiInput::new(p.PC5, p.EXTI5, embassy_stm32::gpio::Pull::Up); + let button7 = ExtiInput::new(p.PB0, p.EXTI0, embassy_stm32::gpio::Pull::Up); + let button8 = ExtiInput::new(p.PB1, p.EXTI1, embassy_stm32::gpio::Pull::Up); + if let Err(err) = spawner.spawn(monitor::steeringio_handler( + CAN_CHANNEL.sender(), + button1, + button2, + button3, + button4, + // button5, + // button6, + button7, + button8, + )) { + warn!("Could not spawn steeringIO task: {}", err); + } + let mut usart = Uart::new( p.USART3, p.PC11, @@ -145,6 +200,16 @@ async fn main(spawner: Spawner) -> ! { core::write!(&mut s, "Hello DMA World!\r\n",).unwrap(); unwrap!(usart.write(s.as_bytes()).await); + if let Err(err) = spawner.spawn(state_machine::state_handler( + &CURRENT_STATE, + PDU_COMMAND.sender(), + &DTI_MPH, + &BRAKE_STATE, + &TSMS_SENSE, + )) { + warn!("Could not spawn BMS task: {}", err); + } + let mut watchdog = IndependentWatchdog::new(p.IWDG, 4000000); watchdog.unleash(); let mut led_pin = Output::new(p.PC8, Level::Low, Speed::Low); diff --git a/cerberus/src/monitor.rs b/cerberus/src/monitor.rs new file mode 100644 index 0000000..c28ac64 --- /dev/null +++ b/cerberus/src/monitor.rs @@ -0,0 +1,273 @@ +use core::sync::atomic::AtomicBool; + +use bitfield::Bit; +use defmt::{unwrap, warn}; +use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice; +use embassy_futures::select::{self, select3, select_array}; +use embassy_stm32::{ + adc::RingBufferedAdc, + can::{Frame, StandardId}, + exti::ExtiInput, + peripherals::ADC1, +}; +use embassy_sync::{ + blocking_mutex::raw::ThreadModeRawMutex, + channel::{Receiver, Sender}, +}; +use embassy_time::{Duration, Instant, Timer}; +use pca9539_ner::{Pca9539, Pin}; + +use crate::{PduCommand, SharedI2c}; + +#[embassy_executor::task] +pub async fn lv_sense_handler( + mut adc1: RingBufferedAdc<'static, ADC1>, + can_send: Sender<'static, ThreadModeRawMutex, Frame, 25>, +) { + let mut measurements: [u16; 20] = [0u16; 40 / 2]; + + loop { + match adc1.read(&mut measurements).await { + Ok(_) => { + adc1.teardown_adc(); + let v_in = (measurements[0] as f32 * 8.967 * 10f32) as u32; + // TODO transform measurements + can_send + .send(unwrap!(Frame::new_standard(0x503, &v_in.to_be_bytes()))) + .await; + } + Err(_) => { + warn!("DMA overrun"); + continue; + } + } + Timer::after_millis(750).await; + } +} + +#[embassy_executor::task] +pub async fn ctrl_expander_handler( + can_send: Sender<'static, ThreadModeRawMutex, Frame, 25>, + pdu_recv: Receiver<'static, ThreadModeRawMutex, PduCommand, 10>, + ctrl_expand_i2c: &'static SharedI2c, + ts_state_send: &'static AtomicBool, +) { + let i2c_dev = I2cDevice::new(ctrl_expand_i2c); + let mut pca9539 = Pca9539::new(i2c_dev, 0x76).unwrap(); + + unwrap!( + pca9539 + .write_register( + pca9539_ner::RegisterType::OutputLevel, + pca9539_ner::Bank::Bank0, + 0b00000010 + ) + .await + ); + unwrap!( + pca9539 + .write_register( + pca9539_ner::RegisterType::OutputLevel, + pca9539_ner::Bank::Bank1, + 0b00000010 + ) + .await + ); + unwrap!( + pca9539 + .write_register( + pca9539_ner::RegisterType::Direction, + pca9539_ner::Bank::Bank0, + 0b11110000 + ) + .await + ); + unwrap!( + pca9539 + .write_register( + pca9539_ner::RegisterType::Direction, + pca9539_ner::Bank::Bank1, + 0b01111111 + ) + .await + ); + + // debounce TSMS sense + let mut tsms_prev_state = false; + let mut tsms_state_count = 0u8; + + // for rtds + let mut active_sounding = false; + let mut rtds_sound_start = Instant::now(); + + loop { + match select3( + Timer::after_millis(100), + Timer::after_millis(800), + pdu_recv.receive(), + ) + .await + { + select::Either3::First(_) => { + if active_sounding + && Instant::now() - rtds_sound_start > Duration::from_millis(1750) + { + unwrap!( + pca9539 + .write_pin( + pca9539_ner::RegisterType::OutputLevel, + pca9539_ner::Bank::Bank1, + Pin::P07, + false + ) + .await + ); + active_sounding = false; + } + let state = unwrap!( + pca9539 + .read_pin( + pca9539_ner::RegisterType::InputLevel, + pca9539_ner::Bank::Bank1, + Pin::P06 + ) + .await + ); + if state == tsms_prev_state { + if tsms_state_count > 5 { + ts_state_send.store(state, core::sync::atomic::Ordering::Release); + tsms_state_count = 0; + } + tsms_state_count += 1; + } + tsms_prev_state = state; + } + select::Either3::Second(_) => { + let data_0 = unwrap!( + pca9539 + .read_register( + pca9539_ner::RegisterType::InputLevel, + pca9539_ner::Bank::Bank0 + ) + .await + ); + + let data_1 = unwrap!( + pca9539 + .read_register( + pca9539_ner::RegisterType::InputLevel, + pca9539_ner::Bank::Bank1 + ) + .await + ); + + let mut send_data_1: u8 = 0; + let mut send_data_2: u8 = 0; + + send_data_1.set_bit(0, data_0.bit(4)); + send_data_1.set_bit(1, data_0.bit(5)); + send_data_1.set_bit(2, data_0.bit(6)); + send_data_1.set_bit(3, data_0.bit(7)); + send_data_1.set_bit(4, data_1.bit(0)); + send_data_1.set_bit(5, data_1.bit(1)); + send_data_1.set_bit(6, data_1.bit(2)); + send_data_1.set_bit(7, data_1.bit(3)); + send_data_2.set_bit(0, data_1.bit(4)); + + // reverse bits + send_data_1 = send_data_1.reverse_bits(); + send_data_2 = send_data_2.reverse_bits(); + + let mut send_data: [u8; 2] = [0u8; 2]; + + send_data[0..1].copy_from_slice(&send_data_1.to_be_bytes()); + send_data[1..2].copy_from_slice(&send_data_2.to_be_bytes()); + + can_send + .send(unwrap!(Frame::new_data( + unwrap!(StandardId::new(0x111)), + &send_data + ))) + .await; + } + select::Either3::Third(cmd) => match cmd { + PduCommand::WritePump(state) => { + unwrap!( + pca9539 + .write_pin( + pca9539_ner::RegisterType::OutputLevel, + pca9539_ner::Bank::Bank0, + Pin::P00, + state + ) + .await + ) + } + PduCommand::WriteBrakelight(state) => unwrap!( + pca9539 + .write_pin( + pca9539_ner::RegisterType::OutputLevel, + pca9539_ner::Bank::Bank0, + Pin::P02, + state + ) + .await + ), + PduCommand::WriteFault(state) => unwrap!( + pca9539 + .write_pin( + pca9539_ner::RegisterType::OutputLevel, + pca9539_ner::Bank::Bank0, + Pin::P01, + state + ) + .await + ), + PduCommand::SoundRtds => { + active_sounding = true; + rtds_sound_start = Instant::now(); + } + }, + } + } +} + +#[embassy_executor::task] +pub async fn steeringio_handler( + can_send: Sender<'static, ThreadModeRawMutex, Frame, 25>, + mut button1: ExtiInput<'static>, + mut button2: ExtiInput<'static>, + mut button3: ExtiInput<'static>, + mut button4: ExtiInput<'static>, + // mut button5: ExtiInput<'static>, + // mut button6: ExtiInput<'static>, + mut button7: ExtiInput<'static>, + mut button8: ExtiInput<'static>, +) { + loop { + let ans = select_array([ + button1.wait_for_falling_edge(), + button2.wait_for_falling_edge(), + button3.wait_for_falling_edge(), + button4.wait_for_falling_edge(), + // button5.wait_for_falling_edge(), + // button6.wait_for_falling_edge(), + button7.wait_for_falling_edge(), + button8.wait_for_falling_edge(), + ]) + .await; + + let buttonValue = match ans.1 { + 0 => button1.get_level(), + 1 => button2.get_level(), + 2 => button3.get_level(), + 3 => button4.get_level(), + // 4 => button5.get_level(), + // 5 => button6.get_level(), + 4 => button7.get_level(), + 5 => button8.get_level(), + _ => panic!("Wtf"), + }; + // TODO map buttons to functions + } +} diff --git a/cerberus/src/state_machine.rs b/cerberus/src/state_machine.rs new file mode 100644 index 0000000..aa1b44b --- /dev/null +++ b/cerberus/src/state_machine.rs @@ -0,0 +1,85 @@ +use core::sync::atomic::{AtomicBool, AtomicI32}; + +use defmt::warn; +use embassy_sync::{ + blocking_mutex::raw::{CriticalSectionRawMutex, ThreadModeRawMutex}, + channel::Sender, + signal::Signal, +}; + +use crate::{FunctionalType, NeroType, PduCommand, StateTransition}; + +#[embassy_executor::task] +pub async fn state_handler( + state_recv: &'static Signal, + pdu_cmd_send: Sender<'static, ThreadModeRawMutex, PduCommand, 10>, + speed: &'static AtomicI32, + brake_state: &'static AtomicBool, + tsms_status: &'static AtomicBool, +) { + let mut prev_func_state = FunctionalType::READY; + let mut prev_nero_state = NeroType::OFF; + + loop { + let new_state = state_recv.wait().await; + match new_state { + StateTransition::Functional(state) => match state { + crate::FunctionalType::READY => { + if speed.load(core::sync::atomic::Ordering::Acquire) > 1 { + warn!("Cannot move to ready, moving!"); + continue; + } + + pdu_cmd_send.send(PduCommand::WritePump(false)).await; + pdu_cmd_send.send(PduCommand::WriteFault(true)).await; + } + crate::FunctionalType::FPit + | crate::FunctionalType::FPerformance + | crate::FunctionalType::FEfficiency => { + if prev_func_state != FunctionalType::REVERSE { + if speed.load(core::sync::atomic::Ordering::Acquire) > 1 { + warn!("Cannot move to active, moving!"); + continue; + } + if !brake_state.load(core::sync::atomic::Ordering::Acquire) + || !tsms_status.load(core::sync::atomic::Ordering::Acquire) + { + warn!("Cannot move to active, no brake or TS!"); + continue; + } + pdu_cmd_send.send(PduCommand::SoundRtds).await; + } + + pdu_cmd_send.send(PduCommand::WritePump(true)).await; + pdu_cmd_send.send(PduCommand::WriteFault(true)).await; + } + crate::FunctionalType::REVERSE => { + if prev_func_state != FunctionalType::FPit { + warn!("Cannot move to reverse out of pit!"); + continue; + } + } + crate::FunctionalType::FAULTED => { + pdu_cmd_send.send(PduCommand::WritePump(false)).await; + pdu_cmd_send.send(PduCommand::WriteFault(false)).await; + state_recv.signal(StateTransition::Nero(NeroType::OFF)) + } + }, + StateTransition::Nero(state) => match state { + crate::NeroType::OFF => todo!(), + crate::NeroType::PIT => todo!(), + crate::NeroType::PERFORMANCE => todo!(), + crate::NeroType::EFFICIENCY => todo!(), + crate::NeroType::DEBUG => todo!(), + crate::NeroType::CONFIGURATION => todo!(), + crate::NeroType::FlappyBird => todo!(), + crate::NeroType::EXIT => todo!(), + }, + } + + match new_state { + StateTransition::Functional(f) => prev_func_state = f, + StateTransition::Nero(n) => prev_nero_state = n, + } + } +} diff --git a/crates/pca9539-ner/Cargo.toml b/crates/pca9539-ner/Cargo.toml index 3e6c0c7..8664ac8 100644 --- a/crates/pca9539-ner/Cargo.toml +++ b/crates/pca9539-ner/Cargo.toml @@ -5,6 +5,4 @@ edition = "2021" [dependencies] embedded-hal-async.workspace = true -embedded-hal.workspace = true -bit_field = "0.10.2" -num_enum = { version = "0.7.3", default-features = false } \ No newline at end of file +embedded-hal.workspace = true \ No newline at end of file diff --git a/crates/pca9539-ner/src/lib.rs b/crates/pca9539-ner/src/lib.rs index 6b34730..53114fa 100644 --- a/crates/pca9539-ner/src/lib.rs +++ b/crates/pca9539-ner/src/lib.rs @@ -1,7 +1,5 @@ #![no_std] -use bit_field::BitField; use embedded_hal_async::i2c::I2c; -use num_enum::TryFromPrimitive; /// Defines errors #[derive(Debug, Copy, Clone)] @@ -16,26 +14,26 @@ impl From for Error { } } -/// Pin modes. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum Direction { - /// Represents input mode. - Input = 1, - /// Represents output mode. - Output = 0, -} - -/// Pin levels. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum Level { - /// High level - High = 1, - /// Low level - Low = 0, -} +// /// Pin modes. +// #[derive(Debug, Copy, Clone, PartialEq, Eq)] +// pub enum Direction { +// /// Represents input mode. +// Input = 1, +// /// Represents output mode. +// Output = 0, +// } + +// /// Pin levels. +// #[derive(Debug, Copy, Clone, PartialEq, Eq)] +// pub enum Level { +// /// High level +// High = 1, +// /// Low level +// Low = 0, +// } /// Pin names -#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, Default)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] #[repr(u8)] pub enum Pin { #[default] @@ -47,14 +45,26 @@ pub enum Pin { P05 = 5, P06 = 6, P07 = 7, - P10 = 8, - P11 = 9, - P12 = 10, - P13 = 11, - P14 = 12, - P15 = 13, - P16 = 14, - P17 = 15, +} + +#[derive(Debug, Copy, Clone)] +#[repr(u8)] +pub enum Bank { + Bank0 = 0, + Bank1 = 1, +} + +#[derive(Debug, Copy, Clone)] +#[repr(u8)] +pub enum RegisterType { + /// 1 = high + InputLevel = 0, + /// 1 = high, default 1 + OutputLevel = 2, + /// 1 = inverted, default 0 + PolarityInverted = 4, + /// 1 = input, default 1 + Direction = 6, } /// PCA9539/TCA9539 is a 16-pin I2C I/O Expander with I2C Interface. @@ -86,6 +96,8 @@ where self.address } + // base functions + /// Read an 8 bit register pub async fn read(&mut self, addr: u8) -> Result { let mut data = [0u8]; @@ -100,32 +112,38 @@ where self.i2c.write(self.address, &[addr, data]).await } - /// Get a single bit in a register - pub async fn bit(&mut self, addr: u8, bit: usize) -> Result { - let data = self.read(addr).await?; - Ok(data.get_bit(bit)) + // register abstractions + + pub async fn write_register( + &mut self, + reg: RegisterType, + bank: Bank, + data: u8, + ) -> Result<(), E> { + self.write(reg as u8 + bank as u8, data).await } - /// Set a single bit in a register - pub async fn set_bit(&mut self, addr: u8, bit: usize, value: bool) -> Result<(), E> { - let mut data = self.read(addr).await?; - data.set_bit(bit, value); - self.write(addr, data).await + pub async fn read_register(&mut self, reg: RegisterType, bank: Bank) -> Result { + self.read(reg as u8 + bank as u8).await } - pub async fn set_level(&mut self, pin: Pin, level: Level) -> Result<(), E> { - let pin = pin as u8; - self.set_bit(0x02 | (pin >> 3), pin as usize & 7, level == Level::High) - .await + // helper functions + + pub async fn write_pin( + &mut self, + reg: RegisterType, + bank: Bank, + pin: Pin, + state: bool, + ) -> Result<(), E> { + let old_state = self.read_register(reg, bank).await?; + let new_state = (old_state & !(1u8 << pin as u8)) | ((state as u8) << pin as u8); + + self.write_register(reg, bank, new_state).await } - pub async fn set_direction(&mut self, pin: Pin, direction: Direction) -> Result<(), E> { - let pin = pin as u8; - self.set_bit( - 0x06 | (pin >> 3), - pin as usize & 7, - direction == Direction::Input, - ) - .await + pub async fn read_pin(&mut self, reg: RegisterType, bank: Bank, pin: Pin) -> Result { + let data = self.read_register(reg, bank).await?; + Ok((data & (1 << pin as u32)) > 0) } } diff --git a/msb-fw-rs/src/can_handler.rs b/msb-fw-rs/src/can_handler.rs index e94528a..23a7ef6 100644 --- a/msb-fw-rs/src/can_handler.rs +++ b/msb-fw-rs/src/can_handler.rs @@ -1,4 +1,4 @@ -use defmt::{trace, unwrap}; +use defmt::{trace, unwrap, warn}; use embassy_stm32::can::{Can, Frame}; use embassy_sync::{blocking_mutex::raw::ThreadModeRawMutex, channel::Receiver}; @@ -17,7 +17,9 @@ pub async fn can_handler( let frame = recv.receive().await; let frame_fixed = unwrap!(Frame::new_data(loc.get_can_id(frame.id()), frame.data())); trace!("Sending frame: {}", frame_fixed); - can.write(&frame_fixed).await; + if let Some(_) = can.write(&frame_fixed).await.dequeued_frame() { + warn!("Dequeing can frames!"); + } //Timer::after_millis(5).await; } diff --git a/rustc-ice-2024-09-06T23_26_24-47544.txt b/rustc-ice-2024-09-06T23_26_24-47544.txt new file mode 100644 index 0000000..82c0b4d --- /dev/null +++ b/rustc-ice-2024-09-06T23_26_24-47544.txt @@ -0,0 +1,66 @@ +thread 'rustc' panicked at compiler/rustc_const_eval/src/interpret/validity.rs:742:21: +assertion `left == right` failed + left: Mut + right: Not +stack backtrace: + 0: 0x7ffb879917d5 - std::backtrace_rs::backtrace::libunwind::trace::h1e63dad4d3117ec5 + at /rustc/24d2ac0b56fcbde13d827745f66e73efb1e17156/library/std/src/../../backtrace/src/backtrace/libunwind.rs:116:5 + 1: 0x7ffb879917d5 - std::backtrace_rs::backtrace::trace_unsynchronized::h5e3fa25754a02ef7 + at /rustc/24d2ac0b56fcbde13d827745f66e73efb1e17156/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5 + 2: 0x7ffb879917d5 - std::backtrace::Backtrace::create::h4beced95b340f3e0 + at /rustc/24d2ac0b56fcbde13d827745f66e73efb1e17156/library/std/src/backtrace.rs:331:13 + 3: 0x7ffb87991725 - std::backtrace::Backtrace::force_capture::hfb176da11c818906 + at /rustc/24d2ac0b56fcbde13d827745f66e73efb1e17156/library/std/src/backtrace.rs:312:9 + 4: 0x7ffb83df734c - std[2e4855af1945f0a9]::panicking::update_hook::>::{closure#0} + 5: 0x7ffb879ac59f - as core::ops::function::Fn>::call::h03eb6ea0e02b2da2 + at /rustc/24d2ac0b56fcbde13d827745f66e73efb1e17156/library/alloc/src/boxed.rs:2084:9 + 6: 0x7ffb879ac59f - std::panicking::rust_panic_with_hook::hd2ef5463e61b163d + at /rustc/24d2ac0b56fcbde13d827745f66e73efb1e17156/library/std/src/panicking.rs:808:13 + 7: 0x7ffb879ac1c7 - std::panicking::begin_panic_handler::{{closure}}::h28192c38bbe1ba24 + at /rustc/24d2ac0b56fcbde13d827745f66e73efb1e17156/library/std/src/panicking.rs:674:13 + 8: 0x7ffb879a98a9 - std::sys::backtrace::__rust_end_short_backtrace::hf1a4d4d8d4c7b389 + at /rustc/24d2ac0b56fcbde13d827745f66e73efb1e17156/library/std/src/sys/backtrace.rs:168:18 + 9: 0x7ffb879abe54 - rust_begin_unwind + at /rustc/24d2ac0b56fcbde13d827745f66e73efb1e17156/library/std/src/panicking.rs:665:5 + 10: 0x7ffb879f53d3 - core::panicking::panic_fmt::h5b7b1f46de2acd0f + at /rustc/24d2ac0b56fcbde13d827745f66e73efb1e17156/library/core/src/panicking.rs:74:14 + 11: 0x7ffb879f58de - core::panicking::assert_failed_inner::hf95798b560be7d18 + at /rustc/24d2ac0b56fcbde13d827745f66e73efb1e17156/library/core/src/panicking.rs:410:17 + 12: 0x7ffb83d61b03 - core[e3368208c650ceb1]::panicking::assert_failed:: + 13: 0x7ffb86ca8832 - rustc_const_eval[8f90cf60b6ff7fc0]::interpret::validity::mutability::.cold + 14: 0x7ffb85fd2666 - as rustc_const_eval[8f90cf60b6ff7fc0]::interpret::visitor::ValueVisitor>::visit_value + 15: 0x7ffb85fd1949 - as rustc_const_eval[8f90cf60b6ff7fc0]::interpret::visitor::ValueVisitor>::visit_value + 16: 0x7ffb85fc9c0f - >::validate_operand_internal + 17: 0x7ffb8545bc35 - rustc_const_eval[8f90cf60b6ff7fc0]::const_eval::eval_queries::eval_body_using_ecx:: + 18: 0x7ffb862d01f1 - rustc_const_eval[8f90cf60b6ff7fc0]::const_eval::eval_queries::eval_static_initializer_provider + 19: 0x7ffb862cff59 - rustc_query_impl[e122d18f0ef1f98e]::plumbing::__rust_begin_short_backtrace::> + 20: 0x7ffb862cff39 - >::call_once + 21: 0x7ffb85b9c340 - rustc_query_system[38440ac6412d6581]::query::plumbing::try_execute_query::>, false, false, false>, rustc_query_impl[e122d18f0ef1f98e]::plumbing::QueryCtxt, true> + 22: 0x7ffb86376c37 - rustc_query_impl[e122d18f0ef1f98e]::query_impl::eval_static_initializer::get_query_incr::__rust_end_short_backtrace + 23: 0x7ffb8568d081 - ::par_body_owners::::{closure#0} + 24: 0x7ffb8568a714 - rustc_hir_analysis[b3306b63a178bcbb]::check_crate + 25: 0x7ffb858a8715 - rustc_interface[10d910312a4163bf]::passes::analysis + 26: 0x7ffb858a82c7 - rustc_query_impl[e122d18f0ef1f98e]::plumbing::__rust_begin_short_backtrace::> + 27: 0x7ffb865bc738 - rustc_query_system[38440ac6412d6581]::query::plumbing::try_execute_query::>, false, false, false>, rustc_query_impl[e122d18f0ef1f98e]::plumbing::QueryCtxt, true> + 28: 0x7ffb865bc3fa - rustc_query_impl[e122d18f0ef1f98e]::query_impl::analysis::get_query_incr::__rust_end_short_backtrace + 29: 0x7ffb861ccd85 - rustc_interface[10d910312a4163bf]::interface::run_compiler::, rustc_driver_impl[a025c0959e606917]::run_compiler::{closure#0}>::{closure#1} + 30: 0x7ffb861ab089 - std[2e4855af1945f0a9]::sys::backtrace::__rust_begin_short_backtrace::, rustc_driver_impl[a025c0959e606917]::run_compiler::{closure#0}>::{closure#1}, core[e3368208c650ceb1]::result::Result<(), rustc_span[8d97099df1a537d7]::ErrorGuaranteed>>::{closure#0}, core[e3368208c650ceb1]::result::Result<(), rustc_span[8d97099df1a537d7]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[e3368208c650ceb1]::result::Result<(), rustc_span[8d97099df1a537d7]::ErrorGuaranteed>> + 31: 0x7ffb861aae3a - <::spawn_unchecked_, rustc_driver_impl[a025c0959e606917]::run_compiler::{closure#0}>::{closure#1}, core[e3368208c650ceb1]::result::Result<(), rustc_span[8d97099df1a537d7]::ErrorGuaranteed>>::{closure#0}, core[e3368208c650ceb1]::result::Result<(), rustc_span[8d97099df1a537d7]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[e3368208c650ceb1]::result::Result<(), rustc_span[8d97099df1a537d7]::ErrorGuaranteed>>::{closure#2} as core[e3368208c650ceb1]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0} + 32: 0x7ffb879b65fb - as core::ops::function::FnOnce>::call_once::hbd2241bb5048f8cc + at /rustc/24d2ac0b56fcbde13d827745f66e73efb1e17156/library/alloc/src/boxed.rs:2070:9 + 33: 0x7ffb879b65fb - as core::ops::function::FnOnce>::call_once::h5c9fad9abff71453 + at /rustc/24d2ac0b56fcbde13d827745f66e73efb1e17156/library/alloc/src/boxed.rs:2070:9 + 34: 0x7ffb879b65fb - std::sys::pal::unix::thread::Thread::new::thread_start::h753c7287ef3cb9cd + at /rustc/24d2ac0b56fcbde13d827745f66e73efb1e17156/library/std/src/sys/pal/unix/thread.rs:108:17 + 35: 0x7ffb80894a42 - start_thread + 36: 0x7ffb8091405c - clone3 + 37: 0x0 - + + +rustc version: 1.81.0-nightly (24d2ac0b5 2024-07-15) +platform: x86_64-unknown-linux-gnu + +query stack during panic: +#0 [eval_static_initializer] evaluating initializer of static `TSMS_SENSE` +#1 [analysis] running analysis passes on this crate +end of query stack