diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 8c950e5a..06c8907b 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,11 +1,24 @@ +# Base image for toolchain download +FROM mcr.microsoft.com/devcontainers/rust:latest as toolchain + +RUN mkdir -p /toolchain && \ + curl -L "https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x86_64-arm-none-eabi.tar.xz" \ + | tar --strip-components=1 -xJ -C /toolchain + +# Final image FROM mcr.microsoft.com/devcontainers/rust:latest +# Copy the toolchain from the previous stage +COPY --from=toolchain /toolchain /toolchain + +ENV PATH="${PATH}:/toolchain/bin" ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get upgrade -y && apt-get install -y cmake pkg-config libusb-1.0-0-dev libftdi1-dev libudev-dev libssl-dev -# Install ARM GCC deps -RUN mkdir -p toolchain && \ - curl -L "https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x86_64-arm-none-eabi.tar.xz" \ - | tar --strip-components=1 -xJ -C toolchain && \ - cargo install --locked probe-rs --features cli -ENV PATH="${PATH}:/toolchain/bin" \ No newline at end of file +# Necessary system packages +RUN apt-get update && apt-get install -y cmake pkg-config libusb-1.0-0-dev libftdi1-dev libudev-dev libssl-dev && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# Install Rust crates +RUN cargo install probe-rs --features cli \ + && cargo install cargo-make \ No newline at end of file diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index bf48bc47..0f021d0f 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -19,6 +19,8 @@ jobs: components: clippy toolchain: stable target: thumbv7em-none-eabihf + - name: cargofmt + run: cargo fmt --check - uses: actions/cache@v3 with: path: | @@ -31,3 +33,4 @@ jobs: - uses: actions-rs/clippy-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} + \ No newline at end of file diff --git a/.gitignore b/.gitignore index ce0aec4d..d5446d17 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /target /.vscode/.cortex-debug.registers.state.json /.vscode/.cortex-debug.peripherals.state.json -/.vscode/settings.json \ No newline at end of file +/.vscode/settings.json +/toolchain diff --git a/README.md b/README.md index 32273847..16db41b5 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # HYDRA   [![Build Status]][actions] [![docs-badge]][docs] -*HYper Dynamic Rocketry Avionics* + +***HY**per **D**ynamic **R**ocketry **A**vionics* [Build Status]: https://github.com/uorocketry/hydra/actions/workflows/build.yml/badge.svg [actions]: https://github.com/uorocketry/hydra/actions?query=branch%3Amaster @@ -12,46 +13,60 @@ ## Getting Started -1. Install Rust: https://www.rust-lang.org/tools/install -2. Build: `cargo build` -3. Install probe-run: `cargo install --git https://github.com/uorocketry/probe-run` - - `probe-run` currently requires a patch to flash our chip, so please use the above version while the patch is upstreamed -4. Install cargo-make: `cargo install cargo-make` -4. Flash: `cargo run --bin main` -5. Run tests: `cargo make test-host` or `cargo make test-device` +> If you are in a DevContainer skip to step 5. + +- Install Rust: https://www.rust-lang.org/tools/install +- Install necessary build tools: + - cargo-make: `cargo install cargo-make` + - probe-rs: `cargo install probe-rs --features cli` +- Install the [ARM GNU Toolchain](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads) (last tested with 13.2) and have it available in your PATH + - Arch Linux: `sudo pacman -S arm-none-eabi-gcc` + - Alpine/Debian/Ubuntu: + - MacOS: `brew install arm-none-eabi-gcc` +- Build: `cargo build` + - In case it fails, try `cargo build --release` +- Run tests: + - In the host machine: `cargo make test-host` + - In the device: `cargo make test-device` +- Flash on hardware: `cargo run --bin main` For more detailed instructions on flashing, debugging, and more, please see [the wiki](https://avwiki.uorocketry.ca/en/Avionics/HYDRA/Software). ## Windows Users ### Setting up with Docker -1. Install Docker: https://docs.docker.com/desktop/install/windows-install/ -2. Install VS Code: https://code.visualstudio.com/download -3. From VS Code, install the "Dev Containers" extension -4. press `ctrl` + `shift` + `p`, and search for `Dev Containers: Open Folder in Container` + +- Install [Docker](https://docs.docker.com/desktop/install/windows-install/) +- Install [VS Code](https://code.visualstudio.com/download) +- From VS Code, install the "Dev Containers" extension +- press `ctrl` + `shift` + `p`, and search for `Dev Containers: Open Folder in Container` ### Setting up with WSL -1. Enable WSL: https://learn.microsoft.com/en-us/windows/wsl/install -2. Install a linux distro from the Microsoft Store -4. Install ARM GNU Toolchain: https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads + +- Enable WSL: https://learn.microsoft.com/en-us/windows/wsl/install +- Install a linux distro from the Microsoft Store +- Install the [ARM GNU Toolchain](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads) - NOTE: You may find this in your distro's package manager, but ensure it is version 13.2. - Ubuntu has an outdated version in its repositories. If using Ubuntu, download it manually from the link above -3. Follow the rest of the instructions in [Getting Started](#-getting-started) +- Follow the rest of the instructions in [Getting Started](#-getting-started) ### Flashing + After plugging in J-Link, it will likely show up as unknown. + 1. Install Zadig: https://zadig.akeo.ie/ 2. From Zadig, select J-Link as the device and WinUSB as the driver 3. click Install Driver If using WSL or Docker with a WSL backend (you probably are), you need to tell Windows to share J-Link with WSL. -1. From WSL, install linux-tools-generic - 1. on Ubuntu: `sudo apt install linux-tools-generic` -2. Install usbipd-win: https://github.com/dorssel/usbipd-win/releases -3. Open command prompt/powershell with admin privileges and run `usbipd list` -4. Make note of the entry called J-Link and run `usbipd bind --busid ` -5. Next, run `usbipd attach --wsl --busid ` -6. You can now follow the flashing instructions in [Getting Started](#-getting-started) + +- From WSL, install linux-tools-generic + - on Ubuntu: `sudo apt install linux-tools-generic` +- Install usbipd-win: https://github.com/dorssel/usbipd-win/releases +- Open command prompt/powershell with admin privileges and run `usbipd list` +- Make note of the entry called J-Link and run `usbipd bind --busid ` +- Next, run `usbipd attach --wsl --busid ` +- You can now follow the flashing instructions in [Getting Started](#getting-started) ## Documentation @@ -60,6 +75,7 @@ Run `cargo doc --open` to build and open the documentation. Most documentation f Documentation is also automatically built and deployed to https://hydra-docs.uorocketry.ca/common_arm ## Project Structure + The project is structured in a way to allow reuse of the code across various boards and other projects. - `boards`: Folder containing each individual board's binary crates. Any code in those crates should only contain logic specific to the board. diff --git a/boards/beacon/src/types.rs b/boards/beacon/src/types.rs index c83ce98d..c13f876d 100644 --- a/boards/beacon/src/types.rs +++ b/boards/beacon/src/types.rs @@ -1,7 +1,7 @@ -use messages::sender::Sender; -use messages::sender::Sender::BeaconBoard; +use messages::node::Node; +use messages::node::Node::BeaconBoard; // ------- -// Sender ID +// Node ID // ------- -pub static COM_ID: Sender = BeaconBoard; +pub static COM_ID: Node = BeaconBoard; diff --git a/boards/camera/src/communication.rs b/boards/camera/src/communication.rs index cb30c676..d3a36b35 100644 --- a/boards/camera/src/communication.rs +++ b/boards/camera/src/communication.rs @@ -103,8 +103,7 @@ impl CanDevice0 { can.filters_standard() .push(Filter::Classic { action: Action::StoreFifo0, - filter: ecan::StandardId::new(messages::sender::Sender::SensorBoard.into()) - .unwrap(), + filter: ecan::StandardId::new(messages::node::Node::SensorBoard.into()).unwrap(), mask: ecan::StandardId::ZERO, }) .unwrap_or_else(|_| panic!("Sensor filter")); diff --git a/boards/camera/src/types.rs b/boards/camera/src/types.rs index 352f57f0..cea33bb0 100644 --- a/boards/camera/src/types.rs +++ b/boards/camera/src/types.rs @@ -1,5 +1,5 @@ -use messages::sender::{Sender, Sender::CameraBoard}; +use messages::node::{Node, Node::CameraBoard}; // ------- -// Sender ID +// Node ID // ------- -pub static _COM_ID: Sender = CameraBoard; +pub static _COM_ID: Node = CameraBoard; diff --git a/boards/communication/src/communication.rs b/boards/communication/src/communication.rs index 1ea183af..bdee0df0 100644 --- a/boards/communication/src/communication.rs +++ b/boards/communication/src/communication.rs @@ -120,8 +120,7 @@ impl CanDevice0 { can.filters_standard() .push(Filter::Classic { action: Action::StoreFifo0, - filter: ecan::StandardId::new(messages::sender::Sender::RecoveryBoard.into()) - .unwrap(), + filter: ecan::StandardId::new(messages::node::Node::RecoveryBoard.into()).unwrap(), mask: ecan::StandardId::ZERO, }) .unwrap_or_else(|_| panic!("Recovery filter")); @@ -129,8 +128,7 @@ impl CanDevice0 { can.filters_standard() .push(Filter::Classic { action: Action::StoreFifo1, - filter: ecan::StandardId::new(messages::sender::Sender::SensorBoard.into()) - .unwrap(), + filter: ecan::StandardId::new(messages::node::Node::SensorBoard.into()).unwrap(), mask: ecan::StandardId::ZERO, }) .unwrap_or_else(|_| panic!("Sensor filter")); @@ -138,7 +136,7 @@ impl CanDevice0 { can.filters_standard() .push(Filter::Classic { action: Action::StoreFifo0, - filter: ecan::StandardId::new(messages::sender::Sender::PowerBoard.into()).unwrap(), + filter: ecan::StandardId::new(messages::node::Node::PowerBoard.into()).unwrap(), mask: ecan::StandardId::ZERO, }) .unwrap_or_else(|_| panic!("Power filter")); @@ -146,8 +144,7 @@ impl CanDevice0 { can.filters_standard() .push(Filter::Classic { action: Action::StoreFifo0, - filter: ecan::StandardId::new(messages::sender::Sender::GroundStation.into()) - .unwrap(), + filter: ecan::StandardId::new(messages::node::Node::GroundStation.into()).unwrap(), mask: ecan::StandardId::ZERO, }) .unwrap_or_else(|_| panic!("Ground Station filter")); diff --git a/boards/communication/src/types.rs b/boards/communication/src/types.rs index 236121d8..34315d1c 100644 --- a/boards/communication/src/types.rs +++ b/boards/communication/src/types.rs @@ -1,13 +1,13 @@ use atsamd_hal::gpio::*; use atsamd_hal::sercom::uart::EightBit; use atsamd_hal::sercom::{uart, IoSet1, Sercom5}; -use messages::sender::Sender; -use messages::sender::Sender::CommunicationBoard; +use messages::node::Node; +use messages::node::Node::CommunicationBoard; // ------- -// Sender ID +// Node ID // ------- -pub static COM_ID: Sender = CommunicationBoard; +pub static COM_ID: Node = CommunicationBoard; // ------- // Ground Station diff --git a/boards/power/src/communication.rs b/boards/power/src/communication.rs index 4d42abf2..59ca7b66 100644 --- a/boards/power/src/communication.rs +++ b/boards/power/src/communication.rs @@ -108,7 +108,7 @@ impl CanDevice0 { can.filters_standard() .push(Filter::Classic { action: Action::StoreFifo1, - filter: ecan::StandardId::new(messages::sender::Sender::CommunicationBoard.into()) + filter: ecan::StandardId::new(messages::node::Node::CommunicationBoard.into()) .unwrap(), mask: ecan::StandardId::ZERO, }) diff --git a/boards/power/src/types.rs b/boards/power/src/types.rs index 196af97b..f8bae4ef 100644 --- a/boards/power/src/types.rs +++ b/boards/power/src/types.rs @@ -1,5 +1,5 @@ -use messages::sender::{Sender, Sender::PowerBoard}; +use messages::node::{Node, Node::PowerBoard}; // ------- -// Sender ID +// Node ID // ------- -pub static _COM_ID: Sender = PowerBoard; +pub static _COM_ID: Node = PowerBoard; diff --git a/boards/recovery/src/communication.rs b/boards/recovery/src/communication.rs index 4d667b7b..ee914d38 100644 --- a/boards/recovery/src/communication.rs +++ b/boards/recovery/src/communication.rs @@ -111,8 +111,7 @@ impl CanDevice0 { can.filters_standard() .push(Filter::Classic { action: Action::StoreFifo0, - filter: ecan::StandardId::new(messages::sender::Sender::SensorBoard.into()) - .unwrap(), + filter: ecan::StandardId::new(messages::node::Node::SensorBoard.into()).unwrap(), mask: ecan::StandardId::ZERO, }) .unwrap_or_else(|_| panic!("Sensor Board filter")); @@ -121,7 +120,7 @@ impl CanDevice0 { can.filters_standard() .push(Filter::Classic { action: Action::StoreFifo1, - filter: ecan::StandardId::new(messages::sender::Sender::CommunicationBoard.into()) + filter: ecan::StandardId::new(messages::node::Node::CommunicationBoard.into()) .unwrap(), mask: ecan::StandardId::ZERO, }) diff --git a/boards/recovery/src/data_manager.rs b/boards/recovery/src/data_manager.rs index ea99ff1d..f5eab5e0 100644 --- a/boards/recovery/src/data_manager.rs +++ b/boards/recovery/src/data_manager.rs @@ -8,6 +8,9 @@ use messages::Message; const MAIN_HEIGHT: f32 = 876.0; // meters ASL const HEIGHT_MIN: f32 = 600.0; // meters ASL +const RECOVERY_DATA_POINTS: u8 = 8; // number of barometric altitude readings held by the recovery + // algorithm +const RECOVERY_TIMER_TIMEOUT: u8 = 15; // minutes pub struct DataManager { pub air: Option, @@ -16,8 +19,11 @@ pub struct DataManager { pub imu: (Option, Option), pub utc_time: Option, pub gps_vel: Option, - pub historical_barometer_altitude: HistoryBuffer<(f32, u32), 8>, + pub historical_barometer_altitude: HistoryBuffer<(f32, u32), 8>, // RECOVERY_DATA_POINTS (issue + // when putting as const) pub current_state: Option, + // each tick represents a minute that passed + pub recovery_counter: u8, } impl DataManager { @@ -32,11 +38,12 @@ impl DataManager { gps_vel: None, historical_barometer_altitude, current_state: None, + recovery_counter: 0, } } /// Returns true if the rocket is descending pub fn is_falling(&self) -> bool { - if self.historical_barometer_altitude.len() < 8 { + if (self.historical_barometer_altitude.len() as u8) < RECOVERY_DATA_POINTS { return false; } let mut buf = self.historical_barometer_altitude.oldest_ordered(); @@ -56,14 +63,14 @@ impl DataManager { avg_sum += slope; prev = i; } - match avg_sum / 7.0 { + match avg_sum / (RECOVERY_DATA_POINTS as f32 - 1.0) { // 7 because we have 8 points. // exclusive range x if !(-100.0..=-5.0).contains(&x) => { return false; } _ => { - info!("avg: {}", avg_sum / 7.0); + info!("avg: {}", avg_sum / (RECOVERY_DATA_POINTS as f32 - 1.0)); } } } @@ -82,8 +89,8 @@ impl DataManager { None => false, } } - pub fn is_landed(&self) -> bool { - if self.historical_barometer_altitude.len() < 8 { + pub fn is_landed(&mut self) -> bool { + if self.historical_barometer_altitude.len() < RECOVERY_DATA_POINTS.into() { return false; } let mut buf = self.historical_barometer_altitude.oldest_ordered(); @@ -99,13 +106,15 @@ impl DataManager { avg_sum += (i.0 - prev.0) / time_diff; prev = i; } - match avg_sum / 7.0 { + match avg_sum / (RECOVERY_DATA_POINTS as f32 - 1.0) { // inclusive range x if (-0.25..=0.25).contains(&x) => { - return true; + if self.recovery_counter >= RECOVERY_TIMER_TIMEOUT { + return true; + } } _ => { - // continue + self.recovery_counter = 0; } } } @@ -132,11 +141,12 @@ impl DataManager { messages::Data::Sensor(sensor) => match sensor.data { messages::sensor::SensorData::Air(air_data) => { /* - NOTE!!! - There should be added a counter to check how many times - the alt is dropped, if the number is high switch to - the on board barometer. - git */ + + NOTE!!! + There should be added a counter to check how many times + the alt is dropped, if the number is high switch to + the on board barometer. + */ if let Some(alt) = air_data.altitude { let tup_data: (f32, u32) = (alt, air_data.time_stamp); diff --git a/boards/recovery/src/main.rs b/boards/recovery/src/main.rs index bd08c8f8..c96fbbc7 100644 --- a/boards/recovery/src/main.rs +++ b/boards/recovery/src/main.rs @@ -19,6 +19,7 @@ use data_manager::DataManager; use gpio_manager::GPIOManager; use hal::gpio::{Pin, Pins, PushPullOutput, PB16, PB17}; use hal::prelude::*; +use hal::timer::TimerCounter2; use mcan::messageram::SharedMemory; use messages::*; use state_machine::{StateMachine, StateMachineContext}; @@ -42,6 +43,7 @@ mod app { data_manager: DataManager, can0: communication::CanDevice0, gpio: GPIOManager, + recovery_timer: TimerCounter2, } #[local] @@ -78,7 +80,7 @@ mod app { // SAFETY: Misusing the PAC API can break the system. // This is safe because we only steal the MCLK. - let (_, _, _, _mclk) = unsafe { clocks.pac.steal() }; + let (_, _, _, mut mclk) = unsafe { clocks.pac.steal() }; /* CAN config */ let (pclk_can, gclk0) = Pclk::enable(tokens.pclks.can0, gclk0); @@ -104,6 +106,11 @@ mod app { /* State Machine config */ let state_machine = StateMachine::new(); + /* Recovery Timer config */ + let (pclk_tc2tc3, gclk0) = Pclk::enable(tokens.pclks.tc2_tc3, gclk0); + let timerclk: hal::clock::v1::Tc2Tc3Clock = pclk_tc2tc3.into(); + let recovery_timer = hal::timer::TimerCounter2::tc2_(&timerclk, peripherals.TC2, &mut mclk); + /* Spawn tasks */ run_sm::spawn().ok(); state_send::spawn().ok(); @@ -120,6 +127,7 @@ mod app { data_manager: DataManager::new(), can0, gpio, + recovery_timer, }, Local { led_green, @@ -136,6 +144,25 @@ mod app { loop {} } + // interrupt handler for recovery counter + #[task(binds=TC2, shared=[data_manager, recovery_timer])] + fn recovery_counter_tick(mut cx: recovery_counter_tick::Context) { + cx.shared.recovery_timer.lock(|timer| { + if timer.wait().is_ok() { + cx.shared.data_manager.lock(|data| { + data.recovery_counter += 1; + }); + // restart timer after interrupt + let duration_mins = atsamd_hal::fugit::MinutesDurationU32::minutes(1); + // timer requires specific duration format + let timer_duration: atsamd_hal::fugit::Duration = + duration_mins.convert(); + timer.start(timer_duration); + } + timer.enable_interrupt(); // clear interrupt + }); + } + #[task(priority = 3, local = [fired: bool = false], shared=[gpio, &em])] fn fire_drogue(mut cx: fire_drogue::Context) { cx.shared.em.run(|| { @@ -175,7 +202,7 @@ mod app { /// Runs the state machine. /// This takes control of the shared resources. - #[task(priority = 3, local = [state_machine], shared = [can0, gpio, data_manager, &em])] + #[task(priority = 3, local = [state_machine], shared = [can0, gpio, data_manager, &em, recovery_timer])] fn run_sm(mut cx: run_sm::Context) { cx.local.state_machine.run(&mut StateMachineContext { shared_resources: &mut cx.shared, diff --git a/boards/recovery/src/state_machine/mod.rs b/boards/recovery/src/state_machine/mod.rs index 553b594b..447190bd 100644 --- a/boards/recovery/src/state_machine/mod.rs +++ b/boards/recovery/src/state_machine/mod.rs @@ -5,6 +5,7 @@ use crate::communication::CanDevice0; use crate::data_manager::DataManager; use crate::gpio_manager::GPIOManager; use crate::state_machine::states::*; +use atsamd_hal::timer::TimerCounter2; pub use black_magic::*; use core::fmt::Debug; use defmt::Format; @@ -18,6 +19,7 @@ pub trait StateMachineSharedResources { fn lock_can(&mut self, f: &dyn Fn(&mut CanDevice0)); fn lock_data_manager(&mut self, f: &dyn Fn(&mut DataManager)); fn lock_gpio(&mut self, f: &dyn Fn(&mut GPIOManager)); + fn lock_recovery_timer(&mut self, f: &dyn Fn(&mut TimerCounter2)); } impl<'a> StateMachineSharedResources for crate::app::__rtic_internal_run_smSharedResources<'a> { @@ -30,6 +32,9 @@ impl<'a> StateMachineSharedResources for crate::app::__rtic_internal_run_smShare fn lock_gpio(&mut self, fun: &dyn Fn(&mut GPIOManager)) { self.gpio.lock(fun) } + fn lock_recovery_timer(&mut self, fun: &dyn Fn(&mut TimerCounter2)) { + self.recovery_timer.lock(fun) + } } pub struct StateMachineContext<'a, 'b> { @@ -125,9 +130,9 @@ impl From for RocketStates { } } // Linter: an implementation of From is preferred since it gives you Into<_> for free where the reverse isn't true -impl Into for RocketStates { - fn into(self) -> state::StateData { - match self { +impl From for state::StateData { + fn from(val: RocketStates) -> Self { + match val { RocketStates::Initializing(_) => state::StateData::Initializing, RocketStates::WaitForTakeoff(_) => state::StateData::WaitForTakeoff, RocketStates::Ascent(_) => state::StateData::Ascent, diff --git a/boards/recovery/src/state_machine/states/terminal_descent.rs b/boards/recovery/src/state_machine/states/terminal_descent.rs index 3d6d93cc..af5278c1 100644 --- a/boards/recovery/src/state_machine/states/terminal_descent.rs +++ b/boards/recovery/src/state_machine/states/terminal_descent.rs @@ -4,6 +4,8 @@ use crate::state_machine::{ RocketEvents, RocketStates, State, StateMachineContext, TransitionInto, WaitForRecovery, }; use crate::{no_transition, transition}; +use atsamd_hal::prelude::_embedded_hal_timer_CountDown; +use atsamd_hal::timer_traits::InterruptDrivenTimer; use common_arm::spawn; use defmt::{write, Format, Formatter}; use rtic::mutex::Mutex; @@ -17,6 +19,14 @@ impl State for TerminalDescent { spawn!(fire_main)?; Ok(()) }); + context.shared_resources.recovery_timer.lock(|timer| { + timer.enable_interrupt(); + let duration_mins = atsamd_hal::fugit::MinutesDurationU32::minutes(1); + // timer requires specific duration format + let timer_duration: atsamd_hal::fugit::Duration = + duration_mins.convert(); + timer.start(timer_duration); + }); } fn step(&mut self, context: &mut StateMachineContext) -> Option { context.shared_resources.data_manager.lock(|data| { diff --git a/boards/recovery/src/state_machine/states/wait_for_recovery.rs b/boards/recovery/src/state_machine/states/wait_for_recovery.rs index cd404c88..ddcef0b3 100644 --- a/boards/recovery/src/state_machine/states/wait_for_recovery.rs +++ b/boards/recovery/src/state_machine/states/wait_for_recovery.rs @@ -3,9 +3,10 @@ use crate::app::monotonics; use crate::no_transition; use crate::state_machine::{RocketStates, State, StateMachineContext, TransitionInto}; use crate::types::COM_ID; +use atsamd_hal::timer_traits::InterruptDrivenTimer; use defmt::{write, Format, Formatter}; use messages::command::{Command, PowerDown, RadioRate, RadioRateChange}; -use messages::sender::Sender::SensorBoard; +use messages::node::Node::SensorBoard; use messages::Message; use rtic::mutex::Mutex; @@ -32,6 +33,9 @@ impl State for WaitForRecovery { }) }); } + context.shared_resources.recovery_timer.lock(|timer| { + timer.disable_interrupt(); + }) } fn step(&mut self, _context: &mut StateMachineContext) -> Option { no_transition!() // this is our final resting place. We should also powerdown this board. diff --git a/boards/recovery/src/types.rs b/boards/recovery/src/types.rs index d7f5356d..6e6c29f3 100644 --- a/boards/recovery/src/types.rs +++ b/boards/recovery/src/types.rs @@ -1,7 +1,7 @@ -use messages::sender::Sender; -use messages::sender::Sender::RecoveryBoard; +use messages::node::Node; +use messages::node::Node::RecoveryBoard; // ------- -// Sender ID +// Node ID // ------- -pub static COM_ID: Sender = RecoveryBoard; +pub static COM_ID: Node = RecoveryBoard; diff --git a/boards/sensor/src/communication.rs b/boards/sensor/src/communication.rs index 2ef700ca..097adcbb 100644 --- a/boards/sensor/src/communication.rs +++ b/boards/sensor/src/communication.rs @@ -112,7 +112,7 @@ impl CanDevice0 { can.filters_standard() .push(Filter::Classic { action: Action::StoreFifo0, - filter: ecan::StandardId::new(messages::sender::Sender::CommunicationBoard.into()) + filter: ecan::StandardId::new(messages::node::Node::CommunicationBoard.into()) .unwrap(), mask: ecan::StandardId::ZERO, }) @@ -121,8 +121,7 @@ impl CanDevice0 { can.filters_standard() .push(Filter::Classic { action: Action::StoreFifo0, - filter: ecan::StandardId::new(messages::sender::Sender::RecoveryBoard.into()) - .unwrap(), + filter: ecan::StandardId::new(messages::node::Node::RecoveryBoard.into()).unwrap(), mask: ecan::StandardId::ZERO, }) .unwrap_or_else(|_| panic!("Recovery filter")); @@ -130,8 +129,7 @@ impl CanDevice0 { can.filters_standard() .push(Filter::Classic { action: Action::StoreFifo1, - filter: ecan::StandardId::new(messages::sender::Sender::GroundStation.into()) - .unwrap(), + filter: ecan::StandardId::new(messages::node::Node::GroundStation.into()).unwrap(), mask: ecan::StandardId::ZERO, }) .unwrap_or_else(|_| panic!("Ground Station filter")); diff --git a/boards/sensor/src/types.rs b/boards/sensor/src/types.rs index fe0877ab..7c063a71 100644 --- a/boards/sensor/src/types.rs +++ b/boards/sensor/src/types.rs @@ -8,14 +8,14 @@ use hal::dmac::BufferPair; use hal::sercom::IoSet2; use hal::sercom::Sercom4; -use messages::sender::Sender; -use messages::sender::Sender::SensorBoard; +use messages::node::Node; +use messages::node::Node::SensorBoard; use sbg_rs::sbg::SBG_BUFFER_SIZE; // ------- -// Sender ID +// Node ID // ------- -pub static COM_ID: Sender = SensorBoard; +pub static COM_ID: Node = SensorBoard; // ------- // SBG diff --git a/libraries/messages/src/command.rs b/libraries/messages/src/command.rs index 6ad0b804..8e2f0b40 100644 --- a/libraries/messages/src/command.rs +++ b/libraries/messages/src/command.rs @@ -1,4 +1,4 @@ -use crate::sender::Sender; +use crate::node::Node; use derive_more::From; use messages_proc_macros_lib::common_derives; @@ -32,7 +32,7 @@ pub struct DeployMain { #[common_derives] #[derive(From)] pub struct PowerDown { - pub board: Sender, // This isn't proper naming !! This is the board to be powered down. Changes name of sender.rs to board.rs. + pub board: Node, } #[common_derives] diff --git a/libraries/messages/src/lib.rs b/libraries/messages/src/lib.rs index c89fb673..9541c85c 100644 --- a/libraries/messages/src/lib.rs +++ b/libraries/messages/src/lib.rs @@ -7,7 +7,7 @@ use crate::command::Command; use crate::health::Health; -use crate::sender::Sender; +use crate::node::Node; use crate::sensor::Sensor; use crate::state::State; use derive_more::From; @@ -19,12 +19,17 @@ use messages_proc_macros_lib::common_derives; pub mod command; pub mod health; mod logging; -pub mod sender; +pub mod node; pub mod sensor; pub mod sensor_status; pub mod state; pub const MAX_SIZE: usize = 64; +pub const MAX_HEALTH_SIZE: usize = 47; +pub const MAX_SENSOR_SIZE: usize = 53; +pub const MAX_STATE_SIZE: usize = 13; +pub const MAX_LOG_SIZE: usize = 15; +pub const MAX_COMMAND_SIZE: usize = 15; pub use logging::{ErrorContext, Event, Log, LogLevel}; @@ -37,7 +42,7 @@ pub struct Message { pub timestamp: u64, /// The original sender of this message. - pub sender: Sender, + pub sender: Node, /// The data contained in this message. pub data: Data, @@ -57,7 +62,7 @@ pub enum Data { impl Message { pub fn new( timestamp: &Instant, - sender: Sender, + sender: Node, data: impl Into, ) -> Self { Message { @@ -70,7 +75,9 @@ impl Message { #[cfg(test)] mod test { - use crate::{Message, MAX_SIZE}; + use crate::{ + Message, MAX_COMMAND_SIZE, MAX_HEALTH_SIZE, MAX_LOG_SIZE, MAX_SENSOR_SIZE, MAX_STATE_SIZE, + }; use proptest::prelude::*; proptest! { @@ -78,8 +85,25 @@ mod test { fn message_size(msg: Message) { let bytes = postcard::to_allocvec(&msg).unwrap(); - dbg!(msg); - assert!(dbg!(bytes.len()) <= MAX_SIZE); + dbg!(&msg); + // The size of the message should be less than or equal the maximum size. + match msg.data { + crate::Data::State(_) => { + assert!(dbg!(bytes.len()) <= MAX_STATE_SIZE); + } + crate::Data::Sensor(_) => { + assert!(dbg!(bytes.len()) <= MAX_SENSOR_SIZE); + } + crate::Data::Log(_) => { + assert!(dbg!(bytes.len()) <= MAX_LOG_SIZE); + } + crate::Data::Command(_) => { + assert!(dbg!(bytes.len()) <= MAX_COMMAND_SIZE); + } + crate::Data::Health(_) => { + assert!(dbg!(bytes.len()) <= MAX_HEALTH_SIZE); + } + } } } } diff --git a/libraries/messages/src/node.rs b/libraries/messages/src/node.rs new file mode 100644 index 00000000..3eff0712 --- /dev/null +++ b/libraries/messages/src/node.rs @@ -0,0 +1,27 @@ +use messages_proc_macros_lib::common_derives; + +#[common_derives] +#[derive(Copy)] +pub enum Node { + GroundStation, + SensorBoard, + RecoveryBoard, + CommunicationBoard, + PowerBoard, + CameraBoard, + BeaconBoard, +} + +impl From for u16 { + fn from(node: Node) -> Self { + match node { + Node::GroundStation => 0, + Node::SensorBoard => 1, + Node::RecoveryBoard => 2, + Node::CommunicationBoard => 3, + Node::PowerBoard => 4, + Node::CameraBoard => 5, + Node::BeaconBoard => 6, + } + } +} diff --git a/libraries/messages/src/sender.rs b/libraries/messages/src/sender.rs deleted file mode 100644 index 2bc90999..00000000 --- a/libraries/messages/src/sender.rs +++ /dev/null @@ -1,28 +0,0 @@ -use messages_proc_macros_lib::common_derives; - -// I don't agree with the naming, We can use these as Ids to sent commands to that specific board. -#[common_derives] -#[derive(Copy)] -pub enum Sender { - GroundStation, - SensorBoard, - RecoveryBoard, - CommunicationBoard, - PowerBoard, - CameraBoard, - BeaconBoard, -} - -impl From for u16 { - fn from(sender: Sender) -> Self { - match sender { - Sender::GroundStation => 0, - Sender::SensorBoard => 1, - Sender::RecoveryBoard => 2, - Sender::CommunicationBoard => 3, - Sender::PowerBoard => 4, - Sender::CameraBoard => 5, - Sender::BeaconBoard => 6, - } - } -}