From dd4162b69275b0294521fb93c05dcca273f81585 Mon Sep 17 00:00:00 2001 From: Mathias Date: Tue, 11 Jul 2023 13:43:49 +0200 Subject: [PATCH 1/7] Add feature gates for module timing for lara-r6 & toby-r2 --- ublox-cellular/Cargo.toml | 2 +- ublox-cellular/src/client.rs | 1 + ublox-cellular/src/module_timing.rs | 14 +++++++++++--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/ublox-cellular/Cargo.toml b/ublox-cellular/Cargo.toml index ae16902..88955fc 100644 --- a/ublox-cellular/Cargo.toml +++ b/ublox-cellular/Cargo.toml @@ -17,7 +17,7 @@ doctest = false [dependencies] # atat = { version = "0.18", features = ["derive", "bytes"] } atat = { git = "https://github.com/BlackbirdHQ/atat", rev = "70283be", features = ["derive", "defmt", "bytes"] } -embedded-hal = "=1.0.0-alpha.10" +embedded-hal = "=1.0.0-alpha.11" embedded-nal = "0.6" fugit = { version = "0.3" } fugit-timer = { version = "0.1.3" } diff --git a/ublox-cellular/src/client.rs b/ublox-cellular/src/client.rs index 510e34f..d8c1177 100644 --- a/ublox-cellular/src/client.rs +++ b/ublox-cellular/src/client.rs @@ -280,6 +280,7 @@ where false, )?; + #[cfg(any(feature = "lara-r6"))] self.network.send_internal( &SetGpioConfiguration { gpio_id: 42, diff --git a/ublox-cellular/src/module_timing.rs b/ublox-cellular/src/module_timing.rs index 0a9dac9..5f2f7dc 100644 --- a/ublox-cellular/src/module_timing.rs +++ b/ublox-cellular/src/module_timing.rs @@ -7,6 +7,8 @@ use fugit::TimerDurationU32; pub fn pwr_on_time() -> TimerDurationU32 { if cfg!(feature = "lara-r6") { 150.millis() + } else if cfg!(feature = "toby-r2") { + 50.micros() } else { 50.micros() } @@ -16,6 +18,8 @@ pub fn pwr_on_time() -> TimerDurationU32 { pub fn pwr_off_time() -> TimerDurationU32 { if cfg!(feature = "lara-r6") { 1500.millis() + } else if cfg!(feature = "toby-r2") { + 1.secs() } else { 1.secs() } @@ -25,16 +29,20 @@ pub fn pwr_off_time() -> TimerDurationU32 { pub fn reset_time() -> TimerDurationU32 { if cfg!(feature = "lara-r6") { 10.millis() + } else if cfg!(feature = "toby-r2") { + 50.millis() } else { 50.millis() } } /// Low time of `RESET_N` pin to trigger module abrupt emergency switch off -pub fn kill_time() -> TimerDurationU32 { +/// +/// NOTE: Not all modules support this operation from `RESET_N` +pub fn kill_time() -> Option> { if cfg!(feature = "lara-r6") { - 10.secs() + Some(10.secs()) } else { - 10.secs() + None } } From 5c445854a0e44f99da4362799b502e1631939a2d Mon Sep 17 00:00:00 2001 From: Kenneth Knudsen Date: Thu, 31 Aug 2023 13:47:26 +0200 Subject: [PATCH 2/7] get signal strength --- ublox-cellular/src/client.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/ublox-cellular/src/client.rs b/ublox-cellular/src/client.rs index d8c1177..aa648ff 100644 --- a/ublox-cellular/src/client.rs +++ b/ublox-cellular/src/client.rs @@ -1,4 +1,4 @@ -use atat::blocking::AtatClient; +use atat::{blocking::AtatClient, AtatResp}; use embedded_hal::digital::{InputPin, OutputPin}; use fugit::ExtU32; use ublox_sockets::SocketSet; @@ -26,8 +26,8 @@ use crate::{ SetGpioConfiguration, }, network_service::{ - responses::OperatorSelection, types::OperatorSelectionMode, GetOperatorSelection, - SetOperatorSelection, + responses::{OperatorSelection, SignalQuality}, types::OperatorSelectionMode, GetOperatorSelection, + SetOperatorSelection , GetSignalQuality, }, psn::{types::PSEventReportingMode, SetPacketSwitchedEventReporting}, }, @@ -167,6 +167,11 @@ where device } + pub fn signal_strength(&mut self) -> Result + { + self.send_at(&GetSignalQuality) + } + /// Set storage for TCP/UDP sockets /// /// # Examples From 60ca1ff2024e8077adfeff391d758726ac43242e Mon Sep 17 00:00:00 2001 From: Mathias Koch Date: Tue, 29 Aug 2023 08:50:12 +0200 Subject: [PATCH 3/7] chore(*): add feature gates for module timing for lara-r6 & toby-r2 (#81) * Add feature gates for module timing for lara-r6 & toby-r2 * Bump embedded-hal to rc.1 --- ublox-cellular/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ublox-cellular/Cargo.toml b/ublox-cellular/Cargo.toml index 88955fc..d202223 100644 --- a/ublox-cellular/Cargo.toml +++ b/ublox-cellular/Cargo.toml @@ -17,7 +17,7 @@ doctest = false [dependencies] # atat = { version = "0.18", features = ["derive", "bytes"] } atat = { git = "https://github.com/BlackbirdHQ/atat", rev = "70283be", features = ["derive", "defmt", "bytes"] } -embedded-hal = "=1.0.0-alpha.11" +embedded-hal = "=1.0.0-rc.1" embedded-nal = "0.6" fugit = { version = "0.3" } fugit-timer = { version = "0.1.3" } From 16b2ad922cee01faba7e9d9e1478acfe27d0fa3f Mon Sep 17 00:00:00 2001 From: Kenneth Knudsen Date: Tue, 5 Sep 2023 12:53:51 +0200 Subject: [PATCH 4/7] cargo alpha 11 fix --- ublox-cellular/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ublox-cellular/Cargo.toml b/ublox-cellular/Cargo.toml index d202223..88955fc 100644 --- a/ublox-cellular/Cargo.toml +++ b/ublox-cellular/Cargo.toml @@ -17,7 +17,7 @@ doctest = false [dependencies] # atat = { version = "0.18", features = ["derive", "bytes"] } atat = { git = "https://github.com/BlackbirdHQ/atat", rev = "70283be", features = ["derive", "defmt", "bytes"] } -embedded-hal = "=1.0.0-rc.1" +embedded-hal = "=1.0.0-alpha.11" embedded-nal = "0.6" fugit = { version = "0.3" } fugit-timer = { version = "0.1.3" } From cdcca1cd7a81a183874aa145c310f65ca3859560 Mon Sep 17 00:00:00 2001 From: Mathias Koch Date: Tue, 29 Aug 2023 08:50:12 +0200 Subject: [PATCH 5/7] chore(*): add feature gates for module timing for lara-r6 & toby-r2 (#81) * Add feature gates for module timing for lara-r6 & toby-r2 * Bump embedded-hal to rc.1 --- ublox-cellular/Cargo.toml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/ublox-cellular/Cargo.toml b/ublox-cellular/Cargo.toml index 88955fc..f46981c 100644 --- a/ublox-cellular/Cargo.toml +++ b/ublox-cellular/Cargo.toml @@ -16,8 +16,12 @@ doctest = false [dependencies] # atat = { version = "0.18", features = ["derive", "bytes"] } -atat = { git = "https://github.com/BlackbirdHQ/atat", rev = "70283be", features = ["derive", "defmt", "bytes"] } -embedded-hal = "=1.0.0-alpha.11" +atat = { git = "https://github.com/BlackbirdHQ/atat", rev = "70283be", features = [ + "derive", + "defmt", + "bytes", +] } +embedded-hal = "=1.0.0-rc.1" embedded-nal = "0.6" fugit = { version = "0.3" } fugit-timer = { version = "0.1.3" } @@ -40,7 +44,13 @@ default = ["socket-udp", "socket-tcp"] async = ["atat/async"] # Use `defmt-impl to enable defmt based logging -defmt-impl = ["defmt", "ublox-sockets/defmt", "fugit/defmt", "atat/defmt", "heapless/defmt-impl"] +defmt-impl = [ + "defmt", + "ublox-sockets/defmt", + "fugit/defmt", + "atat/defmt", + "heapless/defmt-impl", +] # Use `log-impl` to enable log based logging log-impl = ["log", "ublox-sockets/log", "atat/log"] From 558abd94065c9c9a3732b74b28a09ea9e672e9dc Mon Sep 17 00:00:00 2001 From: Mathias Koch Date: Tue, 12 Sep 2023 13:09:08 +0200 Subject: [PATCH 6/7] chore(*): use latest atat, with new urc channel & replace fugit with embassy-time (#83) * - Update ATAT, and implement the new URC subscriber channels - Remove `fugit` and replace it with `embassy-time` - Update `ublox-sockets`, facilitating both of above changes - Remove unimplemented sms, voice and location service skeletons - Remove pin generics in favor of a single `CellularConfig` trait with associated types * Make flowcontrol a bool in config trait, and export config trait * Use latest atat git rev * Fix sometimes stuck in infinite loop at AT probing on initialization * Update CI to use nightly and remove unused workflows --- .github/workflows/audit.yml | 14 - .github/workflows/ci.yml | 56 +++ .github/workflows/docs.yml | 47 --- .github/workflows/lint.yml | 85 ----- .github/workflows/test.yml | 35 -- Cargo.toml | 2 +- rust-toolchain.toml | 7 + ublox-cellular/Cargo.toml | 10 +- ublox-cellular/src/blocking_timer.rs | 21 ++ ublox-cellular/src/client.rs | 328 +++++------------- ublox-cellular/src/config.rs | 103 +----- ublox-cellular/src/error.rs | 7 - ublox-cellular/src/lib.rs | 27 +- ublox-cellular/src/module_timing.rs | 31 +- ublox-cellular/src/network.rs | 283 +++------------ ublox-cellular/src/power.rs | 110 ++---- ublox-cellular/src/registration.rs | 66 ++-- ublox-cellular/src/services/data/apn.rs | 22 +- ublox-cellular/src/services/data/dns.rs | 6 +- ublox-cellular/src/services/data/mod.rs | 57 ++- ublox-cellular/src/services/data/ssl.rs | 8 +- ublox-cellular/src/services/data/tcp_stack.rs | 19 +- ublox-cellular/src/services/data/udp_stack.rs | 17 +- ublox-cellular/src/services/location/error.rs | 0 ublox-cellular/src/services/location/mod.rs | 29 -- ublox-cellular/src/services/mod.rs | 3 - ublox-cellular/src/services/sms/error.rs | 0 ublox-cellular/src/services/sms/mod.rs | 1 - ublox-cellular/src/services/voice/error.rs | 0 ublox-cellular/src/services/voice/mod.rs | 1 - ublox-cellular/src/test_helpers.rs | 115 ------ 31 files changed, 387 insertions(+), 1123 deletions(-) delete mode 100644 .github/workflows/audit.yml create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/docs.yml delete mode 100644 .github/workflows/lint.yml delete mode 100644 .github/workflows/test.yml create mode 100644 rust-toolchain.toml create mode 100644 ublox-cellular/src/blocking_timer.rs delete mode 100644 ublox-cellular/src/services/location/error.rs delete mode 100644 ublox-cellular/src/services/location/mod.rs delete mode 100644 ublox-cellular/src/services/sms/error.rs delete mode 100644 ublox-cellular/src/services/sms/mod.rs delete mode 100644 ublox-cellular/src/services/voice/error.rs delete mode 100644 ublox-cellular/src/services/voice/mod.rs delete mode 100644 ublox-cellular/src/test_helpers.rs diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml deleted file mode 100644 index 4974b63..0000000 --- a/.github/workflows/audit.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: Security audit -on: - push: - paths: - - '**/Cargo.toml' - - '**/Cargo.lock' -jobs: - security_audit: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - uses: actions-rs/audit-check@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8797b4d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,56 @@ +on: + push: + branches: + - master + pull_request: + +name: CI + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + name: Build & Test + runs-on: ubuntu-latest + steps: + - name: Checkout source code + uses: actions/checkout@v3 + - uses: dsherret/rust-toolchain-file@v1 + - name: Build + uses: actions-rs/cargo@v1 + with: + command: build + args: --all --features "defmt-impl,lara-r6" --target thumbv7em-none-eabihf + + - name: Test + uses: actions-rs/cargo@v1 + with: + command: test + args: --lib --features "log,lara-r6" + env: + DEFMT_LOG: off + + rustfmt: + name: rustfmt + runs-on: ubuntu-latest + steps: + - name: Checkout source code + uses: actions/checkout@v3 + - uses: dsherret/rust-toolchain-file@v1 + - name: Rustfmt + run: cargo fmt -- --check + + clippy: + name: clippy + runs-on: ubuntu-latest + steps: + - name: Checkout source code + uses: actions/checkout@v3 + - uses: dsherret/rust-toolchain-file@v1 + - name: Run clippy + uses: actions-rs/clippy-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + args: --features "lara-r6" -- ${{ env.CLIPPY_PARAMS }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml deleted file mode 100644 index 68df0b5..0000000 --- a/.github/workflows/docs.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Documentation - -on: - push: - branches: - - master - -jobs: - docs: - name: Documentation - runs-on: ubuntu-latest - steps: - - name: Checkout source code - uses: actions/checkout@v2 - with: - persist-credentials: false - - - name: Install Rust - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - - - name: Build documentation - uses: actions-rs/cargo@v1 - with: - command: doc - args: --verbose --no-deps --features "log,lara-r6" - - # - name: Finalize documentation - # run: | - # CRATE_NAME=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]' | cut -f2 -d"/") - # echo "" > target/doc/index.html - # touch target/doc/.nojekyll - # - name: Upload as artifact - # uses: actions/upload-artifact@v2 - # with: - # name: Documentation - # path: target/doc - - # - name: Deploy - # uses: JamesIves/github-pages-deploy-action@releases/v3 - # with: - # ACCESS_TOKEN: ${{ secrets.GH_PAT }} - # BRANCH: gh-pages - # FOLDER: target/doc diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index 4f385f6..0000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,85 +0,0 @@ -name: Lint - -on: - push: - branches: - - master - pull_request: - -defaults: - run: - shell: bash - -env: - # CLIPPY_PARAMS: -W clippy::all -W clippy::pedantic -W clippy::nursery -W clippy::cargo - CLIPPY_PARAMS: - -jobs: - rustfmt: - name: rustfmt - runs-on: ubuntu-latest - steps: - - name: Checkout source code - uses: actions/checkout@v2 - - - name: Install Rust - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - components: rustfmt - - - name: Run rustfmt - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check --verbose - - # tomlfmt: - # name: tomlfmt - # runs-on: ubuntu-latest - # steps: - # - name: Checkout source code - # uses: actions/checkout@v2 - - # - name: Install Rust - # uses: actions-rs/toolchain@v1 - # with: - # profile: minimal - # toolchain: nightly - # override: true - - # - name: Install tomlfmt - # uses: actions-rs/install@v0.1 - # with: - # crate: cargo-tomlfmt - # version: latest - # use-tool-cache: true - - # - name: Run Tomlfmt - # uses: actions-rs/cargo@v1 - # with: - # command: tomlfmt - # args: --dryrun - - clippy: - name: clippy - runs-on: ubuntu-latest - steps: - - name: Checkout source code - uses: actions/checkout@v2 - - - name: Install Rust - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - components: clippy - - - name: Run clippy - uses: actions-rs/clippy-check@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - args: --features "lara-r6" -- ${{ env.CLIPPY_PARAMS }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 85aa2dd..0000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Test - -on: - push: - branches: - - master - pull_request: - -jobs: - test: - name: Test - runs-on: ubuntu-latest - steps: - - name: Checkout source code - uses: actions/checkout@v2 - - - name: Install Rust - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - target: thumbv7m-none-eabi - override: true - - - name: Build - uses: actions-rs/cargo@v1 - with: - command: build - args: --all --features "defmt-impl,lara-r6" --target thumbv7m-none-eabi - - - name: Test - uses: actions-rs/cargo@v1 - with: - command: test - args: --lib --features "log,lara-r6" diff --git a/Cargo.toml b/Cargo.toml index fc2bad9..2420618 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,5 +9,5 @@ members = [ ] [patch.crates-io] -atat = { git = "https://github.com/BlackbirdHQ/atat", rev = "70283be" } +atat = { git = "https://github.com/BlackbirdHQ/atat", rev = "c5caaf7" } # ublox-sockets = { path = "../ublox-sockets" } \ No newline at end of file diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..3cd5460 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,7 @@ +[toolchain] +channel = "nightly-2023-06-28" +components = [ "rust-src", "rustfmt", "llvm-tools-preview", "clippy" ] +targets = [ + "x86_64-unknown-linux-gnu", + "thumbv7em-none-eabihf" +] diff --git a/ublox-cellular/Cargo.toml b/ublox-cellular/Cargo.toml index f46981c..f41cf06 100644 --- a/ublox-cellular/Cargo.toml +++ b/ublox-cellular/Cargo.toml @@ -16,21 +16,22 @@ doctest = false [dependencies] # atat = { version = "0.18", features = ["derive", "bytes"] } -atat = { git = "https://github.com/BlackbirdHQ/atat", rev = "70283be", features = [ +atat = { git = "https://github.com/BlackbirdHQ/atat", rev = "c5caaf7", features = [ "derive", "defmt", "bytes", ] } embedded-hal = "=1.0.0-rc.1" embedded-nal = "0.6" -fugit = { version = "0.3" } -fugit-timer = { version = "0.1.3" } hash32 = "^0.2.1" hash32-derive = "^0.1.0" heapless = { version = "^0.7", features = ["serde"] } nb = "^1" serde = { version = "^1", default-features = false, features = ["derive"] } -ublox-sockets = "0.5.0" +# ublox-sockets = "0.5.0" +ublox-sockets = { git = "https://github.com/BlackbirdHQ/ublox-sockets", rev = "b1ff942" } +embassy-time = "0.1" +embedded-io = "0.5" # Enable `serde` feature of `no-std-net` no-std-net = { version = "^0.5", features = ["serde"] } @@ -47,7 +48,6 @@ async = ["atat/async"] defmt-impl = [ "defmt", "ublox-sockets/defmt", - "fugit/defmt", "atat/defmt", "heapless/defmt-impl", ] diff --git a/ublox-cellular/src/blocking_timer.rs b/ublox-cellular/src/blocking_timer.rs new file mode 100644 index 0000000..15be27b --- /dev/null +++ b/ublox-cellular/src/blocking_timer.rs @@ -0,0 +1,21 @@ +use embassy_time::{Duration, Instant}; + +pub struct BlockingTimer { + expires_at: Instant, +} + +impl BlockingTimer { + pub fn after(duration: Duration) -> Self { + Self { + expires_at: Instant::now() + duration, + } + } + + pub fn wait(self) { + loop { + if self.expires_at <= Instant::now() { + break; + } + } + } +} diff --git a/ublox-cellular/src/client.rs b/ublox-cellular/src/client.rs index aa648ff..fb12f36 100644 --- a/ublox-cellular/src/client.rs +++ b/ublox-cellular/src/client.rs @@ -1,9 +1,9 @@ -use atat::{blocking::AtatClient, AtatResp}; -use embedded_hal::digital::{InputPin, OutputPin}; -use fugit::ExtU32; +use atat::{blocking::AtatClient, AtatUrcChannel}; +use embassy_time::Duration; use ublox_sockets::SocketSet; use crate::{ + blocking_timer::BlockingTimer, command::device_lock::{responses::PinStatus, types::PinStatusCode, GetPinStatus}, command::{ control::{ @@ -26,17 +26,19 @@ use crate::{ SetGpioConfiguration, }, network_service::{ - responses::{OperatorSelection, SignalQuality}, types::OperatorSelectionMode, GetOperatorSelection, - SetOperatorSelection , GetSignalQuality, + responses::{OperatorSelection, SignalQuality}, + types::OperatorSelectionMode, + GetOperatorSelection, GetSignalQuality, SetOperatorSelection, }, psn::{types::PSEventReportingMode, SetPacketSwitchedEventReporting}, }, - config::Config, - error::{from_clock, Error, GenericError}, + config::CellularConfig, + error::{Error, GenericError}, network::{AtTx, Network}, power::PowerState, registration::ConnectionState, services::data::ContextState, + UbloxCellularBuffers, UbloxCellularIngress, UbloxCellularUrcChannel, }; use ip_transport_layer::{types::HexMode, SetHexMode}; use network_service::{types::NetworkRegistrationUrcConfig, SetNetworkRegistrationStatus}; @@ -45,6 +47,9 @@ use psn::{ SetEPSNetworkRegistrationStatus, SetGPRSNetworkRegistrationStatus, }; +pub(crate) const URC_CAPACITY: usize = 3; +pub(crate) const URC_SUBSCRIBERS: usize = 1; + #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum State { @@ -56,122 +61,83 @@ pub enum State { FullyInitialized, } -pub struct Device -where - C: AtatClient, - CLK: 'static + fugit_timer::Timer, - RST: OutputPin, - PWR: OutputPin, - DTR: OutputPin, - VINT: InputPin, -{ - pub(crate) config: Config, - pub(crate) network: Network, +pub struct Device<'buf, 'sub, AtCl, AtUrcCh, Config, const N: usize, const L: usize> { + pub(crate) config: Config, + pub(crate) network: Network<'sub, AtCl>, + urc_channel: &'buf AtUrcCh, pub(crate) state: State, pub(crate) power_state: PowerState, // Ublox devices can hold a maximum of 6 active sockets - pub(crate) sockets: Option<&'static mut SocketSet>, + pub(crate) sockets: Option<&'static mut SocketSet>, } -impl Drop - for Device +impl<'buf, 'sub, W, Config, const INGRESS_BUF_SIZE: usize, const N: usize, const L: usize> + Device< + 'buf, + 'sub, + atat::blocking::Client<'buf, W, INGRESS_BUF_SIZE>, + UbloxCellularUrcChannel, + Config, + N, + L, + > where - C: AtatClient, - CLK: fugit_timer::Timer, - RST: OutputPin, - PWR: OutputPin, - DTR: OutputPin, - VINT: InputPin, + 'buf: 'sub, + W: embedded_io::Write, + Config: CellularConfig, { - fn drop(&mut self) { - if self.state != State::Off { - self.state = State::Off; - self.hard_power_off().ok(); - } + /// Create new u-blox device + /// + /// Look for [`data_service`](Device::data_service) how to handle data connection automatically. + /// + pub fn from_buffers( + buffers: &'buf UbloxCellularBuffers, + tx: W, + config: Config, + ) -> (UbloxCellularIngress, Self) { + let (ingress, client) = buffers.split_blocking( + tx, + atat::DefaultDigester::::default(), + atat::Config::default(), + ); + + (ingress, Device::new(client, &buffers.urc_channel, config)) } } -impl - Device +impl<'buf, 'sub, AtCl, AtUrcCh, Config, const N: usize, const L: usize> + Device<'buf, 'sub, AtCl, AtUrcCh, Config, N, L> where - C: AtatClient, - CLK: fugit_timer::Timer, - RST: OutputPin, - PWR: OutputPin, - DTR: OutputPin, - VINT: InputPin, + 'buf: 'sub, + AtCl: AtatClient, + AtUrcCh: AtatUrcChannel, + Config: CellularConfig, { - /// Create new u-blox device - /// - /// Look for [`data_service`](Device::data_service) how to handle data connection automatically. - /// - /// # Examples - /// - /// ```ignore - /// use bbqueue::BBBuffer; - /// use ublox_cellular::prelude::*; - /// use ublox_cellular::atat; - /// use ublox_cellular::{Config, GsmClient}; - /// - /// const RX_BUF_LEN: usize = 256; - /// const RES_CAPACITY: usize = 256; - /// const URC_CAPACITY: usize = 256; - /// const MAX_SOCKET_COUNT: usize = 1; - /// static mut RES_QUEUE: BBBuffer = BBBuffer::new(); - /// static mut URC_QUEUE: BBBuffer = BBBuffer::new(); - /// - /// type UbloxResetPin = gpio::Gpio26; - /// - /// let queues = atat::Queues { - /// res_queue: unsafe { RES_QUEUE.try_split_framed().unwrap() }, - /// urc_queue: unsafe { URC_QUEUE.try_split_framed().unwrap() }, - /// }; - /// - /// let (atat_client, mut ingress) = - /// atat::ClientBuilder::<_, _, _, TIMER_HZ, RX_BUF_LEN, RES_CAPACITY, URC_CAPACITY>::new( - /// tx, - /// timer::SysTimer::new(), - /// atat::AtDigester::::new(), - /// atat::Config::new(atat::Mode::Timeout), - /// ) - /// .build(queues); - /// - /// - /// let mut modem = GsmClient::< - /// _, - /// _, - /// UbloxResetPin, - /// gpio::Gpio0, - /// gpio::Gpio0, - /// gpio::Gpio0, - /// TIMER_HZ, - /// MAX_SOCKET_COUNT, - /// SOCKET_RING_BUFFER_LEN, - /// >::new( - /// atat_client, - /// timer::SysTimer::new(), - /// Config::new("").with_flow_control().with_rst(reset), - /// ); - /// ``` - pub fn new(client: C, timer: CLK, config: Config) -> Self { - let mut device = Self { + pub fn new(client: AtCl, urc_channel: &'buf AtUrcCh, config: Config) -> Self { + let urc_subscription = urc_channel.subscribe().unwrap(); + Self { config, + network: Network::new(AtTx::new(client, urc_subscription)), state: State::Off, power_state: PowerState::Off, - network: Network::new(AtTx::new(client, 10), timer), sockets: None, - }; - - device.power_state = device.power_state().unwrap_or(PowerState::Off); - device + urc_channel, + } } +} - pub fn signal_strength(&mut self) -> Result - { - self.send_at(&GetSignalQuality) - } +pub fn signal_strength(&mut self) -> Result { + self.send_at(&GetSignalQuality) +} +impl<'buf, 'sub, AtCl, AtUrcCh, Config, const N: usize, const L: usize> + Device<'buf, 'sub, AtCl, AtUrcCh, Config, N, L> +where + 'buf: 'sub, + AtCl: AtatClient, + Config: CellularConfig, +{ /// Set storage for TCP/UDP sockets /// /// # Examples @@ -179,11 +145,10 @@ where /// ```ignore /// use ublox_cellular::sockets::SocketSet; /// - /// const TIMER_HZ: u32 = 1000; /// const MAX_SOCKET_COUNT: usize = 1; /// const SOCKET_RING_BUFFER_LEN: usize = 1024; /// - /// static mut SOCKET_SET: Option> = None; + /// static mut SOCKET_SET: Option> = None; /// /// unsafe { /// SOCKET_SET = Some(SocketSet::new()); @@ -191,12 +156,12 @@ where /// /// modem.set_socket_storage(unsafe { SOCKET_SET.as_mut().unwrap() }); /// ``` - pub fn set_socket_storage(&mut self, socket_set: &'static mut SocketSet) { + pub fn set_socket_storage(&mut self, socket_set: &'static mut SocketSet) { socket_set.prune(); self.sockets.replace(socket_set); } - pub fn take_socket_storage(&mut self) -> Option<&'static mut SocketSet> { + pub fn take_socket_storage(&mut self) -> Option<&'static mut SocketSet> { self.sockets.take() } @@ -238,35 +203,13 @@ where self.clear_buffers()?; - if self.config.baud_rate > 230_400_u32 { - // Needs a way to reconfigure uart baud rate temporarily - // Relevant issue: https://github.com/rust-embedded/embedded-hal/issues/79 - return Err(Error::_Unknown); - - // self.network.send_internal( - // &SetDataRate { - // rate: BaudRate::B115200, - // }, - // true, - // )?; - - // NOTE: On the UART AT interface, after the reception of the "OK" result code for the +IPR command, the DTE - // shall wait for at least 100 ms before issuing a new AT command; this is to guarantee a proper baud rate - // reconfiguration. - - // UART end - // delay(100); - // UART begin(self.config.baud_rate) - - // self.is_alive()?; - } else { - // Make sure AT commands parser is in clean state. - // self.network.at_tx.reset()?; - self.power_on()?; - } + self.power_on()?; // At this point, if is_alive fails, the configured Baud rate is probably wrong - self.is_alive(10).map_err(|_| Error::BaudDetection)?; + if let Err(e) = self.is_alive(5).map_err(|_| Error::BaudDetection) { + self.hard_reset()?; + return Err(e); + } // Extended errors on self.network.send_internal( @@ -334,7 +277,7 @@ where false, )?; - if self.config.hex_mode { + if Config::HEX_MODE { self.network.send_internal( &SetHexMode { hex_mode_disable: HexMode::Enabled, @@ -352,7 +295,7 @@ where // Tell module whether we support flow control // FIXME: Use AT+IFC=2,2 instead of AT&K here - if self.config.flow_control { + if Config::FLOW_CONTROL { self.network.send_internal( &SetFlowControl { value: FlowControl::RtsCts, @@ -413,12 +356,7 @@ where _ => {} } - self.network - .status - .timer - .start(1.secs()) - .map_err(from_clock)?; - nb::block!(self.network.status.timer.wait()).map_err(from_clock)?; + BlockingTimer::after(Duration::from_secs(1)).wait(); } // There was an error initializing the SIM @@ -536,14 +474,6 @@ where sockets.prune(); } - // Allow ATAT some time to clear the buffers - self.network - .status - .timer - .start(300.millis()) - .map_err(from_clock)?; - nb::block!(self.network.status.timer.wait()).map_err(from_clock)?; - Ok(()) } @@ -565,6 +495,9 @@ where warn!("Packet domain event reporting set failed"); } + // FIXME: Currently `atat` is unable to distinguish `xREG` family of + // commands from URC's + // CREG URC self.network.send_internal( &SetNetworkRegistrationStatus { @@ -594,7 +527,6 @@ where fn handle_urc_internal(&mut self) -> Result<(), Error> { if let Some(ref mut sockets) = self.sockets.as_deref_mut() { - let ts = self.network.status.timer.now(); self.network .at_tx .handle_urc(|urc| { @@ -604,7 +536,7 @@ where if let Some((_, mut sock)) = sockets.iter_mut().find(|(handle, _)| *handle == socket) { - sock.closed_by_remote(ts); + sock.closed_by_remote(); } } Urc::SocketDataAvailable( @@ -652,95 +584,3 @@ where self.network.at_tx.handle_urc(f).map_err(Error::Network) } } - -#[cfg(test)] -mod tests { - use ublox_sockets::{SocketHandle, TcpSocket, UdpSocket}; - - use super::*; - use crate::test_helpers::{MockAtClient, MockTimer}; - use crate::{config::Config, services::data::ContextState, APNInfo}; - - const SOCKET_SIZE: usize = 128; - const SOCKET_SET_LEN: usize = 2; - const TIMER_HZ: u32 = 1000; - - static mut SOCKET_SET: Option> = None; - - #[test] - #[ignore] - fn prune_on_initialize() { - let client = MockAtClient::new(0); - let timer = MockTimer::new(None); - let config = Config::default(); - - let socket_set: &'static mut _ = unsafe { - SOCKET_SET = Some(SocketSet::new()); - SOCKET_SET.as_mut().unwrap_or_else(|| { - panic!("Failed to get the static com_queue"); - }) - }; - - let mut device = Device::<_, _, _, _, _, _, TIMER_HZ, SOCKET_SET_LEN, SOCKET_SIZE>::new( - client, timer, config, - ); - device.set_socket_storage(socket_set); - - // device.fsm.set_state(State::Connected); - // assert_eq!(device.fsm.get_state(), State::Connected); - device.state = State::FullyInitialized; - device.power_state = PowerState::On; - // assert_eq!(device.spin(), Ok(())); - - device.network.context_state = ContextState::Active; - - let mut data_service = device.data_service(&APNInfo::default()).unwrap(); - - if let Some(ref mut sockets) = data_service.sockets { - sockets - .add(TcpSocket::new(0)) - .expect("Failed to add new tcp socket!"); - assert_eq!(sockets.len(), 1); - - let mut tcp = sockets - .get::>(SocketHandle(0)) - .expect("Failed to get socket"); - - assert_eq!(tcp.rx_window(), SOCKET_SIZE); - let socket_data = b"This is socket data!!"; - tcp.rx_enqueue_slice(socket_data); - assert_eq!(tcp.recv_queue(), socket_data.len()); - assert_eq!(tcp.rx_window(), SOCKET_SIZE - socket_data.len()); - - sockets - .add(UdpSocket::new(1)) - .expect("Failed to add new udp socket!"); - assert_eq!(sockets.len(), 2); - - assert!(sockets.add(UdpSocket::new(0)).is_err()); - } else { - panic!() - } - - drop(data_service); - - device.clear_buffers().expect("Failed to clear buffers"); - - let mut data_service = device.data_service(&APNInfo::default()).unwrap(); - if let Some(ref mut sockets) = data_service.sockets { - assert_eq!(sockets.len(), 0); - - sockets - .add(TcpSocket::new(0)) - .expect("Failed to add new tcp socket!"); - assert_eq!(sockets.len(), 1); - - let tcp = sockets - .get::>(SocketHandle(0)) - .expect("Failed to get socket"); - assert_eq!(tcp.recv_queue(), 0); - } else { - panic!() - } - } -} diff --git a/ublox-cellular/src/config.rs b/ublox-cellular/src/config.rs index 7fb984e..727500b 100644 --- a/ublox-cellular/src/config.rs +++ b/ublox-cellular/src/config.rs @@ -1,5 +1,4 @@ use embedded_hal::digital::{ErrorType, InputPin, OutputPin}; -use heapless::String; pub struct NoPin; @@ -27,99 +26,15 @@ impl OutputPin for NoPin { } } -#[derive(Debug)] -pub struct Config { - pub(crate) rst_pin: Option, - pub(crate) dtr_pin: Option, - pub(crate) pwr_pin: Option, - pub(crate) vint_pin: Option, - pub(crate) baud_rate: u32, - pub(crate) hex_mode: bool, - pub(crate) flow_control: bool, - pub(crate) pin: String<4>, -} - -impl Default for Config { - fn default() -> Self { - Self { - rst_pin: None, - dtr_pin: None, - pwr_pin: None, - vint_pin: None, - baud_rate: 115_200_u32, - hex_mode: true, - flow_control: false, - pin: String::new(), - } - } -} - -impl Config -where - RST: OutputPin, - PWR: OutputPin, - DTR: OutputPin, - VINT: InputPin, -{ - #[must_use] - pub fn new(pin: &str) -> Self { - Self { - rst_pin: None, - dtr_pin: None, - pwr_pin: None, - vint_pin: None, - baud_rate: 115_200_u32, - hex_mode: true, - flow_control: false, - pin: String::from(pin), - } - } +pub trait CellularConfig { + type ResetPin: OutputPin; + type PowerPin: OutputPin; + type VintPin: InputPin; - pub fn with_rst(self, rst_pin: RST) -> Self { - Self { - rst_pin: Some(rst_pin), - ..self - } - } + const FLOW_CONTROL: bool = false; + const HEX_MODE: bool = true; - pub fn with_pwr(self, pwr_pin: PWR) -> Self { - Self { - pwr_pin: Some(pwr_pin), - ..self - } - } - - pub fn with_dtr(self, dtr_pin: DTR) -> Self { - Self { - dtr_pin: Some(dtr_pin), - ..self - } - } - - pub fn with_vint(self, vint_pin: VINT) -> Self { - Self { - vint_pin: Some(vint_pin), - ..self - } - } - - pub fn baud_rate>(self, baud_rate: B) -> Self { - // FIXME: Validate baudrates - - Self { - baud_rate: baud_rate.into(), - ..self - } - } - - pub fn with_flow_control(self) -> Self { - Self { - flow_control: true, - ..self - } - } - - pub fn pin(&self) -> &str { - &self.pin - } + fn reset_pin(&mut self) -> Option<&mut Self::ResetPin>; + fn power_pin(&mut self) -> Option<&mut Self::PowerPin>; + fn vint_pin(&mut self) -> Option<&mut Self::VintPin>; } diff --git a/ublox-cellular/src/error.rs b/ublox-cellular/src/error.rs index c4cb3ec..57e6999 100644 --- a/ublox-cellular/src/error.rs +++ b/ublox-cellular/src/error.rs @@ -50,10 +50,3 @@ impl From for Error { } } } - -// `Clock` trait has associated `Error` type. -// Therefore we cannot use `From` for error converion. -// This is helper that can be used as `.map_err(from_clock)` -pub fn from_clock(_error: E) -> Error { - Error::Generic(GenericError::Clock) -} diff --git a/ublox-cellular/src/lib.rs b/ublox-cellular/src/lib.rs index f36e370..bb2deda 100644 --- a/ublox-cellular/src/lib.rs +++ b/ublox-cellular/src/lib.rs @@ -78,6 +78,7 @@ // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; +mod blocking_timer; mod client; pub mod command; mod config; @@ -89,21 +90,35 @@ mod registration; mod services; pub use atat::serde_bytes; +use client::{URC_CAPACITY, URC_SUBSCRIBERS}; +use command::Urc; pub use ublox_sockets as sockets; -#[cfg(test)] -mod test_helpers; - pub use client::Device as GsmClient; -pub use config::{Config, NoPin}; +pub use config::NoPin; pub use network::{ContextId, ProfileId}; pub use services::data::apn::{APNInfo, Apn}; pub use services::data::ssl::SecurityProfileId; pub use services::data::DataService; -// Re-export atat and fugit +// Re-export atat pub use atat; -pub use fugit; + +pub type UbloxCellularBuffers = + atat::Buffers; + +pub type UbloxCellularIngress<'a, const INGRESS_BUF_SIZE: usize> = atat::Ingress< + 'a, + atat::DefaultDigester, + Urc, + INGRESS_BUF_SIZE, + URC_CAPACITY, + URC_SUBSCRIBERS, +>; + +pub type UbloxCellularUrcChannel = atat::UrcChannel; + +pub use config::CellularConfig; /// Prelude - Include traits pub mod prelude { diff --git a/ublox-cellular/src/module_timing.rs b/ublox-cellular/src/module_timing.rs index 5f2f7dc..18d1fc7 100644 --- a/ublox-cellular/src/module_timing.rs +++ b/ublox-cellular/src/module_timing.rs @@ -1,47 +1,46 @@ #![allow(clippy::if_same_then_else)] -use fugit::ExtU32; -use fugit::TimerDurationU32; +use embassy_time::Duration; /// Low time of `PWR_ON` pin to trigger module switch on from power off mode -pub fn pwr_on_time() -> TimerDurationU32 { +pub fn pwr_on_time() -> Duration { if cfg!(feature = "lara-r6") { - 150.millis() + Duration::from_millis(150) } else if cfg!(feature = "toby-r2") { - 50.micros() + Duration::from_micros(50) } else { - 50.micros() + Duration::from_micros(50) } } /// Low time of `PWR_ON` pin to trigger module graceful switch off -pub fn pwr_off_time() -> TimerDurationU32 { +pub fn pwr_off_time() -> Duration { if cfg!(feature = "lara-r6") { - 1500.millis() + Duration::from_millis(1500) } else if cfg!(feature = "toby-r2") { - 1.secs() + Duration::from_secs(1) } else { - 1.secs() + Duration::from_secs(1) } } /// Low time of `RESET_N` pin to trigger module reset (reboot) -pub fn reset_time() -> TimerDurationU32 { +pub fn reset_time() -> Duration { if cfg!(feature = "lara-r6") { - 10.millis() + Duration::from_millis(10) } else if cfg!(feature = "toby-r2") { - 50.millis() + Duration::from_millis(50) } else { - 50.millis() + Duration::from_millis(50) } } /// Low time of `RESET_N` pin to trigger module abrupt emergency switch off /// /// NOTE: Not all modules support this operation from `RESET_N` -pub fn kill_time() -> Option> { +pub fn kill_time() -> Option { if cfg!(feature = "lara-r6") { - Some(10.secs()) + Some(Duration::from_secs(10)) } else { None } diff --git a/ublox-cellular/src/network.rs b/ublox-cellular/src/network.rs index 28131fe..044dd02 100644 --- a/ublox-cellular/src/network.rs +++ b/ublox-cellular/src/network.rs @@ -1,4 +1,5 @@ use crate::{ + client::{URC_CAPACITY, URC_SUBSCRIBERS}, command::{ general::GetCIMI, mobile_control::{ @@ -15,17 +16,17 @@ use crate::{ Urc, AT, }, error::GenericError, - registration::{self, ConnectionState, RegistrationParams, RegistrationState}, + registration::{self, ConnectionState, RegistrationState}, services::data::{ContextState, PROFILE_ID}, }; -use atat::{atat_derive::AtatLen, blocking::AtatClient}; -use fugit::{ExtU32, MinutesDurationU32, SecsDurationU32}; +use atat::{atat_derive::AtatLen, blocking::AtatClient, UrcSubscription}; +use embassy_time::{Duration, Instant}; use hash32_derive::Hash32; use serde::{Deserialize, Serialize}; -const REGISTRATION_CHECK_INTERVAL: SecsDurationU32 = SecsDurationU32::secs(15); -const REGISTRATION_TIMEOUT: MinutesDurationU32 = MinutesDurationU32::minutes(3); -const CHECK_IMSI_TIMEOUT: MinutesDurationU32 = MinutesDurationU32::minutes(1); +const REGISTRATION_CHECK_INTERVAL: Duration = Duration::from_secs(15); +const REGISTRATION_TIMEOUT: Duration = Duration::from_secs(3 * 60); +const CHECK_IMSI_TIMEOUT: Duration = Duration::from_secs(60); #[derive(Debug, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -46,19 +47,20 @@ pub struct ProfileId(pub u8); #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct ContextId(pub u8); -pub struct AtTx { - urc_attempts: u8, - max_urc_attempts: u8, +pub struct AtTx<'sub, AtCl> { consecutive_timeouts: u8, - client: C, + urc_subscription: UrcSubscription<'sub, Urc, URC_CAPACITY, URC_SUBSCRIBERS>, + client: AtCl, } -impl AtTx { - pub fn new(client: C, max_urc_attempts: u8) -> Self { +impl<'sub, AtCl: AtatClient> AtTx<'sub, AtCl> { + pub fn new( + client: AtCl, + urc_subscription: UrcSubscription<'sub, Urc, URC_CAPACITY, URC_SUBSCRIBERS>, + ) -> Self { Self { - urc_attempts: 0, consecutive_timeouts: 0, - max_urc_attempts, + urc_subscription, client, } } @@ -74,7 +76,8 @@ impl AtTx { .send_retry(req) .map_err(|e| match e { atat::Error::Timeout => { - self.consecutive_timeouts += A::ATTEMPTS; + self.consecutive_timeouts = + self.consecutive_timeouts.saturating_add(A::ATTEMPTS); Error::AT(atat::Error::Timeout) } atat::Error::Read => Error::AT(atat::Error::Read), @@ -98,7 +101,8 @@ impl AtTx { .send_retry(req) .map_err(|e| match e { atat::Error::Timeout => { - self.consecutive_timeouts += A::ATTEMPTS; + self.consecutive_timeouts = + self.consecutive_timeouts.saturating_add(A::ATTEMPTS); Error::AT(atat::Error::Timeout) } atat::Error::Read => Error::AT(atat::Error::Read), @@ -115,41 +119,26 @@ impl AtTx { } pub fn handle_urc bool>(&mut self, f: F) -> Result<(), Error> { - let mut a = self.urc_attempts; - let max = self.max_urc_attempts; - - self.client.try_read_urc_with::(|urc, _| { - if !f(urc) && a < max { - a += 1; - return false; - // } else { - // warn!("Dropping stale URC! {}", Debug2Format(&urc)); - } - a = 0; - true - }); - self.urc_attempts = a; + if let Some(urc) = self.urc_subscription.try_next_message_pure() { + f(urc); + } Ok(()) } } -pub struct Network -where - CLK: fugit_timer::Timer, -{ - pub(crate) status: RegistrationState, +pub struct Network<'sub, AtCl> { + pub(crate) status: RegistrationState, pub(crate) context_state: ContextState, - pub(crate) at_tx: AtTx, + pub(crate) at_tx: AtTx<'sub, AtCl>, } -impl Network +impl<'sub, AtCl> Network<'sub, AtCl> where - C: AtatClient, - CLK: fugit_timer::Timer, + AtCl: AtatClient, { - pub(crate) fn new(at_tx: AtTx, timer: CLK) -> Self { + pub(crate) fn new(at_tx: AtTx<'sub, AtCl>) -> Self { Self { - status: RegistrationState::new(timer), + status: RegistrationState::new(), context_state: ContextState::Setup, at_tx, } @@ -160,9 +149,7 @@ where } pub fn reset_reg_time(&mut self) -> Result<(), Error> { - let now = self.status.timer.now(); - - self.status.reg_start_time.replace(now); + self.status.reg_start_time.replace(Instant::now()); self.status.reg_check_time = self.status.reg_start_time; Ok(()) } @@ -179,7 +166,7 @@ where self.intervene_registration()?; self.check_running_imsi().ok(); // Ignore errors - let now = self.status.timer.now(); + let now = Instant::now(); let should_check = self .status .reg_check_time @@ -197,7 +184,7 @@ where self.update_registration()?; - let now = self.status.timer.now(); + let now = Instant::now(); let is_timeout = self .status .reg_start_time @@ -219,7 +206,7 @@ where // Check current IMSI if registered successfully in which case // imsi_check_time will be `None`, else if not registered, check after // CHECK_IMSI_TIMEOUT is expired - let now = self.status.timer.now(); + let now = Instant::now(); let check_imsi = self .status .imsi_check_time @@ -275,10 +262,10 @@ where return Ok(()); } - let now = self.status.timer.now(); + let now = Instant::now(); // If EPS has been sticky for longer than `timeout` - let timeout: SecsDurationU32 = (self.status.registration_interventions * 15).secs(); + let timeout = Duration::from_secs(self.status.registration_interventions as u64 * 15); if self.status.eps.sticky() && self.status.eps.duration(now) >= timeout { // If (EPS + CSD) is not attempting registration if self.status.eps.get_status() == registration::Status::NotRegistering @@ -292,7 +279,8 @@ where self.status.csd.reset(); self.status.psd.reset(); self.status.eps.reset(); - self.status.registration_interventions += 1; + self.status.registration_interventions = + self.status.registration_interventions.saturating_add(1); self.send_internal( &SetOperatorSelection { @@ -315,7 +303,8 @@ where self.status.csd.reset(); self.status.psd.reset(); self.status.eps.reset(); - self.status.registration_interventions += 1; + self.status.registration_interventions = + self.status.registration_interventions.saturating_add(1); self.send_internal( &SetModuleFunctionality { fun: Functionality::Minimum, @@ -355,7 +344,8 @@ where self.status.csd.reset(); self.status.psd.reset(); self.status.eps.reset(); - self.status.registration_interventions += 1; + self.status.registration_interventions = + self.status.registration_interventions.saturating_add(1); self.send_internal( &SetModuleFunctionality { fun: Functionality::Minimum, @@ -390,7 +380,8 @@ where self.status.psd.duration(now) ); self.status.psd.reset(); - self.status.registration_interventions += 1; + self.status.registration_interventions = + self.status.registration_interventions.saturating_add(1); self.send_internal(&GetPDPContextState, true)?; if self @@ -421,20 +412,18 @@ where } pub fn update_registration(&mut self) -> Result<(), Error> { - let ts = self.status.timer.now(); - self.send_internal(&GetExtendedErrorReport, false).ok(); if let Ok(reg) = self.send_internal(&GetNetworkRegistrationStatus, false) { - self.status.compare_and_set(reg.into(), ts); + self.status.compare_and_set(reg.into()); } if let Ok(reg) = self.send_internal(&GetGPRSNetworkRegistrationStatus, false) { - self.status.compare_and_set(reg.into(), ts); + self.status.compare_and_set(reg.into()); } if let Ok(reg) = self.send_internal(&GetEPSNetworkRegistrationStatus, false) { - self.status.compare_and_set(reg.into(), ts); + self.status.compare_and_set(reg.into()); } Ok(()) @@ -443,7 +432,7 @@ where pub(crate) fn handle_urc(&mut self) -> Result<(), Error> { // TODO: How to do this cleaner? let mut ctx_state = self.context_state; - let mut new_reg_params: Option = None; + // let mut new_reg_params: Option = None; self.at_tx.handle_urc(|urc| { match urc { @@ -470,6 +459,9 @@ where }) => { info!("[URC] ExtendedPSNetworkRegistration {:?}", state); } + // FIXME: Currently `atat` is unable to distinguish `xREG` family of + // commands from URC's + // Urc::GPRSNetworkRegistration(reg_params) => { // new_reg_params.replace(reg_params.into()); // } @@ -506,10 +498,9 @@ where true })?; - if let Some(reg_params) = new_reg_params { - let ts = self.status.timer.now(); - self.status.compare_and_set(reg_params, ts) - } + // if let Some(reg_params) = new_reg_params { + // self.status.compare_and_set(reg_params) + // } self.context_state = ctx_state; Ok(()) @@ -532,169 +523,3 @@ where self.at_tx.send(req) } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - registration::Status, - test_helpers::{MockAtClient, MockTimer}, - }; - use fugit::{MillisDurationU32, TimerInstantU32}; - use fugit_timer::Timer; - - const TIMER_HZ: u32 = 1000; - - #[test] - #[ignore] - fn intervene_registration() { - // Setup - let tx = AtTx::new(MockAtClient::new(0), 5); - let timer: MockTimer = MockTimer::new(Some(TimerInstantU32::from_ticks(25_234))); - let mut network = Network::new(tx, timer); - network.status.conn_state = ConnectionState::Connecting; - // Update both started & updated - network - .status - .eps - .set_status(Status::NotRegistering, TimerInstantU32::from_ticks(1234)); - // Update only updated - network - .status - .eps - .set_status(Status::NotRegistering, TimerInstantU32::from_ticks(1534)); - network - .status - .csd - .set_status(Status::NotRegistering, TimerInstantU32::from_ticks(1534)); - - assert_eq!( - network.status.eps.updated(), - Some(TimerInstantU32::from_ticks(1534)) - ); - assert_eq!( - network.status.eps.started(), - Some(TimerInstantU32::from_ticks(1234)) - ); - assert!(network.status.eps.sticky()); - - let ts = network.status.timer.now(); - assert_eq!( - network.status.eps.duration(ts), - MillisDurationU32::millis(24_000) - ); - - assert!(network.intervene_registration().is_ok()); - - assert_eq!(network.status.registration_interventions, 2); - } - - #[test] - fn reset_reg_time() { - let tx = AtTx::new(MockAtClient::new(0), 5); - let timer: MockTimer = MockTimer::new(Some(TimerInstantU32::from_ticks(1234))); - let mut network = Network::new(tx, timer); - - assert!(network.reset_reg_time().is_ok()); - - assert_eq!( - network.status.reg_start_time, - Some(TimerInstantU32::from_ticks(1234)) - ); - assert_eq!( - network.status.reg_check_time, - Some(TimerInstantU32::from_ticks(1234)) - ); - } - - #[test] - fn check_registration_state() { - let tx = AtTx::new(MockAtClient::new(0), 5); - let timer: MockTimer = MockTimer::new(Some(TimerInstantU32::from_ticks(1234))); - let mut network = Network::new(tx, timer); - - // Check that `ConnectionState` will change from `Connected` to `Connecting` - // with a state reset, if neither (csd + psd) || eps is actually registered - network.status.conn_state = ConnectionState::Connected; - network.status.registration_interventions = 3; - network - .status - .csd - .set_status(Status::Denied, TimerInstantU32::from_ticks(1)); - network - .status - .eps - .set_status(Status::NotRegistering, TimerInstantU32::from_ticks(5)); - - network.check_registration_state(); - - assert_eq!(network.status.conn_state, ConnectionState::Connecting); - assert_eq!( - network.status.reg_start_time, - Some(TimerInstantU32::from_ticks(1234)) - ); - assert_eq!( - network.status.reg_check_time, - Some(TimerInstantU32::from_ticks(1234)) - ); - assert_eq!(network.status.csd.get_status(), Status::None); - assert_eq!(network.status.csd.updated(), None); - assert_eq!(network.status.csd.started(), None); - assert_eq!(network.status.psd.get_status(), Status::None); - assert_eq!(network.status.psd.updated(), None); - assert_eq!(network.status.psd.started(), None); - assert_eq!(network.status.eps.get_status(), Status::None); - assert_eq!(network.status.eps.updated(), None); - assert_eq!(network.status.eps.started(), None); - - // Check that `ConnectionState` will change from `Connecting` to `Connected` - // if eps is actually registered - network - .status - .eps - .set_status(Status::Roaming, TimerInstantU32::from_ticks(5)); - - network.check_registration_state(); - - assert_eq!(network.status.conn_state, ConnectionState::Connected); - - // Check that `ConnectionState` will change from `Connecting` to `Connected` - // if (csd + psd) is actually registered - network.status.conn_state = ConnectionState::Connecting; - network.status.reset(); - network - .status - .eps - .set_status(Status::Denied, TimerInstantU32::from_ticks(5)); - network - .status - .csd - .set_status(Status::Roaming, TimerInstantU32::from_ticks(5)); - network - .status - .psd - .set_status(Status::Home, TimerInstantU32::from_ticks(5)); - - network.check_registration_state(); - - assert_eq!(network.status.conn_state, ConnectionState::Connected); - } - - #[test] - fn unhandled_urcs() { - let mut tx = AtTx::new(MockAtClient::new(0), 5); - - tx.handle_urc(|_| false).unwrap(); - assert_eq!(tx.client.n_urcs_dequeued, 0); - tx.handle_urc(|_| false).unwrap(); - tx.handle_urc(|_| false).unwrap(); - tx.handle_urc(|_| false).unwrap(); - tx.handle_urc(|_| false).unwrap(); - tx.handle_urc(|_| false).unwrap(); - assert_eq!(tx.client.n_urcs_dequeued, 1); - tx.handle_urc(|_| false).unwrap(); - tx.handle_urc(|_| true).unwrap(); - tx.handle_urc(|_| false).unwrap(); - assert_eq!(tx.client.n_urcs_dequeued, 2); - } -} diff --git a/ublox-cellular/src/power.rs b/ublox-cellular/src/power.rs index a308772..aa9355d 100644 --- a/ublox-cellular/src/power.rs +++ b/ublox-cellular/src/power.rs @@ -1,8 +1,9 @@ use atat::blocking::AtatClient; +use embassy_time::{Duration, Instant}; use embedded_hal::digital::{InputPin, OutputPin}; -use fugit::{ExtU32, MillisDurationU32}; use crate::{ + blocking_timer::BlockingTimer, client::Device, command::{ mobile_control::{ @@ -15,7 +16,8 @@ use crate::{ }, AT, }, - error::{from_clock, Error, GenericError}, + config::CellularConfig, + error::{Error, GenericError}, module_timing::{pwr_off_time, pwr_on_time, reset_time}, }; @@ -26,15 +28,11 @@ pub enum PowerState { On, } -impl - Device +impl<'buf, 'sub, AtCl, AtUrcCh, Config, const N: usize, const L: usize> + Device<'buf, 'sub, AtCl, AtUrcCh, Config, N, L> where - C: AtatClient, - CLK: fugit_timer::Timer, - RST: OutputPin, - PWR: OutputPin, - DTR: OutputPin, - VINT: InputPin, + AtCl: AtatClient, + Config: CellularConfig, { /// Check that the cellular module is alive. /// @@ -98,8 +96,8 @@ where false, )?; - self.wait_power_state(PowerState::On, 30_000.millis()) - .map_err(from_clock)?; + self.wait_power_state(PowerState::On, Duration::from_secs(30)) + .map_err(|_| Error::Generic(GenericError::Timeout))?; Ok(()) } @@ -109,23 +107,14 @@ where /// **NOTE** This function will reset NVM settings! pub fn hard_reset(&mut self) -> Result<(), Error> { trace!("Attempting to hard reset of the modem."); - if let Some(ref mut rst) = self.config.rst_pin { + if let Some(rst) = self.config.reset_pin() { rst.set_low().ok(); - self.network - .status - .timer - .start(reset_time::()) - .map_err(from_clock)?; - nb::block!(self.network.status.timer.wait()).map_err(from_clock)?; + BlockingTimer::after(reset_time()).wait(); rst.set_high().ok(); - self.network - .status - .timer - .start(5.secs()) - .map_err(from_clock)?; - nb::block!(self.network.status.timer.wait()).map_err(from_clock)?; + + BlockingTimer::after(Duration::from_secs(5)).wait(); } self.power_state = PowerState::Off; @@ -138,32 +127,23 @@ where pub fn power_on(&mut self) -> Result<(), Error> { info!( "Attempting to power on the modem with PWR_ON pin: {} and VInt pin: {}.", - self.config.pwr_pin.is_some(), - self.config.vint_pin.is_some(), + self.config.power_pin().is_some(), + self.config.vint_pin().is_some(), ); if self.power_state()? != PowerState::On { trace!("Powering modem on."); - match self.config.pwr_pin { + match self.config.power_pin() { // Apply Low pulse on PWR_ON for 50 microseconds to power on - Some(ref mut pwr) => { + Some(pwr) => { pwr.set_low().ok(); - self.network - .status - .timer - .start(pwr_on_time::()) - .map_err(from_clock)?; - nb::block!(self.network.status.timer.wait()).map_err(from_clock)?; + BlockingTimer::after(pwr_on_time()).wait(); pwr.set_high().ok(); - self.network - .status - .timer - .start(1.secs()) - .map_err(from_clock)?; - nb::block!(self.network.status.timer.wait()).map_err(from_clock)?; - - if let Err(e) = self.wait_power_state(PowerState::On, 10.secs()) { + + BlockingTimer::after(Duration::from_secs(1)).wait(); + + if let Err(e) = self.wait_power_state(PowerState::On, Duration::from_secs(10)) { error!("Failed to power on modem"); return Err(e); } else { @@ -191,12 +171,7 @@ where self.power_state = PowerState::Off; trace!("Modem powered off"); - self.network - .status - .timer - .start(10.secs()) - .map_err(from_clock)?; - nb::block!(self.network.status.timer.wait()).map_err(from_clock)?; + BlockingTimer::after(Duration::from_secs(10)).wait(); Ok(()) } @@ -205,16 +180,11 @@ where trace!("Attempting to hard power off the modem."); if self.power_state()? == PowerState::On { - match self.config.pwr_pin { - Some(ref mut pwr) => { + match self.config.power_pin() { + Some(pwr) => { // Apply Low pulse on PWR_ON >= 1 second to power off pwr.set_low().ok(); - self.network - .status - .timer - .start(pwr_off_time::()) - .map_err(from_clock)?; - nb::block!(self.network.status.timer.wait()).map_err(from_clock)?; + BlockingTimer::after(pwr_off_time()).wait(); pwr.set_high().ok(); self.power_state = PowerState::Off; @@ -232,8 +202,8 @@ where /// Check the power state of the module, by probing `Vint` pin if available, /// fallbacking to checking for AT responses through `is_alive` pub fn power_state(&mut self) -> Result { - match self.config.vint_pin { - Some(ref mut vint) => { + match self.config.vint_pin() { + Some(vint) => { if vint .is_high() .map_err(|_| Error::Generic(GenericError::Unsupported))? @@ -248,21 +218,14 @@ where } /// Wait for the power state to change into `expected`, with a timeout - fn wait_power_state( - &mut self, - expected: PowerState, - timeout: MillisDurationU32, - ) -> Result<(), Error> { - let start = self.network.status.timer.now(); + fn wait_power_state(&mut self, expected: PowerState, timeout: Duration) -> Result<(), Error> { + let start = Instant::now(); let mut res = false; trace!("Waiting for the modem to reach {:?}.", expected); - while self - .network - .status - .timer - .now() + + while Instant::now() .checked_duration_since(start) .map_or(false, |dur| dur < timeout) { @@ -271,12 +234,7 @@ where break; } - self.network - .status - .timer - .start(5.millis()) - .map_err(from_clock)?; - nb::block!(self.network.status.timer.wait()).map_err(from_clock)?; + BlockingTimer::after(Duration::from_millis(5)).wait(); } if res { diff --git a/ublox-cellular/src/registration.rs b/ublox-cellular/src/registration.rs index 2a548aa..253c112 100644 --- a/ublox-cellular/src/registration.rs +++ b/ublox-cellular/src/registration.rs @@ -10,17 +10,17 @@ use crate::command::{ // urc::{EPSNetworkRegistration, GPRSNetworkRegistration}, }, }; -use fugit::{ExtU32, TimerInstantU32}; +use embassy_time::{Duration, Instant}; use heapless::String; #[derive(Debug, Clone, Default)] -pub struct CellularRegistrationStatus { +pub struct CellularRegistrationStatus { status: Status, - updated: Option>, - started: Option>, + updated: Option, + started: Option, } -impl CellularRegistrationStatus { +impl CellularRegistrationStatus { pub fn new() -> Self { Self { status: Status::default(), @@ -29,17 +29,17 @@ impl CellularRegistrationStatus { } } - pub fn duration(&self, ts: TimerInstantU32) -> fugit::TimerDurationU32 { + pub fn duration(&self, ts: Instant) -> Duration { self.started .and_then(|started| ts.checked_duration_since(started)) - .unwrap_or_else(|| 0.millis()) + .unwrap_or_else(|| Duration::from_millis(0)) } - pub fn started(&self) -> Option> { + pub fn started(&self) -> Option { self.started } - pub fn updated(&self) -> Option> { + pub fn updated(&self) -> Option { self.updated } @@ -53,7 +53,8 @@ impl CellularRegistrationStatus { self.status } - pub fn set_status(&mut self, stat: Status, ts: TimerInstantU32) { + pub fn set_status(&mut self, stat: Status) { + let ts = Instant::now(); if self.status != stat { self.status = stat; self.started = Some(ts); @@ -185,25 +186,20 @@ pub struct CellularGlobalIdentity { } #[derive(Debug, Clone)] -pub struct RegistrationState -where - CLK: fugit_timer::Timer, -{ - pub(crate) timer: CLK, - - pub(crate) reg_check_time: Option>, - pub(crate) reg_start_time: Option>, - pub(crate) imsi_check_time: Option>, +pub struct RegistrationState { + pub(crate) reg_check_time: Option, + pub(crate) reg_start_time: Option, + pub(crate) imsi_check_time: Option, pub(crate) conn_state: ConnectionState, /// CSD (Circuit Switched Data) registration status (registered/searching/roaming etc.). - pub(crate) csd: CellularRegistrationStatus, + pub(crate) csd: CellularRegistrationStatus, /// PSD (Packet Switched Data) registration status (registered/searching/roaming etc.). - pub(crate) psd: CellularRegistrationStatus, + pub(crate) psd: CellularRegistrationStatus, /// EPS (Evolved Packet Switched) registration status (registered/searching/roaming etc.). - pub(crate) eps: CellularRegistrationStatus, + pub(crate) eps: CellularRegistrationStatus, - pub(crate) registration_interventions: u32, + pub(crate) registration_interventions: u8, check_imsi: bool, pub(crate) cgi: CellularGlobalIdentity, @@ -225,13 +221,9 @@ impl Default for ConnectionState { } } -impl RegistrationState -where - CLK: fugit_timer::Timer, -{ - pub fn new(timer: CLK) -> Self { +impl RegistrationState { + pub fn new() -> Self { Self { - timer, reg_check_time: None, reg_start_time: None, imsi_check_time: None, @@ -252,8 +244,8 @@ where self.csd.reset(); self.psd.reset(); self.eps.reset(); - self.reg_start_time = Some(self.timer.now()); - self.reg_check_time = self.reg_start_time; + self.reg_start_time = Some(Instant::now()); + self.reg_check_time = Some(Instant::now()); self.imsi_check_time = None; self.registration_interventions = 1; } @@ -267,29 +259,25 @@ where self.conn_state = state; } - pub fn compare_and_set( - &mut self, - new_params: RegistrationParams, - ts: TimerInstantU32, - ) { + pub fn compare_and_set(&mut self, new_params: RegistrationParams) { match new_params.reg_type { RegType::Creg => { let prev_reg_status = self.csd.registered(); - self.csd.set_status(new_params.status, ts); + self.csd.set_status(new_params.status); if !prev_reg_status && self.csd.registered() { self.check_imsi = true } } RegType::Cgreg => { let prev_reg_status = self.psd.registered(); - self.psd.set_status(new_params.status, ts); + self.psd.set_status(new_params.status); if !prev_reg_status && self.psd.registered() { self.check_imsi = true } } RegType::Cereg => { let prev_reg_status = self.eps.registered(); - self.eps.set_status(new_params.status, ts); + self.eps.set_status(new_params.status); if !prev_reg_status && self.eps.registered() { self.check_imsi = true } diff --git a/ublox-cellular/src/services/data/apn.rs b/ublox-cellular/src/services/data/apn.rs index 03478ff..9729778 100644 --- a/ublox-cellular/src/services/data/apn.rs +++ b/ublox-cellular/src/services/data/apn.rs @@ -1,29 +1,27 @@ -use heapless::String; - #[derive(Debug, Clone)] -pub enum Apn { - Given(String<99>), +pub enum Apn<'a> { + Given(&'a str), Automatic, } -impl Default for Apn { +impl<'a> Default for Apn<'a> { fn default() -> Self { Self::Automatic } } #[derive(Debug, Clone, Default)] -pub struct APNInfo { - pub apn: Apn, - pub user_name: Option>, - pub password: Option>, +pub struct APNInfo<'a> { + pub apn: Apn<'a>, + pub user_name: Option<&'a str>, + pub password: Option<&'a str>, } -impl APNInfo { +impl<'a> APNInfo<'a> { #[must_use] - pub fn new(apn: &str) -> Self { + pub fn new(apn: &'a str) -> Self { Self { - apn: Apn::Given(String::from(apn)), + apn: Apn::Given(apn), user_name: None, password: None, } diff --git a/ublox-cellular/src/services/data/dns.rs b/ublox-cellular/src/services/data/dns.rs index 7395c28..57bcc28 100644 --- a/ublox-cellular/src/services/data/dns.rs +++ b/ublox-cellular/src/services/data/dns.rs @@ -8,11 +8,9 @@ use super::DataService; use crate::command::dns::{self, types::ResolutionType}; use ublox_sockets::Error; -impl<'a, C, CLK, const TIMER_HZ: u32, const N: usize, const L: usize> Dns - for DataService<'a, C, CLK, TIMER_HZ, N, L> +impl<'a, 'sub, AtCl, const N: usize, const L: usize> Dns for DataService<'a, 'sub, AtCl, N, L> where - C: AtatClient, - CLK: fugit_timer::Timer, + AtCl: AtatClient, { type Error = Error; diff --git a/ublox-cellular/src/services/data/mod.rs b/ublox-cellular/src/services/data/mod.rs index 64986f9..efc1c47 100644 --- a/ublox-cellular/src/services/data/mod.rs +++ b/ublox-cellular/src/services/data/mod.rs @@ -12,6 +12,7 @@ mod udp_stack; mod hex; use crate::{ + blocking_timer::BlockingTimer, client::Device, command::mobile_control::types::{Functionality, ResetMode}, command::mobile_control::SetModuleFunctionality, @@ -26,15 +27,14 @@ use crate::{ }, psn::{self, responses::GPRSAttached, GetPDPContextState}, }, + config::CellularConfig, error::Error as DeviceError, - error::GenericError, network::{ContextId, Network}, ProfileId, }; use apn::{APNInfo, Apn}; use atat::blocking::AtatClient; -use embedded_hal::digital::{InputPin, OutputPin}; -use fugit::ExtU32; +use embassy_time::Duration; pub use error::Error; use psn::{types::GPRSAttachedState, GetGPRSAttached}; @@ -53,15 +53,12 @@ pub const PROFILE_ID: ProfileId = ProfileId(1); #[cfg(not(feature = "upsd-context-activation"))] const CONTEXT_ID: ContextId = ContextId(1); -impl - Device +impl<'buf, 'sub, AtCl, AtUrcCh, Config, const N: usize, const L: usize> + Device<'buf, 'sub, AtCl, AtUrcCh, Config, N, L> where - C: AtatClient, - CLK: fugit_timer::Timer, - RST: OutputPin, - PWR: OutputPin, - DTR: OutputPin, - VINT: InputPin, + 'buf: 'sub, + AtCl: AtatClient, + Config: CellularConfig, { /// Define a PDP context #[cfg(not(feature = "upsd-context-activation"))] @@ -82,12 +79,12 @@ where true, )?; - if let Apn::Given(apn) = apn_info.clone().apn { + if let Apn::Given(apn) = apn_info.apn { self.network.send_internal( &SetPDPContextDefinition { cid, pdp_type: "IP", - apn: apn.as_str(), + apn, }, true, )?; @@ -136,7 +133,7 @@ where pub fn data_service<'a>( &'a mut self, apn_info: &APNInfo, - ) -> nb::Result, DeviceError> { + ) -> nb::Result, DeviceError> { // Spin [`Device`], handling [`Network`] related URC changes and // propagting the FSM match self.spin() { @@ -173,25 +170,22 @@ pub enum ContextState { Active, } -pub struct DataService<'a, C, CLK, const TIMER_HZ: u32, const N: usize, const L: usize> +pub struct DataService<'a, 'sub, AtCl, const N: usize, const L: usize> where - C: atat::blocking::AtatClient, - CLK: 'static + fugit_timer::Timer, + AtCl: AtatClient, { - network: &'a mut Network, - pub(crate) sockets: Option<&'a mut SocketSet>, + network: &'a mut Network<'sub, AtCl>, + pub(crate) sockets: Option<&'a mut SocketSet>, } -impl<'a, C, CLK, const TIMER_HZ: u32, const N: usize, const L: usize> - DataService<'a, C, CLK, TIMER_HZ, N, L> +impl<'a, 'sub, AtCl, const N: usize, const L: usize> DataService<'a, 'sub, AtCl, N, L> where - C: atat::blocking::AtatClient, - CLK: 'static + fugit_timer::Timer, + AtCl: AtatClient, { pub fn try_new( apn_info: &APNInfo, - network: &'a mut Network, - sockets: Option<&'a mut SocketSet>, + network: &'a mut Network<'sub, AtCl>, + sockets: Option<&'a mut SocketSet>, ) -> nb::Result { let mut data_service = Self { network, sockets }; @@ -248,14 +242,7 @@ where return Ok(()); } - self.network - .status - .timer - .start(1.secs()) - .map_err(|_e| Error::Generic(GenericError::Clock))?; - - nb::block!(self.network.status.timer.wait()) - .map_err(|_e| Error::Generic(GenericError::Clock))?; + BlockingTimer::after(Duration::from_secs(1)).wait(); } // self.network .send_internal( &SetGPRSAttached { state: @@ -532,7 +519,7 @@ where if available_data == 0 { // Check for new socket data available at regular // intervals, just in case a URC is missed - if socket.should_update_available_data(network.status.timer.now()) { + if socket.should_update_available_data() { match network.send_internal( &ReadSocketData { socket: handle, @@ -541,7 +528,7 @@ where false, ) { Ok(SocketData { length, .. }) => socket.set_available_data(length), - Err(_) => socket.closed_by_remote(network.status.timer.now()), + Err(_) => socket.closed_by_remote(), } } diff --git a/ublox-cellular/src/services/data/ssl.rs b/ublox-cellular/src/services/data/ssl.rs index 383f9ef..7ac13e8 100644 --- a/ublox-cellular/src/services/data/ssl.rs +++ b/ublox-cellular/src/services/data/ssl.rs @@ -3,7 +3,7 @@ use crate::command::device_data_security::{ types::{CertificateValidationLevel, SecurityDataType, SecurityProfileOperation}, PrepareSecurityDataImport, SecurityProfileManager, SendSecurityDataImport, }; -use atat::atat_derive::AtatLen; +use atat::{atat_derive::AtatLen, blocking::AtatClient}; use heapless::String; use serde::{Deserialize, Serialize}; @@ -38,11 +38,9 @@ pub trait SSL { ) -> Result<(), Error>; } -impl<'a, C, CLK, const TIMER_HZ: u32, const N: usize, const L: usize> SSL - for DataService<'a, C, CLK, TIMER_HZ, N, L> +impl<'a, 'sub, AtCl, const N: usize, const L: usize> SSL for DataService<'a, 'sub, AtCl, N, L> where - C: atat::blocking::AtatClient, - CLK: fugit_timer::Timer, + AtCl: AtatClient, { fn import_certificate( &mut self, diff --git a/ublox-cellular/src/services/data/tcp_stack.rs b/ublox-cellular/src/services/data/tcp_stack.rs index 2b69325..476c8b8 100644 --- a/ublox-cellular/src/services/data/tcp_stack.rs +++ b/ublox-cellular/src/services/data/tcp_stack.rs @@ -6,14 +6,14 @@ use crate::command::ip_transport_layer::{ CloseSocket, ConnectSocket, CreateSocket, PrepareWriteSocketDataBinary, SetSocketSslState, WriteSocketDataBinary, }; +use atat::blocking::AtatClient; use embedded_nal::{SocketAddr, TcpClientStack}; use ublox_sockets::{Error, SocketHandle, TcpSocket, TcpState}; -impl<'a, C, CLK, const TIMER_HZ: u32, const N: usize, const L: usize> TcpClientStack - for DataService<'a, C, CLK, TIMER_HZ, N, L> +impl<'a, 'sub, AtCl, const N: usize, const L: usize> TcpClientStack + for DataService<'a, 'sub, AtCl, N, L> where - C: atat::blocking::AtatClient, - CLK: fugit_timer::Timer, + AtCl: AtatClient, { type Error = Error; @@ -26,10 +26,9 @@ where if let Some(ref mut sockets) = self.sockets { // Check if there are any unused sockets available if sockets.len() >= sockets.capacity() { - let ts = self.network.status.timer.now(); // Check if there are any sockets closed by remote, and close it // if it has exceeded its timeout, in order to recycle it. - if !sockets.recycle(ts) { + if !sockets.recycle() { return Err(Error::SocketSetFull); } } @@ -59,7 +58,7 @@ where ) -> nb::Result<(), Self::Error> { if let Some(ref mut sockets) = self.sockets { let mut tcp = sockets - .get::>(*socket) + .get::>(*socket) .map_err(Self::Error::from)?; if matches!(tcp.state(), TcpState::Created) { @@ -102,9 +101,7 @@ where /// Check if this socket is still connected fn is_connected(&mut self, socket: &Self::TcpSocket) -> Result { if let Some(ref mut sockets) = self.sockets { - Ok(sockets - .get::>(*socket)? - .is_connected()) + Ok(sockets.get::>(*socket)?.is_connected()) } else { Err(Error::Illegal) } @@ -164,7 +161,7 @@ where ) -> nb::Result { if let Some(ref mut sockets) = self.sockets { let mut tcp = sockets - .get::>(*socket) + .get::>(*socket) .map_err(Self::Error::from)?; Ok(tcp.recv_slice(buffer).map_err(Self::Error::from)?) diff --git a/ublox-cellular/src/services/data/udp_stack.rs b/ublox-cellular/src/services/data/udp_stack.rs index c4a0324..82f0b46 100644 --- a/ublox-cellular/src/services/data/udp_stack.rs +++ b/ublox-cellular/src/services/data/udp_stack.rs @@ -4,14 +4,14 @@ use crate::command::ip_transport_layer::{ types::SocketProtocol, CloseSocket, CreateSocket, PrepareUDPSendToDataBinary, UDPSendToDataBinary, }; +use atat::blocking::AtatClient; use embedded_nal::{SocketAddr, UdpClientStack}; use ublox_sockets::{Error, SocketHandle, UdpSocket}; -impl<'a, C, CLK, const TIMER_HZ: u32, const N: usize, const L: usize> UdpClientStack - for DataService<'a, C, CLK, TIMER_HZ, N, L> +impl<'a, 'sub, AtCl, const N: usize, const L: usize> UdpClientStack + for DataService<'a, 'sub, AtCl, N, L> where - C: atat::blocking::AtatClient, - CLK: fugit_timer::Timer, + AtCl: AtatClient, { type Error = Error; @@ -24,10 +24,9 @@ where fn socket(&mut self) -> Result { if let Some(ref mut sockets) = self.sockets { if sockets.len() >= sockets.capacity() { - let ts = self.network.status.timer.now(); // Check if there are any sockets closed by remote, and close it // if it has exceeded its timeout, in order to recycle it. - if sockets.recycle(ts) { + if !sockets.recycle() { return Err(Error::SocketSetFull); } } @@ -56,7 +55,7 @@ where ) -> Result<(), Self::Error> { if let Some(ref mut sockets) = self.sockets { let mut udp = sockets - .get::>(*socket) + .get::>(*socket) .map_err(Self::Error::from)?; udp.bind(remote).map_err(Self::Error::from)?; Ok(()) @@ -69,7 +68,7 @@ where fn send(&mut self, socket: &mut Self::UdpSocket, buffer: &[u8]) -> nb::Result<(), Self::Error> { if let Some(ref mut sockets) = self.sockets { let udp = sockets - .get::>(*socket) + .get::>(*socket) .map_err(Self::Error::from)?; if !udp.is_open() { @@ -125,7 +124,7 @@ where ) -> nb::Result<(usize, SocketAddr), Self::Error> { if let Some(ref mut sockets) = self.sockets { let mut udp = sockets - .get::>(*socket) + .get::>(*socket) .map_err(Self::Error::from)?; let bytes = udp.recv_slice(buffer).map_err(Self::Error::from)?; diff --git a/ublox-cellular/src/services/location/error.rs b/ublox-cellular/src/services/location/error.rs deleted file mode 100644 index e69de29..0000000 diff --git a/ublox-cellular/src/services/location/mod.rs b/ublox-cellular/src/services/location/mod.rs deleted file mode 100644 index 28368b8..0000000 --- a/ublox-cellular/src/services/location/mod.rs +++ /dev/null @@ -1,29 +0,0 @@ -use core::convert::TryInto; - -use crate::services::data::socket::Socket; -use crate::{client::Device, error::Error as DeviceError}; -use atat::blocking::AtatClient; -use embedded_hal::digital::{InputPin, OutputPin}; -use embedded_time::{Clock, duration::{Generic, Milliseconds}}; -use heapless::{ArrayLength, Bucket, Pos}; - -impl Device -where - C: AtatClient, - CLK: fugit_timer::Timer, - RST: OutputPin, - PWR: OutputPin, - DTR: OutputPin, - VINT: InputPin, - N: ArrayLength>> + ArrayLength> + ArrayLength>, - L: ArrayLength, -{ - pub fn location_service(&mut self) -> nb::Result { - self.spin()?; - - Ok(LocationService) - } -} - -/// Empty location service, to showcase how multiple services can be implemented! -pub struct LocationService; diff --git a/ublox-cellular/src/services/mod.rs b/ublox-cellular/src/services/mod.rs index 48aeb4b..7a345e4 100644 --- a/ublox-cellular/src/services/mod.rs +++ b/ublox-cellular/src/services/mod.rs @@ -1,4 +1 @@ pub mod data; -// pub mod location; -// pub mod sms; -// pub mod voice; diff --git a/ublox-cellular/src/services/sms/error.rs b/ublox-cellular/src/services/sms/error.rs deleted file mode 100644 index e69de29..0000000 diff --git a/ublox-cellular/src/services/sms/mod.rs b/ublox-cellular/src/services/sms/mod.rs deleted file mode 100644 index 8b13789..0000000 --- a/ublox-cellular/src/services/sms/mod.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/ublox-cellular/src/services/voice/error.rs b/ublox-cellular/src/services/voice/error.rs deleted file mode 100644 index e69de29..0000000 diff --git a/ublox-cellular/src/services/voice/mod.rs b/ublox-cellular/src/services/voice/mod.rs deleted file mode 100644 index 8b13789..0000000 --- a/ublox-cellular/src/services/voice/mod.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/ublox-cellular/src/test_helpers.rs b/ublox-cellular/src/test_helpers.rs deleted file mode 100644 index 847505a..0000000 --- a/ublox-cellular/src/test_helpers.rs +++ /dev/null @@ -1,115 +0,0 @@ -use atat::blocking::AtatClient; -use fugit::ExtU32; -use fugit_timer::Timer; - -#[derive(Debug)] -pub struct MockAtClient { - pub n_urcs_dequeued: u8, -} - -impl MockAtClient { - pub fn new(n_urcs_dequeued: u8) -> Self { - Self { n_urcs_dequeued } - } -} - -impl AtatClient for MockAtClient { - fn send, const LEN: usize>( - &mut self, - _cmd: &A, - ) -> Result { - todo!() - } - - fn try_read_urc_with FnOnce(Urc::Response, &'b [u8]) -> bool>( - &mut self, - handle: F, - ) -> bool { - if let Some(urc) = Urc::parse(b"+UREG:0") { - if handle(urc, b"") { - self.n_urcs_dequeued += 1; - } - } - true - } - - fn max_urc_len() -> usize { - todo!() - } -} - -#[derive(Debug)] -pub struct MockTimer { - forced_ms_time: Option>, - monotonic: std::time::Instant, - start: Option, - duration: fugit::TimerDurationU32, -} - -impl MockTimer { - pub fn new(forced_ms_time: Option>) -> Self { - Self { - forced_ms_time, - monotonic: std::time::Instant::now(), - start: None, - duration: fugit::TimerDurationU32::millis(0), - } - } -} - -impl Timer for MockTimer { - type Error = std::convert::Infallible; - - fn now(&mut self) -> fugit::TimerInstantU32 { - match self.forced_ms_time { - Some(ts) => ts, - None => { - let millis = self.monotonic.elapsed().as_millis(); - fugit::TimerInstantU32::from_ticks(millis as u32) - } - } - } - - fn start(&mut self, duration: fugit::TimerDurationU32) -> Result<(), Self::Error> { - self.start = Some(std::time::Instant::now()); - self.duration = duration.convert(); - Ok(()) - } - - fn cancel(&mut self) -> Result<(), Self::Error> { - if self.start.is_some() { - self.start = None; - } - Ok(()) - } - - fn wait(&mut self) -> nb::Result<(), Self::Error> { - if let Some(start) = self.start { - if start.elapsed() > std::time::Duration::from_millis(u64::from(self.duration.ticks())) - { - Ok(()) - } else { - Err(nb::Error::WouldBlock) - } - } else { - Ok(()) - } - } -} - -mod tests { - use super::*; - - const TIMER_HZ: u32 = 1000; - - #[test] - fn mock_timer_works() { - let now = std::time::Instant::now(); - - let mut timer: MockTimer = MockTimer::new(None); - timer.start(1.secs()).unwrap(); - nb::block!(timer.wait()).unwrap(); - - assert!(now.elapsed().as_millis() >= 1_000); - } -} From fdd3cd092b335808d87eada416726ecdb97e3bf2 Mon Sep 17 00:00:00 2001 From: Kenneth Knudsen Date: Wed, 20 Sep 2023 14:09:05 +0200 Subject: [PATCH 7/7] cellular signal strength function wrong merge --- ublox-cellular/src/client.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ublox-cellular/src/client.rs b/ublox-cellular/src/client.rs index fb12f36..c1c6509 100644 --- a/ublox-cellular/src/client.rs +++ b/ublox-cellular/src/client.rs @@ -127,10 +127,6 @@ where } } -pub fn signal_strength(&mut self) -> Result { - self.send_at(&GetSignalQuality) -} - impl<'buf, 'sub, AtCl, AtUrcCh, Config, const N: usize, const L: usize> Device<'buf, 'sub, AtCl, AtUrcCh, Config, N, L> where @@ -165,6 +161,9 @@ where self.sockets.take() } + pub fn signal_strength(&mut self) -> Result { + self.send_at(&GetSignalQuality) + } /// Run modem state machine /// /// Turns on modem if needed and processes URCs.