From 7a4f8fa439f8e649ff957495d8504a0f7988385a Mon Sep 17 00:00:00 2001 From: Tobias Breitwieser Date: Wed, 1 Nov 2023 11:23:13 +0100 Subject: [PATCH 01/16] update nightly and embassy-sync --- Cargo.toml | 4 ++-- examples/embassy-stm32-example/Cargo.toml | 4 ++-- examples/embassy-stm32-example/rust-toolchain.toml | 4 ++-- rust-toolchain.toml | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 88abfb9..bc72eec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ nb = "^1" serde = { version = "^1", default-features = false, features = ["derive"] } ublox-sockets = { version = "0.5", optional = true } embassy-time = "0.1.5" -embassy-sync = "0.3" +embassy-sync = "0.4" no-std-net = { version = "^0.6", features = ["serde"] } @@ -80,5 +80,5 @@ default-members = ["."] exclude = ["examples"] [patch.crates-io] -ublox-sockets = { path = "../ublox-sockets" } +ublox-sockets = { git = "https://github.com/BlackbirdHQ/ublox-sockets", branch = "feature/async-borrowed-sockets" } no-std-net = { git = "https://github.com/rushmorem/no-std-net", branch = "issue-15" } diff --git a/examples/embassy-stm32-example/Cargo.toml b/examples/embassy-stm32-example/Cargo.toml index bdb7052..88ce71f 100644 --- a/examples/embassy-stm32-example/Cargo.toml +++ b/examples/embassy-stm32-example/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" embassy-stm32 = { version = "0.1.0", git = "https://github.com/embassy-rs/embassy.git", branch = "main", features = ["nightly", "defmt", "stm32h747xi-cm7", "time-driver-any", "exti", "memory-x", "unstable-pac", "unstable-traits"] } embassy-executor = { version = "0.3.0", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.1", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "nightly"] } -embassy-sync = { version = "0.3.0", features = ["defmt"] } +embassy-sync = { version = "0.4", features = ["defmt"] } cortex-m = { version = "0.7.7", features = ["inline-asm", "critical-section-single-core"] } @@ -24,7 +24,7 @@ atat = { version = "0.20.0", features = ["derive", "bytes", "defmt"] } ublox-cellular-rs = {version = "0.4.0", path = "../..", features = ["sara-r5", "defmt", "async"]} [patch.crates-io] -ublox-sockets = { path = "../../../ublox-sockets" } +ublox-sockets = { git = "https://github.com/BlackbirdHQ/ublox-sockets", branch = "feature/async-borrowed-sockets" } no-std-net = { git = "https://github.com/rushmorem/no-std-net", branch = "issue-15" } embassy-time = { package = "embassy-time", git = "https://github.com/embassy-rs/embassy", branch = "main" } diff --git a/examples/embassy-stm32-example/rust-toolchain.toml b/examples/embassy-stm32-example/rust-toolchain.toml index e33f5e0..419c310 100644 --- a/examples/embassy-stm32-example/rust-toolchain.toml +++ b/examples/embassy-stm32-example/rust-toolchain.toml @@ -1,8 +1,8 @@ # Before upgrading check that everything is available on all tier1 targets here: # https://rust-lang.github.io/rustup-components-history [toolchain] -channel = "nightly-2023-10-02" -components = [ "rust-src", "rustfmt", "llvm-tools-preview" ] +channel = "nightly-2023-11-01" +components = [ "rust-src", "rustfmt", "llvm-tools" ] targets = [ "thumbv7em-none-eabi", "thumbv7m-none-eabi", diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 3cd5460..3487713 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "nightly-2023-06-28" +channel = "nightly-2023-11-01" components = [ "rust-src", "rustfmt", "llvm-tools-preview", "clippy" ] targets = [ "x86_64-unknown-linux-gnu", From d78c6070bddbf80319bb52bdb495d64bde1708d3 Mon Sep 17 00:00:00 2001 From: Tobias Breitwieser Date: Thu, 23 Nov 2023 21:57:34 +0100 Subject: [PATCH 02/16] heapless update and first desired state version --- Cargo.toml | 22 ++- examples/embassy-stm32-example/Cargo.toml | 8 +- examples/embassy-stm32-example/src/main.rs | 57 ++++-- examples/linux_mqtt/src/main.rs | 6 +- src/asynch/control.rs | 29 +++- src/asynch/mod.rs | 17 +- src/asynch/runner.rs | 120 ++++++++++--- src/asynch/state.rs | 191 +++++++++++++++++---- src/asynch/ublox_stack/dns.rs | 13 +- src/asynch/ublox_stack/mod.rs | 11 +- src/command/device_lock/impl_.rs | 2 +- src/command/file_system/responses.rs | 8 +- src/command/psn/types.rs | 3 +- src/config.rs | 14 +- src/error.rs | 2 + src/module_timing.rs | 2 +- 16 files changed, 390 insertions(+), 115 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bc72eec..b459e8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,9 +18,8 @@ doctest = false atat = { version = "0.20.0", features = ["derive", "bytes"] } embedded-hal = "=1.0.0-rc.1" embedded-nal = "0.7" -hash32 = "^0.2.1" -hash32-derive = "^0.1.0" -heapless = { version = "^0.7", features = ["serde"] } +hash32 = "^0.3" +heapless = { version = "^0.8", features = ["serde"] } nb = "^1" serde = { version = "^1", default-features = false, features = ["derive"] } ublox-sockets = { version = "0.5", optional = true } @@ -33,9 +32,12 @@ log = { version = "^0.4", default-features = false, optional = true } defmt = { version = "^0.3", optional = true } embedded-nal-async = { version = "0.6", optional = true } -futures = { version = "0.3.17", default-features = false, features = [ - "async-await", -] } +futures-util = { version = "0.3.29", default-features = false } +#futures = { version = "0.3.17", default-features = false, features = [ +# "async-await", +#] } + +embassy-futures = { version = "0.1", optional = true } embedded-io = "0.6" embedded-io-async = "0.6" @@ -43,14 +45,16 @@ embedded-io-async = "0.6" [features] default = ["socket-udp", "socket-tcp", "async", "ublox-sockets"] -async = ["dep:embedded-nal-async", "atat/async", "ublox-sockets?/async"] +async = ["dep:embedded-nal-async", "dep:embassy-futures", "atat/async", "ublox-sockets?/async"] defmt = [ "dep:defmt", "ublox-sockets?/defmt", "atat/defmt", - "heapless/defmt-impl", + "heapless/defmt-03", "embassy-time/defmt", + "embassy-sync/defmt", + "embassy-futures?/defmt", ] log = ["dep:log", "ublox-sockets?/log", "atat/log"] @@ -82,3 +86,5 @@ exclude = ["examples"] [patch.crates-io] ublox-sockets = { git = "https://github.com/BlackbirdHQ/ublox-sockets", branch = "feature/async-borrowed-sockets" } no-std-net = { git = "https://github.com/rushmorem/no-std-net", branch = "issue-15" } +#ublox-sockets = { path = "../ublox-sockets" } +atat = { path = "../atat/atat" } diff --git a/examples/embassy-stm32-example/Cargo.toml b/examples/embassy-stm32-example/Cargo.toml index 88ce71f..4f052db 100644 --- a/examples/embassy-stm32-example/Cargo.toml +++ b/examples/embassy-stm32-example/Cargo.toml @@ -18,16 +18,20 @@ defmt = "0.3.5" defmt-rtt = "0.4.0" panic-probe = { version = "0.3.1", features = ["print-defmt"] } -static_cell = { version = "1.2.0", features = ["nightly"]} +static_cell = { version = "2.0", features = ["nightly"]} atat = { version = "0.20.0", features = ["derive", "bytes", "defmt"] } ublox-cellular-rs = {version = "0.4.0", path = "../..", features = ["sara-r5", "defmt", "async"]} [patch.crates-io] ublox-sockets = { git = "https://github.com/BlackbirdHQ/ublox-sockets", branch = "feature/async-borrowed-sockets" } +atat = { git = "https://github.com/BlackbirdHQ/atat", branch = "master" } no-std-net = { git = "https://github.com/rushmorem/no-std-net", branch = "issue-15" } embassy-time = { package = "embassy-time", git = "https://github.com/embassy-rs/embassy", branch = "main" } - +embassy-sync = { package = "embassy-sync", git = "https://github.com/embassy-rs/embassy", branch = "main" } +embassy-futures = { package = "embassy-futures", git = "https://github.com/embassy-rs/embassy", branch = "main" } +#ublox-sockets = { path = "../../../ublox-sockets" } +#atat = { path = "../../../atat/atat" } [profile.dev] opt-level = "s" diff --git a/examples/embassy-stm32-example/src/main.rs b/examples/embassy-stm32-example/src/main.rs index 6a16de3..2e1bb69 100644 --- a/examples/embassy-stm32-example/src/main.rs +++ b/examples/embassy-stm32-example/src/main.rs @@ -29,6 +29,7 @@ use atat::asynch::AtatClient; use ublox_cellular::asynch::runner::Runner; use ublox_cellular::asynch::State; use ublox_cellular::command::{AT, Urc}; +use ublox_cellular::asynch::state::{LinkState, PowerState}; bind_interrupts!(struct Irqs { @@ -38,6 +39,7 @@ bind_interrupts!(struct Irqs { const INGRESS_BUF_SIZE: usize = 1024; const URC_CAPACITY: usize = 2; const URC_SUBSCRIBERS: usize = 2; +const MAX_DESIRED_STATE_LISTENERS: usize = 5; struct MyCelullarConfig { reset_pin: Option>, @@ -144,22 +146,53 @@ async fn main_task(spawner: Spawner) { let state = make_static!(State::new(client)); let (device, mut control, mut runner) = ublox_cellular::asynch::new(state, &buffers.urc_channel, celullar_config).await; - // defmt::info!("{:?}", runner.init().await); + // control.set_desired_state(PowerState::Connected).await; + + defmt::unwrap!(spawner.spawn(cellular_task(runner))); loop { + // loop { + // control.set_desired_state(PowerState::Connected).await; + // info!("set_desired_state(PowerState::Connected)"); + // Timer::after(Duration::from_millis(1000)).await; + // control.set_desired_state(PowerState::PowerDown).await; + // info!("set_desired_state(PowerState::PowerDown)"); + // Timer::after(Duration::from_millis(1000)).await; + // } // runner.init().await.unwrap(); - defmt::info!("{:?}", runner.is_alive().await); - if runner.is_alive().await != Ok(true){ - runner.init().await.unwrap(); - } - Timer::after(Duration::from_millis(1000)).await; - if runner.has_power().await == Ok(true){ - runner.power_down().await.unwrap(); + match control.power_state() { + PowerState::PowerDown => { + info!("PowerState::PowerDown"); + control.set_desired_state(PowerState::PowerUp).await; + info!("set_desired_state(PowerState::PowerUp)"); + } + PowerState::PowerUp => { + info!("PowerState::PowerUp"); + control.set_desired_state(PowerState::Alive).await; + info!("set_desired_state(PowerState::Alive)"); + } + PowerState::Alive => { + info!("PowerState::Alive"); + control.set_desired_state(PowerState::Initialized).await; + info!("set_desired_state(PowerState::Initialized)"); + } + PowerState::Initialized => { + info!("PowerState::Initialized"); + control.set_desired_state(PowerState::PowerDown).await; + info!("set_desired_state(PowerState::PowerDown)"); + } + PowerState::Connected => { + info!("PowerState::Connected"); + control.set_desired_state(PowerState::PowerDown).await; + info!("set_desired_state(PowerState::PowerDown)"); + } + PowerState::DataEstablished => { + info!("PowerState::DataEstablished"); + control.set_desired_state(PowerState::PowerDown).await; + info!("set_desired_state(PowerState::PowerDown)"); + } } Timer::after(Duration::from_millis(5000)).await; - if runner.has_power().await == Ok(false){ - runner.power_up().await.unwrap(); - } } defmt::unwrap!(spawner.spawn(cellular_task(runner))); @@ -180,7 +213,7 @@ async fn ingress_task( #[embassy_executor::task] async fn cellular_task( - runner: Runner<'static, atat::asynch::Client<'_, BufferedUartTx<'static, UART8>, {INGRESS_BUF_SIZE}>, MyCelullarConfig, {URC_CAPACITY}>, + runner: Runner<'static, atat::asynch::Client<'_, BufferedUartTx<'static, UART8>, {INGRESS_BUF_SIZE}>, MyCelullarConfig, {URC_CAPACITY}, {MAX_DESIRED_STATE_LISTENERS}>, ) -> ! { runner.run().await } diff --git a/examples/linux_mqtt/src/main.rs b/examples/linux_mqtt/src/main.rs index c37b6d1..5fcaf48 100644 --- a/examples/linux_mqtt/src/main.rs +++ b/examples/linux_mqtt/src/main.rs @@ -156,11 +156,11 @@ fn main() { SubscribeRequest { topics: Vec::from_slice(&[ SubscribeTopic { - topic_path: String::from("mqttrust/tester/subscriber"), + topic_path: String::try_from("mqttrust/tester/subscriber").unwrap(), qos: QoS::AtLeastOnce, }, SubscribeTopic { - topic_path: String::from("mqttrust/tester/subscriber2"), + topic_path: String::try_from("mqttrust/tester/subscriber2").unwrap(), qos: QoS::AtLeastOnce, }, ]) @@ -178,7 +178,7 @@ fn main() { // Subscribe @ http://www.hivemq.com/demos/websocket-client/ p.enqueue( PublishRequest::new( - String::from("fbmini/input/test_mini_1"), + String::try_from("fbmini/input/test_mini_1").unwrap(), format!("{{\"key\": \"Hello World from Factbird Mini - {}!\"}}", cnt) .as_bytes() .to_owned(), diff --git a/src/asynch/control.rs b/src/asynch/control.rs index c96035f..29c2166 100644 --- a/src/asynch/control.rs +++ b/src/asynch/control.rs @@ -6,16 +6,19 @@ use embassy_time::{with_timeout, Duration}; use crate::error::Error; -use super::state::LinkState; +use super::state::{LinkState, PowerState}; use super::{state, AtHandle}; -pub struct Control<'a, AT: AtatClient> { - state_ch: state::StateRunner<'a>, +pub struct Control<'a, AT: AtatClient, const MAX_STATE_LISTENERS: usize> { + state_ch: state::StateRunner<'a, MAX_STATE_LISTENERS>, at: AtHandle<'a, AT>, } -impl<'a, AT: AtatClient> Control<'a, AT> { - pub(crate) fn new(state_ch: state::StateRunner<'a>, at: AtHandle<'a, AT>) -> Self { +impl<'a, AT: AtatClient, const MAX_STATE_LISTENERS: usize> Control<'a, AT, MAX_STATE_LISTENERS> { + pub(crate) fn new( + state_ch: state::StateRunner<'a, MAX_STATE_LISTENERS>, + at: AtHandle<'a, AT>, + ) -> Self { Self { state_ch, at } } @@ -24,4 +27,20 @@ impl<'a, AT: AtatClient> Control<'a, AT> { Ok(()) } + + pub fn link_state(&mut self) -> LinkState { + self.state_ch.link_state() + } + + pub fn power_state(&mut self) -> PowerState { + self.state_ch.power_state() + } + + pub fn desired_state(&mut self) -> PowerState { + self.state_ch.desired_state() + } + + pub async fn set_desired_state(&mut self, ps: PowerState) { + self.state_ch.set_desired_state(ps).await; + } } diff --git a/src/asynch/mod.rs b/src/asynch/mod.rs index 4186903..3899596 100644 --- a/src/asynch/mod.rs +++ b/src/asynch/mod.rs @@ -3,7 +3,7 @@ pub mod runner; #[cfg(feature = "ublox-sockets")] pub mod ublox_stack; -pub(crate) mod state; +pub mod state; use crate::{command::Urc, config::CellularConfig}; use atat::{asynch::AtatClient, AtatUrcChannel}; @@ -24,12 +24,12 @@ impl<'d, AT: AtatClient> AtHandle<'d, AT> { } } -pub struct State { - ch: state::State, +pub struct State { + ch: state::State, at_handle: Mutex, } -impl State { +impl State { pub fn new(at_handle: AT) -> Self { Self { ch: state::State::new(), @@ -44,14 +44,15 @@ pub async fn new< SUB: AtatUrcChannel, C: CellularConfig, const URC_CAPACITY: usize, + const MAX_STATE_LISTENERS: usize, >( - state: &'a mut State, + state: &'a mut State, subscriber: &'a SUB, config: C, ) -> ( - Device<'a, AT, URC_CAPACITY>, - Control<'a, AT>, - Runner<'a, AT, C, URC_CAPACITY>, + Device<'a, AT, URC_CAPACITY, MAX_STATE_LISTENERS>, + Control<'a, AT, MAX_STATE_LISTENERS>, + Runner<'a, AT, C, URC_CAPACITY, MAX_STATE_LISTENERS>, ) { let (ch_runner, net_device) = state::new( &mut state.ch, diff --git a/src/asynch/runner.rs b/src/asynch/runner.rs index 785caa8..0a17936 100644 --- a/src/asynch/runner.rs +++ b/src/asynch/runner.rs @@ -4,6 +4,7 @@ use crate::{command::Urc, config::CellularConfig}; use super::state::{self, LinkState}; use crate::asynch::state::PowerState; +use crate::asynch::state::PowerState::PowerDown; use crate::command::control::types::{Circuit108Behaviour, Circuit109Behaviour, FlowControl}; use crate::command::control::{SetCircuit108Behaviour, SetCircuit109Behaviour, SetFlowControl}; use crate::command::device_lock::responses::PinStatus; @@ -23,29 +24,42 @@ use crate::error::Error; use crate::error::GenericError::Timeout; use crate::module_timing::{boot_time, reset_time}; use atat::{asynch::AtatClient, UrcSubscription}; +use embassy_futures::select::select; use embassy_time::{with_timeout, Duration, Timer}; use embedded_hal::digital::{InputPin, OutputPin}; -use futures::future::ok; use heapless::String; use no_std_net::{Ipv4Addr, Ipv6Addr}; +use embassy_futures::select::Either; + use super::AtHandle; /// Background runner for the Ublox Module. /// /// You must call `.run()` in a background task for the Ublox Module to operate. -pub struct Runner<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> { - ch: state::Runner<'d>, +pub struct Runner< + 'd, + AT: AtatClient, + C: CellularConfig, + const URC_CAPACITY: usize, + const MAX_STATE_LISTENERS: usize, +> { + ch: state::Runner<'d, MAX_STATE_LISTENERS>, at: AtHandle<'d, AT>, config: C, urc_subscription: UrcSubscription<'d, Urc, URC_CAPACITY, 2>, } -impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> - Runner<'d, AT, C, URC_CAPACITY> +impl< + 'd, + AT: AtatClient, + C: CellularConfig, + const URC_CAPACITY: usize, + const MAX_STATE_LISTENERS: usize, + > Runner<'d, AT, C, URC_CAPACITY, MAX_STATE_LISTENERS> { pub(crate) fn new( - ch: state::Runner<'d>, + ch: state::Runner<'d, MAX_STATE_LISTENERS>, at: AtHandle<'d, AT>, config: C, urc_subscription: UrcSubscription<'d, Urc, URC_CAPACITY, 2>, @@ -132,7 +146,7 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> debug!("Powered down"); Ok(()) } else { - defmt::warn!("No power pin configured"); + warn!("No power pin configured"); Ok(()) } } else { @@ -294,24 +308,80 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> pub async fn run(mut self) -> ! { loop { - let event = self.urc_subscription.next_message_pure().await; - match event { - // Handle network URCs - Urc::NetworkDetach => todo!(), - Urc::MobileStationDetach => todo!(), - Urc::NetworkDeactivate => todo!(), - Urc::MobileStationDeactivate => todo!(), - Urc::NetworkPDNDeactivate => todo!(), - Urc::MobileStationPDNDeactivate => todo!(), - Urc::SocketDataAvailable(_) => todo!(), - Urc::SocketDataAvailableUDP(_) => todo!(), - Urc::DataConnectionActivated(_) => todo!(), - Urc::DataConnectionDeactivated(_) => todo!(), - Urc::SocketClosed(_) => todo!(), - Urc::MessageWaitingIndication(_) => todo!(), - Urc::ExtendedPSNetworkRegistration(_) => todo!(), - Urc::HttpResponse(_) => todo!(), - }; + match select( + self.ch.state_runner().wait_for_desired_state_change(), + self.urc_subscription.next_message_pure(), + ) + .await + { + Either::First(desired_state) => { + info!("Desired state: {:?}", desired_state); + match desired_state { + Ok(PowerState::PowerDown) => { + self.power_down().await.ok(); + } + Ok(PowerState::PowerUp) => { + self.power_up().await.ok(); + } + Ok(PowerState::Initialized) => { + self.init_at().await.ok(); + } + Ok(PowerState::Alive) => { + self.is_alive().await.ok(); + } + Ok(PowerState::Connected) => { + todo!() + } + Ok(PowerState::DataEstablished) => { + todo!() + } + Err(err) => { + error!("Error in desired state: {:?}", err); + } + } + } + Either::Second(event) => { + match event { + // Handle network URCs + Urc::NetworkDetach => todo!(), + Urc::MobileStationDetach => todo!(), + Urc::NetworkDeactivate => todo!(), + Urc::MobileStationDeactivate => todo!(), + Urc::NetworkPDNDeactivate => todo!(), + Urc::MobileStationPDNDeactivate => todo!(), + Urc::SocketDataAvailable(_) => todo!(), + Urc::SocketDataAvailableUDP(_) => todo!(), + Urc::DataConnectionActivated(_) => todo!(), + Urc::DataConnectionDeactivated(_) => todo!(), + Urc::SocketClosed(_) => todo!(), + Urc::MessageWaitingIndication(_) => todo!(), + Urc::ExtendedPSNetworkRegistration(_) => todo!(), + Urc::HttpResponse(_) => todo!(), + }; + } + } + + // let desired_state = self.ch.state_runner().wait_for_desired_state_change().await; + // // let desired_state = self.ch.state_runner().desired_state(); + // info!("Desired state: {:?}", desired_state); + // let event = self.urc_subscription.next_message_pure().await; + // match event { + // // Handle network URCs + // Urc::NetworkDetach => todo!(), + // Urc::MobileStationDetach => todo!(), + // Urc::NetworkDeactivate => todo!(), + // Urc::MobileStationDeactivate => todo!(), + // Urc::NetworkPDNDeactivate => todo!(), + // Urc::MobileStationPDNDeactivate => todo!(), + // Urc::SocketDataAvailable(_) => todo!(), + // Urc::SocketDataAvailableUDP(_) => todo!(), + // Urc::DataConnectionActivated(_) => todo!(), + // Urc::DataConnectionDeactivated(_) => todo!(), + // Urc::SocketClosed(_) => todo!(), + // Urc::MessageWaitingIndication(_) => todo!(), + // Urc::ExtendedPSNetworkRegistration(_) => todo!(), + // Urc::HttpResponse(_) => todo!(), + // }; } } } diff --git a/src/asynch/state.rs b/src/asynch/state.rs index cfd67ba..43e27a4 100644 --- a/src/asynch/state.rs +++ b/src/asynch/state.rs @@ -8,6 +8,7 @@ use atat::asynch::AtatClient; use atat::UrcSubscription; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::pubsub::PubSubChannel; use embassy_sync::waitqueue::WakerRegistration; /// The link state of a network device. @@ -28,17 +29,20 @@ pub enum PowerState { PowerUp, Alive, Initialized, + Connected, + DataEstablished, } use crate::command::Urc; +use crate::error::Error; use super::AtHandle; -pub struct State { - inner: MaybeUninit, +pub struct State { + inner: MaybeUninit>, } -impl State { +impl State { pub const fn new() -> Self { Self { inner: MaybeUninit::uninit(), @@ -46,30 +50,35 @@ impl State { } } -struct StateInner { +struct StateInner { shared: Mutex>, + desired_state_pub_sub: PubSubChannel, } /// State of the LinkState pub struct Shared { link_state: LinkState, power_state: PowerState, + desired_state: PowerState, waker: WakerRegistration, } -pub struct Runner<'d> { +pub struct Runner<'d, const MAX_STATE_LISTENERS: usize> { shared: &'d Mutex>, + desired_state_pub_sub: &'d PubSubChannel, } #[derive(Clone, Copy)] -pub struct StateRunner<'d> { +pub struct StateRunner<'d, const MAX_STATE_LISTENERS: usize> { shared: &'d Mutex>, + desired_state_pub_sub: &'d PubSubChannel, } -impl<'d> Runner<'d> { - pub fn state_runner(&self) -> StateRunner<'d> { +impl<'d, const MAX_STATE_LISTENERS: usize> Runner<'d, MAX_STATE_LISTENERS> { + pub fn state_runner(&self) -> StateRunner<'d, MAX_STATE_LISTENERS> { StateRunner { shared: self.shared, + desired_state_pub_sub: self.desired_state_pub_sub, } } @@ -88,9 +97,20 @@ impl<'d> Runner<'d> { s.waker.wake(); }); } + + pub fn set_desired_state(&mut self, ps: PowerState) { + self.shared.lock(|s| { + let s = &mut *s.borrow_mut(); + s.desired_state = ps; + s.waker.wake(); + }); + self.desired_state_pub_sub + .immediate_publisher() + .publish_immediate(ps); + } } -impl<'d> StateRunner<'d> { +impl<'d, const MAX_STATE_LISTENERS: usize> StateRunner<'d, MAX_STATE_LISTENERS> { pub fn set_link_state(&self, state: LinkState) { self.shared.lock(|s| { let s = &mut *s.borrow_mut(); @@ -99,7 +119,7 @@ impl<'d> StateRunner<'d> { }); } - pub fn link_state(&mut self, cx: &mut Context) -> LinkState { + pub fn link_state_poll_fn(&mut self, cx: &mut Context) -> LinkState { self.shared.lock(|s| { let s = &mut *s.borrow_mut(); s.waker.register(cx.waker()); @@ -115,72 +135,183 @@ impl<'d> StateRunner<'d> { }); } - pub fn power_state(&mut self, cx: &mut Context) -> PowerState { + pub fn power_state_poll_fn(&mut self, cx: &mut Context) -> PowerState { self.shared.lock(|s| { let s = &mut *s.borrow_mut(); s.waker.register(cx.waker()); s.power_state }) } + + pub fn link_state(&mut self) -> LinkState { + self.shared.lock(|s| { + let s = &mut *s.borrow_mut(); + s.link_state + }) + } + + pub fn power_state(&mut self) -> PowerState { + self.shared.lock(|s| { + let s = &mut *s.borrow_mut(); + s.power_state + }) + } + + pub fn desired_state(&mut self) -> PowerState { + self.shared.lock(|s| { + let s = &mut *s.borrow_mut(); + s.desired_state + }) + } + + pub async fn set_desired_state(&mut self, ps: PowerState) { + self.shared.lock(|s| { + let s = &mut *s.borrow_mut(); + s.desired_state = ps; + s.waker.wake(); + }); + self.desired_state_pub_sub + .immediate_publisher() + .publish_immediate(ps); + } + + pub async fn wait_for_desired_state(&mut self, ps: PowerState) -> Result { + if self.desired_state() == ps { + info!("Desired state already set to {:?}, returning", ps); + return Ok(ps); + } + let mut sub = self + .desired_state_pub_sub + .subscriber() + .map_err(|x| Error::SubscriberOverflow(x))?; + loop { + let ps_now = sub.next_message_pure().await; + if ps_now == ps { + return Ok(ps_now); + } + } + } + + pub async fn wait_for_desired_state_change(&mut self) -> Result { + let mut sub = self + .desired_state_pub_sub + .subscriber() + .map_err(|x| Error::SubscriberOverflow(x))?; + Ok(sub.next_message_pure().await) + } } -pub fn new<'d, AT: AtatClient, const URC_CAPACITY: usize>( - state: &'d mut State, +pub fn new<'d, AT: AtatClient, const URC_CAPACITY: usize, const MAX_STATE_LISTENERS: usize>( + state: &'d mut State, at: AtHandle<'d, AT>, urc_subscription: UrcSubscription<'d, Urc, URC_CAPACITY, 2>, -) -> (Runner<'d>, Device<'d, AT, URC_CAPACITY>) { +) -> ( + Runner<'d, MAX_STATE_LISTENERS>, + Device<'d, AT, URC_CAPACITY, MAX_STATE_LISTENERS>, +) { // safety: this is a self-referential struct, however: // - it can't move while the `'d` borrow is active. // - when the borrow ends, the dangling references inside the MaybeUninit will never be used again. - let state_uninit: *mut MaybeUninit = - (&mut state.inner as *mut MaybeUninit).cast(); + let state_uninit: *mut MaybeUninit> = + (&mut state.inner as *mut MaybeUninit>).cast(); let state = unsafe { &mut *state_uninit }.write(StateInner { shared: Mutex::new(RefCell::new(Shared { link_state: LinkState::Down, power_state: PowerState::PowerDown, + desired_state: PowerState::PowerDown, waker: WakerRegistration::new(), })), + desired_state_pub_sub: + PubSubChannel::::new(), }); ( Runner { shared: &state.shared, + desired_state_pub_sub: &state.desired_state_pub_sub, }, Device { - shared: TestShared { - inner: &state.shared, - }, + shared: &state.shared, urc_subscription, at, + desired_state_pub_sub: &state.desired_state_pub_sub, }, ) } -pub struct TestShared<'d> { - inner: &'d Mutex>, -} - -pub struct Device<'d, AT: AtatClient, const URC_CAPACITY: usize> { - pub(crate) shared: TestShared<'d>, +pub struct Device<'d, AT: AtatClient, const URC_CAPACITY: usize, const MAX_STATE_LISTENERS: usize> { + pub(crate) shared: &'d Mutex>, + pub(crate) desired_state_pub_sub: + &'d PubSubChannel, pub(crate) at: AtHandle<'d, AT>, pub(crate) urc_subscription: UrcSubscription<'d, Urc, URC_CAPACITY, 2>, } -impl<'d> TestShared<'d> { - pub fn link_state(&mut self, cx: &mut Context) -> LinkState { - self.inner.lock(|s| { +impl<'d, AT: AtatClient, const URC_CAPACITY: usize, const MAX_STATE_LISTENERS: usize> + Device<'d, AT, URC_CAPACITY, MAX_STATE_LISTENERS> +{ + pub fn link_state_poll_fn(&mut self, cx: &mut Context) -> LinkState { + self.shared.lock(|s| { let s = &mut *s.borrow_mut(); s.waker.register(cx.waker()); s.link_state }) } - pub fn power_state(&mut self, cx: &mut Context) -> PowerState { - self.inner.lock(|s| { + pub fn power_state_poll_fn(&mut self, cx: &mut Context) -> PowerState { + self.shared.lock(|s| { let s = &mut *s.borrow_mut(); s.waker.register(cx.waker()); s.power_state }) } + + pub fn link_state(&mut self) -> LinkState { + self.shared.lock(|s| { + let s = &mut *s.borrow_mut(); + s.link_state + }) + } + + pub fn power_state(&mut self) -> PowerState { + self.shared.lock(|s| { + let s = &mut *s.borrow_mut(); + s.power_state + }) + } + + pub fn desired_state(&mut self) -> PowerState { + self.shared.lock(|s| { + let s = &mut *s.borrow_mut(); + s.desired_state + }) + } + + pub fn set_desired_state(&mut self, ps: PowerState) { + self.shared.lock(|s| { + let s = &mut *s.borrow_mut(); + s.desired_state = ps; + s.waker.wake(); + }); + self.desired_state_pub_sub + .immediate_publisher() + .publish_immediate(ps); + } + + pub async fn wait_for_desired_state(&mut self, ps: PowerState) -> Result { + if self.desired_state() == ps { + return Ok(ps); + } + let mut sub = self + .desired_state_pub_sub + .subscriber() + .map_err(|x| Error::SubscriberOverflow(x))?; + loop { + let ps_now = sub.next_message_pure().await; + if ps_now == ps { + return Ok(ps_now); + } + } + } } diff --git a/src/asynch/ublox_stack/dns.rs b/src/asynch/ublox_stack/dns.rs index e181a17..6503936 100644 --- a/src/asynch/ublox_stack/dns.rs +++ b/src/asynch/ublox_stack/dns.rs @@ -60,7 +60,7 @@ impl<'a> DnsSocket<'a> { { let mut s = self.stack.borrow_mut(); if s.dns_queries - .insert(heapless::String::from(name), DnsQuery::new()) + .insert(heapless::String::try_from(name).unwrap(), DnsQuery::new()) .is_err() { error!("Attempted to start more simultaneous DNS requests than the (4) supported"); @@ -93,22 +93,25 @@ impl<'a> DnsSocket<'a> { let drop = OnDrop::new(|| { let mut s = self.stack.borrow_mut(); - s.dns_queries.remove(&heapless::String::from(name)); + s.dns_queries + .remove(&heapless::String::try_from(name).unwrap()); }); let res = poll_fn(|cx| { let mut s = self.stack.borrow_mut(); let query = s .dns_queries - .get_mut(&heapless::String::from(name)) + .get_mut(&heapless::String::try_from(name).unwrap()) .unwrap(); match query.state { DnsState::Ok(ip) => { - s.dns_queries.remove(&heapless::String::from(name)); + s.dns_queries + .remove(&heapless::String::try_from(name).unwrap()); return Poll::Ready(Ok(ip)); } DnsState::Err => { - s.dns_queries.remove(&heapless::String::from(name)); + s.dns_queries + .remove(&heapless::String::try_from(name).unwrap()); return Poll::Ready(Err(Error::Failed)); } _ => { diff --git a/src/asynch/ublox_stack/mod.rs b/src/asynch/ublox_stack/mod.rs index 394ab68..1fe8e23 100644 --- a/src/asynch/ublox_stack/mod.rs +++ b/src/asynch/ublox_stack/mod.rs @@ -146,13 +146,16 @@ impl UbloxStack Poll::Ready(LinkState::Down), (false, LinkState::Up) => Poll::Ready(LinkState::Up), _ => Poll::Pending, - }, - ), + } + }), ) .await { diff --git a/src/command/device_lock/impl_.rs b/src/command/device_lock/impl_.rs index 538cbd2..4e405d8 100644 --- a/src/command/device_lock/impl_.rs +++ b/src/command/device_lock/impl_.rs @@ -148,7 +148,7 @@ mod test { }; let s = to_string::<_, 32>(&PinStatusCode::PhNetSubPin, "", options).unwrap(); - assert_eq!(s, String::<32>::from("PH-NETSUB PIN")) + assert_eq!(s, String::<32>::try_from("PH-NETSUB PIN").unwrap()) } #[test] diff --git a/src/command/file_system/responses.rs b/src/command/file_system/responses.rs index fa39f9f..010f843 100644 --- a/src/command/file_system/responses.rs +++ b/src/command/file_system/responses.rs @@ -36,7 +36,7 @@ mod tests { let resp = b"+URDFILE: \"response.txt\",655,\"HTTP/1.1 400 Bad Request\r\nContent-Type: application/json\r\nContent-Length: 74\r\nConnection: close\r\nDate: Wed, 14 Jul 2021 11:50:30 GMT\r\nx-amzn-RequestId: 021e3877-1e6d-447d-996e-4bc89087bdc5\r\nx-amz-apigw-id: CdVdFFJhjoEFc0w=\r\nX-Amzn-Trace-Id: Root=1-60eecf86-227f4f986747c3113846cd63;Sampled=1\r\nVia: 1.1 32e3b86ae254a231182567c0124af893.cloudfront.net (CloudFront), 1.1 2afacc6ad96dbba3f0b477cd95f16459.cloudfront.net (CloudFront)\r\nX-Amz-Cf-Pop: FRA2-C2\r\nX-Cache: Error from cloudfront\r\nX-Amz-Cf-Pop: FRA2-C2\r\nX-Amz-Cf-Id: FELxJa2hgelObvyEP16HS4yEK-emXa1NiMsRXl-rmarzg309KeD34g==\r\n\r\n{\"uuid\": \"what\"}\""; let exp = ReadFileResponse { - filename: String::from("response.txt"), + filename: String::try_from("response.txt").unwrap(), size: 655, data: Bytes::from_slice(b"\"HTTP/1.1 400 Bad Request\r\nContent-Type: application/json\r\nContent-Length: 74\r\nConnection: close\r\nDate: Wed, 14 Jul 2021 11:50:30 GMT\r\nx-amzn-RequestId: 021e3877-1e6d-447d-996e-4bc89087bdc5\r\nx-amz-apigw-id: CdVdFFJhjoEFc0w=\r\nX-Amzn-Trace-Id: Root=1-60eecf86-227f4f986747c3113846cd63;Sampled=1\r\nVia: 1.1 32e3b86ae254a231182567c0124af893.cloudfront.net (CloudFront), 1.1 2afacc6ad96dbba3f0b477cd95f16459.cloudfront.net (CloudFront)\r\nX-Amz-Cf-Pop: FRA2-C2\r\nX-Cache: Error from cloudfront\r\nX-Amz-Cf-Pop: FRA2-C2\r\nX-Amz-Cf-Id: FELxJa2hgelObvyEP16HS4yEK-emXa1NiMsRXl-rmarzg309KeD34g==\r\n\r\n{\"uuid\": \"what\"}\"").unwrap(), }; @@ -50,7 +50,7 @@ mod tests { let resp = b"+URDBLOCK: \"response.txt\",512,\"HTTP/1.1 404 Not Found\r\nContent-Type: application/json\r\nContent-Length: 25\r\nConnection: close\r\nDate: Mon, 19 Jul 2021 07:23:35 GMT\r\nx-amzn-RequestId: 4a50eb56-5c1a-4388-9a2f-a1966ba9c8a2\r\nx-amz-apigw-id: CtNCvF1SDoEF2dw=\r\nX-Amzn-Trace-Id: Root=1-60f52877-6f5b63ac154d314436832848;Sampled=1\r\nVia: 1.1 58b222ebbb6cc6c8c8c9a46127ae3a3e.cloudfront.net (CloudFront), 1.1 6fa33d47af6f4da7007689083cfe9b9c.cloudfront.net (CloudFront)\r\nX-Amz-Cf-Pop: FRA2-C2\r\nX-Cache: Error from cloudfront\r\nX-Amz-Cf-Pop: FRA2-C2\r\nX-Amz-\""; let exp = ReadBlockResponse { - filename: String::from("response.txt"), + filename: String::try_from("response.txt").unwrap(), size: 512, data: Bytes::from_slice(b"\"HTTP/1.1 404 Not Found\r\nContent-Type: application/json\r\nContent-Length: 25\r\nConnection: close\r\nDate: Mon, 19 Jul 2021 07:23:35 GMT\r\nx-amzn-RequestId: 4a50eb56-5c1a-4388-9a2f-a1966ba9c8a2\r\nx-amz-apigw-id: CtNCvF1SDoEF2dw=\r\nX-Amzn-Trace-Id: Root=1-60f52877-6f5b63ac154d314436832848;Sampled=1\r\nVia: 1.1 58b222ebbb6cc6c8c8c9a46127ae3a3e.cloudfront.net (CloudFront), 1.1 6fa33d47af6f4da7007689083cfe9b9c.cloudfront.net (CloudFront)\r\nX-Amz-Cf-Pop: FRA2-C2\r\nX-Cache: Error from cloudfront\r\nX-Amz-Cf-Pop: FRA2-C2\r\nX-Amz-\"").unwrap(), }; @@ -64,7 +64,7 @@ mod tests { let resp = b"+URDBLOCK: \"response.txt\",512,\"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: 2553\r\nConnection: close\r\nVary: Accept-Encoding\r\nDate: Mon, 19 Jul 2021 07:47:39 GMT\r\nx-amzn-RequestId: 436ba5b8-2aad-4089-a4fd-1b1c38773c87\r\nx-amz-apigw-id: CtQkMFE_DoEFUzg=\r\nX-Amzn-Trace-Id: Root=1-60f52e1a-0a05343260f3ba3331eea9d6;Sampled=1\r\nVia: 1.1 f99b5b46e77cfe9c3413f99dc8a4088c.cloudfront.net (CloudFront), 1.1 2f194b62c8c43859cbf5af8e53a8d2a7.cloudfront.net (CloudFront)\r\nX-Amz-Cf-Pop: FRA2-C2\r\nX-Cache: Miss from cloudfront\r\nX-Amz-Cf-Pop\""; let exp = ReadBlockResponse { - filename: String::from("response.txt"), + filename: String::try_from("response.txt").unwrap(), size: 512, data: Bytes::from_slice(b"\"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: 2553\r\nConnection: close\r\nVary: Accept-Encoding\r\nDate: Mon, 19 Jul 2021 07:47:39 GMT\r\nx-amzn-RequestId: 436ba5b8-2aad-4089-a4fd-1b1c38773c87\r\nx-amz-apigw-id: CtQkMFE_DoEFUzg=\r\nX-Amzn-Trace-Id: Root=1-60f52e1a-0a05343260f3ba3331eea9d6;Sampled=1\r\nVia: 1.1 f99b5b46e77cfe9c3413f99dc8a4088c.cloudfront.net (CloudFront), 1.1 2f194b62c8c43859cbf5af8e53a8d2a7.cloudfront.net (CloudFront)\r\nX-Amz-Cf-Pop: FRA2-C2\r\nX-Cache: Miss from cloudfront\r\nX-Amz-Cf-Pop\"").unwrap(), }; @@ -77,7 +77,7 @@ mod tests { let resp = b"+URDBLOCK: \"response.txt\",512,\": FRA2-C2\r\nX-Amz-Cf-Id: _5ZSzv-MrL1yMkdklMqbtggquF-NEe6lO36pw9cYsKJVEITyIdrbqQ==\r\n\r\n{\"Data\":{\"certificate_pem\":\"-----BEGIN CERTIFICATE-----\nMIIDWjCCAkKgAwIBAgIVANeQUG3TupBxD8FLSz+AAqxU7rU0MA0GCSqGSIb3DQEB\nCwUAME0xSzBJBgNVBAsMQkFtYXpvbiBXZWIgU2VydmljZXMgTz1BbWF6b24uY29t\nIEluYy4gTD1TZWF0dGxlIFNUPVdhc2hpbmd0b24gQz1VUzAeFw0yMTA3MjIwOTA2\nMTlaFw00OTEyMzEyMzU5NTlaMB4xHDAaBgNVBAMME0FXUyBJb1QgQ2VydGlmaWNh\ndGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqCFWHSRH35wSjP0SR\nQijGwEfWArPaqr33S80y9D\""; let exp = ReadBlockResponse { - filename: String::from("response.txt"), + filename: String::try_from("response.txt").unwrap(), size: 512, data: Bytes::from_slice(b"\": FRA2-C2\r\nX-Amz-Cf-Id: _5ZSzv-MrL1yMkdklMqbtggquF-NEe6lO36pw9cYsKJVEITyIdrbqQ==\r\n\r\n{\"Data\":{\"certificate_pem\":\"-----BEGIN CERTIFICATE-----\nMIIDWjCCAkKgAwIBAgIVANeQUG3TupBxD8FLSz+AAqxU7rU0MA0GCSqGSIb3DQEB\nCwUAME0xSzBJBgNVBAsMQkFtYXpvbiBXZWIgU2VydmljZXMgTz1BbWF6b24uY29t\nIEluYy4gTD1TZWF0dGxlIFNUPVdhc2hpbmd0b24gQz1VUzAeFw0yMTA3MjIwOTA2\nMTlaFw00OTEyMzEyMzU5NTlaMB4xHDAaBgNVBAMME0FXUyBJb1QgQ2VydGlmaWNh\ndGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqCFWHSRH35wSjP0SR\nQijGwEfWArPaqr33S80y9D\"").unwrap(), }; diff --git a/src/command/psn/types.rs b/src/command/psn/types.rs index c7e7e19..2195786 100644 --- a/src/command/psn/types.rs +++ b/src/command/psn/types.rs @@ -1,6 +1,5 @@ use atat::atat_derive::{AtatEnum, AtatLen}; use embedded_nal::IpAddr; -use hash32_derive::Hash32; use heapless::String; use serde::{Deserialize, Serialize}; @@ -647,7 +646,7 @@ pub enum EPSNetworkRegistrationStat { AttachedEmergencyOnly = 8, } -#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash32, Serialize, Deserialize, AtatLen)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, AtatLen)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct ProfileId(pub u8); diff --git a/src/config.rs b/src/config.rs index 9ffb488..1021df2 100644 --- a/src/config.rs +++ b/src/config.rs @@ -27,9 +27,11 @@ impl OutputPin for NoPin { } } -pub struct ReverseOutputPin> (pub P); +pub struct ReverseOutputPin>(pub P); -impl> ErrorType for ReverseOutputPin

