defmt works properly now

This commit is contained in:
Robin Müller 2025-04-12 16:45:43 +02:00
parent 86ac7428bb
commit 0515ca5eaa
Signed by: muellerr
GPG Key ID: A649FB78196E3849
23 changed files with 121 additions and 281 deletions

View File

@ -18,9 +18,9 @@ rustflags = [
"-C", "link-arg=-Tlink.x",
# knurling-rs tooling. If you want to use flip-link, ensure it is installed first.
# "-C", "linker=flip-link",
"-C", "linker=flip-link",
# Unfortunately, defmt is clunky to use without probe-rs..
# "-C", "link-arg=-Tdefmt.x",
"-C", "link-arg=-Tdefmt.x",
# Can be useful for debugging.
# "-Clink-args=-Map=app.map"

View File

@ -13,7 +13,6 @@ members = [
"flashloader",
]
exclude = [
"defmt-testapp",
"flashloader/slot-a-blinky",
"flashloader/slot-b-blinky",
]

View File

@ -77,7 +77,7 @@ to flash and run the blinky program on the RAM. There is also a `VA108xx` chip t
available for persistent flashing.
Runner configuration avilable in the `.cargo/def-config.toml` file to use `probe-rs` for
convenience.
convenience. `probe-rs` is also able to process and display `defmt` strings directly.
### Using VS Code
@ -123,13 +123,13 @@ is also run when running the `jlink-gdb.sh` script)
```sh
JLinkGDBServer -select USB -device Cortex-M0 -endian little -if JTAG-speed auto \
-LocalhostOnly
-LocalhostOnly -jtagconf -1,-1
```
After this, you can flash and debug the application with the following command
```sh
gdb-mutliarch -q -x jlink/jlink.gdb target/thumbv6m-none-eabihf/debug/examples/blinky
gdb-mutliarch -q -x jlink/jlink.gdb target/thumbv6m-none-eabihf/debug/examples/blinky -tui
```
Please note that you can automate all steps except starting the GDB server by using a cargo
@ -149,6 +149,16 @@ The Segger RTT viewer can be used to display log messages received from the targ
address for the RTT block placement is 0x10000000. It is recommended to use a search range of
0x1000 around that base address when using the RTT viewer.
The RTT viewer will not be able to process `defmt` printouts. However, you can view the defmt
logs by [installing defmt-print](https://crates.io/crates/defmt-print) first and then piping
the output on telnet port 19021 into `defmt-print`, for example by running
```sh
telnet localhost 19021 | defmt-print -e <pathToElfFile>
```
The path of the ELF file which is being debugged needs to be specified for this to work.
## Learning (Embedded) Rust
If you are unfamiliar with Rust on Embedded Systems or Rust in general, the following resources

View File

@ -1,48 +0,0 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# uncomment ONE of these three option to make `cargo run` start a GDB session
# which option to pick depends on your system
# runner = "arm-none-eabi-gdb -q -x openocd.gdb"
# runner = "gdb-multiarch -q -x openocd.gdb"
# runner = "gdb -q -x openocd.gdb"
runner = "gdb-multiarch -q -x jlink.gdb"
# Probe-rs is currently problematic: https://github.com/probe-rs/probe-rs/issues/2567
# runner = "probe-rs run --chip VA108xx --chip-description-path ./scripts/VA108xx_Series.yaml"
# runner = ["probe-rs", "run", "--chip", "$CHIP", "--log-format", "{L} {s}"]
rustflags = [
# This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
"-C", "link-arg=--nmagic",
# LLD (shipped with the Rust toolchain) is used as the default linker
"-C", "link-arg=-Tlink.x",
# knurling-rs tooling. If you want to use flip-link, ensure it is installed first.
"-C", "linker=flip-link",
# Unfortunately, defmt is clunky to use without probe-rs..
"-C", "link-arg=-Tdefmt.x",
# Can be useful for debugging.
"-Clink-args=-Map=app.map"
]
[build]
# Pick ONE of these compilation targets
target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
# target = "thumbv7m-none-eabi" # Cortex-M3
# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU)
# target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
# target = "thumbv8m.base-none-eabi" # Cortex-M23
# target = "thumbv8m.main-none-eabi" # Cortex-M33 (no FPU)
# target = "thumbv8m.main-none-eabihf" # Cortex-M33 (with FPU)
[alias]
re = "run --example"
rb = "run --bin"
rrb = "run --release --bin"
ut = "test --target x86_64-unknown-linux-gnu"
[env]
DEFMT_LOG = "info"

View File

@ -1 +0,0 @@
/target

View File

@ -1,34 +0,0 @@
[package]
name = "defmt-testapp"
version = "0.1.0"
edition = "2021"
[dependencies]
cortex-m = {version = "0.7", features = ["critical-section-single-core"]}
panic-rtt-target = "0.1"
cortex-m-rt = "0.7"
rtt-target = "0.5"
rtic-sync = { version = "1.3", features = ["defmt-03"] }
embedded-hal = "1"
embedded-hal-nb = "1"
embedded-io = "0.6"
cortex-m-semihosting = "0.5.0"
# Tricky without probe-rs.
defmt = "0.3"
defmt-brtt = { version = "0.1", default-features = false, features = ["rtt"] }
panic-probe = { version = "0.3", features = ["print-defmt"] }
[dependencies.rtic]
version = "2"
features = ["thumbv6-backend"]
[dependencies.rtic-monotonics]
version = "1"
features = ["cortex-m-systick"]
[dependencies.va108xx-hal]
version = "0.10"
features = ["rt", "defmt"]
[dependencies.va108xx]
version = "0.5"

View File

@ -1,9 +0,0 @@
defmt Testapp
======
`defmt` is clunky to use without probe-rs and requires special configuration inside the
`.cargo/config.toml` file.
`probe-rs` is currently problematic for usage with the VA108xx , so it is not the default tool
recommended and used for the whole workspace. This project contains an isolated, `defmt` compatible
configuration for testing with `defmt` (and `probe-rs`).

View File

@ -1,53 +0,0 @@
#![no_main]
#![no_std]
use cortex_m_semihosting::debug;
use defmt_brtt as _; // global logger
use va108xx_hal as _; // memory layout
use panic_probe as _;
// same panicking *behavior* as `panic-probe` but doesn't print a panic message
// this prevents the panic message being printed *twice* when `defmt::panic` is invoked
// #[defmt::panic_handler]
/*
fn panic() -> ! {
cortex_m::asm::udf()
}
*/
/// Terminates the application and makes a semihosting-capable debug tool exit
/// with status code 0.
pub fn exit() -> ! {
loop {
debug::exit(debug::EXIT_SUCCESS);
}
}
/// Hardfault handler.
///
/// Terminates the application and makes a semihosting-capable debug tool exit
/// with an error. This seems better than the default, which is to spin in a
/// loop.
#[cortex_m_rt::exception]
unsafe fn HardFault(_frame: &cortex_m_rt::ExceptionFrame) -> ! {
loop {
debug::exit(debug::EXIT_FAILURE);
}
}
// defmt-test 0.3.0 has the limitation that this `#[tests]` attribute can only be used
// once within a crate. the module can be in any file but there can only be at most
// one `#[tests]` module in this library crate
#[cfg(test)]
#[defmt_test::tests]
mod unit_tests {
use defmt::assert;
#[test]
fn it_works() {
assert!(true)
}
}

View File

@ -1,29 +0,0 @@
//! Empty RTIC project template
#![no_main]
#![no_std]
use defmt_testapp as _;
#[rtic::app(device = pac)]
mod app {
use va108xx_hal::pac;
#[local]
struct Local {}
#[shared]
struct Shared {}
#[init]
fn init(_ctx: init::Context) -> (Shared, Local) {
defmt::println!("-- Vorago RTIC template --");
(Shared {}, Local {})
}
// `shared` cannot be accessed from this context
#[idle]
fn idle(_cx: idle::Context) -> ! {
#[allow(clippy::empty_loop)]
loop {}
}
}

View File

@ -14,8 +14,10 @@ embedded-io-async = "0.6"
heapless = "0.8"
static_cell = "2"
rtt-target = "0.6"
panic-rtt-target = "0.2"
defmt = "1"
defmt-rtt = "0.4"
panic-probe = { version = "0.3", features = ["print-defmt"] }
critical-section = "1"
portable-atomic = { version = "1", features = ["unsafe-assume-single-core"]}
@ -27,7 +29,7 @@ embassy-executor = { version = "0.7", features = [
"executor-interrupt"
]}
va108xx-hal = { version = "0.11" }
va108xx-hal = { version = "0.11", features = ["defmt"] }
va108xx-embassy = { version = "0.2" }
[features]

View File

@ -4,14 +4,14 @@
//! and then set the `CHECK_PB22_TO_PB23` to true to also test async operations on Port B.
#![no_std]
#![no_main]
// This imports the logger and the panic handler.
use embassy_example as _;
use embassy_executor::Spawner;
use embassy_sync::channel::{Receiver, Sender};
use embassy_sync::{blocking_mutex::raw::ThreadModeRawMutex, channel::Channel};
use embassy_time::{Duration, Instant, Timer};
use embedded_hal_async::digital::Wait;
use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::gpio::{
on_interrupt_for_async_gpio_for_port, InputDynPinAsync, InputPinAsync, PinsB, Port,
};
@ -58,8 +58,7 @@ static CHANNEL_PB22_TO_PB23: Channel<ThreadModeRawMutex, GpioCmd, 3> = Channel::
#[embassy_executor::main]
async fn main(spawner: Spawner) {
rtt_init_print!();
rprintln!("-- VA108xx Async GPIO Demo --");
defmt::println!("-- VA108xx Async GPIO Demo --");
let mut dp = pac::Peripherals::take().unwrap();
@ -102,15 +101,15 @@ async fn main(spawner: Spawner) {
if CHECK_PA0_TO_PA1 {
check_pin_to_pin_async_ops("PA0 to PA1", CHANNEL_PA0_PA1.sender(), in_pa1_async).await;
rprintln!("Example PA0 to PA1 done");
defmt::info!("Example PA0 to PA1 done");
}
if CHECK_PB22_TO_PB23 {
check_pin_to_pin_async_ops("PB22 to PB23", CHANNEL_PB22_TO_PB23.sender(), in_pb23_async)
.await;
rprintln!("Example PB22 to PB23 done");
defmt::info!("Example PB22 to PB23 done");
}
rprintln!("Example done, toggling LED0");
defmt::info!("Example done, toggling LED0");
loop {
led0.toggle();
Timer::after(Duration::from_millis(500)).await;
@ -122,46 +121,46 @@ async fn check_pin_to_pin_async_ops(
sender: Sender<'static, ThreadModeRawMutex, GpioCmd, 3>,
mut async_input: impl Wait,
) {
rprintln!(
defmt::info!(
"{}: sending SetHigh command ({} ms)",
ctx,
Instant::now().as_millis()
);
sender.send(GpioCmd::new(GpioCmdType::SetHigh, 20)).await;
async_input.wait_for_high().await.unwrap();
rprintln!(
defmt::info!(
"{}: Input pin is high now ({} ms)",
ctx,
Instant::now().as_millis()
);
rprintln!(
defmt::info!(
"{}: sending SetLow command ({} ms)",
ctx,
Instant::now().as_millis()
);
sender.send(GpioCmd::new(GpioCmdType::SetLow, 20)).await;
async_input.wait_for_low().await.unwrap();
rprintln!(
defmt::info!(
"{}: Input pin is low now ({} ms)",
ctx,
Instant::now().as_millis()
);
rprintln!(
defmt::info!(
"{}: sending RisingEdge command ({} ms)",
ctx,
Instant::now().as_millis()
);
sender.send(GpioCmd::new(GpioCmdType::RisingEdge, 20)).await;
async_input.wait_for_rising_edge().await.unwrap();
rprintln!(
defmt::info!(
"{}: input pin had rising edge ({} ms)",
ctx,
Instant::now().as_millis()
);
rprintln!(
defmt::info!(
"{}: sending Falling command ({} ms)",
ctx,
Instant::now().as_millis()
@ -170,13 +169,13 @@ async fn check_pin_to_pin_async_ops(
.send(GpioCmd::new(GpioCmdType::FallingEdge, 20))
.await;
async_input.wait_for_falling_edge().await.unwrap();
rprintln!(
defmt::info!(
"{}: input pin had a falling edge ({} ms)",
ctx,
Instant::now().as_millis()
);
rprintln!(
defmt::info!(
"{}: sending Falling command ({} ms)",
ctx,
Instant::now().as_millis()
@ -185,20 +184,20 @@ async fn check_pin_to_pin_async_ops(
.send(GpioCmd::new(GpioCmdType::FallingEdge, 20))
.await;
async_input.wait_for_any_edge().await.unwrap();
rprintln!(
defmt::info!(
"{}: input pin had a falling (any) edge ({} ms)",
ctx,
Instant::now().as_millis()
);
rprintln!(
defmt::info!(
"{}: sending Falling command ({} ms)",
ctx,
Instant::now().as_millis()
);
sender.send(GpioCmd::new(GpioCmdType::RisingEdge, 20)).await;
async_input.wait_for_any_edge().await.unwrap();
rprintln!(
defmt::info!(
"{}: input pin had a rising (any) edge ({} ms)",
ctx,
Instant::now().as_millis()
@ -216,22 +215,22 @@ async fn output_task(
Timer::after(Duration::from_millis(next_cmd.after_delay.into())).await;
match next_cmd.cmd_type {
GpioCmdType::SetHigh => {
rprintln!("{}: Set output high", ctx);
defmt::info!("{}: Set output high", ctx);
out.set_high().unwrap();
}
GpioCmdType::SetLow => {
rprintln!("{}: Set output low", ctx);
defmt::info!("{}: Set output low", ctx);
out.set_low().unwrap();
}
GpioCmdType::RisingEdge => {
rprintln!("{}: Rising edge", ctx);
defmt::info!("{}: Rising edge", ctx);
if !out.is_low().unwrap() {
out.set_low().unwrap();
}
out.set_high().unwrap();
}
GpioCmdType::FallingEdge => {
rprintln!("{}: Falling edge", ctx);
defmt::info!("{}: Falling edge", ctx);
if !out.is_high().unwrap() {
out.set_high().unwrap();
}

View File

@ -13,16 +13,16 @@
//! RTT logs to see received data.
#![no_std]
#![no_main]
use core::cell::RefCell;
// This imports the logger and the panic handler.
use embassy_example as _;
use core::cell::RefCell;
use critical_section::Mutex;
use embassy_executor::Spawner;
use embassy_time::Instant;
use embedded_io::Write;
use embedded_io_async::Read;
use heapless::spsc::{Consumer, Producer, Queue};
use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{
gpio::PinsA,
pac::{self, interrupt},
@ -49,8 +49,7 @@ static CONSUMER_UART_B: Mutex<RefCell<Option<Consumer<u8, 256>>>> = Mutex::new(R
// main is itself an async function.
#[embassy_executor::main]
async fn main(spawner: Spawner) {
rtt_init_print!();
rprintln!("-- VA108xx Async UART RX Demo --");
defmt::println!("-- VA108xx Async UART RX Demo --");
let mut dp = pac::Peripherals::take().unwrap();
@ -108,13 +107,13 @@ async fn main(spawner: Spawner) {
.unwrap();
let mut buf = [0u8; 256];
loop {
rprintln!("Current time UART A: {}", Instant::now().as_secs());
defmt::info!("Current time UART A: {}", Instant::now().as_secs());
led0.toggle();
led1.toggle();
led2.toggle();
let read_bytes = async_rx_uart_a.read(&mut buf).await.unwrap();
let read_str = core::str::from_utf8(&buf[..read_bytes]).unwrap();
rprintln!(
defmt::info!(
"Read {} bytes asynchronously on UART A: {:?}",
read_bytes,
read_str
@ -127,11 +126,11 @@ async fn main(spawner: Spawner) {
async fn uart_b_task(mut async_rx: RxAsyncOverwriting<pac::Uartb, 256>, mut tx: Tx<pac::Uartb>) {
let mut buf = [0u8; 256];
loop {
rprintln!("Current time UART B: {}", Instant::now().as_secs());
defmt::info!("Current time UART B: {}", Instant::now().as_secs());
// Infallible asynchronous operation.
let read_bytes = async_rx.read(&mut buf).await.unwrap();
let read_str = core::str::from_utf8(&buf[..read_bytes]).unwrap();
rprintln!(
defmt::info!(
"Read {} bytes asynchronously on UART B: {:?}",
read_bytes,
read_str
@ -149,7 +148,7 @@ fn OC2() {
critical_section::with(|cs| *PRODUCER_UART_A.borrow(cs).borrow_mut() = Some(prod));
// In a production app, we could use a channel to send the errors to the main task.
if let Err(errors) = errors {
rprintln!("UART A errors: {:?}", errors);
defmt::info!("UART A errors: {:?}", errors);
}
}
@ -162,6 +161,6 @@ fn OC3() {
critical_section::with(|cs| *PRODUCER_UART_B.borrow(cs).borrow_mut() = Some(prod));
// In a production app, we could use a channel to send the errors to the main task.
if let Err(errors) = errors {
rprintln!("UART B errors: {:?}", errors);
defmt::info!("UART B errors: {:?}", errors);
}
}

View File

@ -10,11 +10,12 @@
//! can verify the correctness of the sent strings.
#![no_std]
#![no_main]
// This imports the logger and the panic handler.
use embassy_example as _;
use embassy_executor::Spawner;
use embassy_time::{Duration, Instant, Ticker};
use embedded_io_async::Write;
use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print};
use va108xx_hal::{
gpio::PinsA,
pac::{self, interrupt},
@ -35,8 +36,7 @@ const STR_LIST: &[&str] = &[
// main is itself an async function.
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
rtt_init_print!();
rprintln!("-- VA108xx Async UART TX Demo --");
defmt::println!("-- VA108xx Async UART TX Demo --");
let mut dp = pac::Peripherals::take().unwrap();
@ -70,7 +70,7 @@ async fn main(_spawner: Spawner) {
let mut ticker = Ticker::every(Duration::from_secs(1));
let mut idx = 0;
loop {
rprintln!("Current time: {}", Instant::now().as_secs());
defmt::info!("Current time: {}", Instant::now().as_secs());
led0.toggle();
led1.toggle();
led2.toggle();

View File

@ -0,0 +1,3 @@
#![no_std]
use panic_probe as _;
use defmt_rtt as _;

View File

@ -2,8 +2,7 @@
#![no_main]
use embassy_executor::Spawner;
use embassy_time::{Duration, Instant, Ticker};
use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print};
use embassy_example as _;
cfg_if::cfg_if! {
if #[cfg(feature = "custom-irqs")] {
@ -20,8 +19,7 @@ const SYSCLK_FREQ: Hertz = Hertz::from_raw(50_000_000);
// main is itself an async function.
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
rtt_init_print!();
rprintln!("-- VA108xx Embassy Demo --");
defmt::println!("-- VA108xx Embassy Demo --");
let mut dp = pac::Peripherals::take().unwrap();
@ -55,7 +53,7 @@ async fn main(_spawner: Spawner) {
let mut ticker = Ticker::every(Duration::from_secs(1));
loop {
ticker.next().await;
rprintln!("Current time: {}", Instant::now().as_secs());
defmt::info!("Current time: {}", Instant::now().as_secs());
led0.toggle();
led1.toggle();
led2.toggle();

View File

@ -17,7 +17,7 @@ cortex-m-semihosting = "0.5.0"
[dependencies.va108xx-hal]
version = "0.11"
features = ["rt", "defmt"]
features = ["defmt"]
[dependencies.vorago-reb1]
version = "0.8"

View File

@ -3,6 +3,7 @@
#![no_std]
use cortex_m_rt::entry;
use va108xx_hal as _;
use panic_rtt_target as _;
#[entry]

View File

@ -9,17 +9,16 @@ 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"]}
@ -30,6 +29,7 @@ rtic-sync = {version = "1", features = ["defmt-03"]}
[dependencies.va108xx-hal]
version = "0.11"
features = ["defmt"]
[dependencies.vorago-reb1]
version = "0.8"

View File

@ -1,9 +0,0 @@
#![no_std]
#[cfg(test)]
mod tests {
#[test]
fn simple() {
assert_eq!(1 + 1, 2);
}
}

View File

@ -4,7 +4,8 @@
#![no_std]
use num_enum::TryFromPrimitive;
use panic_rtt_target as _;
use panic_probe as _;
use defmt_rtt as _; // global logger
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,10 +61,8 @@ 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::{
@ -102,8 +101,7 @@ 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());
@ -181,8 +179,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 +191,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 +205,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 +221,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 +252,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 +266,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 +312,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 +344,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 +369,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 +391,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 +402,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 +420,7 @@ mod app {
.expect("completion success failed")
};
write_and_send(&tm);
log::info!(
target: "TC Handler",
"NVM operation done");
defmt::info!("NVM operation done");
}
}
}

View File

@ -1,3 +1,3 @@
#!/bin/bash
JLinkGDBServer -select USB -device Cortex-M0 -endian little -if JTAG -speed auto \
-LocalhostOnly
JLinkGDBServer -select USB -device VA10820 -endian little -if JTAG -speed auto \
-LocalhostOnly -jtagconf -1,-1

18
scripts/defmt-telnet.sh Executable file
View File

@ -0,0 +1,18 @@
#!/bin/bash
# Check if binary path was provided
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <path-to-binary>"
exit 1
fi
BINARY="$1"
# Check if file exists
if [ ! -f "$BINARY" ]; then
echo "Error: File '$BINARY' not found."
exit 1
fi
# Run the command
telnet localhost 19021 | defmt-print -e "$BINARY"

View File

@ -13,7 +13,7 @@ categories = ["embedded", "no-std", "hardware-support"]
[dependencies]
cortex-m = "0.7"
vcell = "0.1.3"
defmt = { version = "0.3", optional = true }
defmt = { version = "1", optional = true }
critical-section = { version = "1", optional = true }
[dependencies.cortex-m-rt]