BL/FL progress
Some checks failed
Rust/va416xx-rs/pipeline/pr-main There was a failure building this commit

This commit is contained in:
2024-07-07 13:48:50 +02:00
parent bc0b18ab7c
commit c53702ee74
12 changed files with 527 additions and 140 deletions

1
flashloader/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/venv

View File

@ -38,5 +38,5 @@ version = "2"
features = ["thumbv7-backend"]
[dependencies.rtic-monotonics]
version = "1"
version = "2"
features = ["cortex-m-systick"]

86
flashloader/image-loader.py Executable file
View File

@ -0,0 +1,86 @@
#!/usr/bin/env python3
from spacepackets.ecss.defs import PusService
import toml
import logging
import argparse
import time
from tmtccmd.com.serial_base import SerialCfg
from tmtccmd.com.serial_cobs import SerialCobsComIF
from tmtccmd.com.ser_utils import prompt_com_port
from spacepackets.ecss.tc import PusTc
from pathlib import Path
BAUD_RATE = 115200
BOOTLOADER_START_ADDR = 0x0
BOOTLOADER_END_ADDR = 0x4000
BOOTLOADER_CRC_ADDR = 0x3FFE
APP_A_START_ADDR = 0x4000
APP_A_END_ADDR = 0x22000
# The actual size of the image which is relevant for CRC calculation.
APP_A_SIZE_ADDR = 0x21FF8
APP_A_CRC_ADDR = 0x21FFC
APP_B_START_ADDR = 0x22000
APP_B_END_ADDR = 0x40000
# The actual size of the image which is relevant for CRC calculation.
APP_B_SIZE_ADDR = 0x3FFF8
APP_B_CRC_ADDR = 0x3FFFC
APP_IMG_SZ = 0x1E000
_LOGGER = logging.getLogger(__name__)
def main():
print("Python VA416XX Image Loader Application")
logging.basicConfig(
format="[%(asctime)s] [%(levelname)s] %(message)s", level=logging.DEBUG
)
parser = argparse.ArgumentParser(
prog="image-loader", description="Python VA416XX Image Loader Application"
)
parser.add_argument("-p", "--ping", action="store_true", help="Send ping command")
parser.add_argument(
"-f",
"--flash",
choices=["bl", "a", "b"],
help="Flash target (Bootloader or slot A or B)",
)
parser.add_argument(
"path", nargs="?", default=None, help="Path to the App to flash"
)
args = parser.parse_args()
serial_port = None
if Path("loader.toml").exists():
with open("loader.toml", "r") as toml_file:
parsed_toml = toml.loads(toml_file.read())
if "serial_port" in parsed_toml:
serial_port = parsed_toml["serial_port"]
if serial_port is None:
serial_port = prompt_com_port()
serial_cfg = SerialCfg(
com_if_id="ser_cobs",
serial_port=serial_port,
baud_rate=BAUD_RATE,
serial_timeout=0.1,
)
com_if = SerialCobsComIF(serial_cfg)
com_if.open()
if args.flash and not args.path:
_LOGGER.error("App Path needs to be specified for the flash process")
ping_tc = PusTc(apid=0x00, service=PusService.S17_TEST, subservice=1)
if args.ping:
_LOGGER.info("Sending ping command")
com_if.send(ping_tc.pack())
if args.flash:
while True:
data_available = com_if.data_available(0.4)
if data_available:
reply = com_if.receive()
# TODO: Parse replies
print("Received replies: {}", reply)
break
com_if.close()
if __name__ == "__main__":
main()

1
flashloader/loader.toml Normal file
View File

@ -0,0 +1 @@
serial_port = "/dev/ttyUSB0"

View File

@ -0,0 +1,3 @@
spacepackets == 0.24
tmtccmd == 8.0.1
toml == 0.10

View File

