From 2318cd4293c85b4c7659d79bedf3a88e175c882d Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 25 Mar 2024 14:26:07 +0100 Subject: [PATCH] Update satrs-example for the STM32F3 - Update RTIC to v2 - Update Python client version --- satrs-example-stm32f3-disco/Cargo.lock | 244 +++++++++-------- satrs-example-stm32f3-disco/Cargo.toml | 22 +- .../pyclient/.gitignore | 1 + .../pyclient/def_tmtc_conf.json | 2 +- satrs-example-stm32f3-disco/pyclient/main.py | 6 +- satrs-example-stm32f3-disco/src/main.rs | 256 ++++++++++-------- 6 files changed, 294 insertions(+), 237 deletions(-) diff --git a/satrs-example-stm32f3-disco/Cargo.lock b/satrs-example-stm32f3-disco/Cargo.lock index 838f17d..9043d7a 100644 --- a/satrs-example-stm32f3-disco/Cargo.lock +++ b/satrs-example-stm32f3-disco/Cargo.lock @@ -55,11 +55,12 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bxcan" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b13b4b2ea9ab2ba924063ebb86ad895cb79f4a79bf90f27949eb20c335b30f9" +checksum = "40ac3d0c0a542d0ab5521211f873f62706a7136df415676f676d347e5a41dd80" dependencies = [ "bitflags", + "embedded-hal 0.2.7", "nb 1.1.0", "vcell", ] @@ -113,7 +114,8 @@ checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" dependencies = [ "bare-metal 0.2.5", "bitfield", - "embedded-hal", + "critical-section", + "embedded-hal 0.2.7", "volatile-register", ] @@ -137,34 +139,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "cortex-m-rtic" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d696ae7390bdb9f7978f71ca7144256a2c4616240a6df9002da3c451f9fc8f02" -dependencies = [ - "bare-metal 1.0.0", - "cortex-m", - "cortex-m-rtic-macros", - "heapless 0.7.17", - "rtic-core", - "rtic-monotonic", - "version_check", -] - -[[package]] -name = "cortex-m-rtic-macros" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eefb40b1ca901c759d29526e5c8a0a1b246c20caaa5b4cc5d0f0b94debecd4c7" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "rtic-syntax", - "syn 1.0.109", -] - [[package]] name = "crc" version = "3.0.1" @@ -250,6 +224,12 @@ dependencies = [ "void", ] +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + [[package]] name = "embedded-time" version = "0.12.1" @@ -280,6 +260,12 @@ dependencies = [ "syn 2.0.53", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "fnv" version = "1.0.7" @@ -295,6 +281,30 @@ dependencies = [ "gcd", ] +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + [[package]] name = "gcd" version = "2.3.0" @@ -320,15 +330,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - [[package]] name = "hash32" version = "0.3.1" @@ -340,22 +341,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "heapless" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" -dependencies = [ - "atomic-polyfill", - "hash32 0.2.1", - "rustc_version 0.4.0", - "spin", - "stable_deref_trait", -] +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "heapless" @@ -363,7 +351,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" dependencies = [ - "hash32 0.3.1", + "hash32", "stable_deref_trait", ] @@ -375,11 +363,11 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "indexmap" -version = "1.9.3" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ - "autocfg", + "equivalent", "hashbrown", ] @@ -392,16 +380,6 @@ dependencies = [ "log", ] -[[package]] -name = "lock_api" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" -dependencies = [ - "autocfg", - "scopeguard", -] - [[package]] name = "log" version = "0.4.21" @@ -415,7 +393,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5d1a5c290951321d1b0d4a40edd828537de9889134a0e67c5146542ae57706" dependencies = [ "cast", - "embedded-hal", + "embedded-hal 0.2.7", "generic-array 0.11.2", ] @@ -540,6 +518,18 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -591,6 +581,29 @@ dependencies = [ "chrono", ] +[[package]] +name = "rtic" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c443db16326376bdd64377da268f6616d5f804aba8ce799bac7d1f7f244e9d51" +dependencies = [ + "atomic-polyfill", + "bare-metal 1.0.0", + "cortex-m", + "critical-section", + "rtic-core", + "rtic-macros", +] + +[[package]] +name = "rtic-common" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0786b50b81ef9d2a944a000f60405bb28bf30cd45da2d182f3fe636b2321f35c" +dependencies = [ + "critical-section", +] + [[package]] name = "rtic-core" version = "1.0.0" @@ -598,21 +611,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9369355b04d06a3780ec0f51ea2d225624db777acbc60abd8ca4832da5c1a42" [[package]] -name = "rtic-monotonic" -version = "1.0.0" +name = "rtic-macros" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb8b0b822d1a366470b9cea83a1d4e788392db763539dc4ba022bcc787fece82" - -[[package]] -name = "rtic-syntax" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5e215601dc467752c2bddc6284a622c6f3d2bab569d992adcd5ab7e4cb9478" +checksum = "54053598ea24b1b74937724e366558412a1777eb2680b91ef646db540982789a" dependencies = [ "indexmap", + "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.53", +] + +[[package]] +name = "rtic-monotonics" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058c2397dbd5bb4c5650a0e368c3920953e458805ff5097a0511b8147b3619d7" +dependencies = [ + "atomic-polyfill", + "cfg-if", + "cortex-m", + "embedded-hal 1.0.0", + "fugit", + "rtic-time", +] + +[[package]] +name = "rtic-time" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b232e7aebc045cfea81cdd164bc2727a10aca9a4568d406d0a5661cdfd0f19" +dependencies = [ + "critical-section", + "futures-util", + "rtic-common", ] [[package]] @@ -657,16 +690,16 @@ dependencies = [ "cobs 0.2.3 (git+https://github.com/robamu/cobs.rs.git?branch=all_features)", "cortex-m", "cortex-m-rt", - "cortex-m-rtic", - "embedded-hal", + "embedded-hal 0.2.7", "enumset", - "heapless 0.8.0", + "heapless", "itm_logger", "panic-itm", + "rtic", + "rtic-monotonics", "satrs", "stm32f3-discovery", "stm32f3xx-hal", - "systick-monotonic", ] [[package]] @@ -678,12 +711,6 @@ dependencies = [ "spacepackets", ] -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "semver" version = "0.9.0" @@ -731,15 +758,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -759,9 +777,9 @@ dependencies = [ [[package]] name = "stm32f3" -version = "0.14.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "265cda62ac13307414de4aca58dbbbd8038ddba85cffbb335823aa216f2e3200" +checksum = "b28b37228ef3fa47956af38c6abd756e912f244c1657f14e66d42fc8d74ea96f" dependencies = [ "bare-metal 1.0.0", "cortex-m", @@ -772,7 +790,7 @@ dependencies = [ [[package]] name = "stm32f3-discovery" version = "0.8.0-alpha.0" -source = "git+https://github.com/robamu/stm32f3-discovery?branch=all_features#7b1d21b0463331ada405ceed876c93e82b987a9f" +source = "git+https://github.com/robamu/stm32f3-discovery?branch=complete-dma-update-hal#5ccacae07ceff02d7d3649df67a6a0ba2a144752" dependencies = [ "accelerometer", "cortex-m", @@ -784,19 +802,20 @@ dependencies = [ [[package]] name = "stm32f3xx-hal" -version = "0.10.0-alpha.0" -source = "git+https://github.com/robamu/stm32f3xx-hal?branch=all_features#c9b3a4fcaaf48f8264475de2b34387597211478e" +version = "0.11.0-alpha.0" +source = "git+https://github.com/robamu/stm32f3xx-hal?branch=complete-dma-update#04fc76b7912649c84b57bd0ab803ea3ccf2aadae" dependencies = [ - "bare-metal 1.0.0", "bxcan", "cfg-if", "cortex-m", "cortex-m-rt", + "critical-section", "embedded-dma", - "embedded-hal", + "embedded-hal 0.2.7", "embedded-time", "enumset", "nb 1.1.0", + "num-traits", "paste", "rtcc", "slice-group-by", @@ -811,7 +830,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90a4adc8cbd1726249b161898e48e0f3f1ce74d34dc784cbbc98fba4ed283fbf" dependencies = [ - "embedded-hal", + "embedded-hal 0.2.7", ] [[package]] @@ -836,17 +855,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "systick-monotonic" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fb822d5c615a0ae3a4795ee5b1d06381c7faf488d861c0a4fa8e6a88d5ff84" -dependencies = [ - "cortex-m", - "fugit", - "rtic-monotonic", -] - [[package]] name = "typenum" version = "1.17.0" diff --git a/satrs-example-stm32f3-disco/Cargo.toml b/satrs-example-stm32f3-disco/Cargo.toml index b74efac..4337919 100644 --- a/satrs-example-stm32f3-disco/Cargo.toml +++ b/satrs-example-stm32f3-disco/Cargo.toml @@ -6,13 +6,19 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cortex-m = "0.7" +cortex-m = { version = "0.7", features = ["critical-section-single-core"] } cortex-m-rt = "0.7" -embedded-hal = "0.2.6" -cortex-m-rtic = "1.0" -enumset = "1.0" +embedded-hal = "0.2.7" +enumset = "1" heapless = "0.8" -systick-monotonic = "1.0" + +[dependencies.rtic] +version = "2" +features = ["thumbv7-backend"] + +[dependencies.rtic-monotonics] +version = "1" +features = ["cortex-m-systick"] [dependencies.cobs] git = "https://github.com/robamu/cobs.rs.git" @@ -29,16 +35,16 @@ version = "0.1.3-alpha.0" [dependencies.stm32f3xx-hal] git = "https://github.com/robamu/stm32f3xx-hal" -version = "0.10.0-alpha.0" +version = "0.11.0-alpha.0" features = ["stm32f303xc", "rt", "enumset"] -branch = "all_features" +branch = "complete-dma-update" # Can be used in workspace to develop and update HAL # path = "../stm32f3xx-hal" [dependencies.stm32f3-discovery] git = "https://github.com/robamu/stm32f3-discovery" version = "0.8.0-alpha.0" -branch = "all_features" +branch = "complete-dma-update-hal" # Can be used in workspace to develop and update BSP # path = "../stm32f3-discovery" diff --git a/satrs-example-stm32f3-disco/pyclient/.gitignore b/satrs-example-stm32f3-disco/pyclient/.gitignore index a0c9366..da26576 100644 --- a/satrs-example-stm32f3-disco/pyclient/.gitignore +++ b/satrs-example-stm32f3-disco/pyclient/.gitignore @@ -1,4 +1,5 @@ /venv +/.tmtc-history.txt /log /.idea/* !/.idea/runConfigurations diff --git a/satrs-example-stm32f3-disco/pyclient/def_tmtc_conf.json b/satrs-example-stm32f3-disco/pyclient/def_tmtc_conf.json index 5665681..76db442 100644 --- a/satrs-example-stm32f3-disco/pyclient/def_tmtc_conf.json +++ b/satrs-example-stm32f3-disco/pyclient/def_tmtc_conf.json @@ -1,4 +1,4 @@ { "com_if": "serial_cobs", "serial_baudrate": 115200 -} \ No newline at end of file +} diff --git a/satrs-example-stm32f3-disco/pyclient/main.py b/satrs-example-stm32f3-disco/pyclient/main.py index 8f5aee4..d37da58 100755 --- a/satrs-example-stm32f3-disco/pyclient/main.py +++ b/satrs-example-stm32f3-disco/pyclient/main.py @@ -16,6 +16,7 @@ from spacepackets.ecss.pus_1_verification import UnpackParams, Service1Tm from tmtccmd import TcHandlerBase, ProcedureParamsWrapper from tmtccmd.core.base import BackendRequest from tmtccmd.core.ccsds_backend import QueueWrapper +from tmtccmd.logging import add_colorlog_console_logger from tmtccmd.pus import VerificationWrapper from tmtccmd.tmtc import CcsdsTmHandler, SpecificApidHandlerBase from tmtccmd.com import ComInterface @@ -45,8 +46,6 @@ from tmtccmd.pus.s5_fsfw_event import Service5Tm from tmtccmd.util import FileSeqCountProvider, PusFileSeqCountProvider from tmtccmd.util.obj_id import ObjectIdDictT -# from tmtccmd.util.tmtc_printer import FsfwTmTcPrinter - _LOGGER = logging.getLogger() EXAMPLE_PUS_APID = 0x02 @@ -215,10 +214,11 @@ class TcHandler(TcHandlerBase): cmd_path = def_proc.cmd_path if cmd_path == "/ping": q.add_log_cmd("Sending PUS ping telecommand") - return q.add_pus_tc(PusTelecommand(service=17, subservice=1)) + q.add_pus_tc(PusTelecommand(service=17, subservice=1)) def main(): + add_colorlog_console_logger(_LOGGER) tmtccmd.init_printout(False) hook_obj = SatRsConfigHook(json_cfg_path=default_json_path()) parser_wrapper = PreArgsParsingWrapper() diff --git a/satrs-example-stm32f3-disco/src/main.rs b/satrs-example-stm32f3-disco/src/main.rs index 1c7a8c6..8795786 100644 --- a/satrs-example-stm32f3-disco/src/main.rs +++ b/satrs-example-stm32f3-disco/src/main.rs @@ -7,6 +7,8 @@ use rtic::app; use heapless::{mpmc::Q8, Vec}; #[allow(unused_imports)] use itm_logger::{debug, info, logger_init, warn}; +use rtic_monotonics::systick::fugit::TimerInstantU32; +use rtic_monotonics::systick::ExtU32; use satrs::seq_count::SequenceCountProviderCore; use satrs::{ pool::StoreError, @@ -17,19 +19,18 @@ use stm32f3xx_hal::dma::dma1; use stm32f3xx_hal::gpio::{PushPull, AF7, PA2, PA3}; use stm32f3xx_hal::pac::USART2; use stm32f3xx_hal::serial::{Rx, RxEvent, Serial, SerialDmaRx, SerialDmaTx, Tx, TxEvent}; -use systick_monotonic::{fugit::Duration, Systick}; const UART_BAUD: u32 = 115200; -const BLINK_FREQ_MS: u64 = 1000; -const TX_HANDLER_FREQ_MS: u64 = 20; -const MIN_DELAY_BETWEEN_TX_PACKETS_MS: u16 = 5; +const BLINK_FREQ_MS: u32 = 1000; +const TX_HANDLER_FREQ_MS: u32 = 20; +const MIN_DELAY_BETWEEN_TX_PACKETS_MS: u32 = 5; const MAX_TC_LEN: usize = 128; const MAX_TM_LEN: usize = 128; pub const PUS_APID: u16 = 0x02; type TxType = Tx>>; type RxType = Rx>>; -type MsDuration = Duration; +type InstantFugit = TimerInstantU32<1000>; type TxDmaTransferType = SerialDmaTx<&'static [u8], dma1::C7, TxType>; type RxDmaTransferType = SerialDmaRx<&'static mut [u8], dma1::C6, RxType>; @@ -53,9 +54,6 @@ type TcPacket = Vec; static TM_REQUESTS: Q8 = Q8::new(); -const TC_POOL_SLOTS: usize = 8; -const TM_POOL_SLOTS: usize = 8; - use core::cell::RefCell; use core::sync::atomic::{AtomicU16, Ordering}; @@ -151,11 +149,18 @@ pub enum UartTxState { Transmitting(Option), } -#[app(device = stm32f3xx_hal::pac, peripherals = true, dispatchers = [TIM20_BRK, TIM20_UP, TIM20_TRG_COM])] +pub struct UartTxShared { + last_completed: Option, + state: UartTxState, +} + +#[app(device = stm32f3xx_hal::pac, peripherals = true)] mod app { use super::*; use core::slice::Iter; use cortex_m::iprintln; + use rtic_monotonics::systick::Systick; + use rtic_monotonics::Monotonic; use satrs::pus::verification::FailParams; use satrs::pus::verification::VerificationReporterCore; use satrs::spacepackets::{ @@ -166,15 +171,15 @@ mod app { use stm32f3_discovery::leds::Direction; use stm32f3_discovery::leds::Leds; use stm32f3xx_hal::prelude::*; - use stm32f3xx_hal::Toggle; use stm32f3_discovery::switch_hal::OutputSwitch; + use stm32f3xx_hal::Switch; #[allow(dead_code)] type SerialType = Serial>, PA3>)>; #[shared] struct Shared { - tx_transfer: UartTxState, + tx_shared: UartTxShared, rx_transfer: Option, } @@ -186,17 +191,14 @@ mod app { curr_dir: Iter<'static, Direction>, } - #[monotonic(binds = SysTick, default = true)] - type MonoTimer = Systick<1000>; - - #[init(local = [ - tc_pool_mem: [u8; TC_BUF_LEN * TC_POOL_SLOTS] = [0; TC_BUF_LEN * TC_POOL_SLOTS], - tm_pool_mem: [u8; MAX_TM_LEN * TM_POOL_SLOTS] = [0; MAX_TM_LEN * TM_POOL_SLOTS] - ])] - fn init(mut cx: init::Context) -> (Shared, Local, init::Monotonics) { + #[init] + fn init(mut cx: init::Context) -> (Shared, Local) { let mut rcc = cx.device.RCC.constrain(); - let mono = Systick::new(cx.core.SYST, 8_000_000); + // Initialize the systick interrupt & obtain the token to prove that we did + let systick_mono_token = rtic_monotonics::create_systick_token!(); + Systick::start(cx.core.SYST, 8_000_000, systick_mono_token); + logger_init(); let mut flash = cx.device.FLASH.constrain(); let clocks = rcc @@ -205,6 +207,10 @@ mod app { .sysclk(8.MHz()) .pclk1(8.MHz()) .freeze(&mut flash.acr); + + // Set up monotonic timer. + //let mono_timer = MonoTimer::new(cx.core.DWT, clocks, &mut cx.core.DCB); + // setup ITM output iprintln!( &mut cx.core.ITM.stim[0], @@ -246,106 +252,138 @@ mod app { clocks, &mut rcc.apb1, ); - usart2.configure_rx_interrupt(RxEvent::Idle, Toggle::On); + usart2.configure_rx_interrupt(RxEvent::Idle, Switch::On); // This interrupt is enabled to re-schedule new transfers in the interrupt handler immediately. - usart2.configure_tx_interrupt(TxEvent::TransmissionComplete, Toggle::On); + usart2.configure_tx_interrupt(TxEvent::TransmissionComplete, Switch::On); let dma1 = cx.device.DMA1.split(&mut rcc.ahb); - let (tx_serial, mut rx_serial) = usart2.split(); + let (mut tx_serial, mut rx_serial) = usart2.split(); // This interrupt is immediately triggered, clear it. It will only be reset // by the hardware when data is received on RX (RXNE event) rx_serial.clear_event(RxEvent::Idle); + // For some reason, this is also immediately triggered.. + tx_serial.clear_event(TxEvent::TransmissionComplete); let rx_transfer = rx_serial.read_exact(unsafe { DMA_RX_BUF.as_mut_slice() }, dma1.ch6); info!(target: "init", "Spawning tasks"); blink::spawn().unwrap(); serial_tx_handler::spawn().unwrap(); ( Shared { - tx_transfer: UartTxState::Idle(Some(TxIdle { - tx: tx_serial, - dma_channel: dma1.ch7, - })), + tx_shared: UartTxShared { + last_completed: None, + state: UartTxState::Idle(Some(TxIdle { + tx: tx_serial, + dma_channel: dma1.ch7, + })), + }, rx_transfer: Some(rx_transfer), }, Local { + //timer: mono_timer, leds, last_dir: Direction::North, curr_dir: Direction::iter(), verif_reporter, }, - init::Monotonics(mono), ) } #[task(local = [leds, curr_dir, last_dir])] - fn blink(cx: blink::Context) { - let toggle_leds = |dir: &Direction| { - let leds = cx.local.leds; - let last_led = leds.for_direction(*cx.local.last_dir); + async fn blink(cx: blink::Context) { + let blink::LocalResources { + leds, + curr_dir, + last_dir, + .. + } = cx.local; + let mut toggle_leds = |dir: &Direction| { + let last_led = leds.for_direction(*last_dir); last_led.off().ok(); let led = leds.for_direction(*dir); led.on().ok(); - *cx.local.last_dir = *dir; + *last_dir = *dir; }; - - match cx.local.curr_dir.next() { - Some(dir) => { - toggle_leds(dir); - } - None => { - *cx.local.curr_dir = Direction::iter(); - toggle_leds(cx.local.curr_dir.next().unwrap()); + loop { + match curr_dir.next() { + Some(dir) => { + toggle_leds(dir); + } + None => { + *curr_dir = Direction::iter(); + toggle_leds(curr_dir.next().unwrap()); + } } + Systick::delay(BLINK_FREQ_MS.millis()).await; } - blink::spawn_after(MsDuration::from_ticks(BLINK_FREQ_MS)).unwrap(); } #[task( - shared = [tx_transfer], - local = [] + shared = [tx_shared], )] - fn serial_tx_handler(mut cx: serial_tx_handler::Context) { - if let Some(vec) = TM_REQUESTS.dequeue() { - cx.shared.tx_transfer.lock(|tx_state| match tx_state { - UartTxState::Idle(tx) => { - //debug!(target: "serial_tx_handler", "bytes: {:x?}", &buf[0..len]); - // Safety: We only copy the data into the TX DMA buffer in this task. - // If the DMA is active, another branch will be taken. - let mut_tx_dma_buf = unsafe { &mut DMA_TX_BUF }; - // 0 sentinel value as start marker - mut_tx_dma_buf[0] = 0; - // Should never panic, we accounted for the overhead. - // Write into transfer buffer directly, no need for intermediate - // encoding buffer. - let encoded_len = cobs::encode(&vec[0..vec.len()], &mut mut_tx_dma_buf[1..]); - // 0 end marker - mut_tx_dma_buf[encoded_len + 1] = 0; - //debug!(target: "serial_tx_handler", "Sending {} bytes", encoded_len + 2); - //debug!("sent: {:x?}", &mut_tx_dma_buf[0..encoded_len + 2]); - let tx_idle = tx.take().unwrap(); - // Transfer completion and re-scheduling of new TX transfers will be done - // by the IRQ handler. - let transfer = tx_idle - .tx - .write_all(&mut_tx_dma_buf[0..encoded_len + 2], tx_idle.dma_channel); - *tx_state = UartTxState::Transmitting(Some(transfer)); - // The memory block is automatically returned to the pool when it is dropped. - } - UartTxState::Transmitting(_) => { - // This is a SW configuration error. Only the ISR which - // detects transfer completion should be able to spawn a new - // task, and that ISR should set the state to IDLE. - panic!("invalid internal tx state detected") - } - }) - } else { - cx.shared.tx_transfer.lock(|tx_state| { - if let UartTxState::Idle(_) = tx_state { - serial_tx_handler::spawn_after(MsDuration::from_ticks(TX_HANDLER_FREQ_MS)) - .unwrap(); + async fn serial_tx_handler(mut cx: serial_tx_handler::Context) { + loop { + let is_idle = cx.shared.tx_shared.lock(|tx_shared| { + if let UartTxState::Idle(_) = tx_shared.state { + return true; } + false }); + if is_idle { + let last_completed = cx.shared.tx_shared.lock(|shared| shared.last_completed); + if let Some(last_completed) = last_completed { + let elapsed_ms = (Systick::now() - last_completed).to_millis(); + if elapsed_ms < MIN_DELAY_BETWEEN_TX_PACKETS_MS { + Systick::delay((MIN_DELAY_BETWEEN_TX_PACKETS_MS - elapsed_ms).millis()) + .await; + } + } + } else { + // Check for completion after 1 ms + Systick::delay(1.millis()).await; + continue; + } + if let Some(vec) = TM_REQUESTS.dequeue() { + cx.shared + .tx_shared + .lock(|tx_shared| match &mut tx_shared.state { + UartTxState::Idle(tx) => { + let encoded_len; + //debug!(target: "serial_tx_handler", "bytes: {:x?}", &buf[0..len]); + // Safety: We only copy the data into the TX DMA buffer in this task. + // If the DMA is active, another branch will be taken. + unsafe { + // 0 sentinel value as start marker + DMA_TX_BUF[0] = 0; + encoded_len = + cobs::encode(&vec[0..vec.len()], &mut DMA_TX_BUF[1..]); + // Should never panic, we accounted for the overhead. + // Write into transfer buffer directly, no need for intermediate + // encoding buffer. + // 0 end marker + DMA_TX_BUF[encoded_len + 1] = 0; + } + //debug!(target: "serial_tx_handler", "Sending {} bytes", encoded_len + 2); + //debug!("sent: {:x?}", &mut_tx_dma_buf[0..encoded_len + 2]); + let tx_idle = tx.take().unwrap(); + // Transfer completion and re-scheduling of new TX transfers will be done + // by the IRQ handler. + // SAFETY: The DMA is the exclusive writer to the DMA buffer now. + let transfer = tx_idle.tx.write_all( + unsafe { &DMA_TX_BUF[0..encoded_len + 2] }, + tx_idle.dma_channel, + ); + tx_shared.state = UartTxState::Transmitting(Some(transfer)); + // The memory block is automatically returned to the pool when it is dropped. + } + UartTxState::Transmitting(_) => (), + }); + // Check for completion after 1 ms + Systick::delay(1.millis()).await; + continue; + } + // Nothing to do, and we are idle. + Systick::delay(TX_HANDLER_FREQ_MS.millis()).await; } } @@ -357,7 +395,11 @@ mod app { verif_reporter ], )] - fn serial_rx_handler(cx: serial_rx_handler::Context, received_packet: Vec) { + async fn serial_rx_handler( + cx: serial_rx_handler::Context, + received_packet: Vec, + ) { + info!("running rx handler"); let tgt: &'static str = "serial_rx_handler"; cx.local.stamp_buf[0] = P_FIELD_BASE; info!(target: tgt, "Received packet with {} bytes", received_packet.len()); @@ -434,7 +476,6 @@ mod app { FailParams::new(stamp_buf, &EcssEnumU16::new(0), &[]), ) .unwrap(); - // let mem_block = poolmod::TM::alloc().unwrap().init([0u8; MAX_TM_LEN]); let sender = TmSender::new(TmPacket::new(), tgt); if let Err(e) = verif_reporter.send_acceptance_failure(sendable, &sender) { warn!(target: tgt, "Sending acceptance failure failed: {:?}", e.0); @@ -445,7 +486,6 @@ mod app { .acceptance_success(src_data_buf, token, SEQ_COUNT_PROVIDER.get(), 0, stamp_buf) .unwrap(); - // let mem_block = poolmod::TM::alloc().unwrap().init([0u8; MAX_TM_LEN]); let sender = TmSender::new(TmPacket::new(), tgt); let accepted_token = match verif_reporter.send_acceptance_success(sendable, &sender) { Ok(token) => token, @@ -484,7 +524,8 @@ mod app { let sec_header = PusTmSecondaryHeader::new_simple(17, 2, stamp_buf); let ping_reply = PusTmCreator::new(&mut sp_header, sec_header, &[], true); let mut tm_packet = TmPacket::new(); - tm_packet.resize(ping_reply.len_written(), 0) + tm_packet + .resize(ping_reply.len_written(), 0) .expect("vec resize failed"); ping_reply.write_to_bytes(&mut tm_packet).unwrap(); if TM_REQUESTS.enqueue(tm_packet).is_err() { @@ -501,7 +542,6 @@ mod app { stamp_buf, ) .unwrap(); - // let mem_block = poolmod::TM::alloc().unwrap().init([0u8; MAX_TM_LEN]); let sender = TmSender::new(TmPacket::new(), tgt); if let Err(e) = verif_reporter.send_step_or_completion_success(sendable, &sender) { warn!(target: tgt, "Sending completion success failed: {:?}", e.0); @@ -514,6 +554,7 @@ mod app { #[task(binds = DMA1_CH6, shared = [rx_transfer])] fn rx_dma_isr(mut cx: rx_dma_isr::Context) { + let mut tc_packet = TcPacket::new(); cx.shared.rx_transfer.lock(|rx_transfer| { let rx_ref = rx_transfer.as_ref().unwrap(); if rx_ref.is_complete() { @@ -522,7 +563,6 @@ mod app { // The received data is transferred to another task now to avoid any processing overhead // during the interrupt. There are multiple ways to do this, we use a stack allocaed vector here // to do this. - let mut tc_packet = TcPacket::new(); tc_packet.resize(buf.len(), 0).expect("vec resize failed"); tc_packet.copy_from_slice(buf); @@ -541,23 +581,26 @@ mod app { }); } - #[task(binds = USART2_EXTI26, shared = [rx_transfer, tx_transfer])] + #[task(binds = USART2_EXTI26, shared = [rx_transfer, tx_shared])] fn serial_isr(mut cx: serial_isr::Context) { - cx.shared.tx_transfer.lock(|tx_state| match tx_state { - UartTxState::Idle(_) => (), - UartTxState::Transmitting(transfer) => { - let transfer_ref = transfer.as_ref().unwrap(); - if transfer_ref.is_complete() { - let transfer = transfer.take().unwrap(); - let (_, dma_channel, tx) = transfer.stop(); - *tx_state = UartTxState::Idle(Some(TxIdle { tx, dma_channel })); - serial_tx_handler::spawn_after(MsDuration::from_ticks( - MIN_DELAY_BETWEEN_TX_PACKETS_MS.into(), - )) - .unwrap(); + cx.shared + .tx_shared + .lock(|tx_shared| match &mut tx_shared.state { + UartTxState::Idle(_) => (), + UartTxState::Transmitting(transfer) => { + let transfer_ref = transfer.as_ref().unwrap(); + if transfer_ref.is_complete() { + let transfer = transfer.take().unwrap(); + let (_, dma_channel, mut tx) = transfer.stop(); + tx.clear_event(TxEvent::TransmissionComplete); + tx_shared.state = UartTxState::Idle(Some(TxIdle { tx, dma_channel })); + // We cache the last completed time to ensure that there is a minimum delay between consecutive + // transferred packets. + tx_shared.last_completed = Some(Systick::now()); + } } - } - }); + }); + let mut tc_packet = TcPacket::new(); cx.shared.rx_transfer.lock(|rx_transfer| { let rx_transfer_ref = rx_transfer.as_ref().unwrap(); // Received a partial packet. @@ -567,14 +610,13 @@ mod app { // The received data is transferred to another task now to avoid any processing overhead // during the interrupt. There are multiple ways to do this, we use a stack // allocated vector to do this. - let mut tc_packet = TcPacket::new(); tc_packet .resize(rx_len as usize, 0) .expect("vec resize failed"); tc_packet[0..rx_len as usize].copy_from_slice(&buf[0..rx_len as usize]); rx.clear_event(RxEvent::Idle); - // Only send owning pointer to pool memory and the received packet length. - serial_rx_handler::spawn(tc_packet).expect("spawning rx handler task failed"); + info!("spawning rx task"); + serial_rx_handler::spawn(tc_packet).expect("spawning rx handler failed"); *rx_transfer = Some(rx.read_exact(buf, ch)); } }); -- 2.43.0