STM32 defmt + RTT support #144

Merged
muellerr merged 2 commits from stm32-defmt-support into main 2024-03-29 12:34:02 +01:00
14 changed files with 38913 additions and 238 deletions

View File

@ -5,11 +5,17 @@
# runner = "arm-none-eabi-gdb -q -x openocd.gdb" # runner = "arm-none-eabi-gdb -q -x openocd.gdb"
# runner = "gdb-multiarch -q -x openocd.gdb" # runner = "gdb-multiarch -q -x openocd.gdb"
# runner = "gdb -q -x openocd.gdb" # runner = "gdb -q -x openocd.gdb"
# runner = "probe-run --chip STM32F303VCTx --connect-under-reset" runner = "probe-rs run --chip STM32F303VCTx"
rustflags = [ rustflags = [
"-C", "linker=flip-link",
# LLD (shipped with the Rust toolchain) is used as the default linker # LLD (shipped with the Rust toolchain) is used as the default linker
"-C", "link-arg=-Tlink.x", "-C", "link-arg=-Tlink.x",
"-C", "link-arg=-Tdefmt.x",
# 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",
# if you run into problems with LLD switch to the GNU linker by commenting out # if you run into problems with LLD switch to the GNU linker by commenting out
# this line # this line
@ -26,3 +32,6 @@ rustflags = [
[build] [build]
# comment out the following line if you intend to run unit tests on host machine # comment out the following line if you intend to run unit tests on host machine
target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
[env]
DEFMT_LOG = "info"

View File

@ -139,6 +139,15 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "cortex-m-semihosting"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c23234600452033cc77e4b761e740e02d2c4168e11dbf36ab14a0f58973592b0"
dependencies = [
"cortex-m",
]
[[package]] [[package]]
name = "crc" name = "crc"
version = "3.0.1" version = "3.0.1"
@ -194,6 +203,71 @@ dependencies = [
"syn 2.0.53", "syn 2.0.53",
] ]
[[package]]
name = "defmt"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3939552907426de152b3c2c6f51ed53f98f448babd26f28694c95f5906194595"
dependencies = [
"bitflags",
"defmt-macros",
]
[[package]]
name = "defmt-brtt"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2f0ac3635d0c89d12b8101fcb44a7625f5f030a1c0491124b74467eb5a58a78"
dependencies = [
"critical-section",
"defmt",
]
[[package]]
name = "defmt-macros"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18bdc7a7b92ac413e19e95240e75d3a73a8d8e78aa24a594c22cbb4d44b4bbda"
dependencies = [
"defmt-parser",
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.53",
]
[[package]]
name = "defmt-parser"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff4a5fefe330e8d7f31b16a318f9ce81000d8e35e69b93eae154d16d2278f70f"
dependencies = [
"thiserror",
]
[[package]]
name = "defmt-test"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290966e8c38f94b11884877242de876280d0eab934900e9642d58868e77c5df1"
dependencies = [
"cortex-m-rt",
"cortex-m-semihosting",
"defmt",
"defmt-test-macros",
]
[[package]]
name = "defmt-test-macros"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "984bc6eca246389726ac2826acc2488ca0fe5fcd6b8d9b48797021951d76a125"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.53",
]
[[package]] [[package]]
name = "delegate" name = "delegate"
version = "0.10.0" version = "0.10.0"
@ -371,21 +445,6 @@ dependencies = [
"hashbrown", "hashbrown",
] ]
[[package]]
name = "itm_logger"
version = "0.1.3-alpha.0"
source = "git+https://github.com/robamu/itm_logger.rs.git?branch=all_features#83ee7a6c57f525a70d0cc5bb7e65826d0ce938a0"
dependencies = [
"cortex-m",
"log",
]
[[package]]
name = "log"
version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]] [[package]]
name = "lsm303dlhc" name = "lsm303dlhc"
version = "0.2.0" version = "0.2.0"
@ -504,12 +563,13 @@ dependencies = [
] ]
[[package]] [[package]]
name = "panic-itm" name = "panic-probe"
version = "0.4.2" version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d577d97d1b31268087b6dddf2470e6794ef5eee87d9dca7fcd0481695391a4c" checksum = "aa6fa5645ef5a760cd340eaa92af9c1ce131c8c09e7f8926d8a24b59d26652b9"
dependencies = [ dependencies = [
"cortex-m", "cortex-m",
"defmt",
] ]
[[package]] [[package]]
@ -690,11 +750,14 @@ dependencies = [
"cobs 0.2.3 (git+https://github.com/robamu/cobs.rs.git?branch=all_features)", "cobs 0.2.3 (git+https://github.com/robamu/cobs.rs.git?branch=all_features)",
"cortex-m", "cortex-m",
"cortex-m-rt", "cortex-m-rt",
"cortex-m-semihosting",
"defmt",
"defmt-brtt",
"defmt-test",
"embedded-hal 0.2.7", "embedded-hal 0.2.7",
"enumset", "enumset",
"heapless", "heapless",
"itm_logger", "panic-probe",
"panic-itm",
"rtic", "rtic",
"rtic-monotonics", "rtic-monotonics",
"satrs", "satrs",
@ -855,6 +918,26 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "thiserror"
version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.53",
]
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.17.0" version = "1.17.0"

