start updating the ancient flash loader
shared-hal-ci / Check build (push) Has been cancelled
shared-hal-ci / Check formatting (push) Has been cancelled
shared-hal-ci / Check Documentation Build (push) Has been cancelled
shared-hal-ci / Clippy (push) Has been cancelled
va108xx-ci / Run Tests (push) Has been cancelled
va108xx-ci / Check formatting (push) Has been cancelled
va108xx-ci / Check Documentation Build (push) Has been cancelled
va108xx-ci / Clippy (push) Has been cancelled
va416xx-ci / Run Tests (push) Has been cancelled
va416xx-ci / Check formatting (push) Has been cancelled
va416xx-ci / Check Documentation Build (push) Has been cancelled
va416xx-ci / Clippy (push) Has been cancelled
va108xx-ci / Check build (push) Has been cancelled
va416xx-ci / Check build (push) Has been cancelled
shared-hal-ci / Check build (push) Has been cancelled
shared-hal-ci / Check formatting (push) Has been cancelled
shared-hal-ci / Check Documentation Build (push) Has been cancelled
shared-hal-ci / Clippy (push) Has been cancelled
va108xx-ci / Run Tests (push) Has been cancelled
va108xx-ci / Check formatting (push) Has been cancelled
va108xx-ci / Check Documentation Build (push) Has been cancelled
va108xx-ci / Clippy (push) Has been cancelled
va416xx-ci / Run Tests (push) Has been cancelled
va416xx-ci / Check formatting (push) Has been cancelled
va416xx-ci / Check Documentation Build (push) Has been cancelled
va416xx-ci / Clippy (push) Has been cancelled
va108xx-ci / Check build (push) Has been cancelled
va416xx-ci / Check build (push) Has been cancelled
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "shared"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
@@ -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 {}
|
||||
+74
-151
@@ -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<const BUF_SIZE: usize, const SIZES_LEN: usize> {
|
||||
pub buf: StaticRb<u8, BUF_SIZE>,
|
||||
pub sizes: StaticRb<usize, SIZES_LEN>,
|
||||
}
|
||||
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<BUF_RB_SIZE_TM, SIZES_RB_SIZE_TM>,
|
||||
tc_rb: RingBufWrapper<BUF_RB_SIZE_TC, SIZES_RB_SIZE_TC>,
|
||||
}
|
||||
|
||||
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<CriticalSectionRawMutex, TC_PIPE_SIZE>,
|
||||
> = static_cell::ConstStaticCell::new(embassy_sync::pipe::Pipe::new());
|
||||
static TM_PIPE: static_cell::ConstStaticCell<
|
||||
embassy_sync::pipe::Pipe<CriticalSectionRawMutex, TM_PIPE_SIZE>,
|
||||
> = 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;
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user