From 7bef3ec84f4f4b53432a8a62f979cb2536c6c608 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 19 May 2026 12:13:46 +0200 Subject: [PATCH] start updating the ancient flash loader --- va108xx/flashloader/Cargo.toml | 12 +- va108xx/flashloader/shared/Cargo.toml | 6 + va108xx/flashloader/shared/src/lib.rs | 18 +++ va108xx/flashloader/src/main.rs | 225 +++++++++----------------- 4 files changed, 105 insertions(+), 156 deletions(-) create mode 100644 va108xx/flashloader/shared/Cargo.toml create mode 100644 va108xx/flashloader/shared/src/lib.rs diff --git a/va108xx/flashloader/Cargo.toml b/va108xx/flashloader/Cargo.toml index 008e361..8ce7d36 100644 --- a/va108xx/flashloader/Cargo.toml +++ b/va108xx/flashloader/Cargo.toml @@ -12,22 +12,24 @@ defmt-rtt = { version = "1" } panic-probe = { version = "1", features = ["print-defmt"] } num_enum = { version = "0.7", default-features = false } cobs = { version = "0.5", default-features = false } -satrs = { version = "0.3.0-alpha.3", default-features = false, features = ["defmt"] } +# satrs = { version = "0.3.0-alpha.3", default-features = false, features = ["defmt"] } fugit = "0.4" arbitrary-int = "2" -ringbuf = { version = "0.4.7", default-features = false, features = ["portable-atomic"] } -# spacepackets = { version = "0.17", path = "https://egit.irs.uni-stuttgart.de/rust/spacepackets.git", default-features = false, features = ["defmt"] } +embassy-sync = "0.8" +embassy-time = "0.5" +static_cell = "2" +spacepackets = { version = "0.17", default-features = false, features = ["defmt"] } +serde = { version = "1", default-features = false } # Even though we do not use this directly, we need to activate this feature explicitely # so that RTIC compiles because thumv6 does not have CAS operations natively. portable-atomic = {version = "1", features = ["unsafe-assume-single-core"]} rtic = { version = "2", features = ["thumbv6-backend"] } -rtic-monotonics = { version = "2", features = ["cortex-m-systick"] } [dependencies.va108xx-hal] version = "0.13" path = "../va108xx-hal" -features = ["defmt"] +features = ["defmt", "embassy-oc30-oc31"] [dependencies.vorago-reb1] version = "0.10" diff --git a/va108xx/flashloader/shared/Cargo.toml b/va108xx/flashloader/shared/Cargo.toml new file mode 100644 index 0000000..5e22169 --- /dev/null +++ b/va108xx/flashloader/shared/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "shared" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/va108xx/flashloader/shared/src/lib.rs b/va108xx/flashloader/shared/src/lib.rs new file mode 100644 index 0000000..1b94908 --- /dev/null +++ b/va108xx/flashloader/shared/src/lib.rs @@ -0,0 +1,18 @@ +#![no_std] + +#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, defmt::Format)] +#[repr(u8)] +enum AppSel { + A = 0, + B = 1, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, defmt::Format)] +pub enum Request { + CorruptImageA, + CorruptImageB, + SetBootSlot(AppSel), +} + +#[cfg(test)] +mod tests {} diff --git a/va108xx/flashloader/src/main.rs b/va108xx/flashloader/src/main.rs index 5776257..5feff5e 100644 --- a/va108xx/flashloader/src/main.rs +++ b/va108xx/flashloader/src/main.rs @@ -4,13 +4,7 @@ #![no_std] use defmt_rtt as _; // global logger -use num_enum::TryFromPrimitive; use panic_probe as _; -use ringbuf::{ - traits::{Consumer, Observer, Producer}, - StaticRb, -}; -use rtic_monotonics::fugit::ExtU32; use va108xx_hal::time::Hertz; const SYSCLK_FREQ: Hertz = Hertz::from_raw(50_000_000); @@ -25,30 +19,8 @@ const UART_BAUDRATE: u32 = 115200; const BOOT_NVM_MEMORY_ID: u8 = 1; const RX_DEBUGGING: bool = false; -pub enum ActionId { - CorruptImageA = 128, - CorruptImageB = 129, - SetBootSlot = 130, -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, defmt::Format)] -#[repr(u8)] -enum AppSel { - A = 0, - B = 1, -} - -// Larger buffer for TC to be able to hold the possibly large memory write packets. -const BUF_RB_SIZE_TC: usize = 1024; -const SIZES_RB_SIZE_TC: usize = 16; - -const BUF_RB_SIZE_TM: usize = 256; -const SIZES_RB_SIZE_TM: usize = 16; - -pub struct RingBufWrapper { - pub buf: StaticRb, - pub sizes: StaticRb, -} +const TC_PIPE_SIZE: usize = 1024; +const TM_PIPE_SIZE: usize = 128; pub const APP_A_START_ADDR: u32 = 0x3000; pub const APP_A_END_ADDR: u32 = 0x117FC; @@ -60,21 +32,13 @@ pub const PREFERRED_SLOT_OFFSET: u32 = 0x20000 - 1; #[rtic::app(device = pac, dispatchers = [OC20, OC21, OC22])] mod app { use super::*; - use arbitrary_int::traits::Integer as _; - use arbitrary_int::{u11, u14}; use cortex_m::asm; + use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embedded_io::Write; - use rtic::Mutex; - use rtic_monotonics::Monotonic; - use satrs::pus::verification::{FailParams, VerificationReportCreator}; - use satrs::spacepackets::ecss::PusServiceId; - use satrs::spacepackets::ecss::{ - tc::PusTcReader, tm::PusTmCreator, EcssEnumU8, PusPacket, WritablePusPacket, - }; use va108xx_hal::pins::PinsA; use va108xx_hal::spi::SpiClockConfig; - use va108xx_hal::uart::InterruptContextTimeoutOrMaxSize; - use va108xx_hal::{pac, uart, InterruptConfig}; + use va108xx_hal::uart; + use va108xx_hal::{pac, InterruptConfig}; use vorago_reb1::m95m01::M95M01; #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] @@ -89,31 +53,27 @@ mod app { struct Local { uart_rx: uart::RxWithInterrupt, uart_tx: uart::Tx, - rx_context: InterruptContextTimeoutOrMaxSize, - verif_reporter: VerificationReportCreator, nvm: M95M01, + tc_tx: embassy_sync::pipe::Writer<'static, CriticalSectionRawMutex, TC_PIPE_SIZE>, + tc_rx: embassy_sync::pipe::Reader<'static, CriticalSectionRawMutex, TC_PIPE_SIZE>, + tm_tx: embassy_sync::pipe::Writer<'static, CriticalSectionRawMutex, TM_PIPE_SIZE>, + tm_rx: embassy_sync::pipe::Reader<'static, CriticalSectionRawMutex, TM_PIPE_SIZE>, } #[shared] - struct Shared { - // Having this shared allows multiple tasks to generate telemetry. - tm_rb: RingBufWrapper, - tc_rb: RingBufWrapper, - } - - rtic_monotonics::systick_monotonic!(Mono, 1000); + struct Shared {} #[init] fn init(cx: init::Context) -> (Shared, Local) { defmt::println!("-- Vorago flashloader --"); - Mono::start(cx.core.SYST, SYSCLK_FREQ.to_raw()); + let periphs = cx.device; + va108xx_hal::embassy_time::init(periphs.tim14, periphs.tim15, SYSCLK_FREQ); - let dp = cx.device; let spi_clock_config = SpiClockConfig::new(2, 4); - let nvm = M95M01::new(dp.spic, spi_clock_config); + let nvm = M95M01::new(periphs.spic, spi_clock_config); - let gpioa = PinsA::new(dp.porta); + let gpioa = PinsA::new(periphs.porta); let tx = gpioa.pa9; let rx = gpioa.pa8; @@ -124,7 +84,7 @@ mod app { ); let uart_config = uart::Config::new_with_clock_config(clock_config); let irq_uart = uart::Uart::new_with_interrupt_uart0( - dp.uarta, + periphs.uarta, tx, rx, uart_config, @@ -134,30 +94,28 @@ mod app { // Unwrap is okay, we explicitely set the interrupt ID. let mut rx = rx.into_rx_with_irq(); - let verif_reporter = VerificationReportCreator::new(u11::new(0)); + rx.start(); + tc_handler::spawn().unwrap(); + tm_tx_handler::spawn().unwrap(); - let mut rx_context = InterruptContextTimeoutOrMaxSize::new(MAX_TC_FRAME_SIZE); - rx.read_fixed_len_or_timeout_based_using_irq(&mut rx_context) - .expect("initiating UART RX failed"); - pus_tc_handler::spawn().unwrap(); - pus_tm_tx_handler::spawn().unwrap(); + static TC_PIPE: static_cell::ConstStaticCell< + embassy_sync::pipe::Pipe, + > = static_cell::ConstStaticCell::new(embassy_sync::pipe::Pipe::new()); + static TM_PIPE: static_cell::ConstStaticCell< + embassy_sync::pipe::Pipe, + > = static_cell::ConstStaticCell::new(embassy_sync::pipe::Pipe::new()); + let (tc_rx, tc_tx) = TC_PIPE.take().split(); + let (tm_rx, tm_tx) = TM_PIPE.take().split(); ( - Shared { - tc_rb: RingBufWrapper { - buf: StaticRb::default(), - sizes: StaticRb::default(), - }, - tm_rb: RingBufWrapper { - buf: StaticRb::default(), - sizes: StaticRb::default(), - }, - }, + Shared {}, Local { uart_rx: rx, uart_tx: tx, - rx_context, - verif_reporter, nvm, + tc_tx, + tc_rx, + tm_tx, + tm_rx, }, ) } @@ -176,66 +134,25 @@ mod app { local = [ cnt: u32 = 0, rx_buf: [u8; MAX_TC_FRAME_SIZE] = [0; MAX_TC_FRAME_SIZE], - rx_context, uart_rx, + tc_tx ], - shared = [tc_rb] )] - fn uart_rx_irq(mut cx: uart_rx_irq::Context) { - match cx - .local - .uart_rx - .on_interrupt_max_size_or_timeout_based(cx.local.rx_context, cx.local.rx_buf) - { - Ok(result) => { - if RX_DEBUGGING { - defmt::debug!("RX Info: {:?}", cx.local.rx_context); - defmt::debug!("RX Result: {:?}", result); + fn uart_rx_irq(cx: uart_rx_irq::Context) { + let mut buf: [u8; 16] = [0; 16]; + let result = cx.local.uart_rx.on_interrupt(&mut buf); + if result.bytes_read > 0 { + let mut written_so_far = 0; + while written_so_far < result.bytes_read { + let write_result = cx + .local + .tc_tx + .try_write(&buf[written_so_far..result.bytes_read]); + if write_result.is_err() { + defmt::warn!("TC pipe full, dropping bytes"); + break; } - if result.complete() { - // Check frame validity (must have COBS format) and decode the frame. - // Currently, we expect a full frame or a frame received through a timeout - // to be one COBS frame. We could parse for multiple COBS packets in one - // frame, but the additional complexity is not necessary here.. - if cx.local.rx_buf[0] == 0 && cx.local.rx_buf[result.bytes_read - 1] == 0 { - let decoded_size = - cobs::decode_in_place(&mut cx.local.rx_buf[1..result.bytes_read]); - if decoded_size.is_err() { - defmt::warn!("COBS decoding failed"); - } else { - let decoded_size = decoded_size.unwrap(); - let mut tc_rb_full = false; - cx.shared.tc_rb.lock(|rb| { - if rb.sizes.vacant_len() >= 1 && rb.buf.vacant_len() >= decoded_size - { - rb.sizes.try_push(decoded_size).unwrap(); - rb.buf.push_slice(&cx.local.rx_buf[1..1 + decoded_size]); - } else { - tc_rb_full = true; - } - }); - if tc_rb_full { - defmt::warn!("COBS TC queue full"); - } - } - } else { - defmt::warn!( - "COBS frame with invalid format, start and end bytes are not 0" - ); - } - - // Initiate next transfer. - cx.local - .uart_rx - .read_fixed_len_or_timeout_based_using_irq(cx.local.rx_context) - .expect("read operation failed"); - } - if result.has_errors() { - defmt::warn!("UART error: {:?}", result.errors.unwrap()); - } - } - Err(e) => { - defmt::warn!("UART error: {:?}", e); + written_so_far += write_result.unwrap(); } } } @@ -248,32 +165,35 @@ mod app { src_data_buf: [u8; 16] = [0; 16], verif_buf: [u8; 32] = [0; 32], nvm, - verif_reporter + tc_rx ], - shared=[tm_rb, tc_rb] + shared=[] )] - async fn pus_tc_handler(mut cx: pus_tc_handler::Context) { + async fn tc_handler(mut cx: tc_handler::Context) { loop { - // Try to read a TC from the ring buffer. - let packet_len = cx.shared.tc_rb.lock(|rb| rb.sizes.try_pop()); - if packet_len.is_none() { - // Small delay, TCs might arrive very quickly. - Mono::delay(20_u32.millis()).await; - continue; - } - let packet_len = packet_len.unwrap(); - defmt::info!("received packet with length {}", packet_len); - let popped_packet_len = cx - .shared - .tc_rb - .lock(|rb| rb.buf.pop_slice(&mut cx.local.tc_buf[0..packet_len])); - assert_eq!(popped_packet_len, packet_len); - // Read a telecommand, now handle it. - handle_valid_pus_tc(&mut cx); + /* + // Try to read a TC from the ring buffer. + let packet_len = cx.shared.tc_rb.lock(|rb| rb.sizes.try_pop()); + if packet_len.is_none() { + // Small delay, TCs might arrive very quickly. + Mono::delay(20_u32.millis()).await; + continue; + } + let packet_len = packet_len.unwrap(); + defmt::info!("received packet with length {}", packet_len); + let popped_packet_len = cx + .shared + .tc_rb + .lock(|rb| rb.buf.pop_slice(&mut cx.local.tc_buf[0..packet_len])); + assert_eq!(popped_packet_len, packet_len); + // Read a telecommand, now handle it. + handle_valid_pus_tc(&mut cx); + */ } } - fn handle_valid_pus_tc(cx: &mut pus_tc_handler::Context) { + /* + fn handle_valid_pus_tc(cx: &mut tc_handler::Context) { let pus_tc = PusTcReader::new(cx.local.tc_buf); if let Err(e) = pus_tc { defmt::warn!("PUS TC error: {}", e); @@ -420,6 +340,7 @@ mod app { } } } + */ #[task( priority = 1, @@ -428,10 +349,11 @@ mod app { encoded_buf: [u8;MAX_TM_FRAME_SIZE] = [0; MAX_TM_FRAME_SIZE], uart_tx, ], - shared=[tm_rb] + shared=[] )] - async fn pus_tm_tx_handler(mut cx: pus_tm_tx_handler::Context) { + async fn tm_tx_handler(mut cx: tm_tx_handler::Context) { loop { + /* let mut occupied_len = cx.shared.tm_rb.lock(|rb| rb.sizes.occupied_len()); while occupied_len > 0 { let next_size = cx.shared.tm_rb.lock(|rb| { @@ -453,6 +375,7 @@ mod app { Mono::delay(2.millis()).await; } Mono::delay(50.millis()).await; + */ } } }