Make flashload COM more reliable
Some checks are pending
Rust/va416xx-rs/pipeline/pr-main Build queued...

Fixes for UART RX with IRQ implementation
This commit is contained in:
2024-09-13 18:09:29 +02:00
parent cad968342a
commit 78dd7ee5c3
5 changed files with 425 additions and 491 deletions

View File

@ -1,12 +1,10 @@
#!/usr/bin/env python3
from spacepackets.ecss import RequestId
from spacepackets.ecss.defs import PusService
from spacepackets.ecss.tm import PusTm
import toml
import struct
import logging
import argparse
import threading
import time
import enum
from tmtccmd.com.serial_base import SerialCfg
@ -45,6 +43,7 @@ ACTION_SERVICE = 8
RAW_MEMORY_WRITE_SUBSERVICE = 2
BOOT_NVM_MEMORY_ID = 1
PING_PAYLOAD_SIZE = 0
class ActionId(enum.IntEnum):
@ -104,6 +103,29 @@ def main() -> int:
com_if = SerialCobsComIF(serial_cfg)
com_if.open()
file_path = None
if args.ping:
_LOGGER.info("Sending ping command")
ping_tc = PusTc(
apid=0x00,
service=PusService.S17_TEST,
subservice=1,
seq_count=SEQ_PROVIDER.get_and_increment(),
app_data=bytes(PING_PAYLOAD_SIZE),
)
verificator.add_tc(ping_tc)
com_if.send(ping_tc.pack())
data_available = com_if.data_available(0.4)
if not data_available:
_LOGGER.warning("no ping reply received")
for reply in com_if.receive():
result = verificator.add_tm(
Service1Tm.from_tm(PusTm.unpack(reply, 0), UnpackParams(0))
)
if result is not None and result.completed:
_LOGGER.info("received ping completion reply")
if not args.target:
return 0
if args.target:
if not args.corrupt:
if not args.path:
@ -113,15 +135,6 @@ def main() -> int:
if not file_path.exists():
_LOGGER.error("File does not exist")
return -1
if args.ping:
_LOGGER.info("Sending ping command")
ping_tc = PusTc(
apid=0x00,
service=PusService.S17_TEST,
subservice=1,
seq_count=SEQ_PROVIDER.get_and_increment(),
)
com_if.send(ping_tc.pack())
if args.corrupt:
if not args.target:
_LOGGER.error("target for corruption command required")
@ -254,7 +267,7 @@ def main() -> int:
):
done = True
# Still keep a small delay
time.sleep(0.01)
# time.sleep(0.05)
verificator.remove_completed_entries()
if done:
break

View File