View File

@ -2,13 +2,18 @@
name = "satrs-example-stm32f3-disco" name = "satrs-example-stm32f3-disco"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
default-run = "satrs-example-stm32f3-disco"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
cortex-m = { version = "0.7", features = ["critical-section-single-core"] } cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7" cortex-m-rt = "0.7"
defmt = "0.3"
defmt-brtt = { version = "0.1", default-features = false, features = ["rtt"] }
panic-probe = { version = "0.3", features = ["print-defmt"] }
embedded-hal = "0.2.7" embedded-hal = "0.2.7"
cortex-m-semihosting = "0.5.0"
enumset = "1" enumset = "1"
heapless = "0.8" heapless = "0.8"
@ -25,14 +30,6 @@ git = "https://github.com/robamu/cobs.rs.git"
branch = "all_features" branch = "all_features"
default-features = false default-features = false
[dependencies.panic-itm]
version = "0.4"
[dependencies.itm_logger]
git = "https://github.com/robamu/itm_logger.rs.git"
branch = "all_features"
version = "0.1.3-alpha.0"
[dependencies.stm32f3xx-hal] [dependencies.stm32f3xx-hal]
git = "https://github.com/robamu/stm32f3xx-hal" git = "https://github.com/robamu/stm32f3xx-hal"
version = "0.11.0-alpha.0" version = "0.11.0-alpha.0"
@ -49,17 +46,37 @@ branch = "complete-dma-update-hal"
# path = "../stm32f3-discovery" # path = "../stm32f3-discovery"
[dependencies.satrs] [dependencies.satrs]
# git = "https://egit.irs.uni-stuttgart.de/rust/satrs-core.git"
version = "0.2.0-rc.0" version = "0.2.0-rc.0"
default-features = false default-features = false
# this lets you use `cargo fix`! [dev-dependencies]
# [[bin]] defmt-test = "0.3"
# name = "stm32f3-blinky"
# test = false
# bench = false
# cargo test
[profile.test]
codegen-units = 1
debug = 2
debug-assertions = true # <-
incremental = false
opt-level = "s" # <-
overflow-checks = true # <-
# cargo build/run --release
[profile.release] [profile.release]
codegen-units = 1 # better optimizations codegen-units = 1
debug = true # symbols are nice and they don't increase the size on Flash debug = 2
lto = true # better optimizations debug-assertions = false # <-
incremental = false
lto = 'fat'
opt-level = "s" # <-
overflow-checks = false # <-
# cargo test --release
[profile.bench]
codegen-units = 1
debug = 2
debug-assertions = false # <-
incremental = false
lto = 'fat'
opt-level = "s" # <-
overflow-checks = false # <-

View File

