Merge branch 'main' into update-flashloader-testapps
This commit is contained in:
@@ -4,32 +4,31 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
cortex-m = "0.7"
|
||||
cortex-m = { version = "0.7", features = ["critical-section-single-core"]}
|
||||
cortex-m-rt = "0.7"
|
||||
embedded-hal = "1"
|
||||
embedded-hal-nb = "1"
|
||||
embedded-io = "0.6"
|
||||
panic-rtt-target = "0.2"
|
||||
rtt-target = "0.6"
|
||||
defmt = "1"
|
||||
defmt-rtt = { version = "0.4" }
|
||||
panic-probe = { version = "0.3", features = ["print-defmt"] }
|
||||
num_enum = { version = "0.7", default-features = false }
|
||||
log = "0.4"
|
||||
crc = "3"
|
||||
cobs = { version = "0.3", default-features = false }
|
||||
satrs = { version = "0.2", default-features = false }
|
||||
rtt-log = "0.5"
|
||||
ringbuf = { version = "0.4.7", default-features = false, features = ["portable-atomic"] }
|
||||
once_cell = { version = "1", default-features = false, features = ["critical-section"] }
|
||||
spacepackets = { version = "0.11", default-features = false }
|
||||
spacepackets = { version = "0.11", default-features = false, features = ["defmt"] }
|
||||
# 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"] }
|
||||
rtic-sync = {version = "1", features = ["defmt-03"]}
|
||||
|
||||
[dependencies.va108xx-hal]
|
||||
version = "0.11"
|
||||
path = "../va108xx-hal"
|
||||
features = ["defmt"]
|
||||
|
||||
[dependencies.vorago-reb1]
|
||||
version = "0.8"
|
||||
|
||||
[package.metadata.cargo-machete]
|
||||
ignored = ["portable-atomic", "cortex-m-rt"]
|
||||
|
||||
@@ -2,16 +2,15 @@
|
||||
from typing import List, Tuple
|
||||
from spacepackets.ecss.defs import PusService
|
||||
from spacepackets.ecss.tm import PusTm
|
||||
from tmtccmd.com import ComInterface
|
||||
import toml
|
||||
import struct
|
||||
import logging
|
||||
import argparse
|
||||
import time
|
||||
import enum
|
||||
from tmtccmd.com.serial_base import SerialCfg
|
||||
from tmtccmd.com.serial_cobs import SerialCobsComIF
|
||||
from tmtccmd.com.ser_utils import prompt_com_port
|
||||
from com_interface import ComInterface
|
||||
from com_interface.serial_base import SerialCfg
|
||||
from com_interface.serial_cobs import SerialCobsComIF
|
||||
from crcmod.predefined import PredefinedCrc
|
||||
from spacepackets.ecss.tc import PusTc
|
||||
from spacepackets.ecss.pus_verificator import PusVerificator, StatusField
|
||||
@@ -101,15 +100,7 @@ class ImageLoader:
|
||||
)
|
||||
self.verificator.add_tc(action_tc)
|
||||
self.com_if.send(bytes(action_tc.pack()))
|
||||
data_available = self.com_if.data_available(0.4)
|
||||
if not data_available:
|
||||
_LOGGER.warning("no reply received for boot image selection command")
|
||||
for reply in self.com_if.receive():
|
||||
result = self.verificator.add_tm(
|
||||
Service1Tm.from_tm(PusTm.unpack(reply, 0), UnpackParams(0))
|
||||
)
|
||||
if result is not None and result.completed:
|
||||
_LOGGER.info("received boot image selection command confirmation")
|
||||
self.await_for_command_copletion("boot image selection command")
|
||||
|
||||
def handle_ping_cmd(self):
|
||||
_LOGGER.info("Sending ping command")
|
||||
@@ -122,16 +113,26 @@ class ImageLoader:
|
||||
)
|
||||
self.verificator.add_tc(ping_tc)
|
||||
self.com_if.send(bytes(ping_tc.pack()))
|
||||
self.await_for_command_copletion("ping command")
|
||||
|
||||
data_available = self.com_if.data_available(0.4)
|
||||
if not data_available:
|
||||
_LOGGER.warning("no ping reply received")
|
||||
for reply in self.com_if.receive():
|
||||
result = self.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")
|
||||
def await_for_command_copletion(self, context: str):
|
||||
done = False
|
||||
now = time.time()
|
||||
while time.time() - now < 2.0:
|
||||
if not self.com_if.data_available():
|
||||
time.sleep(0.2)
|
||||
continue
|
||||
for reply in self.com_if.receive():
|
||||
result = self.verificator.add_tm(
|
||||
Service1Tm.from_tm(PusTm.unpack(reply, 0), UnpackParams(0))
|
||||
)
|
||||
if result is not None and result.completed:
|
||||
_LOGGER.info(f"received {context} reply")
|
||||
done = True
|
||||
if done:
|
||||
break
|
||||
if not done:
|
||||
_LOGGER.warning(f"no {context} reply received")
|
||||
|
||||
def handle_corruption_cmd(self, target: Target):
|
||||
if target == Target.BOOTLOADER:
|
||||
@@ -300,12 +301,12 @@ def main() -> int:
|
||||
if "serial_port" in parsed_toml:
|
||||
serial_port = parsed_toml["serial_port"]
|
||||
if serial_port is None:
|
||||
serial_port = prompt_com_port()
|
||||
serial_port = input("Please specify the serial port manually: ")
|
||||
serial_cfg = SerialCfg(
|
||||
com_if_id="ser_cobs",
|
||||
serial_port=serial_port,
|
||||
baud_rate=BAUD_RATE,
|
||||
serial_timeout=0.1,
|
||||
polling_frequency=0.1,
|
||||
)
|
||||
verificator = PusVerificator()
|
||||
com_if = SerialCobsComIF(serial_cfg)
|
||||
|
||||
@@ -1 +1 @@
|
||||
serial_port = "/dev/ttyUSB0"
|
||||
serial_port = "/dev/ttyUSB1"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
spacepackets == 0.24
|
||||
tmtccmd == 8.0.2
|
||||
spacepackets == 0.28
|
||||
com-interface == 0.1
|
||||
toml == 0.10
|
||||
pyelftools == 0.31
|
||||
crcmod == 1.7
|
||||
|
||||
@@ -9,7 +9,6 @@ edition = "2021"
|
||||
cortex-m-rt = "0.7"
|
||||
panic-rtt-target = { version = "0.1.3" }
|
||||
rtt-target = { version = "0.5" }
|
||||
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
|
||||
embedded-hal = "1"
|
||||
va108xx-hal = { version = "0.11" }
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ edition = "2021"
|
||||
cortex-m-rt = "0.7"
|
||||
panic-rtt-target = { version = "0.1.3" }
|
||||
rtt-target = { version = "0.5" }
|
||||
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
|
||||
embedded-hal = "1"
|
||||
va108xx-hal = { version = "0.11" }
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#![no_std]
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn simple() {
|
||||
assert_eq!(1 + 1, 2);
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,9 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use defmt_rtt as _; // global logger
|
||||
use num_enum::TryFromPrimitive;
|
||||
use panic_rtt_target as _;
|
||||
use panic_probe as _;
|
||||
use ringbuf::{
|
||||
traits::{Consumer, Observer, Producer},
|
||||
StaticRb,
|
||||
@@ -29,7 +30,7 @@ pub enum ActionId {
|
||||
SetBootSlot = 130,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, defmt::Format)]
|
||||
#[repr(u8)]
|
||||
enum AppSel {
|
||||
A = 0,
|
||||
@@ -60,16 +61,14 @@ mod app {
|
||||
use super::*;
|
||||
use cortex_m::asm;
|
||||
use embedded_io::Write;
|
||||
use panic_rtt_target as _;
|
||||
use rtic::Mutex;
|
||||
use rtic_monotonics::systick::prelude::*;
|
||||
use rtt_target::rprintln;
|
||||
use satrs::pus::verification::{FailParams, VerificationReportCreator};
|
||||
use spacepackets::ecss::PusServiceId;
|
||||
use spacepackets::ecss::{
|
||||
tc::PusTcReader, tm::PusTmCreator, EcssEnumU8, PusPacket, WritablePusPacket,
|
||||
};
|
||||
use va108xx_hal::gpio::PinsA;
|
||||
use va108xx_hal::pins::PinsA;
|
||||
use va108xx_hal::uart::IrqContextTimeoutOrMaxSize;
|
||||
use va108xx_hal::{pac, uart, InterruptConfig};
|
||||
use vorago_reb1::m95m01::M95M01;
|
||||
@@ -84,8 +83,8 @@ mod app {
|
||||
|
||||
#[local]
|
||||
struct Local {
|
||||
uart_rx: uart::RxWithInterrupt<pac::Uarta>,
|
||||
uart_tx: uart::Tx<pac::Uarta>,
|
||||
uart_rx: uart::RxWithInterrupt,
|
||||
uart_tx: uart::Tx,
|
||||
rx_context: IrqContextTimeoutOrMaxSize,
|
||||
verif_reporter: VerificationReportCreator,
|
||||
nvm: M95M01,
|
||||
@@ -102,26 +101,26 @@ mod app {
|
||||
|
||||
#[init]
|
||||
fn init(cx: init::Context) -> (Shared, Local) {
|
||||
rtt_log::init();
|
||||
rprintln!("-- Vorago flashloader --");
|
||||
defmt::println!("-- Vorago flashloader --");
|
||||
|
||||
Mono::start(cx.core.SYST, SYSCLK_FREQ.raw());
|
||||
|
||||
let mut dp = cx.device;
|
||||
let nvm = M95M01::new(&mut dp.sysconfig, SYSCLK_FREQ, dp.spic);
|
||||
|
||||
let gpioa = PinsA::new(&mut dp.sysconfig, dp.porta);
|
||||
let tx = gpioa.pa9.into_funsel_2();
|
||||
let rx = gpioa.pa8.into_funsel_2();
|
||||
let gpioa = PinsA::new(dp.porta);
|
||||
let tx = gpioa.pa9;
|
||||
let rx = gpioa.pa8;
|
||||
|
||||
let irq_uart = uart::Uart::new_with_interrupt(
|
||||
&mut dp.sysconfig,
|
||||
SYSCLK_FREQ,
|
||||
dp.uarta,
|
||||
(tx, rx),
|
||||
UART_BAUDRATE.Hz(),
|
||||
tx,
|
||||
rx,
|
||||
SYSCLK_FREQ,
|
||||
UART_BAUDRATE.Hz().into(),
|
||||
InterruptConfig::new(pac::Interrupt::OC0, true, true),
|
||||
);
|
||||
)
|
||||
.unwrap();
|
||||
let (tx, rx) = irq_uart.split();
|
||||
// Unwrap is okay, we explicitely set the interrupt ID.
|
||||
let mut rx = rx.into_rx_with_irq();
|
||||
@@ -181,8 +180,8 @@ mod app {
|
||||
{
|
||||
Ok(result) => {
|
||||
if RX_DEBUGGING {
|
||||
log::debug!("RX Info: {:?}", cx.local.rx_context);
|
||||
log::debug!("RX Result: {:?}", result);
|
||||
defmt::debug!("RX Info: {:?}", cx.local.rx_context);
|
||||
defmt::debug!("RX Result: {:?}", result);
|
||||
}
|
||||
if result.complete() {
|
||||
// Check frame validity (must have COBS format) and decode the frame.
|
||||
@@ -193,7 +192,7 @@ mod app {
|
||||
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");
|
||||
defmt::warn!("COBS decoding failed");
|
||||
} else {
|
||||
let decoded_size = decoded_size.unwrap();
|
||||
let mut tc_rb_full = false;
|
||||
@@ -207,11 +206,13 @@ mod app {
|
||||
}
|
||||
});
|
||||
if tc_rb_full {
|
||||
log::warn!("COBS TC queue full");
|
||||
defmt::warn!("COBS TC queue full");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::warn!("COBS frame with invalid format, start and end bytes are not 0");
|
||||
defmt::warn!(
|
||||
"COBS frame with invalid format, start and end bytes are not 0"
|
||||
);
|
||||
}
|
||||
|
||||
// Initiate next transfer.
|
||||
@@ -221,11 +222,11 @@ mod app {
|
||||
.expect("read operation failed");
|
||||
}
|
||||
if result.has_errors() {
|
||||
log::warn!("UART error: {:?}", result.errors.unwrap());
|
||||
defmt::warn!("UART error: {:?}", result.errors.unwrap());
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("UART error: {:?}", e);
|
||||
defmt::warn!("UART error: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -252,7 +253,7 @@ mod app {
|
||||
continue;
|
||||
}
|
||||
let packet_len = packet_len.unwrap();
|
||||
log::info!(target: "TC Handler", "received packet with length {}", packet_len);
|
||||
defmt::info!("received packet with length {}", packet_len);
|
||||
let popped_packet_len = cx
|
||||
.shared
|
||||
.tc_rb
|
||||
@@ -266,7 +267,7 @@ mod app {
|
||||
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!(target: "TC Handler", "PUS TC error: {}", pus_tc.unwrap_err());
|
||||
defmt::warn!("PUS TC error: {}", pus_tc.unwrap_err());
|
||||
return;
|
||||
}
|
||||
let (pus_tc, _) = pus_tc.unwrap();
|
||||
@@ -312,22 +313,25 @@ mod app {
|
||||
write_and_send(&tm);
|
||||
};
|
||||
if pus_tc.subservice() == ActionId::CorruptImageA as u8 {
|
||||
rprintln!("corrupting App Image A");
|
||||
defmt::info!("corrupting App Image A");
|
||||
corrupt_image(APP_A_START_ADDR);
|
||||
}
|
||||
if pus_tc.subservice() == ActionId::CorruptImageB as u8 {
|
||||
rprintln!("corrupting App Image B");
|
||||
defmt::info!("corrupting App Image B");
|
||||
corrupt_image(APP_B_START_ADDR);
|
||||
}
|
||||
if pus_tc.subservice() == ActionId::SetBootSlot as u8 {
|
||||
if pus_tc.app_data().is_empty() {
|
||||
log::warn!(target: "TC Handler", "App data for preferred image command too short");
|
||||
defmt::warn!("App data for preferred image command too short");
|
||||
}
|
||||
let app_sel_result = AppSel::try_from(pus_tc.app_data()[0]);
|
||||
if app_sel_result.is_err() {
|
||||
log::warn!("Invalid app selection value: {}", pus_tc.app_data()[0]);
|
||||
defmt::warn!("Invalid app selection value: {}", pus_tc.app_data()[0]);
|
||||
}
|
||||
log::info!(target: "TC Handler", "received boot selection command with app select: {:?}", app_sel_result.unwrap());
|
||||
defmt::info!(
|
||||
"received boot selection command with app select: {:?}",
|
||||
app_sel_result.unwrap()
|
||||
);
|
||||
cx.local
|
||||
.nvm
|
||||
.write(PREFERRED_SLOT_OFFSET as usize, &[pus_tc.app_data()[0]])
|
||||
@@ -341,7 +345,7 @@ mod app {
|
||||
}
|
||||
}
|
||||
if pus_tc.service() == PusServiceId::Test as u8 && pus_tc.subservice() == 1 {
|
||||
log::info!(target: "TC Handler", "received ping TC");
|
||||
defmt::info!("received ping TC");
|
||||
let tm = cx
|
||||
.local
|
||||
.verif_reporter
|
||||
@@ -366,23 +370,21 @@ mod app {
|
||||
if pus_tc.subservice() == 2 {
|
||||
let app_data = pus_tc.app_data();
|
||||
if app_data.len() < 10 {
|
||||
log::warn!(
|
||||
target: "TC Handler",
|
||||
defmt::warn!(
|
||||
"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);
|
||||
defmt::warn!("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",
|
||||
defmt::warn!(
|
||||
"invalid data length {} for raw mem write detected",
|
||||
data_len
|
||||
);
|
||||
@@ -390,12 +392,7 @@ mod app {
|
||||
return;
|
||||
}
|
||||
let data = &app_data[10..10 + data_len as usize];
|
||||
log::info!(
|
||||
target: "TC Handler",
|
||||
"writing {} bytes at offset {} to NVM",
|
||||
data_len,
|
||||
offset
|
||||
);
|
||||
defmt::info!("writing {} bytes at offset {} to NVM", data_len, offset);
|
||||
cx.local
|
||||
.nvm
|
||||
.write(offset as usize, data)
|
||||
@@ -406,7 +403,7 @@ mod app {
|
||||
.verify(offset as usize, data)
|
||||
.expect("NVM verification failed")
|
||||
{
|
||||
log::warn!("verification of data written to NVM failed");
|
||||
defmt::warn!("verification of data written to NVM failed");
|
||||
cx.local
|
||||
.verif_reporter
|
||||
.completion_failure(
|
||||
@@ -424,9 +421,7 @@ mod app {
|
||||
.expect("completion success failed")
|
||||
};
|
||||
write_and_send(&tm);
|
||||
log::info!(
|
||||
target: "TC Handler",
|
||||
"NVM operation done");
|
||||
defmt::info!("NVM operation done");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -457,7 +452,7 @@ mod app {
|
||||
cx.local.encoded_buf[send_size + 1] = 0;
|
||||
cx.local
|
||||
.uart_tx
|
||||
.write(&cx.local.encoded_buf[0..send_size + 2])
|
||||
.write_all(&cx.local.encoded_buf[0..send_size + 2])
|
||||
.unwrap();
|
||||
occupied_len -= 1;
|
||||
Mono::delay(2.millis()).await;
|
||||
|
||||
Reference in New Issue
Block a user