dashboard/
can_mod.rs

1//! Module for CAN communication
2//!
3//! Handles the reception and transmission of CAN messages
4//!
5//! This requires a lot of global mutable data. See this
6//! [article](https://blog.theembeddedrustacean.com/sharing-data-among-tasks-in-rust-embassy-synchronization-primitives#heading-the-list-of-primitives)
7//! on sharing data in Embassy.
8//!
9//! <div class="warning">
10//! Anytime a mutex lock is acquired it should be dropped as soon as it is not needed
11//! to avoid deadlocks. Mutex locks will last to the end of its scope if they are not
12//! dropped before then. See <a href="https://stackoverflow.com/questions/57467555/will-the-non-lexical-lifetime-borrow-checker-release-locks-prematurely">here</a>
13//! for more information.
14//! </div>
15
16use bincode::{
17    Decode, Encode,
18    config::Configuration,
19    error::{DecodeError, EncodeError},
20};
21use defmt::*;
22use embassy_stm32::can::{BufferedCanFd, Can, Frame, frame::FdFrame};
23use embassy_sync::{blocking_mutex::raw::ThreadModeRawMutex, mutex::Mutex};
24use embassy_time::Timer;
25use embedded_can::Id;
26
27use crate::eco_can::{
28    ECOCAN_H2Pack1_t, ECOCAN_H2Pack2_t, FDCAN_BOOSTPack1_t, FDCAN_BOOSTPack2_t, FDCAN_BOOSTPack3_t,
29    FDCAN_FccPack1_t, FDCAN_FccPack2_t, FDCAN_FccPack3_t, FDCAN_FetPack_t, FDCAN_RelPackCap_t,
30    FDCAN_RelPackFc_t, FDCAN_RelPackMtr_t, FDCANPack, RelayState,
31};
32
33/// Buffer Size for the CAN TX buffer
34pub const TX_BUF_SIZE: usize = 1;
35/// Buffer Size for the CAN RX buffer
36pub const RX_BUF_SIZE: usize = 20;
37
38const BINCODE_CONFIG: Configuration<bincode::config::BigEndian, bincode::config::Fixint> =
39    bincode::config::standard()
40        .with_big_endian()
41        .with_fixed_int_encoding();
42
43pub static RELAY_STATE: Mutex<ThreadModeRawMutex, RelayState> = Mutex::new(RelayState::RELAY_STRTP);
44
45pub static FET_DATA: Mutex<ThreadModeRawMutex, FDCAN_FetPack_t> = Mutex::new(FDCAN_FetPack_t {
46    fet_config: 0,
47    input_volt: 0,
48    cap_volt: 0,
49    cap_curr: 0,
50    res_curr: 0,
51    out_curr: 0,
52});
53
54pub static FCC_PACK1_DATA: Mutex<ThreadModeRawMutex, FDCAN_FccPack1_t> =
55    Mutex::new(FDCAN_FccPack1_t {
56        fc_press: 0,
57        fc_temp: 0,
58    });
59pub static FCC_PACK2_DATA: Mutex<ThreadModeRawMutex, FDCAN_FccPack2_t> =
60    Mutex::new(FDCAN_FccPack2_t {
61        fan_rpm1: 0,
62        fan_rpm2: 0,
63    });
64pub static FCC_PACK3_DATA: Mutex<ThreadModeRawMutex, FDCAN_FccPack3_t> =
65    Mutex::new(FDCAN_FccPack3_t {
66        bme_temp: 0,
67        bme_humid: 0,
68    });
69
70pub static H2_PACK1_DATA: Mutex<ThreadModeRawMutex, ECOCAN_H2Pack1_t> =
71    Mutex::new(ECOCAN_H2Pack1_t {
72        h2_sense_1: 0,
73        h2_sense_2: 0,
74        h2_sense_3: 0,
75        h2_sense_4: 0,
76    });
77pub static H2_PACK2_DATA: Mutex<ThreadModeRawMutex, ECOCAN_H2Pack2_t> =
78    Mutex::new(ECOCAN_H2Pack2_t {
79        bme_temp: 0,
80        bme_humid: 0,
81        imon_7v: 0,
82        imon_12v: 0,
83    });
84
85pub static BOOST_PACK1_DATA: Mutex<ThreadModeRawMutex, FDCAN_BOOSTPack1_t> =
86    Mutex::new(FDCAN_BOOSTPack1_t {
87        in_curr: 0,
88        in_volt: 0,
89    });
90pub static BOOST_PACK2_DATA: Mutex<ThreadModeRawMutex, FDCAN_BOOSTPack2_t> =
91    Mutex::new(FDCAN_BOOSTPack2_t {
92        out_curr: 0,
93        out_volt: 0,
94    });
95pub static BOOST_PACK3_DATA: Mutex<ThreadModeRawMutex, FDCAN_BOOSTPack3_t> =
96    Mutex::new(FDCAN_BOOSTPack3_t {
97        efficiency: 0,
98        joules: 0,
99    });
100
101/// Fuel Cell Reading
102pub static REL_FC_PACK: Mutex<ThreadModeRawMutex, FDCAN_RelPackFc_t> =
103    Mutex::new(FDCAN_RelPackFc_t {
104        fc_volt: 0,
105        fc_curr: 0,
106    });
107pub static REL_CAP_PACK: Mutex<ThreadModeRawMutex, FDCAN_RelPackCap_t> =
108    Mutex::new(FDCAN_RelPackCap_t {
109        cap_volt: 0,
110        cap_curr: 0,
111    });
112pub static RELAY_MOTOR_PACK: Mutex<ThreadModeRawMutex, FDCAN_RelPackMtr_t> =
113    Mutex::new(FDCAN_RelPackMtr_t {
114        mtr_volt: 0,
115        mtr_curr: 0,
116    });
117
118/// Responsible for handling the reception of CAN messages
119#[embassy_executor::task]
120pub async fn can_receive_task(mut can: Can<'static>) {
121    // pub async fn can_receive_task(mut can: BufferedCanFd<'static, TX_BUF_SIZE, RX_BUF_SIZE>) {
122    // Use the FD API's even if we don't get FD packets.
123    let debug = true;
124    if debug {
125        let mut tx_data = [0; 64];
126        loop {
127            // for _ in 0..40 {
128            let mut pack = RELAY_MOTOR_PACK.lock().await;
129            pack.mtr_curr += 1;
130            if pack.mtr_curr > 100 {
131                pack.mtr_curr = 0;
132            }
133            drop(pack);
134
135            match encode_can_package(&RELAY_MOTOR_PACK, &mut tx_data).await {
136                Ok(tx_len) => {
137                    let frame =
138                        Frame::new_extended(FDCAN_RelPackCap_t::FDCAN_ID, &tx_data[..tx_len])
139                            .unwrap();
140                    info!("Sending CAN frame...");
141                    let _ = can.write(&frame).await;
142                    // info!("{:?}", f);
143                }
144                Err(_) => {
145                    error!("CAN Encode Error");
146                }
147            }
148            info!("Sent CAN Frame");
149            Timer::after_millis(1000).await;
150        }
151    }
152    // loop {
153    //     // await one frame (blocks until at least one frame arrives)
154    //     debug!("Waiting to receive CAN frame...");
155    //     match can.read_fd().await {
156    //         Ok(envelope) => {
157    //             // Process the first can frame received
158    //             process_rx_can_frame(&envelope.frame).await;
159    //             // then drain the receive buffer
160    //             // drain_rx_can_buffer(&can).await;
161    //         }
162    //         Err(err) => error!("CAN Frame Error: {}", err),
163    //     }
164    //     debug!("CAN Healh Check");
165    //     Timer::after_millis(1000).await;
166    // }
167}
168
169/// Process the remaining CAN frames in the RX buffer
170async fn _drain_rx_can_buffer(can: &BufferedCanFd<'static, TX_BUF_SIZE, RX_BUF_SIZE>) {
171    // repeatedly call try_receive() until the buffer is empty
172    let reader = can.reader();
173    for _ in 0..RX_BUF_SIZE {
174        if let Ok(frame) = reader.try_receive() {
175            match frame {
176                Ok(envelope) => {
177                    process_rx_can_frame(&envelope.frame).await;
178                }
179                Err(err) => error!("CAN Frame Error: {}", err),
180            }
181        } else {
182            return;
183        }
184    }
185}
186
187/// Decodes a CAN frame and handles decode errors
188async fn process_rx_can_frame(rx_frame: &FdFrame) {
189    if let Err(_) = decode_can_frame(&rx_frame).await {
190        error!("CAN Decode Error");
191    }
192}
193
194/// Decodes a CAN frame into its corresponding CAN package
195///
196/// Returns an error if the frame cannot be decoded.
197async fn decode_can_frame(frame: &FdFrame) -> Result<(), DecodeError> {
198    // Get ID
199    let id = match frame.header().id() {
200        Id::Standard(id) => u32::from(id.as_raw()),
201        Id::Extended(id) => id.as_raw(),
202    };
203    // Get data of CAN package (up to 64 bytes)
204    let rx_data = &frame.data()[..frame.header().len() as usize];
205
206    // Match ID to CAN package, and decode
207    match id {
208        RelayState::FDCAN_ID => {
209            let mut relay_state = RELAY_STATE.lock().await;
210            *relay_state = RelayState::try_from(rx_data[0])?;
211            debug!("Updated Relay State: {:?}", *relay_state);
212            Ok(())
213        }
214
215        FDCAN_FccPack1_t::FDCAN_ID => decode_can_data(&FCC_PACK1_DATA, rx_data).await,
216        FDCAN_FccPack2_t::FDCAN_ID => decode_can_data(&FCC_PACK2_DATA, rx_data).await,
217        FDCAN_FccPack3_t::FDCAN_ID => decode_can_data(&FCC_PACK3_DATA, rx_data).await,
218
219        FDCAN_FetPack_t::FDCAN_ID => decode_can_data(&FET_DATA, rx_data).await,
220
221        FDCAN_RelPackMtr_t::FDCAN_ID => decode_can_data(&RELAY_MOTOR_PACK, rx_data).await,
222        FDCAN_RelPackCap_t::FDCAN_ID => decode_can_data(&REL_CAP_PACK, rx_data).await,
223        FDCAN_RelPackFc_t::FDCAN_ID => decode_can_data(&REL_FC_PACK, rx_data).await,
224
225        ECOCAN_H2Pack1_t::FDCAN_ID => decode_can_data(&H2_PACK1_DATA, rx_data).await,
226        ECOCAN_H2Pack2_t::FDCAN_ID => decode_can_data(&H2_PACK2_DATA, rx_data).await,
227
228        FDCAN_BOOSTPack1_t::FDCAN_ID => decode_can_data(&BOOST_PACK1_DATA, rx_data).await,
229        FDCAN_BOOSTPack2_t::FDCAN_ID => decode_can_data(&BOOST_PACK2_DATA, rx_data).await,
230        FDCAN_BOOSTPack3_t::FDCAN_ID => decode_can_data(&BOOST_PACK3_DATA, rx_data).await,
231
232        _ => {
233            debug!("Non-Relevant ID: {:016b}", id);
234            Ok(())
235        }
236    }
237}
238
239/// Decodes a byte array into a CAN package
240async fn decode_can_data<T: Decode<()> + Format>(
241    package: &Mutex<ThreadModeRawMutex, T>,
242    rx_data: &[u8],
243) -> Result<(), DecodeError> {
244    // Decode received package bytes into the desired package struct and update can package
245    let mut p = package.lock().await;
246    *p = bincode::decode_from_slice(&rx_data, BINCODE_CONFIG)?.0;
247    trace!("updated can pack: {:?}", *p);
248
249    Ok(())
250}
251
252/// Encodes a CAN package into a byte array
253async fn encode_can_package<T: Encode + Clone>(
254    package: &Mutex<ThreadModeRawMutex, T>,
255    mut tx_data: &mut [u8],
256) -> Result<usize, EncodeError> {
257    let p = package.lock().await;
258    bincode::encode_into_slice(p.clone(), &mut tx_data, BINCODE_CONFIG)
259}