@ -2,26 +2,24 @@ sat-rs example for the STM32F3-Discovery board
======= =======
This example application shows how the [sat-rs framework](https://egit.irs.uni-stuttgart.de/rust/satrs-launchpad) This example application shows how the [sat-rs framework](https://egit.irs.uni-stuttgart.de/rust/satrs-launchpad)
can be used on an embedded target. It also shows how a relatively simple OBSW could be built when no can be used on an embedded target.
standard runtime is available. It uses [RTIC](https://rtic.rs/1/book/en/) as the concurrency It also shows how a relatively simple OBSW could be built when no standard runtime is available.
framework. It uses [RTIC](https://rtic.rs/1/book/en/) as the concurrency framework and the
[defmt](https://defmt.ferrous-systems.com/) framework for logging.
The STM32F3-Discovery device was picked because it is a cheap Cortex-M4 based device which is also The STM32F3-Discovery device was picked because it is a cheap Cortex-M4 based device which is also
used by the [Rust Embedded Book](https://docs.rust-embedded.org/book/intro/hardware.html) and the used by the [Rust Embedded Book](https://docs.rust-embedded.org/book/intro/hardware.html) and the
[Rust Discovery](https://docs.rust-embedded.org/discovery/f3discovery/) book as an introduction [Rust Discovery](https://docs.rust-embedded.org/discovery/f3discovery/) book as an introduction
to embedded Rust. to embedded Rust.
If you would like to access the ITM log output, you need to connect the PB3 pin to the CN3 pin
of the SWD header like [shown here](https://docs.rust-embedded.org/discovery/f3discovery/06-hello-world/index.html).
## Pre-Requisites ## Pre-Requisites
Make sure the following tools are installed: Make sure the following tools are installed:
1. `openocd`: This is the debug server used to debug the STM32F3. You can install this from 1. [`probe-rs`](https://probe.rs/): Application used to flash and debug the MCU.
[`xPacks`](https://xpack.github.io/dev-tools/openocd/install/). You can also use the one provided 2. Optional and recommended: [VS Code](https://code.visualstudio.com/) with
by a STM32Cube installation. [probe-rs plugin](https://marketplace.visualstudio.com/items?itemName=probe-rs.probe-rs-debugger)
2. A debugger like `arm-none-eabi-gdb` or `gdb-multiarch`. for debugging.
## Preparing Rust and the repository ## Preparing Rust and the repository
@ -52,23 +50,19 @@ you can simply build the application with
cargo build cargo build
``` ```
## Flashing and Debugging from the command line ## Flashing from the command line
Make sure you have `openocd` and `itmdump` installed first. You can flash the application from the command line using `probe-rs`:
1. Configure a runner inside your `.cargo/config.toml` file by uncommenting an appropriate line ```sh
depending on the application you want to use for debugging probe-rs run --chip STM32F303VCTx
2. Start `openocd` inside the project folder. This will start `openocd` with the provided ```
`openocd.cfg` configuration file.
3. Use `cargo run` to flash and debug the application in your terminal
4. Use `itmdump -F -f itm.txt` to print the logs received from the STM32F3 device. Please note
that the PB3 and CN3 pin of the SWD header need to be connected for this to work.
## Debugging with VS Code ## Debugging with VS Code
The STM32F3-Discovery comes with an on-board ST-Link so all that is required to flash and debug The STM32F3-Discovery comes with an on-board ST-Link so all that is required to flash and debug
the board is a Mini-USB cable. The code in this repository was debugged using `openocd` the board is a Mini-USB cable. The code in this repository was debugged using [`probe-rs`](https://probe.rs/docs/tools/debuggerA)
and the VS Code [`Cortex-Debug` plugin](https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug). and the VS Code [`probe-rs` plugin](https://marketplace.visualstudio.com/items?itemName=probe-rs.probe-rs-debugger).
Make sure to install this plugin first. Make sure to install this plugin first.
Sample configuration files are provided inside the `vscode` folder. Sample configuration files are provided inside the `vscode` folder.
@ -80,14 +74,6 @@ to automatically rebuild and flash your application.
The `tasks.json` and `launch.json` files are generic and you can use them immediately by opening The `tasks.json` and `launch.json` files are generic and you can use them immediately by opening
the folder in VS code or adding it to a workspace. the folder in VS code or adding it to a workspace.
If you would like to use a custom GDB application, you can specify the gdb binary in the following
configuration variables in your `settings.json`:
- `"cortex-debug.gdbPath"`
- `"cortex-debug.gdbPath.linux"`
- `"cortex-debug.gdbPath.windows"`
- `"cortex-debug.gdbPath.osx"`
## Commanding with Python ## Commanding with Python
When the SW is running on the Discovery board, you can command the MCU via a serial interface, When the SW is running on the Discovery board, you can command the MCU via a serial interface,
@ -111,3 +97,9 @@ A default configuration file for the python application is provided and can be u
```sh ```sh
cp def_tmtc_conf.json tmtc_conf.json cp def_tmtc_conf.json tmtc_conf.json
``` ```
After that, you can for example send a ping to the MCU using the following command
```sh
./main.py -p /ping
```

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +0,0 @@
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
fn main() {
// Put the linker script somewhere the linker can find it
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
File::create(out.join("memory.x"))
.unwrap()
.write_all(include_bytes!("memory.x"))
.unwrap();
println!("cargo:rustc-link-search={}", out.display());
// Only re-run the build script when memory.x is changed,
// instead of when any part of the source code changes.
println!("cargo:rerun-if-changed=memory.x");
}

View File

@ -26,7 +26,7 @@ break main
# # 8000000 must match the core clock frequency # # 8000000 must match the core clock frequency
# # 2000000 is the frequency of the SWO pin. This was added for newer # # 2000000 is the frequency of the SWO pin. This was added for newer
# openocd versions like v0.12.0. # openocd versions like v0.12.0.
monitor tpiu config internal itm.txt uart off 8000000 2000000 # monitor tpiu config internal itm.txt uart off 8000000 2000000
# # OR: make the microcontroller SWO pin output compatible with UART (8N1) # # OR: make the microcontroller SWO pin output compatible with UART (8N1)
# # 8000000 must match the core clock frequency # # 8000000 must match the core clock frequency
@ -34,7 +34,7 @@ monitor tpiu config internal itm.txt uart off 8000000 2000000
# monitor tpiu config external uart off 8000000 2000000 # monitor tpiu config external uart off 8000000 2000000
# # enable ITM port 0 # # enable ITM port 0
monitor itm port 0 on # monitor itm port 0 on
load load

View File

@ -1,17 +1,15 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
use satrs_example_stm32f3_disco as _;
extern crate panic_itm; use stm32f3_discovery::leds::Leds;
use cortex_m_rt::entry;
use stm32f3_discovery::stm32f3xx_hal::delay::Delay; use stm32f3_discovery::stm32f3xx_hal::delay::Delay;
use stm32f3_discovery::stm32f3xx_hal::{pac, prelude::*}; use stm32f3_discovery::stm32f3xx_hal::{pac, prelude::*};
use stm32f3_discovery::leds::Leds;
use stm32f3_discovery::switch_hal::{OutputSwitch, ToggleableOutputSwitch}; use stm32f3_discovery::switch_hal::{OutputSwitch, ToggleableOutputSwitch};
#[entry] #[cortex_m_rt::entry]
fn main()-> ! { fn main() -> ! {
defmt::println!("STM32F3 Discovery Blinky");
let dp = pac::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap();
let mut rcc = dp.RCC.constrain(); let mut rcc = dp.RCC.constrain();
let cp = cortex_m::Peripherals::take().unwrap(); let cp = cortex_m::Peripherals::take().unwrap();
@ -30,49 +28,49 @@ fn main()-> ! {
gpioe.pe14, gpioe.pe14,
gpioe.pe15, gpioe.pe15,
&mut gpioe.moder, &mut gpioe.moder,
&mut gpioe.otyper &mut gpioe.otyper,
); );
let delay_ms = 200u16; let delay_ms = 200u16;
loop { loop {
leds.ld3.toggle().ok(); leds.ld3_n.toggle().ok();
delay.delay_ms(delay_ms); delay.delay_ms(delay_ms);
leds.ld3.toggle().ok(); leds.ld3_n.toggle().ok();
delay.delay_ms(delay_ms); delay.delay_ms(delay_ms);
//explicit on/off //explicit on/off
leds.ld4.on().ok(); leds.ld4_nw.on().ok();
delay.delay_ms(delay_ms); delay.delay_ms(delay_ms);
leds.ld4.off().ok(); leds.ld4_nw.off().ok();
delay.delay_ms(delay_ms); delay.delay_ms(delay_ms);
leds.ld5.on().ok(); leds.ld5_ne.on().ok();
delay.delay_ms(delay_ms); delay.delay_ms(delay_ms);
leds.ld5.off().ok(); leds.ld5_ne.off().ok();
delay.delay_ms(delay_ms); delay.delay_ms(delay_ms);
leds.ld6.on().ok(); leds.ld6_w.on().ok();
delay.delay_ms(delay_ms); delay.delay_ms(delay_ms);
leds.ld6.off().ok(); leds.ld6_w.off().ok();
delay.delay_ms(delay_ms); delay.delay_ms(delay_ms);
leds.ld7.on().ok(); leds.ld7_e.on().ok();
delay.delay_ms(delay_ms); delay.delay_ms(delay_ms);
leds.ld7.off().ok(); leds.ld7_e.off().ok();
delay.delay_ms(delay_ms); delay.delay_ms(delay_ms);
leds.ld8.on().ok(); leds.ld8_sw.on().ok();
delay.delay_ms(delay_ms); delay.delay_ms(delay_ms);
leds.ld8.off().ok(); leds.ld8_sw.off().ok();
delay.delay_ms(delay_ms); delay.delay_ms(delay_ms);
leds.ld9.on().ok(); leds.ld9_se.on().ok();
delay.delay_ms(delay_ms); delay.delay_ms(delay_ms);
leds.ld9.off().ok(); leds.ld9_se.off().ok();
delay.delay_ms(delay_ms); delay.delay_ms(delay_ms);
leds.ld10.on().ok(); leds.ld10_s.on().ok();
delay.delay_ms(delay_ms); delay.delay_ms(delay_ms);
leds.ld10.off().ok(); leds.ld10_s.off().ok();
delay.delay_ms(delay_ms); delay.delay_ms(delay_ms);
} }
} }

View File

@ -0,0 +1,51 @@
#![no_main]
#![no_std]
use cortex_m_semihosting::debug;
use defmt_brtt as _; // global logger
use stm32f3xx_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,12 +1,12 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
extern crate panic_itm; // global logger + panicking-behavior + memory layout
use satrs_example_stm32f3_disco as _;
use rtic::app; use rtic::app;
use heapless::{mpmc::Q8, Vec}; use heapless::{mpmc::Q8, Vec};
#[allow(unused_imports)] #[allow(unused_imports)]
use itm_logger::{debug, info, logger_init, warn};
use rtic_monotonics::systick::fugit::TimerInstantU32; use rtic_monotonics::systick::fugit::TimerInstantU32;
use rtic_monotonics::systick::ExtU32; use rtic_monotonics::systick::ExtU32;
use satrs::seq_count::SequenceCountProviderCore; use satrs::seq_count::SequenceCountProviderCore;
@ -95,14 +95,12 @@ pub struct TxIdle {
pub struct TmSender { pub struct TmSender {
vec: Option<RefCell<Vec<u8, MAX_TM_LEN>>>, vec: Option<RefCell<Vec<u8, MAX_TM_LEN>>>,
ctx: &'static str,
} }
impl TmSender { impl TmSender {
pub fn new(tm_packet: TmPacket, ctx: &'static str) -> Self { pub fn new(tm_packet: TmPacket) -> Self {
Self { Self {
vec: Some(RefCell::new(tm_packet)), vec: Some(RefCell::new(tm_packet)),
ctx,
} }
} }
} }
@ -131,7 +129,12 @@ impl EcssTmSenderCore for TmSender {
} }
vec.resize(tm.len_written(), 0).expect("vec resize failed"); vec.resize(tm.len_written(), 0).expect("vec resize failed");
tm.write_to_bytes(vec.as_mut_slice())?; tm.write_to_bytes(vec.as_mut_slice())?;
info!(target: self.ctx, "Sending TM[{},{}] with size {}", tm.service(), tm.subservice(), tm.len_written()); defmt::info!(
"Sending TM[{},{}] with size {}",
tm.service(),
tm.subservice(),
tm.len_written()
);
drop(vec); drop(vec);
TM_REQUESTS TM_REQUESTS
.enqueue(vec_ref.take()) .enqueue(vec_ref.take())
@ -158,7 +161,6 @@ pub struct UartTxShared {
mod app { mod app {
use super::*; use super::*;
use core::slice::Iter; use core::slice::Iter;
use cortex_m::iprintln;
use rtic_monotonics::systick::Systick; use rtic_monotonics::systick::Systick;
use rtic_monotonics::Monotonic; use rtic_monotonics::Monotonic;
use satrs::pus::verification::FailParams; use satrs::pus::verification::FailParams;
@ -192,14 +194,13 @@ mod app {
} }
#[init] #[init]
fn init(mut cx: init::Context) -> (Shared, Local) { fn init(cx: init::Context) -> (Shared, Local) {
let mut rcc = cx.device.RCC.constrain(); let mut rcc = cx.device.RCC.constrain();
// Initialize the systick interrupt & obtain the token to prove that we did // Initialize the systick interrupt & obtain the token to prove that we did
let systick_mono_token = rtic_monotonics::create_systick_token!(); let systick_mono_token = rtic_monotonics::create_systick_token!();
Systick::start(cx.core.SYST, 8_000_000, systick_mono_token); Systick::start(cx.core.SYST, 8_000_000, systick_mono_token);
logger_init();
let mut flash = cx.device.FLASH.constrain(); let mut flash = cx.device.FLASH.constrain();
let clocks = rcc let clocks = rcc
.cfgr .cfgr
@ -211,11 +212,7 @@ mod app {
// Set up monotonic timer. // Set up monotonic timer.
//let mono_timer = MonoTimer::new(cx.core.DWT, clocks, &mut cx.core.DCB); //let mono_timer = MonoTimer::new(cx.core.DWT, clocks, &mut cx.core.DCB);
// setup ITM output defmt::info!("Starting sat-rs demo application for the STM32F3-Discovery");
iprintln!(
&mut cx.core.ITM.stim[0],
"Starting sat-rs demo application for the STM32F3-Discovery"
);
let mut gpioe = cx.device.GPIOE.split(&mut rcc.ahb); let mut gpioe = cx.device.GPIOE.split(&mut rcc.ahb);
let verif_reporter = VerificationReporterCore::new(PUS_APID).unwrap(); let verif_reporter = VerificationReporterCore::new(PUS_APID).unwrap();
@ -265,7 +262,7 @@ mod app {
// For some reason, this is also immediately triggered.. // For some reason, this is also immediately triggered..
tx_serial.clear_event(TxEvent::TransmissionComplete); tx_serial.clear_event(TxEvent::TransmissionComplete);
let rx_transfer = rx_serial.read_exact(unsafe { DMA_RX_BUF.as_mut_slice() }, dma1.ch6); let rx_transfer = rx_serial.read_exact(unsafe { DMA_RX_BUF.as_mut_slice() }, dma1.ch6);
info!(target: "init", "Spawning tasks"); defmt::info!("Spawning tasks");
blink::spawn().unwrap(); blink::spawn().unwrap();
serial_tx_handler::spawn().unwrap(); serial_tx_handler::spawn().unwrap();
( (
@ -399,10 +396,9 @@ mod app {
cx: serial_rx_handler::Context, cx: serial_rx_handler::Context,
received_packet: Vec<u8, MAX_TC_LEN>, received_packet: Vec<u8, MAX_TC_LEN>,
) { ) {
info!("running rx handler"); defmt::info!("running rx handler");
let tgt: &'static str = "serial_rx_handler";
cx.local.stamp_buf[0] = P_FIELD_BASE; cx.local.stamp_buf[0] = P_FIELD_BASE;
info!(target: tgt, "Received packet with {} bytes", received_packet.len()); defmt::info!("Received packet with {} bytes", received_packet.len());
let decode_buf = cx.local.decode_buf; let decode_buf = cx.local.decode_buf;
let packet = received_packet.as_slice(); let packet = received_packet.as_slice();
let mut start_idx = None; let mut start_idx = None;
@ -413,16 +409,13 @@ mod app {
} }
} }
if start_idx.is_none() { if start_idx.is_none() {
warn!( defmt::warn!("decoding error, can only process cobs encoded frames, data is all 0");
target: tgt,
"decoding error, can only process cobs encoded frames, data is all 0"
);
return; return;
} }
let start_idx = start_idx.unwrap(); let start_idx = start_idx.unwrap();
match cobs::decode(&received_packet.as_slice()[start_idx..], decode_buf) { match cobs::decode(&received_packet.as_slice()[start_idx..], decode_buf) {
Ok(len) => { Ok(len) => {
info!(target: tgt, "Decoded packet length: {}", len); defmt::info!("Decoded packet length: {}", len);
let pus_tc = PusTcReader::new(decode_buf); let pus_tc = PusTcReader::new(decode_buf);
let verif_reporter = cx.local.verif_reporter; let verif_reporter = cx.local.verif_reporter;
match pus_tc { match pus_tc {
@ -432,18 +425,15 @@ mod app {
verif_reporter, verif_reporter,
cx.local.src_data_buf, cx.local.src_data_buf,
cx.local.stamp_buf, cx.local.stamp_buf,
tgt,
), ),
Err(e) => { Err(_e) => {
warn!(target: tgt, "Error unpacking PUS TC: {}", e); // TODO: Print error after API rework.
defmt::warn!("Error unpacking PUS TC");
} }
} }
} }
Err(_) => { Err(_) => {
warn!( defmt::warn!("decoding error, can only process cobs encoded frames")
target: tgt,
"decoding error, can only process cobs encoded frames"
)
} }
} }
} }
@ -454,10 +444,8 @@ mod app {
verif_reporter: &mut VerificationReporterCore, verif_reporter: &mut VerificationReporterCore,
src_data_buf: &mut [u8; MAX_TM_LEN], src_data_buf: &mut [u8; MAX_TM_LEN],
stamp_buf: &[u8; 7], stamp_buf: &[u8; 7],
tgt: &'static str,
) { ) {
info!( defmt::info!(
target: tgt,
"Found PUS TC [{},{}] with length {}", "Found PUS TC [{},{}] with length {}",
tc.service(), tc.service(),
tc.subservice(), tc.subservice(),
@ -466,7 +454,7 @@ mod app {
let token = verif_reporter.add_tc(&tc); let token = verif_reporter.add_tc(&tc);
if tc.apid() != PUS_APID { if tc.apid() != PUS_APID {
warn!(target: tgt, "Received tc with unknown APID {}", tc.apid()); defmt::warn!("Received tc with unknown APID {}", tc.apid());
let sendable = verif_reporter let sendable = verif_reporter
.acceptance_failure( .acceptance_failure(
src_data_buf, src_data_buf,
@ -476,9 +464,9 @@ mod app {
FailParams::new(stamp_buf, &EcssEnumU16::new(0), &[]), FailParams::new(stamp_buf, &EcssEnumU16::new(0), &[]),
) )
.unwrap(); .unwrap();
let sender = TmSender::new(TmPacket::new(), tgt); let sender = TmSender::new(TmPacket::new());
if let Err(e) = verif_reporter.send_acceptance_failure(sendable, &sender) { if let Err(_e) = verif_reporter.send_acceptance_failure(sendable, &sender) {
warn!(target: tgt, "Sending acceptance failure failed: {:?}", e.0); defmt::warn!("Sending acceptance failure failed");
}; };
return; return;
} }
@ -486,11 +474,12 @@ mod app {
.acceptance_success(src_data_buf, token, SEQ_COUNT_PROVIDER.get(), 0, stamp_buf) .acceptance_success(src_data_buf, token, SEQ_COUNT_PROVIDER.get(), 0, stamp_buf)
.unwrap(); .unwrap();
let sender = TmSender::new(TmPacket::new(), tgt); let sender = TmSender::new(TmPacket::new());
let accepted_token = match verif_reporter.send_acceptance_success(sendable, &sender) { let accepted_token = match verif_reporter.send_acceptance_success(sendable, &sender) {
Ok(token) => token, Ok(token) => token,
Err(e) => { Err(_e) => {
warn!(target: "serial_rx_handler", "Sending acceptance success failed: {:?}", e.0); // TODO: Print error as soon as EcssTmtcError has Format attr.. or rework API.
defmt::warn!("Sending acceptance success failed");
return; return;
} }
}; };
@ -507,18 +496,16 @@ mod app {
) )
.unwrap(); .unwrap();
// let mem_block = poolmod::TM::alloc().unwrap().init([0u8; MAX_TM_LEN]); // let mem_block = poolmod::TM::alloc().unwrap().init([0u8; MAX_TM_LEN]);
let sender = TmSender::new(TmPacket::new(), tgt); let sender = TmSender::new(TmPacket::new());
let started_token = match verif_reporter.send_start_success(sendable, &sender) { let started_token = match verif_reporter.send_start_success(sendable, &sender) {
Ok(token) => token, Ok(token) => token,
Err(e) => { Err(_e) => {
warn!(target: tgt, "Sending acceptance success failed: {:?}", e.0); // TODO: Print error as soon as EcssTmtcError has Format attr.. or rework API.
defmt::warn!("Sending acceptance success failed");
return; return;
} }
}; };
info!( defmt::info!("Received PUS ping telecommand, sending ping reply TM[17,2]");
target: tgt,
"Received PUS ping telecommand, sending ping reply TM[17,2]"
);
let mut sp_header = let mut sp_header =
SpHeader::tc_unseg(PUS_APID, SEQ_COUNT_PROVIDER.get(), 0).unwrap(); SpHeader::tc_unseg(PUS_APID, SEQ_COUNT_PROVIDER.get(), 0).unwrap();
let sec_header = PusTmSecondaryHeader::new_simple(17, 2, stamp_buf); let sec_header = PusTmSecondaryHeader::new_simple(17, 2, stamp_buf);
@ -529,7 +516,7 @@ mod app {
.expect("vec resize failed"); .expect("vec resize failed");
ping_reply.write_to_bytes(&mut tm_packet).unwrap(); ping_reply.write_to_bytes(&mut tm_packet).unwrap();
if TM_REQUESTS.enqueue(tm_packet).is_err() { if TM_REQUESTS.enqueue(tm_packet).is_err() {
warn!(target: tgt, "TC queue full"); defmt::warn!("TC queue full");
return; return;
} }
SEQ_COUNT_PROVIDER.increment(); SEQ_COUNT_PROVIDER.increment();
@ -542,9 +529,9 @@ mod app {
stamp_buf, stamp_buf,
) )
.unwrap(); .unwrap();
let sender = TmSender::new(TmPacket::new(), tgt); let sender = TmSender::new(TmPacket::new());
if let Err(e) = verif_reporter.send_step_or_completion_success(sendable, &sender) { if let Err(_e) = verif_reporter.send_step_or_completion_success(sendable, &sender) {
warn!(target: tgt, "Sending completion success failed: {:?}", e.0); defmt::warn!("Sending completion success failed");
} }
} else { } else {
// TODO: Invalid subservice // TODO: Invalid subservice
@ -573,7 +560,7 @@ mod app {
serial_rx_handler::spawn(tc_packet).expect("spawning rx handler task failed"); serial_rx_handler::spawn(tc_packet).expect("spawning rx handler task failed");
// If this happens, there is a high chance that the maximum packet length was // If this happens, there is a high chance that the maximum packet length was
// exceeded. Circular mode is not used here, so data might be missed. // exceeded. Circular mode is not used here, so data might be missed.
warn!( defmt::warn!(
"rx transfer with maximum length {}, might miss data", "rx transfer with maximum length {}, might miss data",
TC_BUF_LEN TC_BUF_LEN
); );
@ -615,7 +602,6 @@ mod app {
.expect("vec resize failed"); .expect("vec resize failed");
tc_packet[0..rx_len as usize].copy_from_slice(&buf[0..rx_len as usize]); tc_packet[0..rx_len as usize].copy_from_slice(&buf[0..rx_len as usize]);
rx.clear_event(RxEvent::Idle); rx.clear_event(RxEvent::Idle);
info!("spawning rx task");
serial_rx_handler::spawn(tc_packet).expect("spawning rx handler failed"); serial_rx_handler::spawn(tc_packet).expect("spawning rx handler failed");
*rx_transfer = Some(rx.read_exact(buf, ch)); *rx_transfer = Some(rx.read_exact(buf, ch));
} }

View File

@ -5,7 +5,7 @@
// List of extensions which should be recommended for users of this workspace. // List of extensions which should be recommended for users of this workspace.
"recommendations": [ "recommendations": [
"rust-lang.rust", "rust-lang.rust",
"marus25.cortex-debug", "probe-rs.probe-rs-debugger"
], ],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace. // List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": [] "unwantedRecommendations": []

View File

@ -1,66 +1,22 @@
{ {
/*
* Requires the Rust Language Server (RLS) and Cortex-Debug extensions
* https://marketplace.visualstudio.com/items?itemName=rust-lang.rust
* https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug
*/
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
/* Launches debug session for currently open example */ "preLaunchTask": "${defaultBuildTask}",
"type": "cortex-debug", "type": "probe-rs-debug",
"request": "launch", "request": "launch",
"name": "Debug", "name": "probe-rs Debugging ",
"servertype": "openocd", "flashingConfig": {
"cwd": "${workspaceRoot}", "flashingEnabled": true
"preLaunchTask": "cargo build",
"runToEntryPoint": "true",
"executable": "./target/thumbv7em-none-eabihf/debug/satrs-example-stm32f3-disco",
"preLaunchCommands": ["break rust_begin_unwind"],
"device": "STM32F303VCT6",
"configFiles": [
"${workspaceRoot}/.vscode/openocd-helpers.tcl",
"interface/stlink.cfg",
"target/stm32f3x.cfg"
],
"svdFile": "${env:HOME}/.svd/STM32F303.svd",
"swoConfig": {
"enabled": true,
"cpuFrequency": 8000000,
"swoFrequency": 2000000,
"source": "probe",
"decoders": [
{ "type": "console", "label": "ITM", "port": 0 }
]
}
}, },
"chip": "STM32F303VCTx",
"coreConfigs": [
{ {
/* Launches debug session for currently open example */ "programBinary": "${workspaceFolder}/target/thumbv7em-none-eabihf/debug/satrs-example-stm32f3-disco",
"type": "cortex-debug", "rttEnabled": true,
"request": "launch", "svdFile": "STM32F303.svd"
"name": "Release",
"servertype": "openocd",
"cwd": "${workspaceRoot}",
"preLaunchTask": "cargo build",
"runToEntryPoint": "true",
"executable": "./target/thumbv7em-none-eabihf/release/satrs-example-stm32f3-disco",
"preLaunchCommands": ["break rust_begin_unwind"],
"device": "STM32F303VCT6",
"configFiles": [
"${workspaceRoot}/.vscode/openocd-helpers.tcl",
"interface/stlink.cfg",
"target/stm32f3x.cfg"
],
"svdFile": "${env:HOME}/.svd/STM32F303.svd",
"swoConfig": {
"enabled": true,
"cpuFrequency": 8000000,
"swoFrequency": 2000000,
"source": "probe",
"decoders": [
{ "type": "console", "label": "ITM", "port": 0 }
]
} }
]
} }
] ]
} }