@ -28,6 +28,8 @@ const COBS_FRAME_SEPARATOR: u8 = 0x0;
const MAX_PACKET_SIZE: usize = 1024;
const MAX_FRAME_SIZE: usize = cobs::max_encoding_length(MAX_PACKET_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;
@ -52,8 +54,8 @@ mod app {
use super::*;
use embedded_hal_nb::nb;
use panic_rtt_target as _;
use rtic_monotonics::systick::ExtU32;
use rtic_monotonics::systick::Systick;
use rtic::Mutex;
use rtic_monotonics::systick::prelude::*;
use rtic_sync::{
channel::{Receiver, Sender},
make_channel,
@ -99,13 +101,14 @@ mod app {
pub type TcTx = Sender<'static, usize, 2>;
pub type TcRx = Receiver<'static, usize, 2>;
rtic_monotonics::systick_monotonic!(Mono, 10_000);
#[init]
fn init(mut cx: init::Context) -> (Shared, Local) {
//rtt_init_default!();
rtt_log::init();
rprintln!("-- Vorago flashloader --");
// Initialize the systick interrupt & obtain the token to prove that we did
let systick_mono_token = rtic_monotonics::create_systick_token!();
// Use the external clock connected to XTAL_N.
let clocks = cx
.device
@ -130,8 +133,11 @@ mod app {
let (tx, rx) = uart0.split();
let (tc_tx, tc_rx) = make_channel!(usize, 2);
Systick::start(cx.core.SYST, clocks.sysclk().raw(), systick_mono_token);
Mono::start(cx.core.SYST, clocks.sysclk().raw());
CLOCKS.set(clocks).unwrap();
pus_tc_handler::spawn().unwrap();
uart_reader_task::spawn().unwrap();
pus_tm_tx_handler::spawn().unwrap();
(
Shared {
decode_buffer_busy: false,
@ -168,68 +174,108 @@ mod app {
async fn uart_reader_task(mut cx: uart_reader_task::Context) {
let mut current_idx = 0;
loop {
match nb::block!(cx.local.uart_rx.read()) {
Ok(byte) => match cx.local.cobs_reader_state {
CobsReaderStates::WaitingForStart => {
if byte == COBS_FRAME_SEPARATOR {
*cx.local.cobs_reader_state = CobsReaderStates::WatingForEnd;
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)
}
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 => todo!(),
uart::Error::ParityError => todo!(),
uart::Error::BreakCondition => todo!(),
uart::Error::TransferPending => todo!(),
uart::Error::BufferTooShort => todo!(),
}
}
nb::Error::WouldBlock => {
// Delay for a short period before polling again.
Mono::delay(400.micros()).await;
}
}
CobsReaderStates::WatingForEnd => {
if byte == COBS_FRAME_SEPARATOR {
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 cx.local.tc_tx.try_send(packet_len).is_err() {
sending_failed = true;
}
}
Err(_) => {
decoding_error = true;
}
}
}
}
}
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;
}
}
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
);
}
});
*busy = true;
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");
}
} 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;
}
});
if sending_failed {
log::warn!("sending TC packet failed, queue full");
}
CobsReaderStates::FrameOverflow => {
if byte == COBS_FRAME_SEPARATOR {
*cx.local.cobs_reader_state = CobsReaderStates::WaitingForStart;
current_idx = 0;
}
if decoding_error {
log::warn!("decoding error");
}
},
Err(e) => match e {
uart::Error::Overrun => todo!(),
uart::Error::FramingError => todo!(),
uart::Error::ParityError => todo!(),
uart::Error::BreakCondition => todo!(),
uart::Error::TransferPending => todo!(),
uart::Error::BufferTooShort => todo!(),
},
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;
}
}
}
}
@ -245,7 +291,8 @@ mod app {
)]
async fn pus_tc_handler(mut cx: pus_tc_handler::Context) {
loop {
let _ = cx.local.tc_rx.recv().await;
let packet_len = cx.local.tc_rx.recv().await.expect("all senders down");
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
@ -255,20 +302,21 @@ mod app {
match PusTcReader::new(cx.local.read_buf) {
Ok((pus_tc, _)) => {
if pus_tc.service() == PusServiceId::Test as u8 && pus_tc.subservice() == 1 {
log::info!("Received ping TC");
log::info!(target: "TC Handler", "received ping TC");
} else if pus_tc.service() == PusServiceId::MemoryManagement as u8 {
// 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!("memory ID {} not supported", memory_id);
log::warn!(target: "TC Handler", "memory ID {} not supported", memory_id);
// TODO: Error reporting
return;
}
@ -276,6 +324,7 @@ mod app {
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
);
@ -300,7 +349,7 @@ mod app {
}
Err(e) => {
log::warn!("PUS TC error: {}", e);
},
}
}
}
}
@ -314,7 +363,7 @@ mod app {
)]
async fn pus_tm_tx_handler(_cx: pus_tm_tx_handler::Context) {
loop {
Systick::delay(500.millis()).await;
Mono::delay(500.millis()).await;
}
}