@ -18,13 +18,11 @@
#![no_main]
#![no_std]
use embedded_hal_nb::serial::Read;
use once_cell::sync::OnceCell;
use panic_rtt_target as _;
use va416xx_hal::{clock::Clocks, edac, pac, time::Hertz, wdt::Wdt};
const EXTCLK_FREQ: u32 = 40_000_000;
const COBS_FRAME_SEPARATOR: u8 = 0x0;
const MAX_TC_SIZE: usize = 1024;
const MAX_TC_FRAME_SIZE: usize = cobs::max_encoding_length(MAX_TC_SIZE);
@ -33,10 +31,8 @@ const MAX_TM_SIZE: usize = 128;
const MAX_TM_FRAME_SIZE: usize = cobs::max_encoding_length(MAX_TM_SIZE);
const UART_BAUDRATE: u32 = 115200;
const SERIAL_RX_WIRETAPPING: bool = false;
const COBS_RX_DEBUGGING: bool = false;
const BOOT_NVM_MEMORY_ID: u8 = 1;
const RX_DEBUGGING: bool = false;
pub enum ActionId {
CorruptImageA = 128,
@ -62,13 +58,24 @@ use ringbuf::{
CachingCons, StaticProd, StaticRb,
};
const BUF_RB_SIZE_TX: usize = 1024;
const SIZES_RB_SIZE_TX: usize = 16;
// Larger buffer for TC to be able to hold the possibly large memory write packets.
const BUF_RB_SIZE_TC: usize = 2048;
const SIZES_RB_SIZE_TC: usize = 16;
static mut BUF_RB_TX: Lazy<StaticRb<u8, BUF_RB_SIZE_TX>> =
Lazy::new(StaticRb::<u8, BUF_RB_SIZE_TX>::default);
static mut SIZES_RB_TX: Lazy<StaticRb<usize, SIZES_RB_SIZE_TX>> =
Lazy::new(StaticRb::<usize, SIZES_RB_SIZE_TX>::default);
const BUF_RB_SIZE_TM: usize = 512;
const SIZES_RB_SIZE_TM: usize = 16;
// Ring buffers to handling variable sized telemetry
static mut BUF_RB_TM: Lazy<StaticRb<u8, BUF_RB_SIZE_TM>> =
Lazy::new(StaticRb::<u8, BUF_RB_SIZE_TM>::default);
static mut SIZES_RB_TM: Lazy<StaticRb<usize, SIZES_RB_SIZE_TM>> =
Lazy::new(StaticRb::<usize, SIZES_RB_SIZE_TM>::default);
// Ring buffers to handling variable sized telecommands
static mut BUF_RB_TC: Lazy<StaticRb<u8, BUF_RB_SIZE_TC>> =
Lazy::new(StaticRb::<u8, BUF_RB_SIZE_TC>::default);
static mut SIZES_RB_TC: Lazy<StaticRb<usize, SIZES_RB_SIZE_TC>> =
Lazy::new(StaticRb::<usize, SIZES_RB_SIZE_TC>::default);
pub struct DataProducer<const BUF_SIZE: usize, const SIZES_LEN: usize> {
pub buf_prod: StaticProd<'static, u8, BUF_SIZE>,
@ -91,15 +98,10 @@ pub const APP_B_END_ADDR: u32 = 0x40000;
mod app {
use super::*;
use cortex_m::asm;
use embedded_hal_nb::nb;
use embedded_io::Write;
use panic_rtt_target as _;
use rtic::Mutex;
use rtic_monotonics::systick::prelude::*;
use rtic_sync::{
channel::{Receiver, Sender},
make_channel,
};
use rtt_target::rprintln;
use satrs::pus::verification::VerificationReportCreator;
use spacepackets::ecss::PusServiceId;
@ -127,26 +129,24 @@ mod app {
#[local]
struct Local {
uart_rx: uart::Rx<pac::Uart0>,
uart_rx: uart::RxWithIrq<pac::Uart0>,
uart_tx: uart::Tx<pac::Uart0>,
cobs_reader_state: CobsReaderStates,
tc_tx: TcTx,
tc_rx: TcRx,
rom_spi: Option<pac::Spi3>,
tx_cons: DataConsumer<BUF_RB_SIZE_TX, SIZES_RB_SIZE_TX>,
// We handle all TM in one task.
tm_cons: DataConsumer<BUF_RB_SIZE_TM, SIZES_RB_SIZE_TM>,
// We consume all TC in one task.
tc_cons: DataConsumer<BUF_RB_SIZE_TC, SIZES_RB_SIZE_TC>,
// We produce all TC in one task.
tc_prod: DataProducer<BUF_RB_SIZE_TC, SIZES_RB_SIZE_TC>,
verif_reporter: VerificationReportCreator,
}
#[shared]
struct Shared {
decode_buffer_busy: bool,
decode_buf: [u8; MAX_TC_SIZE],
tx_prod: DataProducer<BUF_RB_SIZE_TX, SIZES_RB_SIZE_TX>,
// Having this shared allows multiple tasks to generate telemetry.
tm_prod: DataProducer<BUF_RB_SIZE_TM, SIZES_RB_SIZE_TM>,
}
pub type TcTx = Sender<'static, usize, 2>;
pub type TcRx = Receiver<'static, usize, 2>;
rtic_monotonics::systick_monotonic!(Mono, 10_000);
#[init]
@ -176,38 +176,45 @@ mod app {
&mut cx.device.sysconfig,
&clocks,
);
let (tx, rx) = uart0.split();
let (tc_tx, tc_rx) = make_channel!(usize, 2);
let (tx, mut rx, _) = uart0.split_with_irq();
let verif_reporter = VerificationReportCreator::new(0).unwrap();
let (buf_prod, buf_cons) = unsafe { BUF_RB_TX.split_ref() };
let (sizes_prod, sizes_cons) = unsafe { SIZES_RB_TX.split_ref() };
let (buf_prod_tm, buf_cons_tm) = unsafe { BUF_RB_TM.split_ref() };
let (sizes_prod_tm, sizes_cons_tm) = unsafe { SIZES_RB_TM.split_ref() };
let (buf_prod_tc, buf_cons_tc) = unsafe { BUF_RB_TC.split_ref() };
let (sizes_prod_tc, sizes_cons_tc) = unsafe { SIZES_RB_TC.split_ref() };
Mono::start(cx.core.SYST, clocks.sysclk().raw());
CLOCKS.set(clocks).unwrap();
rx.read_fixed_len_using_irq(MAX_TC_FRAME_SIZE, true)
.expect("initiating UART RX failed");
pus_tc_handler::spawn().unwrap();
uart_reader_task::spawn().unwrap();
pus_tm_tx_handler::spawn().unwrap();
(
Shared {
decode_buffer_busy: false,
decode_buf: [0; MAX_TC_SIZE],
tx_prod: DataProducer {
buf_prod,
sizes_prod,
tm_prod: DataProducer {
buf_prod: buf_prod_tm,
sizes_prod: sizes_prod_tm,
},
},
Local {
uart_rx: rx,
uart_tx: tx,
cobs_reader_state: CobsReaderStates::default(),
tc_tx,
tc_rx,
rom_spi: Some(cx.device.spi3),
tx_cons: DataConsumer {
buf_cons,
sizes_cons,
tm_cons: DataConsumer {
buf_cons: buf_cons_tm,
sizes_cons: sizes_cons_tm,
},
tc_cons: DataConsumer {
buf_cons: buf_cons_tc,
sizes_cons: sizes_cons_tc,
},
tc_prod: DataProducer {
buf_prod: buf_prod_tc,
sizes_prod: sizes_prod_tc,
},
verif_reporter,
},
@ -223,120 +230,62 @@ mod app {
}
#[task(
priority = 4,
local=[
read_buf: [u8;MAX_TC_FRAME_SIZE] = [0; MAX_TC_FRAME_SIZE],
binds = UART0_RX,
local = [
cnt: u32 = 0,
rx_buf: [u8; MAX_TC_FRAME_SIZE] = [0; MAX_TC_FRAME_SIZE],
uart_rx,
cobs_reader_state,
tc_tx
tc_prod
],
shared=[decode_buffer_busy, decode_buf]
)]
async fn uart_reader_task(mut cx: uart_reader_task::Context) {
let mut current_idx = 0;
loop {
match cx.local.uart_rx.read() {
Ok(byte) => {
if SERIAL_RX_WIRETAPPING {
log::debug!("RX Byte: 0x{:x?}", byte);
}
handle_single_rx_byte(&mut cx, byte, &mut current_idx)
fn uart_rx_irq(cx: uart_rx_irq::Context) {
match cx.local.uart_rx.irq_handler(cx.local.rx_buf) {
Ok(result) => {
if RX_DEBUGGING {
log::debug!("RX Info: {:?}", cx.local.uart_rx.irq_info());
log::debug!("RX Result: {:?}", result);
}
Err(e) => {
match e {
nb::Error::Other(e) => {
log::warn!("UART error: {:?}", e);
match e {
uart::Error::Overrun => {
cx.local.uart_rx.clear_fifo();
}
uart::Error::FramingError => (),
uart::Error::ParityError => (),
uart::Error::BreakCondition => (),
uart::Error::TransferPending => (),
uart::Error::BufferTooShort => (),
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() {
log::warn!("COBS decoding failed");
} else {
let decoded_size = decoded_size.unwrap();
if cx.local.tc_prod.sizes_prod.vacant_len() >= 1
&& cx.local.tc_prod.buf_prod.vacant_len() >= decoded_size
{
// Should never fail, we checked there is enough space.
cx.local.tc_prod.sizes_prod.try_push(decoded_size).unwrap();
cx.local
.tc_prod
.buf_prod
.push_slice(&cx.local.rx_buf[1..1 + decoded_size]);
} else {
log::warn!("COBS TC queue full");
}
}
nb::Error::WouldBlock => {
// Delay for a short period before polling again.
Mono::delay(400.micros()).await;
}
} else {
log::warn!("COBS frame with invalid format, start and end bytes are not 0");
}
}
}
}
}
fn handle_single_rx_byte(
cx: &mut uart_reader_task::Context,
byte: u8,
current_idx: &mut usize,
) {
match cx.local.cobs_reader_state {
CobsReaderStates::WaitingForStart => {
if byte == COBS_FRAME_SEPARATOR {
if COBS_RX_DEBUGGING {
log::debug!("COBS start marker detected");
}
*cx.local.cobs_reader_state = CobsReaderStates::WatingForEnd;
*current_idx = 0;
// Initiate next transfer.
cx.local
.uart_rx
.read_fixed_len_using_irq(MAX_TC_FRAME_SIZE, true)
.expect("read operation failed");
}
if result.error() {
log::warn!("UART error: {:?}", result.error());
}
}
CobsReaderStates::WatingForEnd => {
if byte == COBS_FRAME_SEPARATOR {
if COBS_RX_DEBUGGING {
log::debug!("COBS end marker detected");
}
let mut sending_failed = false;
let mut decoding_error = false;
let mut decode_buffer_busy = false;
cx.shared.decode_buffer_busy.lock(|busy| {
if *busy {
decode_buffer_busy = true;
} else {
cx.shared.decode_buf.lock(|buf| {
match cobs::decode(&cx.local.read_buf[..*current_idx], buf) {
Ok(packet_len) => {
if COBS_RX_DEBUGGING {
log::debug!(
"COBS decoded packet with length {}",
packet_len
);
}
if cx.local.tc_tx.try_send(packet_len).is_err() {
sending_failed = true;
}
*busy = true;
}
Err(_) => {
decoding_error = true;
}
}
});
}
});
if sending_failed {
log::warn!("sending TC packet failed, queue full");
}
if decoding_error {
log::warn!("decoding error");
}
if decode_buffer_busy {
log::warn!("decode buffer busy. data arriving too fast");
}
*cx.local.cobs_reader_state = CobsReaderStates::WaitingForStart;
} else if *current_idx >= cx.local.read_buf.len() {
*cx.local.cobs_reader_state = CobsReaderStates::FrameOverflow;
} else {
cx.local.read_buf[*current_idx] = byte;
*current_idx += 1;
}
}
CobsReaderStates::FrameOverflow => {
if byte == COBS_FRAME_SEPARATOR {
*cx.local.cobs_reader_state = CobsReaderStates::WaitingForStart;
*current_idx = 0;
}
Err(e) => {
log::warn!("UART error: {:?}", e);
}
}
}
@ -344,149 +293,167 @@ mod app {
#[task(
priority = 2,
local=[
read_buf: [u8;MAX_TC_FRAME_SIZE] = [0; MAX_TC_FRAME_SIZE],
tc_buf: [u8; MAX_TC_SIZE] = [0; MAX_TC_SIZE],
src_data_buf: [u8; 16] = [0; 16],
verif_buf: [u8; 32] = [0; 32],
tc_rx,
tc_cons,
rom_spi,
verif_reporter
],
shared=[decode_buffer_busy, decode_buf, tx_prod]
shared=[tm_prod]
)]
async fn pus_tc_handler(mut cx: pus_tc_handler::Context) {
loop {
let packet_len = cx.local.tc_rx.recv().await.expect("all senders down");
// Try to read a TC from the ring buffer.
let packet_len = cx.local.tc_cons.sizes_cons.try_pop();
if packet_len.is_none() {
// Small delay, TCs might arrive very quickly.
Mono::delay(20.millis()).await;
continue;
}
let packet_len = packet_len.unwrap();
log::info!(target: "TC Handler", "received packet with length {}", packet_len);
// We still copy the data to a local buffer, so the exchange buffer can already be used
// for the next packet / decode process.
cx.shared
.decode_buf
.lock(|buf| cx.local.read_buf[0..buf.len()].copy_from_slice(buf));
cx.shared.decode_buffer_busy.lock(|busy| *busy = false);
match PusTcReader::new(cx.local.read_buf) {
Ok((pus_tc, _)) => {
let mut write_and_send = |tm: &PusTmCreator| {
let written_size = tm.write_to_bytes(cx.local.verif_buf).unwrap();
cx.shared.tx_prod.lock(|prod| {
prod.sizes_prod.try_push(tm.len_written()).unwrap();
prod.buf_prod
.push_slice(&cx.local.verif_buf[0..written_size]);
});
};
let token = cx.local.verif_reporter.add_tc(&pus_tc);
let (tm, accepted_token) = cx
.local
.verif_reporter
.acceptance_success(cx.local.src_data_buf, token, 0, 0, &[])
.expect("acceptance success failed");
write_and_send(&tm);
assert_eq!(
cx.local
.tc_cons
.buf_cons
.pop_slice(&mut cx.local.tc_buf[0..packet_len]),
packet_len
);
// Read a telecommand, now handle it.
handle_valid_pus_tc(&mut cx);
}
}
let (tm, started_token) = cx
.local
.verif_reporter
.start_success(cx.local.src_data_buf, accepted_token, 0, 0, &[])
.expect("acceptance success failed");
write_and_send(&tm);
fn handle_valid_pus_tc(cx: &mut pus_tc_handler::Context) {
let pus_tc = PusTcReader::new(cx.local.tc_buf);
if pus_tc.is_err() {
log::warn!("PUS TC error: {}", pus_tc.unwrap_err());
return;
}
let (pus_tc, _) = pus_tc.unwrap();
let mut write_and_send = |tm: &PusTmCreator| {
let written_size = tm.write_to_bytes(cx.local.verif_buf).unwrap();
cx.shared.tm_prod.lock(|prod| {
prod.sizes_prod.try_push(tm.len_written()).unwrap();
prod.buf_prod
.push_slice(&cx.local.verif_buf[0..written_size]);
});
};
let token = cx.local.verif_reporter.add_tc(&pus_tc);
let (tm, accepted_token) = cx
.local
.verif_reporter
.acceptance_success(cx.local.src_data_buf, token, 0, 0, &[])
.expect("acceptance success failed");
write_and_send(&tm);
if pus_tc.service() == PusServiceId::Action as u8 {
let mut corrupt_image = |base_addr: u32| {
// Safety: We only use this for NVM handling and we only do NVM
// handling here.
let mut sys_cfg = unsafe { pac::Sysconfig::steal() };
let nvm = Nvm::new(
&mut sys_cfg,
cx.local.rom_spi.take().unwrap(),
CLOCKS.get().as_ref().unwrap(),
);
let mut buf = [0u8; 4];
nvm.read_data(base_addr + 32, &mut buf);
buf[0] += 1;
nvm.write_data(base_addr + 32, &buf);
*cx.local.rom_spi = Some(nvm.release(&mut sys_cfg));
let tm = cx
.local
.verif_reporter
.completion_success(cx.local.src_data_buf, started_token, 0, 0, &[])
.expect("completion success failed");
write_and_send(&tm);
};
if pus_tc.subservice() == ActionId::CorruptImageA as u8 {
rprintln!("corrupting App Image A");
corrupt_image(APP_A_START_ADDR);
}
if pus_tc.subservice() == ActionId::CorruptImageB as u8 {
rprintln!("corrupting App Image B");
corrupt_image(APP_B_START_ADDR);
}
}
if pus_tc.service() == PusServiceId::Test as u8 && pus_tc.subservice() == 1 {
log::info!(target: "TC Handler", "received ping TC");
} else if pus_tc.service() == PusServiceId::MemoryManagement as u8 {
let tm = cx
.local
.verif_reporter
.step_success(
cx.local.src_data_buf,
&started_token,
0,
0,
&[],
EcssEnumU8::new(0),
)
.expect("step success failed");
write_and_send(&tm);
// Raw memory write TC
if pus_tc.subservice() == 2 {
let app_data = pus_tc.app_data();
if app_data.len() < 10 {
log::warn!(
target: "TC Handler",
"app data for raw memory write is too short: {}",
app_data.len()
);
}
let memory_id = app_data[0];
if memory_id != BOOT_NVM_MEMORY_ID {
log::warn!(target: "TC Handler", "memory ID {} not supported", memory_id);
// TODO: Error reporting
return;
}
let offset = u32::from_be_bytes(app_data[2..6].try_into().unwrap());
let data_len = u32::from_be_bytes(app_data[6..10].try_into().unwrap());
if 10 + data_len as usize > app_data.len() {
log::warn!(
target: "TC Handler",
"invalid data length {} for raw mem write detected",
data_len
);
// TODO: Error reporting
return;
}
let data = &app_data[10..10 + data_len as usize];
log::info!("writing {} bytes at offset {} to NVM", data_len, offset);
// Safety: We only use this for NVM handling and we only do NVM
// handling here.
let mut sys_cfg = unsafe { pac::Sysconfig::steal() };
let nvm = Nvm::new(
&mut sys_cfg,
cx.local.rom_spi.take().unwrap(),
CLOCKS.get().as_ref().unwrap(),
);
nvm.write_data(offset, data);
*cx.local.rom_spi = Some(nvm.release(&mut sys_cfg));
let tm = cx
.local
.verif_reporter
.completion_success(cx.local.src_data_buf, started_token, 0, 0, &[])
.expect("completion success failed");
write_and_send(&tm);
log::info!("NVM operation done");
}
}
let (tm, started_token) = cx
.local
.verif_reporter
.start_success(cx.local.src_data_buf, accepted_token, 0, 0, &[])
.expect("acceptance success failed");
write_and_send(&tm);
if pus_tc.service() == PusServiceId::Action as u8 {
let mut corrupt_image = |base_addr: u32| {
// Safety: We only use this for NVM handling and we only do NVM
// handling here.
let mut sys_cfg = unsafe { pac::Sysconfig::steal() };
let nvm = Nvm::new(
&mut sys_cfg,
cx.local.rom_spi.take().unwrap(),
CLOCKS.get().as_ref().unwrap(),
);
let mut buf = [0u8; 4];
nvm.read_data(base_addr + 32, &mut buf);
buf[0] += 1;
nvm.write_data(base_addr + 32, &buf);
*cx.local.rom_spi = Some(nvm.release(&mut sys_cfg));
let tm = cx
.local
.verif_reporter
.completion_success(cx.local.src_data_buf, started_token, 0, 0, &[])
.expect("completion success failed");
write_and_send(&tm);
};
if pus_tc.subservice() == ActionId::CorruptImageA as u8 {
rprintln!("corrupting App Image A");
corrupt_image(APP_A_START_ADDR);
}
if pus_tc.subservice() == ActionId::CorruptImageB as u8 {
rprintln!("corrupting App Image B");
corrupt_image(APP_B_START_ADDR);
}
}
if pus_tc.service() == PusServiceId::Test as u8 && pus_tc.subservice() == 1 {
log::info!(target: "TC Handler", "received ping TC");
let tm = cx
.local
.verif_reporter
.completion_success(cx.local.src_data_buf, started_token, 0, 0, &[])
.expect("completion success failed");
write_and_send(&tm);
} else if pus_tc.service() == PusServiceId::MemoryManagement as u8 {
let tm = cx
.local
.verif_reporter
.step_success(
cx.local.src_data_buf,
&started_token,
0,
0,
&[],
EcssEnumU8::new(0),
)
.expect("step success failed");
write_and_send(&tm);
// Raw memory write TC
if pus_tc.subservice() == 2 {
let app_data = pus_tc.app_data();
if app_data.len() < 10 {
log::warn!(
target: "TC Handler",
"app data for raw memory write is too short: {}",
app_data.len()
);
}
Err(e) => {
log::warn!("PUS TC error: {}", e);
let memory_id = app_data[0];
if memory_id != BOOT_NVM_MEMORY_ID {
log::warn!(target: "TC Handler", "memory ID {} not supported", memory_id);
// TODO: Error reporting
return;
}
let offset = u32::from_be_bytes(app_data[2..6].try_into().unwrap());
let data_len = u32::from_be_bytes(app_data[6..10].try_into().unwrap());
if 10 + data_len as usize > app_data.len() {
log::warn!(
target: "TC Handler",
"invalid data length {} for raw mem write detected",
data_len
);
// TODO: Error reporting
return;
}
let data = &app_data[10..10 + data_len as usize];
log::info!("writing {} bytes at offset {} to NVM", data_len, offset);
// Safety: We only use this for NVM handling and we only do NVM
// handling here.
let mut sys_cfg = unsafe { pac::Sysconfig::steal() };
let nvm = Nvm::new(
&mut sys_cfg,
cx.local.rom_spi.take().unwrap(),
CLOCKS.get().as_ref().unwrap(),
);
nvm.write_data(offset, data);
*cx.local.rom_spi = Some(nvm.release(&mut sys_cfg));
let tm = cx
.local
.verif_reporter
.completion_success(cx.local.src_data_buf, started_token, 0, 0, &[])
.expect("completion success failed");
write_and_send(&tm);
log::info!("NVM operation done");
}
}
}
@ -497,16 +464,16 @@ mod app {
read_buf: [u8;MAX_TM_SIZE] = [0; MAX_TM_SIZE],
encoded_buf: [u8;MAX_TM_FRAME_SIZE] = [0; MAX_TM_FRAME_SIZE],
uart_tx,
tx_cons,
tm_cons
],
shared=[]
)]
async fn pus_tm_tx_handler(cx: pus_tm_tx_handler::Context) {
loop {
while cx.local.tx_cons.sizes_cons.occupied_len() > 0 {
let next_size = cx.local.tx_cons.sizes_cons.try_pop().unwrap();
while cx.local.tm_cons.sizes_cons.occupied_len() > 0 {
let next_size = cx.local.tm_cons.sizes_cons.try_pop().unwrap();
cx.local
.tx_cons
.tm_cons
.buf_cons
.pop_slice(&mut cx.local.read_buf[0..next_size]);
cx.local.encoded_buf[0] = 0;