{ type Error = Infallible; } +impl> ErrorType for ReverseOutputPin

{ + type Error = Infallible; +} impl> OutputPin for ReverseOutputPin

{ fn set_low(&mut self) -> Result<(), Self::Error> { @@ -48,11 +50,13 @@ impl> OutputPin for ReverseOutputPin

{ } } -pub struct ReverseInputPin> (pub P); +pub struct ReverseInputPin>(pub P); -impl > ErrorType for ReverseInputPin

{ type Error = Infallible; } +impl> ErrorType for ReverseInputPin

{ + type Error = Infallible; +} -impl > InputPin for ReverseInputPin

{ +impl> InputPin for ReverseInputPin

{ fn is_high(&self) -> Result { self.0.is_low() } diff --git a/src/error.rs b/src/error.rs index 7f057fb..2d825d2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -32,6 +32,8 @@ pub enum Error { _Unknown, IoPin, + + SubscriberOverflow(embassy_sync::pubsub::Error), } #[cfg(feature = "defmt")] diff --git a/src/module_timing.rs b/src/module_timing.rs index 58b16d4..3f04f95 100644 --- a/src/module_timing.rs +++ b/src/module_timing.rs @@ -23,7 +23,7 @@ pub fn pwr_off_time() -> Duration { Duration::from_millis(5000) } else if cfg!(feature = "toby-r2") { Duration::from_secs(1) - } else { + } else { Duration::from_secs(1) } } From 032393a3aa803b14951c77ab438bcb5826ecd541 Mon Sep 17 00:00:00 2001 From: Tobias Breitwieser Date: Mon, 4 Dec 2023 12:23:38 +0100 Subject: [PATCH 03/16] make subscriber count a constant --- examples/embassy-stm32-example/src/main.rs | 3 +- src/asynch/control.rs | 8 ++--- src/asynch/mod.rs | 16 ++++----- src/asynch/runner.rs | 10 +++--- src/asynch/state.rs | 39 ++++++++++++---------- 5 files changed, 39 insertions(+), 37 deletions(-) diff --git a/examples/embassy-stm32-example/src/main.rs b/examples/embassy-stm32-example/src/main.rs index 2e1bb69..1f00620 100644 --- a/examples/embassy-stm32-example/src/main.rs +++ b/examples/embassy-stm32-example/src/main.rs @@ -39,7 +39,6 @@ bind_interrupts!(struct Irqs { const INGRESS_BUF_SIZE: usize = 1024; const URC_CAPACITY: usize = 2; const URC_SUBSCRIBERS: usize = 2; -const MAX_DESIRED_STATE_LISTENERS: usize = 5; struct MyCelullarConfig { reset_pin: Option>, @@ -213,7 +212,7 @@ async fn ingress_task( #[embassy_executor::task] async fn cellular_task( - runner: Runner<'static, atat::asynch::Client<'_, BufferedUartTx<'static, UART8>, {INGRESS_BUF_SIZE}>, MyCelullarConfig, {URC_CAPACITY}, {MAX_DESIRED_STATE_LISTENERS}>, + runner: Runner<'static, atat::asynch::Client<'_, BufferedUartTx<'static, UART8>, {INGRESS_BUF_SIZE}>, MyCelullarConfig, {URC_CAPACITY}>, ) -> ! { runner.run().await } diff --git a/src/asynch/control.rs b/src/asynch/control.rs index 29c2166..39ad3fe 100644 --- a/src/asynch/control.rs +++ b/src/asynch/control.rs @@ -9,14 +9,14 @@ use crate::error::Error; use super::state::{LinkState, PowerState}; use super::{state, AtHandle}; -pub struct Control<'a, AT: AtatClient, const MAX_STATE_LISTENERS: usize> { - state_ch: state::StateRunner<'a, MAX_STATE_LISTENERS>, +pub struct Control<'a, AT: AtatClient> { + state_ch: state::StateRunner<'a>, at: AtHandle<'a, AT>, } -impl<'a, AT: AtatClient, const MAX_STATE_LISTENERS: usize> Control<'a, AT, MAX_STATE_LISTENERS> { +impl<'a, AT: AtatClient> Control<'a, AT> { pub(crate) fn new( - state_ch: state::StateRunner<'a, MAX_STATE_LISTENERS>, + state_ch: state::StateRunner<'a>, at: AtHandle<'a, AT>, ) -> Self { Self { state_ch, at } diff --git a/src/asynch/mod.rs b/src/asynch/mod.rs index 3899596..30b4abd 100644 --- a/src/asynch/mod.rs +++ b/src/asynch/mod.rs @@ -24,12 +24,12 @@ impl<'d, AT: AtatClient> AtHandle<'d, AT> { } } -pub struct State { - ch: state::State, +pub struct State { + ch: state::State, at_handle: Mutex, } -impl State { +impl State { pub fn new(at_handle: AT) -> Self { Self { ch: state::State::new(), @@ -44,15 +44,15 @@ pub async fn new< SUB: AtatUrcChannel, C: CellularConfig, const URC_CAPACITY: usize, - const MAX_STATE_LISTENERS: usize, + >( - state: &'a mut State, + state: &'a mut State, subscriber: &'a SUB, config: C, ) -> ( - Device<'a, AT, URC_CAPACITY, MAX_STATE_LISTENERS>, - Control<'a, AT, MAX_STATE_LISTENERS>, - Runner<'a, AT, C, URC_CAPACITY, MAX_STATE_LISTENERS>, + Device<'a, AT, URC_CAPACITY>, + Control<'a, AT>, + Runner<'a, AT, C, URC_CAPACITY>, ) { let (ch_runner, net_device) = state::new( &mut state.ch, diff --git a/src/asynch/runner.rs b/src/asynch/runner.rs index 0a17936..1ab7ac3 100644 --- a/src/asynch/runner.rs +++ b/src/asynch/runner.rs @@ -42,9 +42,9 @@ pub struct Runner< AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize, - const MAX_STATE_LISTENERS: usize, + > { - ch: state::Runner<'d, MAX_STATE_LISTENERS>, + ch: state::Runner<'d>, at: AtHandle<'d, AT>, config: C, urc_subscription: UrcSubscription<'d, Urc, URC_CAPACITY, 2>, @@ -55,11 +55,11 @@ impl< AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize, - const MAX_STATE_LISTENERS: usize, - > Runner<'d, AT, C, URC_CAPACITY, MAX_STATE_LISTENERS> + + > Runner<'d, AT, C, URC_CAPACITY> { pub(crate) fn new( - ch: state::Runner<'d, MAX_STATE_LISTENERS>, + ch: state::Runner<'d>, at: AtHandle<'d, AT>, config: C, urc_subscription: UrcSubscription<'d, Urc, URC_CAPACITY, 2>, diff --git a/src/asynch/state.rs b/src/asynch/state.rs index 43e27a4..5dbab9f 100644 --- a/src/asynch/state.rs +++ b/src/asynch/state.rs @@ -11,6 +11,9 @@ use embassy_sync::blocking_mutex::Mutex; use embassy_sync::pubsub::PubSubChannel; use embassy_sync::waitqueue::WakerRegistration; + +const MAX_STATE_LISTENERS: usize = 5; + /// The link state of a network device. #[derive(PartialEq, Eq, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -38,11 +41,11 @@ use crate::error::Error; use super::AtHandle; -pub struct State { - inner: MaybeUninit>, +pub struct State { + inner: MaybeUninit, } -impl State { +impl State { pub const fn new() -> Self { Self { inner: MaybeUninit::uninit(), @@ -50,7 +53,7 @@ impl State { } } -struct StateInner { +struct StateInner { shared: Mutex>, desired_state_pub_sub: PubSubChannel, } @@ -63,19 +66,19 @@ pub struct Shared { waker: WakerRegistration, } -pub struct Runner<'d, const MAX_STATE_LISTENERS: usize> { +pub struct Runner<'d> { shared: &'d Mutex>, desired_state_pub_sub: &'d PubSubChannel, } #[derive(Clone, Copy)] -pub struct StateRunner<'d, const MAX_STATE_LISTENERS: usize> { +pub struct StateRunner<'d> { shared: &'d Mutex>, desired_state_pub_sub: &'d PubSubChannel, } -impl<'d, const MAX_STATE_LISTENERS: usize> Runner<'d, MAX_STATE_LISTENERS> { - pub fn state_runner(&self) -> StateRunner<'d, MAX_STATE_LISTENERS> { +impl<'d> Runner<'d> { + pub fn state_runner(&self) -> StateRunner<'d> { StateRunner { shared: self.shared, desired_state_pub_sub: self.desired_state_pub_sub, @@ -110,7 +113,7 @@ impl<'d, const MAX_STATE_LISTENERS: usize> Runner<'d, MAX_STATE_LISTENERS> { } } -impl<'d, const MAX_STATE_LISTENERS: usize> StateRunner<'d, MAX_STATE_LISTENERS> { +impl<'d> StateRunner<'d> { pub fn set_link_state(&self, state: LinkState) { self.shared.lock(|s| { let s = &mut *s.borrow_mut(); @@ -201,19 +204,19 @@ impl<'d, const MAX_STATE_LISTENERS: usize> StateRunner<'d, MAX_STATE_LISTENERS> } } -pub fn new<'d, AT: AtatClient, const URC_CAPACITY: usize, const MAX_STATE_LISTENERS: usize>( - state: &'d mut State, +pub fn new<'d, AT: AtatClient, const URC_CAPACITY: usize>( + state: &'d mut State, at: AtHandle<'d, AT>, urc_subscription: UrcSubscription<'d, Urc, URC_CAPACITY, 2>, ) -> ( - Runner<'d, MAX_STATE_LISTENERS>, - Device<'d, AT, URC_CAPACITY, MAX_STATE_LISTENERS>, + Runner<'d>, + Device<'d, AT, URC_CAPACITY>, ) { // safety: this is a self-referential struct, however: // - it can't move while the `'d` borrow is active. // - when the borrow ends, the dangling references inside the MaybeUninit will never be used again. - let state_uninit: *mut MaybeUninit> = - (&mut state.inner as *mut MaybeUninit>).cast(); + let state_uninit: *mut MaybeUninit = + (&mut state.inner as *mut MaybeUninit).cast(); let state = unsafe { &mut *state_uninit }.write(StateInner { shared: Mutex::new(RefCell::new(Shared { @@ -240,7 +243,7 @@ pub fn new<'d, AT: AtatClient, const URC_CAPACITY: usize, const MAX_STATE_LISTEN ) } -pub struct Device<'d, AT: AtatClient, const URC_CAPACITY: usize, const MAX_STATE_LISTENERS: usize> { +pub struct Device<'d, AT: AtatClient, const URC_CAPACITY: usize> { pub(crate) shared: &'d Mutex>, pub(crate) desired_state_pub_sub: &'d PubSubChannel, @@ -248,8 +251,8 @@ pub struct Device<'d, AT: AtatClient, const URC_CAPACITY: usize, const MAX_STATE pub(crate) urc_subscription: UrcSubscription<'d, Urc, URC_CAPACITY, 2>, } -impl<'d, AT: AtatClient, const URC_CAPACITY: usize, const MAX_STATE_LISTENERS: usize> - Device<'d, AT, URC_CAPACITY, MAX_STATE_LISTENERS> +impl<'d, AT: AtatClient, const URC_CAPACITY: usize> + Device<'d, AT, URC_CAPACITY> { pub fn link_state_poll_fn(&mut self, cx: &mut Context) -> LinkState { self.shared.lock(|s| { From d8f41a2d56b24814cfd46b0e43491eb78ee8f046 Mon Sep 17 00:00:00 2001 From: Tobias Breitwieser Date: Mon, 4 Dec 2023 12:34:54 +0100 Subject: [PATCH 04/16] rename PowerState to OperationState --- examples/embassy-stm32-example/src/main.rs | 26 ++++++------ src/asynch/control.rs | 8 ++-- src/asynch/runner.rs | 32 +++++++-------- src/asynch/state.rs | 48 +++++++++++----------- 4 files changed, 57 insertions(+), 57 deletions(-) diff --git a/examples/embassy-stm32-example/src/main.rs b/examples/embassy-stm32-example/src/main.rs index 1f00620..f089e55 100644 --- a/examples/embassy-stm32-example/src/main.rs +++ b/examples/embassy-stm32-example/src/main.rs @@ -29,7 +29,7 @@ use atat::asynch::AtatClient; use ublox_cellular::asynch::runner::Runner; use ublox_cellular::asynch::State; use ublox_cellular::command::{AT, Urc}; -use ublox_cellular::asynch::state::{LinkState, PowerState}; +use ublox_cellular::asynch::state::{LinkState, OperationState}; bind_interrupts!(struct Irqs { @@ -160,34 +160,34 @@ async fn main_task(spawner: Spawner) { // } // runner.init().await.unwrap(); match control.power_state() { - PowerState::PowerDown => { + OperationState::PowerDown => { info!("PowerState::PowerDown"); - control.set_desired_state(PowerState::PowerUp).await; + control.set_desired_state(OperationState::PowerUp).await; info!("set_desired_state(PowerState::PowerUp)"); } - PowerState::PowerUp => { + OperationState::PowerUp => { info!("PowerState::PowerUp"); - control.set_desired_state(PowerState::Alive).await; + control.set_desired_state(OperationState::Alive).await; info!("set_desired_state(PowerState::Alive)"); } - PowerState::Alive => { + OperationState::Alive => { info!("PowerState::Alive"); - control.set_desired_state(PowerState::Initialized).await; + control.set_desired_state(OperationState::Initialized).await; info!("set_desired_state(PowerState::Initialized)"); } - PowerState::Initialized => { + OperationState::Initialized => { info!("PowerState::Initialized"); - control.set_desired_state(PowerState::PowerDown).await; + control.set_desired_state(OperationState::PowerDown).await; info!("set_desired_state(PowerState::PowerDown)"); } - PowerState::Connected => { + OperationState::Connected => { info!("PowerState::Connected"); - control.set_desired_state(PowerState::PowerDown).await; + control.set_desired_state(OperationState::PowerDown).await; info!("set_desired_state(PowerState::PowerDown)"); } - PowerState::DataEstablished => { + OperationState::DataEstablished => { info!("PowerState::DataEstablished"); - control.set_desired_state(PowerState::PowerDown).await; + control.set_desired_state(OperationState::PowerDown).await; info!("set_desired_state(PowerState::PowerDown)"); } } diff --git a/src/asynch/control.rs b/src/asynch/control.rs index 39ad3fe..6c79d88 100644 --- a/src/asynch/control.rs +++ b/src/asynch/control.rs @@ -6,7 +6,7 @@ use embassy_time::{with_timeout, Duration}; use crate::error::Error; -use super::state::{LinkState, PowerState}; +use super::state::{LinkState, OperationState}; use super::{state, AtHandle}; pub struct Control<'a, AT: AtatClient> { @@ -32,15 +32,15 @@ impl<'a, AT: AtatClient> Control<'a, AT> { self.state_ch.link_state() } - pub fn power_state(&mut self) -> PowerState { + pub fn power_state(&mut self) -> OperationState { self.state_ch.power_state() } - pub fn desired_state(&mut self) -> PowerState { + pub fn desired_state(&mut self) -> OperationState { self.state_ch.desired_state() } - pub async fn set_desired_state(&mut self, ps: PowerState) { + pub async fn set_desired_state(&mut self, ps: OperationState) { self.state_ch.set_desired_state(ps).await; } } diff --git a/src/asynch/runner.rs b/src/asynch/runner.rs index 1ab7ac3..81a0ef1 100644 --- a/src/asynch/runner.rs +++ b/src/asynch/runner.rs @@ -3,8 +3,8 @@ use core::str::FromStr; use crate::{command::Urc, config::CellularConfig}; use super::state::{self, LinkState}; -use crate::asynch::state::PowerState; -use crate::asynch::state::PowerState::PowerDown; +use crate::asynch::state::OperationState; +use crate::asynch::state::OperationState::PowerDown; use crate::command::control::types::{Circuit108Behaviour, Circuit109Behaviour, FlowControl}; use crate::command::control::{SetCircuit108Behaviour, SetCircuit109Behaviour, SetFlowControl}; use crate::command::device_lock::responses::PinStatus; @@ -94,7 +94,7 @@ impl< let alive = match self.at.send(AT).await { Ok(_) => { - self.ch.set_power_state(PowerState::Alive); + self.ch.set_power_state(OperationState::Alive); Ok(true) } Err(err) => return Err(Error::Atat(err)), @@ -105,15 +105,15 @@ impl< pub async fn has_power(&mut self) -> Result { if let Some(pin) = self.config.vint_pin() { if pin.is_high().map_err(|_| Error::IoPin)? { - self.ch.set_power_state(PowerState::PowerUp); + self.ch.set_power_state(OperationState::PowerUp); Ok(true) } else { - self.ch.set_power_state(PowerState::PowerDown); + self.ch.set_power_state(OperationState::PowerDown); Ok(false) } } else { info!("No VInt pin configured"); - self.ch.set_power_state(PowerState::PowerUp); + self.ch.set_power_state(OperationState::PowerUp); Ok(true) } } @@ -124,7 +124,7 @@ impl< pin.set_low().map_err(|_| Error::IoPin)?; Timer::after(crate::module_timing::pwr_on_time()).await; pin.set_high().map_err(|_| Error::IoPin)?; - self.ch.set_power_state(PowerState::PowerUp); + self.ch.set_power_state(OperationState::PowerUp); debug!("Powered up"); Ok(()) } else { @@ -142,7 +142,7 @@ impl< pin.set_low().map_err(|_| Error::IoPin)?; Timer::after(crate::module_timing::pwr_off_time()).await; pin.set_high().map_err(|_| Error::IoPin)?; - self.ch.set_power_state(PowerState::PowerDown); + self.ch.set_power_state(OperationState::PowerDown); debug!("Powered down"); Ok(()) } else { @@ -248,7 +248,7 @@ impl< .await?; } - self.ch.set_power_state(PowerState::Initialized); + self.ch.set_power_state(OperationState::Initialized); Ok(()) } @@ -295,7 +295,7 @@ impl< Timer::after(reset_time()).await; pin.set_high().ok(); Timer::after(boot_time()).await; - self.ch.set_power_state(PowerState::PowerUp); + self.ch.set_power_state(OperationState::PowerUp); } else { warn!("No reset pin configured"); } @@ -317,22 +317,22 @@ impl< Either::First(desired_state) => { info!("Desired state: {:?}", desired_state); match desired_state { - Ok(PowerState::PowerDown) => { + Ok(OperationState::PowerDown) => { self.power_down().await.ok(); } - Ok(PowerState::PowerUp) => { + Ok(OperationState::PowerUp) => { self.power_up().await.ok(); } - Ok(PowerState::Initialized) => { + Ok(OperationState::Initialized) => { self.init_at().await.ok(); } - Ok(PowerState::Alive) => { + Ok(OperationState::Alive) => { self.is_alive().await.ok(); } - Ok(PowerState::Connected) => { + Ok(OperationState::Connected) => { todo!() } - Ok(PowerState::DataEstablished) => { + Ok(OperationState::DataEstablished) => { todo!() } Err(err) => { diff --git a/src/asynch/state.rs b/src/asynch/state.rs index 5dbab9f..e75ea2b 100644 --- a/src/asynch/state.rs +++ b/src/asynch/state.rs @@ -27,7 +27,7 @@ pub enum LinkState { /// If the celular modem is up and responding to AT. #[derive(PartialEq, Eq, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum PowerState { +pub enum OperationState { PowerDown, PowerUp, Alive, @@ -55,26 +55,26 @@ impl State { struct StateInner { shared: Mutex>, - desired_state_pub_sub: PubSubChannel, + desired_state_pub_sub: PubSubChannel, } /// State of the LinkState pub struct Shared { link_state: LinkState, - power_state: PowerState, - desired_state: PowerState, + power_state: OperationState, + desired_state: OperationState, waker: WakerRegistration, } pub struct Runner<'d> { shared: &'d Mutex>, - desired_state_pub_sub: &'d PubSubChannel, + desired_state_pub_sub: &'d PubSubChannel, } #[derive(Clone, Copy)] pub struct StateRunner<'d> { shared: &'d Mutex>, - desired_state_pub_sub: &'d PubSubChannel, + desired_state_pub_sub: &'d PubSubChannel, } impl<'d> Runner<'d> { @@ -93,7 +93,7 @@ impl<'d> Runner<'d> { }); } - pub fn set_power_state(&mut self, state: PowerState) { + pub fn set_power_state(&mut self, state: OperationState) { self.shared.lock(|s| { let s = &mut *s.borrow_mut(); s.power_state = state; @@ -101,7 +101,7 @@ impl<'d> Runner<'d> { }); } - pub fn set_desired_state(&mut self, ps: PowerState) { + pub fn set_desired_state(&mut self, ps: OperationState) { self.shared.lock(|s| { let s = &mut *s.borrow_mut(); s.desired_state = ps; @@ -130,7 +130,7 @@ impl<'d> StateRunner<'d> { }) } - pub fn set_power_state(&self, state: PowerState) { + pub fn set_power_state(&self, state: OperationState) { self.shared.lock(|s| { let s = &mut *s.borrow_mut(); s.power_state = state; @@ -138,7 +138,7 @@ impl<'d> StateRunner<'d> { }); } - pub fn power_state_poll_fn(&mut self, cx: &mut Context) -> PowerState { + pub fn power_state_poll_fn(&mut self, cx: &mut Context) -> OperationState { self.shared.lock(|s| { let s = &mut *s.borrow_mut(); s.waker.register(cx.waker()); @@ -153,21 +153,21 @@ impl<'d> StateRunner<'d> { }) } - pub fn power_state(&mut self) -> PowerState { + pub fn power_state(&mut self) -> OperationState { self.shared.lock(|s| { let s = &mut *s.borrow_mut(); s.power_state }) } - pub fn desired_state(&mut self) -> PowerState { + pub fn desired_state(&mut self) -> OperationState { self.shared.lock(|s| { let s = &mut *s.borrow_mut(); s.desired_state }) } - pub async fn set_desired_state(&mut self, ps: PowerState) { + pub async fn set_desired_state(&mut self, ps: OperationState) { self.shared.lock(|s| { let s = &mut *s.borrow_mut(); s.desired_state = ps; @@ -178,7 +178,7 @@ impl<'d> StateRunner<'d> { .publish_immediate(ps); } - pub async fn wait_for_desired_state(&mut self, ps: PowerState) -> Result { + pub async fn wait_for_desired_state(&mut self, ps: OperationState) -> Result { if self.desired_state() == ps { info!("Desired state already set to {:?}, returning", ps); return Ok(ps); @@ -195,7 +195,7 @@ impl<'d> StateRunner<'d> { } } - pub async fn wait_for_desired_state_change(&mut self) -> Result { + pub async fn wait_for_desired_state_change(&mut self) -> Result { let mut sub = self .desired_state_pub_sub .subscriber() @@ -221,12 +221,12 @@ pub fn new<'d, AT: AtatClient, const URC_CAPACITY: usize>( let state = unsafe { &mut *state_uninit }.write(StateInner { shared: Mutex::new(RefCell::new(Shared { link_state: LinkState::Down, - power_state: PowerState::PowerDown, - desired_state: PowerState::PowerDown, + power_state: OperationState::PowerDown, + desired_state: OperationState::PowerDown, waker: WakerRegistration::new(), })), desired_state_pub_sub: - PubSubChannel::::new(), + PubSubChannel::::new(), }); ( @@ -246,7 +246,7 @@ pub fn new<'d, AT: AtatClient, const URC_CAPACITY: usize>( pub struct Device<'d, AT: AtatClient, const URC_CAPACITY: usize> { pub(crate) shared: &'d Mutex>, pub(crate) desired_state_pub_sub: - &'d PubSubChannel, + &'d PubSubChannel, pub(crate) at: AtHandle<'d, AT>, pub(crate) urc_subscription: UrcSubscription<'d, Urc, URC_CAPACITY, 2>, } @@ -262,7 +262,7 @@ impl<'d, AT: AtatClient, const URC_CAPACITY: usize> }) } - pub fn power_state_poll_fn(&mut self, cx: &mut Context) -> PowerState { + pub fn power_state_poll_fn(&mut self, cx: &mut Context) -> OperationState { self.shared.lock(|s| { let s = &mut *s.borrow_mut(); s.waker.register(cx.waker()); @@ -277,21 +277,21 @@ impl<'d, AT: AtatClient, const URC_CAPACITY: usize> }) } - pub fn power_state(&mut self) -> PowerState { + pub fn power_state(&mut self) -> OperationState { self.shared.lock(|s| { let s = &mut *s.borrow_mut(); s.power_state }) } - pub fn desired_state(&mut self) -> PowerState { + pub fn desired_state(&mut self) -> OperationState { self.shared.lock(|s| { let s = &mut *s.borrow_mut(); s.desired_state }) } - pub fn set_desired_state(&mut self, ps: PowerState) { + pub fn set_desired_state(&mut self, ps: OperationState) { self.shared.lock(|s| { let s = &mut *s.borrow_mut(); s.desired_state = ps; @@ -302,7 +302,7 @@ impl<'d, AT: AtatClient, const URC_CAPACITY: usize> .publish_immediate(ps); } - pub async fn wait_for_desired_state(&mut self, ps: PowerState) -> Result { + pub async fn wait_for_desired_state(&mut self, ps: OperationState) -> Result { if self.desired_state() == ps { return Ok(ps); } From 59ae613022c121c64a5694454ebcb95b2868d215 Mon Sep 17 00:00:00 2001 From: Tobias Breitwieser Date: Mon, 4 Dec 2023 12:36:16 +0100 Subject: [PATCH 05/16] fmt --- src/asynch/control.rs | 5 +---- src/asynch/mod.rs | 1 - src/asynch/runner.rs | 17 +++-------------- src/asynch/state.rs | 35 +++++++++++++++++++++-------------- 4 files changed, 25 insertions(+), 33 deletions(-) diff --git a/src/asynch/control.rs b/src/asynch/control.rs index 6c79d88..c9d9b3d 100644 --- a/src/asynch/control.rs +++ b/src/asynch/control.rs @@ -15,10 +15,7 @@ pub struct Control<'a, AT: AtatClient> { } impl<'a, AT: AtatClient> Control<'a, AT> { - pub(crate) fn new( - state_ch: state::StateRunner<'a>, - at: AtHandle<'a, AT>, - ) -> Self { + pub(crate) fn new(state_ch: state::StateRunner<'a>, at: AtHandle<'a, AT>) -> Self { Self { state_ch, at } } diff --git a/src/asynch/mod.rs b/src/asynch/mod.rs index 30b4abd..bd3c56c 100644 --- a/src/asynch/mod.rs +++ b/src/asynch/mod.rs @@ -44,7 +44,6 @@ pub async fn new< SUB: AtatUrcChannel, C: CellularConfig, const URC_CAPACITY: usize, - >( state: &'a mut State, subscriber: &'a SUB, diff --git a/src/asynch/runner.rs b/src/asynch/runner.rs index 81a0ef1..94157a2 100644 --- a/src/asynch/runner.rs +++ b/src/asynch/runner.rs @@ -37,26 +37,15 @@ use super::AtHandle; /// Background runner for the Ublox Module. /// /// You must call `.run()` in a background task for the Ublox Module to operate. -pub struct Runner< - 'd, - AT: AtatClient, - C: CellularConfig, - const URC_CAPACITY: usize, - -> { +pub struct Runner<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> { ch: state::Runner<'d>, at: AtHandle<'d, AT>, config: C, urc_subscription: UrcSubscription<'d, Urc, URC_CAPACITY, 2>, } -impl< - 'd, - AT: AtatClient, - C: CellularConfig, - const URC_CAPACITY: usize, - - > Runner<'d, AT, C, URC_CAPACITY> +impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> + Runner<'d, AT, C, URC_CAPACITY> { pub(crate) fn new( ch: state::Runner<'d>, diff --git a/src/asynch/state.rs b/src/asynch/state.rs index e75ea2b..629521b 100644 --- a/src/asynch/state.rs +++ b/src/asynch/state.rs @@ -11,7 +11,6 @@ use embassy_sync::blocking_mutex::Mutex; use embassy_sync::pubsub::PubSubChannel; use embassy_sync::waitqueue::WakerRegistration; - const MAX_STATE_LISTENERS: usize = 5; /// The link state of a network device. @@ -68,13 +67,15 @@ pub struct Shared { pub struct Runner<'d> { shared: &'d Mutex>, - desired_state_pub_sub: &'d PubSubChannel, + desired_state_pub_sub: + &'d PubSubChannel, } #[derive(Clone, Copy)] pub struct StateRunner<'d> { shared: &'d Mutex>, - desired_state_pub_sub: &'d PubSubChannel, + desired_state_pub_sub: + &'d PubSubChannel, } impl<'d> Runner<'d> { @@ -178,7 +179,10 @@ impl<'d> StateRunner<'d> { .publish_immediate(ps); } - pub async fn wait_for_desired_state(&mut self, ps: OperationState) -> Result { + pub async fn wait_for_desired_state( + &mut self, + ps: OperationState, + ) -> Result { if self.desired_state() == ps { info!("Desired state already set to {:?}, returning", ps); return Ok(ps); @@ -208,10 +212,7 @@ pub fn new<'d, AT: AtatClient, const URC_CAPACITY: usize>( state: &'d mut State, at: AtHandle<'d, AT>, urc_subscription: UrcSubscription<'d, Urc, URC_CAPACITY, 2>, -) -> ( - Runner<'d>, - Device<'d, AT, URC_CAPACITY>, -) { +) -> (Runner<'d>, Device<'d, AT, URC_CAPACITY>) { // safety: this is a self-referential struct, however: // - it can't move while the `'d` borrow is active. // - when the borrow ends, the dangling references inside the MaybeUninit will never be used again. @@ -225,8 +226,13 @@ pub fn new<'d, AT: AtatClient, const URC_CAPACITY: usize>( desired_state: OperationState::PowerDown, waker: WakerRegistration::new(), })), - desired_state_pub_sub: - PubSubChannel::::new(), + desired_state_pub_sub: PubSubChannel::< + NoopRawMutex, + OperationState, + 1, + MAX_STATE_LISTENERS, + 1, + >::new(), }); ( @@ -251,9 +257,7 @@ pub struct Device<'d, AT: AtatClient, const URC_CAPACITY: usize> { pub(crate) urc_subscription: UrcSubscription<'d, Urc, URC_CAPACITY, 2>, } -impl<'d, AT: AtatClient, const URC_CAPACITY: usize> - Device<'d, AT, URC_CAPACITY> -{ +impl<'d, AT: AtatClient, const URC_CAPACITY: usize> Device<'d, AT, URC_CAPACITY> { pub fn link_state_poll_fn(&mut self, cx: &mut Context) -> LinkState { self.shared.lock(|s| { let s = &mut *s.borrow_mut(); @@ -302,7 +306,10 @@ impl<'d, AT: AtatClient, const URC_CAPACITY: usize> .publish_immediate(ps); } - pub async fn wait_for_desired_state(&mut self, ps: OperationState) -> Result { + pub async fn wait_for_desired_state( + &mut self, + ps: OperationState, + ) -> Result { if self.desired_state() == ps { return Ok(ps); } From 0e005f990546ae6061d6e5f9cedbc679ebabdc77 Mon Sep 17 00:00:00 2001 From: Tobias Breitwieser Date: Sun, 24 Dec 2023 01:20:52 +0100 Subject: [PATCH 06/16] first state transition state machine --- src/asynch/runner.rs | 156 +++++++++++++++++++++++-------------------- src/asynch/state.rs | 17 ++++- 2 files changed, 98 insertions(+), 75 deletions(-) diff --git a/src/asynch/runner.rs b/src/asynch/runner.rs index 94157a2..1f4dfc5 100644 --- a/src/asynch/runner.rs +++ b/src/asynch/runner.rs @@ -4,7 +4,7 @@ use crate::{command::Urc, config::CellularConfig}; use super::state::{self, LinkState}; use crate::asynch::state::OperationState; -use crate::asynch::state::OperationState::PowerDown; +use crate::asynch::state::OperationState::{PowerDown, PowerUp}; use crate::command::control::types::{Circuit108Behaviour, Circuit109Behaviour, FlowControl}; use crate::command::control::{SetCircuit108Behaviour, SetCircuit109Behaviour, SetFlowControl}; use crate::command::device_lock::responses::PinStatus; @@ -77,32 +77,30 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> } pub async fn is_alive(&mut self) -> Result { - if !self.has_power().await? { - return Ok(false); + let has_power = self.has_power().await?; + if !has_power { + return Err(Error::PoweredDown); } let alive = match self.at.send(AT).await { Ok(_) => { - self.ch.set_power_state(OperationState::Alive); - Ok(true) + return Ok(true); + } + Err(err) => { + return Err(Error::Atat(err)); } - Err(err) => return Err(Error::Atat(err)), }; - alive } pub async fn has_power(&mut self) -> Result { if let Some(pin) = self.config.vint_pin() { if pin.is_high().map_err(|_| Error::IoPin)? { - self.ch.set_power_state(OperationState::PowerUp); Ok(true) } else { - self.ch.set_power_state(OperationState::PowerDown); Ok(false) } } else { info!("No VInt pin configured"); - self.ch.set_power_state(OperationState::PowerUp); Ok(true) } } @@ -236,9 +234,6 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> }) .await?; } - - self.ch.set_power_state(OperationState::Initialized); - Ok(()) } @@ -284,7 +279,7 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> Timer::after(reset_time()).await; pin.set_high().ok(); Timer::after(boot_time()).await; - self.ch.set_power_state(OperationState::PowerUp); + self.is_alive().await?; } else { warn!("No reset pin configured"); } @@ -305,72 +300,85 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> { Either::First(desired_state) => { info!("Desired state: {:?}", desired_state); - match desired_state { - Ok(OperationState::PowerDown) => { - self.power_down().await.ok(); - } - Ok(OperationState::PowerUp) => { - self.power_up().await.ok(); - } - Ok(OperationState::Initialized) => { - self.init_at().await.ok(); - } - Ok(OperationState::Alive) => { - self.is_alive().await.ok(); - } - Ok(OperationState::Connected) => { - todo!() - } - Ok(OperationState::DataEstablished) => { - todo!() - } - Err(err) => { - error!("Error in desired state: {:?}", err); + if let Err(err) = desired_state { + error!("Error in desired_state retrival: {:?}", err); + continue; + } + let desired_state = desired_state.unwrap(); + if 0 < desired_state as isize - self.ch.state_runner().power_state() as isize { + self.power_down().await.ok(); + self.ch.set_power_state(OperationState::PowerDown); + } + let start_state = self.ch.state_runner().power_state() as isize; + let steps = desired_state as isize - start_state; + for step in 0..steps { + let next_state = start_state + step; + match OperationState::from(next_state) { + Some(OperationState::PowerDown) => {} + Some(OperationState::PowerUp) => match self.power_up().await { + Ok(_) => { + self.ch.set_power_state(OperationState::PowerUp); + } + Err(err) => { + error!("Error in power_up: {:?}", err); + break; + } + }, + Some(OperationState::Alive) => match self.is_alive().await { + Ok(_) => { + self.ch.set_power_state(OperationState::Alive); + } + Err(err) => { + error!("Error in is_alive: {:?}", err); + break; + } + }, + Some(OperationState::Initialized) => match self.init_at().await { + Ok(_) => { + self.ch.set_power_state(OperationState::Initialized); + } + Err(err) => { + error!("Error in init_at: {:?}", err); + break; + } + }, + Some(OperationState::Connected) => { + todo!() + } + Some(OperationState::DataEstablished) => { + todo!() + } + None => { + error!("State transition next_state not valid: start_state={}, next_state={}, steps={} ", start_state, next_state, steps); + break; + } } } } Either::Second(event) => { - match event { - // Handle network URCs - Urc::NetworkDetach => todo!(), - Urc::MobileStationDetach => todo!(), - Urc::NetworkDeactivate => todo!(), - Urc::MobileStationDeactivate => todo!(), - Urc::NetworkPDNDeactivate => todo!(), - Urc::MobileStationPDNDeactivate => todo!(), - Urc::SocketDataAvailable(_) => todo!(), - Urc::SocketDataAvailableUDP(_) => todo!(), - Urc::DataConnectionActivated(_) => todo!(), - Urc::DataConnectionDeactivated(_) => todo!(), - Urc::SocketClosed(_) => todo!(), - Urc::MessageWaitingIndication(_) => todo!(), - Urc::ExtendedPSNetworkRegistration(_) => todo!(), - Urc::HttpResponse(_) => todo!(), - }; + self.handle_urc(event).await; } } - - // let desired_state = self.ch.state_runner().wait_for_desired_state_change().await; - // // let desired_state = self.ch.state_runner().desired_state(); - // info!("Desired state: {:?}", desired_state); - // let event = self.urc_subscription.next_message_pure().await; - // match event { - // // Handle network URCs - // Urc::NetworkDetach => todo!(), - // Urc::MobileStationDetach => todo!(), - // Urc::NetworkDeactivate => todo!(), - // Urc::MobileStationDeactivate => todo!(), - // Urc::NetworkPDNDeactivate => todo!(), - // Urc::MobileStationPDNDeactivate => todo!(), - // Urc::SocketDataAvailable(_) => todo!(), - // Urc::SocketDataAvailableUDP(_) => todo!(), - // Urc::DataConnectionActivated(_) => todo!(), - // Urc::DataConnectionDeactivated(_) => todo!(), - // Urc::SocketClosed(_) => todo!(), - // Urc::MessageWaitingIndication(_) => todo!(), - // Urc::ExtendedPSNetworkRegistration(_) => todo!(), - // Urc::HttpResponse(_) => todo!(), - // }; } } + + async fn handle_urc(&mut self, event: Urc) -> Error { + match event { + // Handle network URCs + Urc::NetworkDetach => todo!(), + Urc::MobileStationDetach => todo!(), + Urc::NetworkDeactivate => todo!(), + Urc::MobileStationDeactivate => todo!(), + Urc::NetworkPDNDeactivate => todo!(), + Urc::MobileStationPDNDeactivate => todo!(), + Urc::SocketDataAvailable(_) => todo!(), + Urc::SocketDataAvailableUDP(_) => todo!(), + Urc::DataConnectionActivated(_) => todo!(), + Urc::DataConnectionDeactivated(_) => todo!(), + Urc::SocketClosed(_) => todo!(), + Urc::MessageWaitingIndication(_) => todo!(), + Urc::ExtendedPSNetworkRegistration(_) => todo!(), + Urc::HttpResponse(_) => todo!(), + }; + } } diff --git a/src/asynch/state.rs b/src/asynch/state.rs index 629521b..f46aa4d 100644 --- a/src/asynch/state.rs +++ b/src/asynch/state.rs @@ -4,6 +4,7 @@ use core::cell::RefCell; use core::mem::MaybeUninit; use core::task::Context; +use crate::asynch::state::OperationState::DataEstablished; use atat::asynch::AtatClient; use atat::UrcSubscription; use embassy_sync::blocking_mutex::raw::NoopRawMutex; @@ -27,7 +28,7 @@ pub enum LinkState { #[derive(PartialEq, Eq, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum OperationState { - PowerDown, + PowerDown = 0, PowerUp, Alive, Initialized, @@ -35,6 +36,20 @@ pub enum OperationState { DataEstablished, } +impl OperationState { + pub fn from(state: isize) -> Option { + match state { + 0 => Some(OperationState::PowerDown), + 1 => Some(OperationState::PowerUp), + 2 => Some(OperationState::Alive), + 3 => Some(OperationState::Initialized), + 4 => Some(OperationState::Connected), + 5 => Some(OperationState::DataEstablished), + _ => None, + } + } +} + use crate::command::Urc; use crate::error::Error; From 4e9117b94ba48140e142fdc136e91d48cad2bd89 Mon Sep 17 00:00:00 2001 From: Tobias Breitwieser Date: Sun, 24 Dec 2023 16:05:12 +0100 Subject: [PATCH 07/16] change to TryFrom for State --- src/asynch/runner.rs | 16 ++++++++-------- src/asynch/state.rs | 19 ++++++++++--------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/asynch/runner.rs b/src/asynch/runner.rs index 1f4dfc5..eec1b37 100644 --- a/src/asynch/runner.rs +++ b/src/asynch/runner.rs @@ -313,9 +313,9 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> let steps = desired_state as isize - start_state; for step in 0..steps { let next_state = start_state + step; - match OperationState::from(next_state) { - Some(OperationState::PowerDown) => {} - Some(OperationState::PowerUp) => match self.power_up().await { + match OperationState::try_from(next_state) { + Ok(OperationState::PowerDown) => {} + Ok(OperationState::PowerUp) => match self.power_up().await { Ok(_) => { self.ch.set_power_state(OperationState::PowerUp); } @@ -324,7 +324,7 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> break; } }, - Some(OperationState::Alive) => match self.is_alive().await { + Ok(OperationState::Alive) => match self.is_alive().await { Ok(_) => { self.ch.set_power_state(OperationState::Alive); } @@ -333,7 +333,7 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> break; } }, - Some(OperationState::Initialized) => match self.init_at().await { + Ok(OperationState::Initialized) => match self.init_at().await { Ok(_) => { self.ch.set_power_state(OperationState::Initialized); } @@ -342,13 +342,13 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> break; } }, - Some(OperationState::Connected) => { + Ok(OperationState::Connected) => { todo!() } - Some(OperationState::DataEstablished) => { + Ok(OperationState::DataEstablished) => { todo!() } - None => { + Err(_) => { error!("State transition next_state not valid: start_state={}, next_state={}, steps={} ", start_state, next_state, steps); break; } diff --git a/src/asynch/state.rs b/src/asynch/state.rs index f46aa4d..9feae6e 100644 --- a/src/asynch/state.rs +++ b/src/asynch/state.rs @@ -36,18 +36,19 @@ pub enum OperationState { DataEstablished, } -impl OperationState { - pub fn from(state: isize) -> Option { +impl TryFrom for OperationState { + fn try_from(state: isize) -> Result { match state { - 0 => Some(OperationState::PowerDown), - 1 => Some(OperationState::PowerUp), - 2 => Some(OperationState::Alive), - 3 => Some(OperationState::Initialized), - 4 => Some(OperationState::Connected), - 5 => Some(OperationState::DataEstablished), - _ => None, + 0 => Ok(OperationState::PowerDown), + 1 => Ok(OperationState::PowerUp), + 2 => Ok(OperationState::Alive), + 3 => Ok(OperationState::Initialized), + 4 => Ok(OperationState::Connected), + 5 => Ok(OperationState::DataEstablished), + _ => Err(()), } } + type Error = (); } use crate::command::Urc; From 9582e058333cb5efe4ddb681b26098144e7b4f27 Mon Sep 17 00:00:00 2001 From: Tobias Breitwieser Date: Sun, 24 Dec 2023 18:04:21 +0100 Subject: [PATCH 08/16] working example, some timing issues --- examples/embassy-stm32-example/src/main.rs | 49 +++++----------------- src/asynch/runner.rs | 29 ++++++++++++- 2 files changed, 37 insertions(+), 41 deletions(-) diff --git a/examples/embassy-stm32-example/src/main.rs b/examples/embassy-stm32-example/src/main.rs index f089e55..22c9183 100644 --- a/examples/embassy-stm32-example/src/main.rs +++ b/examples/embassy-stm32-example/src/main.rs @@ -149,48 +149,19 @@ async fn main_task(spawner: Spawner) { // control.set_desired_state(PowerState::Connected).await; defmt::unwrap!(spawner.spawn(cellular_task(runner))); + Timer::after(Duration::from_millis(1000)).await; loop { - // loop { - // control.set_desired_state(PowerState::Connected).await; - // info!("set_desired_state(PowerState::Connected)"); - // Timer::after(Duration::from_millis(1000)).await; - // control.set_desired_state(PowerState::PowerDown).await; - // info!("set_desired_state(PowerState::PowerDown)"); - // Timer::after(Duration::from_millis(1000)).await; - // } - // runner.init().await.unwrap(); - match control.power_state() { - OperationState::PowerDown => { - info!("PowerState::PowerDown"); - control.set_desired_state(OperationState::PowerUp).await; - info!("set_desired_state(PowerState::PowerUp)"); + control.set_desired_state(OperationState::Alive).await; + info!("set_desired_state(PowerState::Initialized)"); + while control.power_state() != OperationState::Alive { + Timer::after(Duration::from_millis(1000)).await; } - OperationState::PowerUp => { - info!("PowerState::PowerUp"); - control.set_desired_state(OperationState::Alive).await; - info!("set_desired_state(PowerState::Alive)"); + Timer::after(Duration::from_millis(1000)).await; + control.set_desired_state(OperationState::PowerDown).await; + info!("set_desired_state(PowerState::PowerDown)"); + while control.power_state() != OperationState::PowerDown { + Timer::after(Duration::from_millis(1000)).await; } - OperationState::Alive => { - info!("PowerState::Alive"); - control.set_desired_state(OperationState::Initialized).await; - info!("set_desired_state(PowerState::Initialized)"); - } - OperationState::Initialized => { - info!("PowerState::Initialized"); - control.set_desired_state(OperationState::PowerDown).await; - info!("set_desired_state(PowerState::PowerDown)"); - } - OperationState::Connected => { - info!("PowerState::Connected"); - control.set_desired_state(OperationState::PowerDown).await; - info!("set_desired_state(PowerState::PowerDown)"); - } - OperationState::DataEstablished => { - info!("PowerState::DataEstablished"); - control.set_desired_state(OperationState::PowerDown).await; - info!("set_desired_state(PowerState::PowerDown)"); - } - } Timer::after(Duration::from_millis(5000)).await; } defmt::unwrap!(spawner.spawn(cellular_task(runner))); diff --git a/src/asynch/runner.rs b/src/asynch/runner.rs index eec1b37..5af5728 100644 --- a/src/asynch/runner.rs +++ b/src/asynch/runner.rs @@ -111,6 +111,7 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> pin.set_low().map_err(|_| Error::IoPin)?; Timer::after(crate::module_timing::pwr_on_time()).await; pin.set_high().map_err(|_| Error::IoPin)?; + Timer::after(boot_time()).await; self.ch.set_power_state(OperationState::PowerUp); debug!("Powered up"); Ok(()) @@ -291,6 +292,17 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> } pub async fn run(mut self) -> ! { + match self.has_power().await.ok() { + Some(false) => { + self.ch.set_power_state(OperationState::PowerDown); + } + Some(true) => { + self.ch.set_power_state(OperationState::PowerUp); + } + None => { + self.ch.set_power_state(OperationState::PowerDown); + } + } loop { match select( self.ch.state_runner().wait_for_desired_state_change(), @@ -305,13 +317,24 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> continue; } let desired_state = desired_state.unwrap(); - if 0 < desired_state as isize - self.ch.state_runner().power_state() as isize { + if 0 >= desired_state as isize - self.ch.state_runner().power_state() as isize { + debug!( + "Power steps was negative, power down: {}", + desired_state as isize - self.ch.state_runner().power_state() as isize + ); self.power_down().await.ok(); self.ch.set_power_state(OperationState::PowerDown); } let start_state = self.ch.state_runner().power_state() as isize; let steps = desired_state as isize - start_state; - for step in 0..steps { + for step in 0..=steps { + debug!( + "State transition {} steps: {} -> {}, {}", + steps, + start_state, + start_state + step, + step + ); let next_state = start_state + step; match OperationState::try_from(next_state) { Ok(OperationState::PowerDown) => {} @@ -326,7 +349,9 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> }, Ok(OperationState::Alive) => match self.is_alive().await { Ok(_) => { + debug!("Will set Alive"); self.ch.set_power_state(OperationState::Alive); + debug!("Set Alive"); } Err(err) => { error!("Error in is_alive: {:?}", err); From d2386590ff88a43b1c9ed21c51e2c9463aeba557 Mon Sep 17 00:00:00 2001 From: Tobias Breitwieser Date: Tue, 26 Dec 2023 01:36:52 +0100 Subject: [PATCH 09/16] adjust bootup time to have is_alive work reliable after bootup --- examples/embassy-stm32-example/src/main.rs | 81 +++++++++++----------- src/module_timing.rs | 4 +- 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/examples/embassy-stm32-example/src/main.rs b/examples/embassy-stm32-example/src/main.rs index 22c9183..7e04f41 100644 --- a/examples/embassy-stm32-example/src/main.rs +++ b/examples/embassy-stm32-example/src/main.rs @@ -7,30 +7,28 @@ use core::cell::RefCell; use cortex_m_rt::entry; use defmt::*; use embassy_executor::{Executor, Spawner}; -use embassy_stm32::gpio::{AnyPin, Input, Level, Output, Pin, Pull, Speed, OutputOpenDrain}; +use embassy_stm32::gpio::{AnyPin, Input, Level, Output, OutputOpenDrain, Pin, Pull, Speed}; +use embassy_stm32::peripherals::UART8; use embassy_stm32::rcc::VoltageScale; use embassy_stm32::time::{khz, mhz}; -use embassy_stm32::{bind_interrupts, peripherals, Config, interrupt, usart}; -use embassy_stm32::peripherals::UART8; use embassy_stm32::usart::{BufferedUart, BufferedUartRx, BufferedUartTx}; +use embassy_stm32::{bind_interrupts, interrupt, peripherals, usart, Config}; use embassy_time::{Duration, Timer}; -use static_cell::StaticCell; use static_cell::make_static; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; - // use embedded_hal::digital::{ErrorType, InputPin, OutputPin}; use ublox_cellular; use ublox_cellular::config::{CellularConfig, ReverseOutputPin}; -use atat::{Buffers, DefaultDigester, Ingress, AtatIngress, AtDigester, Parser}; use atat::asynch::AtatClient; +use atat::{AtDigester, AtatIngress, Buffers, DefaultDigester, Ingress, Parser}; use ublox_cellular::asynch::runner::Runner; -use ublox_cellular::asynch::State; -use ublox_cellular::command::{AT, Urc}; use ublox_cellular::asynch::state::{LinkState, OperationState}; - +use ublox_cellular::asynch::State; +use ublox_cellular::command::{Urc, AT}; bind_interrupts!(struct Irqs { UART8 => embassy_stm32::usart::BufferedInterruptHandler; @@ -61,15 +59,15 @@ impl CellularConfig for MyCelullarConfig { const HEX_MODE: bool = true; fn reset_pin(&mut self) -> Option<&mut Self::ResetPin> { info!("reset_pin"); - return self.reset_pin.as_mut() + return self.reset_pin.as_mut(); } fn power_pin(&mut self) -> Option<&mut Self::PowerPin> { info!("power_pin"); - return self.power_pin.as_mut() + return self.power_pin.as_mut(); } fn vint_pin(&mut self) -> Option<&mut Self::VintPin> { info!("vint_pin = {}", self.vint_pin.as_mut()?.is_high()); - return self.vint_pin.as_mut() + return self.vint_pin.as_mut(); } } @@ -102,8 +100,6 @@ async fn main_task(spawner: Spawner) { let led2_pin = p.PI13.degrade(); let led3_pin = p.PI14.degrade(); - - let tx_buf = &mut make_static!([0u8; 16])[..]; let rx_buf = &mut make_static!([0u8; 16])[..]; let (tx_pin, rx_pin, uart) = (p.PJ8, p.PJ9, p.UART8); @@ -116,26 +112,19 @@ async fn main_task(spawner: Spawner) { uart_config.data_bits = embassy_stm32::usart::DataBits::DataBits8; } - - let uart = BufferedUart::new( - uart, - Irqs, - rx_pin, - tx_pin, - tx_buf, - rx_buf, - uart_config, - ); + let uart = BufferedUart::new(uart, Irqs, rx_pin, tx_pin, tx_buf, rx_buf, uart_config); let (writer, reader) = uart.unwrap().split(); // let power = Output::new(p.PJ4, Level::High, Speed::VeryHigh).degrade(); // let reset = Output::new(p.PF8, Level::High, Speed::VeryHigh).degrade(); let celullar_config = MyCelullarConfig { reset_pin: Some(Output::new(p.PF8, Level::High, Speed::Low).degrade()), - power_pin: Some(ReverseOutputPin(Output::new(p.PJ4, Level::High, Speed::Low).degrade())), + power_pin: Some(ReverseOutputPin( + Output::new(p.PJ4, Level::High, Speed::Low).degrade(), + )), // reset_pin: Some(OutputOpenDrain::new(p.PF8, Level::High, Speed::Low, Pull::None).degrade()), // power_pin: Some(OutputOpenDrain::new(p.PJ4, Level::High, Speed::Low, Pull::None).degrade()), // power_pin: None, - vint_pin: Some(Input::new(p.PJ3, Pull::Down).degrade()) + vint_pin: Some(Input::new(p.PJ3, Pull::Down).degrade()), }; let buffers = &*make_static!(atat::Buffers::new()); @@ -144,24 +133,25 @@ async fn main_task(spawner: Spawner) { spawner.spawn(ingress_task(ingress, reader)).unwrap(); let state = make_static!(State::new(client)); - let (device, mut control, mut runner) = ublox_cellular::asynch::new(state, &buffers.urc_channel, celullar_config).await; + let (device, mut control, mut runner) = + ublox_cellular::asynch::new(state, &buffers.urc_channel, celullar_config).await; // defmt::info!("{:?}", runner.init().await); // control.set_desired_state(PowerState::Connected).await; defmt::unwrap!(spawner.spawn(cellular_task(runner))); Timer::after(Duration::from_millis(1000)).await; loop { - control.set_desired_state(OperationState::Alive).await; - info!("set_desired_state(PowerState::Initialized)"); - while control.power_state() != OperationState::Alive { - Timer::after(Duration::from_millis(1000)).await; - } + control.set_desired_state(OperationState::Alive).await; + info!("set_desired_state(PowerState::Alive)"); + while control.power_state() != OperationState::Alive { Timer::after(Duration::from_millis(1000)).await; - control.set_desired_state(OperationState::PowerDown).await; - info!("set_desired_state(PowerState::PowerDown)"); - while control.power_state() != OperationState::PowerDown { - Timer::after(Duration::from_millis(1000)).await; - } + } + Timer::after(Duration::from_millis(1000)).await; + control.set_desired_state(OperationState::PowerDown).await; + info!("set_desired_state(PowerState::PowerDown)"); + while control.power_state() != OperationState::PowerDown { + Timer::after(Duration::from_millis(1000)).await; + } Timer::after(Duration::from_millis(5000)).await; } defmt::unwrap!(spawner.spawn(cellular_task(runner))); @@ -171,10 +161,16 @@ async fn main_task(spawner: Spawner) { } } - #[embassy_executor::task] async fn ingress_task( - mut ingress: Ingress<'static, DefaultDigester, ublox_cellular::command::Urc, {INGRESS_BUF_SIZE}, {URC_CAPACITY}, {URC_SUBSCRIBERS}>, + mut ingress: Ingress< + 'static, + DefaultDigester, + ublox_cellular::command::Urc, + { INGRESS_BUF_SIZE }, + { URC_CAPACITY }, + { URC_SUBSCRIBERS }, + >, mut reader: BufferedUartRx<'static, UART8>, ) -> ! { ingress.read_from(&mut reader).await; @@ -183,7 +179,12 @@ async fn ingress_task( #[embassy_executor::task] async fn cellular_task( - runner: Runner<'static, atat::asynch::Client<'_, BufferedUartTx<'static, UART8>, {INGRESS_BUF_SIZE}>, MyCelullarConfig, {URC_CAPACITY}>, + runner: Runner< + 'static, + atat::asynch::Client<'_, BufferedUartTx<'static, UART8>, { INGRESS_BUF_SIZE }>, + MyCelullarConfig, + { URC_CAPACITY }, + >, ) -> ! { runner.run().await } diff --git a/src/module_timing.rs b/src/module_timing.rs index 3f04f95..cd97881 100644 --- a/src/module_timing.rs +++ b/src/module_timing.rs @@ -44,9 +44,9 @@ pub fn reset_time() -> Duration { /// Time to wait for module to boot pub fn boot_time() -> Duration { if cfg!(feature = "sara-r5") { - Duration::from_secs(1) + Duration::from_secs(3) } else { - Duration::from_secs(1) + Duration::from_secs(3) } } From a1d65600fe2e64cdf46acdc89f24015b7b9b2e3b Mon Sep 17 00:00:00 2001 From: Tobias Breitwieser Date: Tue, 26 Dec 2023 14:33:18 +0100 Subject: [PATCH 10/16] update dependencies and make compatible with atat master --- Cargo.toml | 21 +++++++----- examples/embassy-stm32-example/Cargo.toml | 10 +++--- .../embassy-stm32-example/rust-toolchain.toml | 3 +- examples/embassy-stm32-example/src/main.rs | 19 ++++++++--- src/asynch/mod.rs | 11 +++--- src/asynch/runner.rs | 34 +++++++++---------- src/config.rs | 8 ++--- 7 files changed, 62 insertions(+), 44 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b459e8e..723b734 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,22 +16,19 @@ doctest = false [dependencies] atat = { version = "0.20.0", features = ["derive", "bytes"] } -embedded-hal = "=1.0.0-rc.1" -embedded-nal = "0.7" hash32 = "^0.3" heapless = { version = "^0.8", features = ["serde"] } nb = "^1" serde = { version = "^1", default-features = false, features = ["derive"] } ublox-sockets = { version = "0.5", optional = true } -embassy-time = "0.1.5" -embassy-sync = "0.4" +embassy-time = "0.2" +embassy-sync = "0.5" no-std-net = { version = "^0.6", features = ["serde"] } log = { version = "^0.4", default-features = false, optional = true } defmt = { version = "^0.3", optional = true } -embedded-nal-async = { version = "0.6", optional = true } futures-util = { version = "0.3.29", default-features = false } #futures = { version = "0.3.17", default-features = false, features = [ # "async-await", @@ -39,6 +36,11 @@ futures-util = { version = "0.3.29", default-features = false } embassy-futures = { version = "0.1", optional = true } +embedded-hal = "=1.0.0-rc.3" +embedded-nal = "0.8" +embedded-nal-async = { version = "0.7", optional = true } + + embedded-io = "0.6" embedded-io-async = "0.6" @@ -84,7 +86,10 @@ default-members = ["."] exclude = ["examples"] [patch.crates-io] -ublox-sockets = { git = "https://github.com/BlackbirdHQ/ublox-sockets", branch = "feature/async-borrowed-sockets" } +#ublox-sockets = { git = "https://github.com/BlackbirdHQ/ublox-sockets", branch = "feature/async-borrowed-sockets" } no-std-net = { git = "https://github.com/rushmorem/no-std-net", branch = "issue-15" } -#ublox-sockets = { path = "../ublox-sockets" } -atat = { path = "../atat/atat" } +ublox-sockets = { path = "../ublox-sockets" } +atat = { git = "https://github.com/BlackbirdHQ/atat", branch = "master" } +embassy-time = { package = "embassy-time", git = "https://github.com/embassy-rs/embassy", branch = "main" } +embassy-sync = { package = "embassy-sync", git = "https://github.com/embassy-rs/embassy", branch = "main" } +embassy-futures = { package = "embassy-futures", git = "https://github.com/embassy-rs/embassy", branch = "main" } diff --git a/examples/embassy-stm32-example/Cargo.toml b/examples/embassy-stm32-example/Cargo.toml index 4f052db..61d5585 100644 --- a/examples/embassy-stm32-example/Cargo.toml +++ b/examples/embassy-stm32-example/Cargo.toml @@ -5,10 +5,10 @@ edition = "2021" # Example for the STM32H747I-DISCO board with SARA-R5 modem attached to UART8 [dependencies] -embassy-stm32 = { version = "0.1.0", git = "https://github.com/embassy-rs/embassy.git", branch = "main", features = ["nightly", "defmt", "stm32h747xi-cm7", "time-driver-any", "exti", "memory-x", "unstable-pac", "unstable-traits"] } -embassy-executor = { version = "0.3.0", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "nightly"] } -embassy-sync = { version = "0.4", features = ["defmt"] } +embassy-stm32 = { version = "0.1.0", git = "https://github.com/embassy-rs/embassy.git", branch = "main", features = ["defmt", "stm32h747xi-cm7", "time-driver-any", "exti", "memory-x", "unstable-pac"] } +embassy-executor = { version = "0.4.0", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-time = { version = "0.2", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-sync = { version = "0.5", features = ["defmt"] } cortex-m = { version = "0.7.7", features = ["inline-asm", "critical-section-single-core"] } @@ -30,6 +30,8 @@ no-std-net = { git = "https://github.com/rushmorem/no-std-net", branch = "issue- embassy-time = { package = "embassy-time", git = "https://github.com/embassy-rs/embassy", branch = "main" } embassy-sync = { package = "embassy-sync", git = "https://github.com/embassy-rs/embassy", branch = "main" } embassy-futures = { package = "embassy-futures", git = "https://github.com/embassy-rs/embassy", branch = "main" } +embassy-executor = { package = "embassy-executor", git = "https://github.com/embassy-rs/embassy", branch = "main" } + #ublox-sockets = { path = "../../../ublox-sockets" } #atat = { path = "../../../atat/atat" } diff --git a/examples/embassy-stm32-example/rust-toolchain.toml b/examples/embassy-stm32-example/rust-toolchain.toml index 419c310..3c44968 100644 --- a/examples/embassy-stm32-example/rust-toolchain.toml +++ b/examples/embassy-stm32-example/rust-toolchain.toml @@ -1,7 +1,8 @@ # Before upgrading check that everything is available on all tier1 targets here: # https://rust-lang.github.io/rustup-components-history [toolchain] -channel = "nightly-2023-11-01" +#channel = "beta-2023-12-17" +channel = "nightly-2023-12-17" components = [ "rust-src", "rustfmt", "llvm-tools" ] targets = [ "thumbv7em-none-eabi", diff --git a/examples/embassy-stm32-example/src/main.rs b/examples/embassy-stm32-example/src/main.rs index 7e04f41..593666d 100644 --- a/examples/embassy-stm32-example/src/main.rs +++ b/examples/embassy-stm32-example/src/main.rs @@ -3,6 +3,9 @@ #![allow(stable_features)] #![feature(type_alias_impl_trait)] +use atat::asynch::Client; +use atat::UrcChannel; +use atat::ResponseSlot; use core::cell::RefCell; use cortex_m_rt::entry; use defmt::*; @@ -24,10 +27,11 @@ use ublox_cellular; use ublox_cellular::config::{CellularConfig, ReverseOutputPin}; use atat::asynch::AtatClient; -use atat::{AtDigester, AtatIngress, Buffers, DefaultDigester, Ingress, Parser}; +use atat::{AtDigester, AtatIngress, DefaultDigester, Ingress, Parser}; use ublox_cellular::asynch::runner::Runner; use ublox_cellular::asynch::state::{LinkState, OperationState}; use ublox_cellular::asynch::State; +use ublox_cellular::command; use ublox_cellular::command::{Urc, AT}; bind_interrupts!(struct Irqs { @@ -127,14 +131,21 @@ async fn main_task(spawner: Spawner) { vint_pin: Some(Input::new(p.PJ3, Pull::Down).degrade()), }; - let buffers = &*make_static!(atat::Buffers::new()); - let (ingress, client) = buffers.split(writer, AtDigester::default(), atat::Config::new()); + static RES_SLOT: ResponseSlot = ResponseSlot::new(); + static URC_CHANNEL: UrcChannel = UrcChannel::new(); + let ingress = Ingress::new( + DefaultDigester::::default(), + &RES_SLOT, + &URC_CHANNEL, + ); + let buf = static_cell::make_static!([0; 1024]); + let mut client = Client::new(writer, &RES_SLOT, buf, atat::Config::default()); spawner.spawn(ingress_task(ingress, reader)).unwrap(); let state = make_static!(State::new(client)); let (device, mut control, mut runner) = - ublox_cellular::asynch::new(state, &buffers.urc_channel, celullar_config).await; + ublox_cellular::asynch::new(state, &URC_CHANNEL, celullar_config).await; // defmt::info!("{:?}", runner.init().await); // control.set_desired_state(PowerState::Connected).await; diff --git a/src/asynch/mod.rs b/src/asynch/mod.rs index bd3c56c..3f8edda 100644 --- a/src/asynch/mod.rs +++ b/src/asynch/mod.rs @@ -6,7 +6,7 @@ pub mod ublox_stack; pub mod state; use crate::{command::Urc, config::CellularConfig}; -use atat::{asynch::AtatClient, AtatUrcChannel}; +use atat::{asynch::AtatClient, UrcChannel}; use embassy_sync::{blocking_mutex::raw::NoopRawMutex, mutex::Mutex}; use runner::Runner; use state::Device; @@ -16,11 +16,11 @@ use self::control::Control; pub struct AtHandle<'d, AT: AtatClient>(&'d Mutex); impl<'d, AT: AtatClient> AtHandle<'d, AT> { - async fn send, const LEN: usize>( + async fn send( &mut self, - cmd: Cmd, + cmd: &Cmd, ) -> Result { - self.0.lock().await.send_retry::(&cmd).await + self.0.lock().await.send_retry::(cmd).await } } @@ -41,12 +41,11 @@ impl State { pub async fn new< 'a, AT: AtatClient, - SUB: AtatUrcChannel, C: CellularConfig, const URC_CAPACITY: usize, >( state: &'a mut State, - subscriber: &'a SUB, + subscriber: &'a UrcChannel, config: C, ) -> ( Device<'a, AT, URC_CAPACITY>, diff --git a/src/asynch/runner.rs b/src/asynch/runner.rs index 5af5728..b5e76da 100644 --- a/src/asynch/runner.rs +++ b/src/asynch/runner.rs @@ -82,7 +82,7 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> return Err(Error::PoweredDown); } - let alive = match self.at.send(AT).await { + let alive = match self.at.send(&AT).await { Ok(_) => { return Ok(true); } @@ -149,14 +149,14 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> // Extended errors on self.at - .send(SetReportMobileTerminationError { + .send(&SetReportMobileTerminationError { n: TerminationErrorMode::Enabled, }) .await?; // Select SIM self.at - .send(SetGpioConfiguration { + .send(&SetGpioConfiguration { gpio_id: 25, gpio_mode: GpioMode::Output(GpioOutValue::High), }) @@ -164,13 +164,13 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> #[cfg(any(feature = "lara-r6"))] self.at - .send(SetGpioConfiguration { + .send(&SetGpioConfiguration { gpio_id: 42, gpio_mode: GpioMode::Input(GpioInPull::NoPull), }) .await?; - let model_id = self.at.send(GetModelId).await?; + let model_id = self.at.send(&GetModelId).await?; // self.at.send( // &IdentificationInformation { @@ -178,29 +178,29 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> // }, // ).await?; - self.at.send(GetFirmwareVersion).await?; + self.at.send(&GetFirmwareVersion).await?; self.select_sim_card().await?; - let ccid = self.at.send(GetCCID).await?; + let ccid = self.at.send(&GetCCID).await?; info!("CCID: {}", ccid.ccid); // DCD circuit (109) changes in accordance with the carrier self.at - .send(SetCircuit109Behaviour { + .send(&SetCircuit109Behaviour { value: Circuit109Behaviour::ChangesWithCarrier, }) .await?; // Ignore changes to DTR self.at - .send(SetCircuit108Behaviour { + .send(&SetCircuit108Behaviour { value: Circuit108Behaviour::Ignore, }) .await?; // Switch off UART power saving until it is integrated into this API self.at - .send(SetPowerSavingControl { + .send(&SetPowerSavingControl { mode: PowerSavingMode::Disabled, timeout: None, }) @@ -208,13 +208,13 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> if C::HEX_MODE { self.at - .send(SetHexMode { + .send(&SetHexMode { hex_mode_disable: HexMode::Enabled, }) .await?; } else { self.at - .send(SetHexMode { + .send(&SetHexMode { hex_mode_disable: HexMode::Disabled, }) .await?; @@ -224,13 +224,13 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> // FIXME: Use AT+IFC=2,2 instead of AT&K here if C::FLOW_CONTROL { self.at - .send(SetFlowControl { + .send(&SetFlowControl { value: FlowControl::RtsCts, }) .await?; } else { self.at - .send(SetFlowControl { + .send(&SetFlowControl { value: FlowControl::Disabled, }) .await?; @@ -240,7 +240,7 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> pub async fn select_sim_card(&mut self) -> Result<(), Error> { for _ in 0..2 { - match self.at.send(GetPinStatus).await { + match self.at.send(&GetPinStatus).await { Ok(PinStatus { code }) if code == PinStatusCode::Ready => { return Ok(()); } @@ -254,7 +254,7 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> // We've seen issues on uBlox-based devices, as a precation, we'll cycle // the modem here through minimal/full functional state. self.at - .send(SetModuleFunctionality { + .send(&SetModuleFunctionality { fun: Functionality::Minimum, // SARA-R5 This parameter can be used only when is 1, 4 or 19 #[cfg(feature = "sara-r5")] @@ -264,7 +264,7 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> }) .await?; self.at - .send(SetModuleFunctionality { + .send(&SetModuleFunctionality { fun: Functionality::Full, rst: Some(ResetMode::DontReset), }) diff --git a/src/config.rs b/src/config.rs index 1021df2..32a84bd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -8,11 +8,11 @@ impl ErrorType for NoPin { } impl InputPin for NoPin { - fn is_high(&self) -> Result { + fn is_high(&mut self) -> Result { Ok(true) } - fn is_low(&self) -> Result { + fn is_low(&mut self) -> Result { Ok(false) } } @@ -57,11 +57,11 @@ impl> ErrorType for ReverseInputPin

{ } impl> InputPin for ReverseInputPin

{ - fn is_high(&self) -> Result { + fn is_high(&mut self) -> Result { self.0.is_low() } - fn is_low(&self) -> Result { + fn is_low(&mut self) -> Result { self.0.is_high() } } From c9b703978b4dbb6d7de20cc7fdef721472c02968 Mon Sep 17 00:00:00 2001 From: Tobias Breitwieser Date: Tue, 26 Dec 2023 14:33:41 +0100 Subject: [PATCH 11/16] fmt --- src/asynch/mod.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/asynch/mod.rs b/src/asynch/mod.rs index 3f8edda..940b6fc 100644 --- a/src/asynch/mod.rs +++ b/src/asynch/mod.rs @@ -16,10 +16,7 @@ use self::control::Control; pub struct AtHandle<'d, AT: AtatClient>(&'d Mutex); impl<'d, AT: AtatClient> AtHandle<'d, AT> { - async fn send( - &mut self, - cmd: &Cmd, - ) -> Result { + async fn send(&mut self, cmd: &Cmd) -> Result { self.0.lock().await.send_retry::(cmd).await } } @@ -38,12 +35,7 @@ impl State { } } -pub async fn new< - 'a, - AT: AtatClient, - C: CellularConfig, - const URC_CAPACITY: usize, ->( +pub async fn new<'a, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize>( state: &'a mut State, subscriber: &'a UrcChannel, config: C, From 4e1f1932c78f65d8575497e882906a9c6a570e65 Mon Sep 17 00:00:00 2001 From: Tobias Breitwieser Date: Tue, 26 Dec 2023 17:18:28 +0100 Subject: [PATCH 12/16] remove things to comply with non nighty; set supply configuration to match old default --- Cargo.toml | 10 +++-- examples/embassy-stm32-example/Cargo.toml | 21 ++++++--- .../embassy-stm32-example/rust-toolchain.toml | 4 +- examples/embassy-stm32-example/src/main.rs | 44 +++++++++++++------ src/lib.rs | 6 +-- 5 files changed, 57 insertions(+), 28 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 723b734..b44eb81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -90,6 +90,10 @@ exclude = ["examples"] no-std-net = { git = "https://github.com/rushmorem/no-std-net", branch = "issue-15" } ublox-sockets = { path = "../ublox-sockets" } atat = { git = "https://github.com/BlackbirdHQ/atat", branch = "master" } -embassy-time = { package = "embassy-time", git = "https://github.com/embassy-rs/embassy", branch = "main" } -embassy-sync = { package = "embassy-sync", git = "https://github.com/embassy-rs/embassy", branch = "main" } -embassy-futures = { package = "embassy-futures", git = "https://github.com/embassy-rs/embassy", branch = "main" } +embassy-time = { git = "https://github.com/embassy-rs/embassy", branch = "main" } +embassy-sync = { git = "https://github.com/embassy-rs/embassy", branch = "main" } +embassy-futures = { git = "https://github.com/embassy-rs/embassy", branch = "main" } + +#embassy-time = { path = "../embassy/embassy-time" } +#embassy-sync = { path = "../embassy/embassy-sync" } +#embassy-futures = { path = "../embassy/embassy-futures" } diff --git a/examples/embassy-stm32-example/Cargo.toml b/examples/embassy-stm32-example/Cargo.toml index 61d5585..f8dd8ea 100644 --- a/examples/embassy-stm32-example/Cargo.toml +++ b/examples/embassy-stm32-example/Cargo.toml @@ -5,8 +5,8 @@ edition = "2021" # Example for the STM32H747I-DISCO board with SARA-R5 modem attached to UART8 [dependencies] -embassy-stm32 = { version = "0.1.0", git = "https://github.com/embassy-rs/embassy.git", branch = "main", features = ["defmt", "stm32h747xi-cm7", "time-driver-any", "exti", "memory-x", "unstable-pac"] } -embassy-executor = { version = "0.4.0", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-stm32 = { version = "0.1.0", features = ["defmt", "stm32h747xi-cm7", "time-driver-any", "exti", "memory-x", "unstable-pac"] } +embassy-executor = { version = "0.4.0", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.2", features = ["defmt", "defmt-timestamp-uptime"] } embassy-sync = { version = "0.5", features = ["defmt"] } @@ -18,7 +18,7 @@ defmt = "0.3.5" defmt-rtt = "0.4.0" panic-probe = { version = "0.3.1", features = ["print-defmt"] } -static_cell = { version = "2.0", features = ["nightly"]} +static_cell = { version = "2.0", features = []} atat = { version = "0.20.0", features = ["derive", "bytes", "defmt"] } ublox-cellular-rs = {version = "0.4.0", path = "../..", features = ["sara-r5", "defmt", "async"]} @@ -27,10 +27,17 @@ ublox-cellular-rs = {version = "0.4.0", path = "../..", features = ["sara-r5", " ublox-sockets = { git = "https://github.com/BlackbirdHQ/ublox-sockets", branch = "feature/async-borrowed-sockets" } atat = { git = "https://github.com/BlackbirdHQ/atat", branch = "master" } no-std-net = { git = "https://github.com/rushmorem/no-std-net", branch = "issue-15" } -embassy-time = { package = "embassy-time", git = "https://github.com/embassy-rs/embassy", branch = "main" } -embassy-sync = { package = "embassy-sync", git = "https://github.com/embassy-rs/embassy", branch = "main" } -embassy-futures = { package = "embassy-futures", git = "https://github.com/embassy-rs/embassy", branch = "main" } -embassy-executor = { package = "embassy-executor", git = "https://github.com/embassy-rs/embassy", branch = "main" } +embassy-stm32 = { git = "https://github.com/embassy-rs/embassy", branch = "main" } +embassy-time = { git = "https://github.com/embassy-rs/embassy", branch = "main" } +embassy-sync = { git = "https://github.com/embassy-rs/embassy", branch = "main" } +embassy-futures = { git = "https://github.com/embassy-rs/embassy", branch = "main" } +embassy-executor = { git = "https://github.com/embassy-rs/embassy", branch = "main" } + +#embassy-stm32 = { path = "../../../embassy/embassy-stm32" } +#embassy-time = { path = "../../../embassy/embassy-time" } +#embassy-sync = { path = "../../../embassy/embassy-sync" } +#embassy-futures = { path = "../../../embassy/embassy-futures" } +#embassy-executor = { path = "../../../embassy/embassy-executor" } #ublox-sockets = { path = "../../../ublox-sockets" } #atat = { path = "../../../atat/atat" } diff --git a/examples/embassy-stm32-example/rust-toolchain.toml b/examples/embassy-stm32-example/rust-toolchain.toml index 3c44968..203817d 100644 --- a/examples/embassy-stm32-example/rust-toolchain.toml +++ b/examples/embassy-stm32-example/rust-toolchain.toml @@ -1,8 +1,8 @@ # Before upgrading check that everything is available on all tier1 targets here: # https://rust-lang.github.io/rustup-components-history [toolchain] -#channel = "beta-2023-12-17" -channel = "nightly-2023-12-17" +channel = "beta-2023-12-17" +#channel = "nightly-2023-12-17" components = [ "rust-src", "rustfmt", "llvm-tools" ] targets = [ "thumbv7em-none-eabi", diff --git a/examples/embassy-stm32-example/src/main.rs b/examples/embassy-stm32-example/src/main.rs index 593666d..2634ec0 100644 --- a/examples/embassy-stm32-example/src/main.rs +++ b/examples/embassy-stm32-example/src/main.rs @@ -1,11 +1,11 @@ #![no_std] #![no_main] #![allow(stable_features)] -#![feature(type_alias_impl_trait)] +// #![feature(type_alias_impl_trait)] use atat::asynch::Client; -use atat::UrcChannel; use atat::ResponseSlot; +use atat::UrcChannel; use core::cell::RefCell; use cortex_m_rt::entry; use defmt::*; @@ -17,7 +17,6 @@ use embassy_stm32::time::{khz, mhz}; use embassy_stm32::usart::{BufferedUart, BufferedUartRx, BufferedUartTx}; use embassy_stm32::{bind_interrupts, interrupt, peripherals, usart, Config}; use embassy_time::{Duration, Timer}; -use static_cell::make_static; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -80,6 +79,7 @@ async fn main_task(spawner: Spawner) { let mut config = Config::default(); { use embassy_stm32::rcc::*; + config.rcc.supply_config = SupplyConfig::DirectSMPS; config.rcc.hsi = Some(HSIPrescaler::DIV1); config.rcc.csi = true; config.rcc.pll1 = Some(Pll { @@ -87,7 +87,7 @@ async fn main_task(spawner: Spawner) { prediv: PllPreDiv::DIV4, mul: PllMul::MUL50, divp: Some(PllDiv::DIV2), - divq: Some(PllDiv::DIV8), // used by SPI3. 100Mhz. + divq: Some(PllDiv::DIV8), // 100mhz divr: None, }); config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz @@ -104,8 +104,9 @@ async fn main_task(spawner: Spawner) { let led2_pin = p.PI13.degrade(); let led3_pin = p.PI14.degrade(); - let tx_buf = &mut make_static!([0u8; 16])[..]; - let rx_buf = &mut make_static!([0u8; 16])[..]; + static tx_buf: StaticCell<[u8; 16]> = StaticCell::new(); + static rx_buf: StaticCell<[u8; 16]> = StaticCell::new(); + let (tx_pin, rx_pin, uart) = (p.PJ8, p.PJ9, p.UART8); let mut uart_config = embassy_stm32::usart::Config::default(); { @@ -116,7 +117,15 @@ async fn main_task(spawner: Spawner) { uart_config.data_bits = embassy_stm32::usart::DataBits::DataBits8; } - let uart = BufferedUart::new(uart, Irqs, rx_pin, tx_pin, tx_buf, rx_buf, uart_config); + let uart = BufferedUart::new( + uart, + Irqs, + rx_pin, + tx_pin, + tx_buf.init([0u8; 16]), + rx_buf.init([0u8; 16]), + uart_config, + ); let (writer, reader) = uart.unwrap().split(); // let power = Output::new(p.PJ4, Level::High, Speed::VeryHigh).degrade(); // let reset = Output::new(p.PF8, Level::High, Speed::VeryHigh).degrade(); @@ -138,14 +147,24 @@ async fn main_task(spawner: Spawner) { &RES_SLOT, &URC_CHANNEL, ); - let buf = static_cell::make_static!([0; 1024]); - let mut client = Client::new(writer, &RES_SLOT, buf, atat::Config::default()); + static buf: StaticCell<[u8; INGRESS_BUF_SIZE]> = StaticCell::new(); + let mut client = Client::new( + writer, + &RES_SLOT, + buf.init([0; INGRESS_BUF_SIZE]), + atat::Config::default(), + ); spawner.spawn(ingress_task(ingress, reader)).unwrap(); - let state = make_static!(State::new(client)); - let (device, mut control, mut runner) = - ublox_cellular::asynch::new(state, &URC_CHANNEL, celullar_config).await; + static state: StaticCell, INGRESS_BUF_SIZE>>> = + StaticCell::new(); + let (device, mut control, mut runner) = ublox_cellular::asynch::new( + state.init(State::new(client)), + &URC_CHANNEL, + celullar_config, + ) + .await; // defmt::info!("{:?}", runner.init().await); // control.set_desired_state(PowerState::Connected).await; @@ -165,7 +184,6 @@ async fn main_task(spawner: Spawner) { } Timer::after(Duration::from_millis(5000)).await; } - defmt::unwrap!(spawner.spawn(cellular_task(runner))); loop { Timer::after(Duration::from_millis(1000)).await; diff --git a/src/lib.rs b/src/lib.rs index c34fb44..312a885 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,8 @@ #![cfg_attr(not(test), no_std)] #![cfg_attr(feature = "async", allow(incomplete_features))] -#![cfg_attr(feature = "async", feature(generic_const_exprs))] -#![cfg_attr(feature = "async", feature(async_fn_in_trait))] -#![cfg_attr(feature = "async", feature(type_alias_impl_trait))] +// #![cfg_attr(feature = "async", feature(generic_const_exprs))] +// #![cfg_attr(feature = "async", feature(async_fn_in_trait))] +// #![cfg_attr(feature = "async", feature(type_alias_impl_trait))] // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; From bfee9cc466e9440adb9f285fdfba47c5792f251b Mon Sep 17 00:00:00 2001 From: Tobias Breitwieser Date: Tue, 26 Dec 2023 20:49:21 +0100 Subject: [PATCH 13/16] add connected state; add utility functions for soft_reset --- examples/embassy-stm32-example/src/main.rs | 6 +- src/asynch/runner.rs | 213 +++++++++++++++++++-- 2 files changed, 203 insertions(+), 16 deletions(-) diff --git a/examples/embassy-stm32-example/src/main.rs b/examples/embassy-stm32-example/src/main.rs index 2634ec0..fbf8617 100644 --- a/examples/embassy-stm32-example/src/main.rs +++ b/examples/embassy-stm32-example/src/main.rs @@ -132,7 +132,7 @@ async fn main_task(spawner: Spawner) { let celullar_config = MyCelullarConfig { reset_pin: Some(Output::new(p.PF8, Level::High, Speed::Low).degrade()), power_pin: Some(ReverseOutputPin( - Output::new(p.PJ4, Level::High, Speed::Low).degrade(), + Output::new(p.PJ4, Level::Low, Speed::Low).degrade(), )), // reset_pin: Some(OutputOpenDrain::new(p.PF8, Level::High, Speed::Low, Pull::None).degrade()), // power_pin: Some(OutputOpenDrain::new(p.PJ4, Level::High, Speed::Low, Pull::None).degrade()), @@ -171,9 +171,9 @@ async fn main_task(spawner: Spawner) { defmt::unwrap!(spawner.spawn(cellular_task(runner))); Timer::after(Duration::from_millis(1000)).await; loop { - control.set_desired_state(OperationState::Alive).await; + control.set_desired_state(OperationState::Initialized).await; info!("set_desired_state(PowerState::Alive)"); - while control.power_state() != OperationState::Alive { + while control.power_state() != OperationState::Initialized { Timer::after(Duration::from_millis(1000)).await; } Timer::after(Duration::from_millis(1000)).await; diff --git a/src/asynch/runner.rs b/src/asynch/runner.rs index b5e76da..437ac4d 100644 --- a/src/asynch/runner.rs +++ b/src/asynch/runner.rs @@ -184,6 +184,7 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> let ccid = self.at.send(&GetCCID).await?; info!("CCID: {}", ccid.ccid); + // DCD circuit (109) changes in accordance with the carrier self.at .send(&SetCircuit109Behaviour { @@ -237,11 +238,108 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> } Ok(()) } + /// Initializes the network only valid after `init_at`. + /// + /// # Errors + /// + /// Returns an error if any of the internal network operations fail. + /// + pub async fn init_network(&mut self) -> Result<(), Error> { + // Disable Message Waiting URCs (UMWI) + #[cfg(any(feature = "toby-r2"))] + self.at + .send(&crate::command::sms::SetMessageWaitingIndication { + mode: crate::command::sms::types::MessageWaitingMode::Disabled, + }) + .await?; + + self.at + .send( + &crate::command::mobile_control::SetAutomaticTimezoneUpdate { + on_off: crate::command::mobile_control::types::AutomaticTimezone::EnabledLocal, + }, + ) + .await?; + + self.at + .send(&crate::command::mobile_control::SetModuleFunctionality { + fun: Functionality::Full, + rst: None, + }) + .await?; + + self.enable_registration_urcs().await?; + + // Set automatic operator selection, if not already set + let crate::command::network_service::responses::OperatorSelection { mode, .. } = self + .at + .send(&crate::command::network_service::GetOperatorSelection) + .await?; + + // Only run AT+COPS=0 if currently de-registered, to avoid PLMN reselection + if !matches!( + mode, + crate::command::network_service::types::OperatorSelectionMode::Automatic + | crate::command::network_service::types::OperatorSelectionMode::Manual + ) { + self.at + .send(&crate::command::network_service::SetOperatorSelection { + mode: crate::command::network_service::types::OperatorSelectionMode::Automatic, + format: Some(2), + }) + .await?; + } + + Ok(()) + } + + pub(crate) async fn enable_registration_urcs(&mut self) -> Result<(), Error> { + // if packet domain event reporting is not set it's not a stopper. We + // might lack some events when we are dropped from the network. + // TODO: Re-enable this when it works, and is useful! + if self + .at + .send(&crate::command::psn::SetPacketSwitchedEventReporting { + mode: crate::command::psn::types::PSEventReportingMode::CircularBufferUrcs, + bfr: None, + }) + .await + .is_err() + { + warn!("Packet domain event reporting set failed"); + } + + // FIXME: Currently `atat` is unable to distinguish `xREG` family of + // commands from URC's + + // CREG URC + self.at.send( + &crate::command::network_service::SetNetworkRegistrationStatus { + n: crate::command::network_service::types::NetworkRegistrationUrcConfig::UrcDisabled, + }).await?; + + // CGREG URC + self.at + .send(&crate::command::psn::SetGPRSNetworkRegistrationStatus { + n: crate::command::psn::types::GPRSNetworkRegistrationUrcConfig::UrcDisabled, + }) + .await?; + + // CEREG URC + self.at + .send(&crate::command::psn::SetEPSNetworkRegistrationStatus { + n: crate::command::psn::types::EPSNetworkRegistrationUrcConfig::UrcDisabled, + }) + .await?; + + Ok(()) + } pub async fn select_sim_card(&mut self) -> Result<(), Error> { for _ in 0..2 { match self.at.send(&GetPinStatus).await { Ok(PinStatus { code }) if code == PinStatusCode::Ready => { + debug!("SIM is ready"); return Ok(()); } _ => {} @@ -270,9 +368,12 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> }) .await?; - Err(Error::Busy) + Ok(()) } + /// Reset the module by driving it's `RESET_N` pin low for 50 ms + /// + /// **NOTE** This function will reset NVM settings! pub async fn reset(&mut self) -> Result<(), Error> { warn!("Hard resetting Ublox Cellular Module"); if let Some(pin) = self.config.reset_pin() { @@ -287,10 +388,71 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> Ok(()) } - pub async fn restart(&mut self, store: bool) -> Result<(), Error> { + /// Perform at full factory reset of the module, clearing all NVM sectors in the process + pub async fn factory_reset(&mut self) -> Result<(), Error> { + self.at + .send(&crate::command::system_features::SetFactoryConfiguration { + fs_op: crate::command::system_features::types::FSFactoryRestoreType::AllFiles, + nvm_op: + crate::command::system_features::types::NVMFactoryRestoreType::NVMFlashSectors, + }) + .await?; + + info!("Successfully factory reset modem!"); + + if self.soft_reset(true).await.is_err() { + self.reset().await?; + } + Ok(()) } + /// Reset the module by sending AT CFUN command + pub async fn soft_reset(&mut self, sim_reset: bool) -> Result<(), Error> { + trace!( + "Attempting to soft reset of the modem with sim reset: {}.", + sim_reset + ); + + let fun = if sim_reset { + Functionality::SilentResetWithSimReset + } else { + Functionality::SilentReset + }; + + match self + .at + .send(&SetModuleFunctionality { + fun, + // SARA-R5 This parameter can be used only when is 1, 4 or 19 + #[cfg(feature = "sara-r5")] + rst: None, + #[cfg(not(feature = "sara-r5"))] + rst: Some(ResetMode::DontReset), + }) + .await + { + Ok(_) => { + info!("Successfully soft reset modem!"); + Ok(()) + } + Err(err) => { + error!("Failed to soft reset modem: {:?}", err); + Err(Error::Atat(err)) + } + } + } + + // checks alive status continuiously until it is alive + async fn check_is_alive_loop(&mut self) -> bool { + loop { + if let Ok(alive) = self.is_alive().await { + return alive; + } + Timer::after(Duration::from_millis(100)).await; + } + } + pub async fn run(mut self) -> ! { match self.has_power().await.ok() { Some(false) => { @@ -347,29 +509,54 @@ impl<'d, AT: AtatClient, C: CellularConfig, const URC_CAPACITY: usize> break; } }, - Ok(OperationState::Alive) => match self.is_alive().await { + Ok(OperationState::Alive) => { + match with_timeout(boot_time() * 2, self.check_is_alive_loop()) + .await + { + Ok(true) => { + debug!("Will set Alive"); + self.ch.set_power_state(OperationState::Alive); + debug!("Set Alive"); + } + Ok(false) => { + error!("Error in is_alive: {:?}", Error::PoweredDown); + break; + } + Err(err) => { + error!("Error in is_alive: {:?}", err); + break; + } + } + } + // Ok(OperationState::Alive) => match self.is_alive().await { + // Ok(_) => { + // debug!("Will set Alive"); + // self.ch.set_power_state(OperationState::Alive); + // debug!("Set Alive"); + // } + // Err(err) => { + // error!("Error in is_alive: {:?}", err); + // break; + // } + // }, + Ok(OperationState::Initialized) => match self.init_at().await { Ok(_) => { - debug!("Will set Alive"); - self.ch.set_power_state(OperationState::Alive); - debug!("Set Alive"); + self.ch.set_power_state(OperationState::Initialized); } Err(err) => { - error!("Error in is_alive: {:?}", err); + error!("Error in init_at: {:?}", err); break; } }, - Ok(OperationState::Initialized) => match self.init_at().await { + Ok(OperationState::Connected) => match self.init_network().await { Ok(_) => { - self.ch.set_power_state(OperationState::Initialized); + self.ch.set_power_state(OperationState::Connected); } Err(err) => { - error!("Error in init_at: {:?}", err); + error!("Error in init_network: {:?}", err); break; } }, - Ok(OperationState::Connected) => { - todo!() - } Ok(OperationState::DataEstablished) => { todo!() } From 1cde3b5bc89171d2993b101fb5719a478dac213e Mon Sep 17 00:00:00 2001 From: Tobias Breitwieser Date: Sat, 30 Dec 2023 20:12:49 +0100 Subject: [PATCH 14/16] toolchain stable 1.75 --- .../embassy-stm32-example/rust-toolchain.toml | 3 +-- examples/embassy-stm32-example/src/main.rs | 18 +++++++++++++++--- rust-toolchain.toml | 2 +- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/examples/embassy-stm32-example/rust-toolchain.toml b/examples/embassy-stm32-example/rust-toolchain.toml index 203817d..25d771e 100644 --- a/examples/embassy-stm32-example/rust-toolchain.toml +++ b/examples/embassy-stm32-example/rust-toolchain.toml @@ -1,8 +1,7 @@ # Before upgrading check that everything is available on all tier1 targets here: # https://rust-lang.github.io/rustup-components-history [toolchain] -channel = "beta-2023-12-17" -#channel = "nightly-2023-12-17" +channel = "1.75" components = [ "rust-src", "rustfmt", "llvm-tools" ] targets = [ "thumbv7em-none-eabi", diff --git a/examples/embassy-stm32-example/src/main.rs b/examples/embassy-stm32-example/src/main.rs index fbf8617..b124f50 100644 --- a/examples/embassy-stm32-example/src/main.rs +++ b/examples/embassy-stm32-example/src/main.rs @@ -104,6 +104,10 @@ async fn main_task(spawner: Spawner) { let led2_pin = p.PI13.degrade(); let led3_pin = p.PI14.degrade(); + spawner.spawn(blinky(led1_pin)).unwrap(); + spawner.spawn(blinky(led2_pin)).unwrap(); + spawner.spawn(blinky(led3_pin)).unwrap(); + static tx_buf: StaticCell<[u8; 16]> = StaticCell::new(); static rx_buf: StaticCell<[u8; 16]> = StaticCell::new(); @@ -185,9 +189,6 @@ async fn main_task(spawner: Spawner) { Timer::after(Duration::from_millis(5000)).await; } - loop { - Timer::after(Duration::from_millis(1000)).await; - } } #[embassy_executor::task] @@ -218,6 +219,17 @@ async fn cellular_task( runner.run().await } +#[embassy_executor::task(pool_size = 3)] +async fn blinky(mut led: AnyPin){ + let mut output = Output::new(led, Level::High, Speed::Low).degrade(); + loop { + output.set_high(); + Timer::after(Duration::from_millis(1000)).await; + output.set_low(); + Timer::after(Duration::from_millis(1000)).await; + } +} + static EXECUTOR: StaticCell = StaticCell::new(); #[entry] diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 3487713..cab8465 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "nightly-2023-11-01" +channel = "1.75" components = [ "rust-src", "rustfmt", "llvm-tools-preview", "clippy" ] targets = [ "x86_64-unknown-linux-gnu", From 2ee188a83f6d4b931d3513e4f20d1042ea0d4389 Mon Sep 17 00:00:00 2001 From: Tobias Breitwieser Date: Wed, 3 Jan 2024 21:52:03 +0100 Subject: [PATCH 15/16] use ublox-sockets git dependency --- Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b44eb81..ae5fd6d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,8 @@ hash32 = "^0.3" heapless = { version = "^0.8", features = ["serde"] } nb = "^1" serde = { version = "^1", default-features = false, features = ["derive"] } -ublox-sockets = { version = "0.5", optional = true } +#ublox-sockets = { version = "0.5", optional = true } +ublox-sockets = { git = "https://github.com/BlackbirdHQ/ublox-sockets", branch = "feature/async-borrowed-sockets", optional = true } embassy-time = "0.2" embassy-sync = "0.5" From d281c421f155e979bf97957283092d7ca390631c Mon Sep 17 00:00:00 2001 From: Tobias Breitwieser Date: Wed, 3 Jan 2024 21:54:40 +0100 Subject: [PATCH 16/16] remove hash32 dependency --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ae5fd6d..476de9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,6 @@ doctest = false [dependencies] atat = { version = "0.20.0", features = ["derive", "bytes"] } -hash32 = "^0.3" heapless = { version = "^0.8", features = ["serde"] } nb = "^1" serde = { version = "^1", default-features = false, features = ["derive"] }