From 8206f138d3dbf0139937044b265fbf7144cd9e58 Mon Sep 17 00:00:00 2001 From: Mathias Date: Fri, 15 Mar 2024 12:58:23 +0100 Subject: [PATCH] Working PPP + CMUX implementation --- .vscode/settings.json | 1 + Cargo.toml | 6 +- .../.vscode/settings.json | 18 + examples/embassy-rp2040-example/Cargo.toml | 60 +++- .../rust-toolchain.toml | 8 +- .../src/bin/embassy-smoltcp-ppp.rs | 166 ++++++--- examples/tokio-std-example/.cargo/config.toml | 5 + examples/tokio-std-example/.gitignore | 9 + .../tokio-std-example/.vscode/settings.json | 17 + examples/tokio-std-example/Cargo.toml | 81 +++++ .../tokio-std-example/rust-toolchain.toml | 8 + .../src/bin/embassy-internal-stack.rs | 188 ++++++++++ .../src/bin/tokio-smoltcp-ppp.rs | 198 +++++++++++ rust-toolchain.toml | 2 +- src/asynch/control.rs | 7 + src/asynch/internal_stack.rs | 15 +- src/asynch/mod.rs | 10 + src/asynch/ppp.rs | 258 ++++++-------- src/asynch/resources.rs | 7 +- src/asynch/runner.rs | 326 +++++++++--------- src/asynch/state.rs | 12 +- src/asynch/ublox_stack/tcp.rs | 21 +- src/command/control/mod.rs | 40 ++- src/command/control/responses.rs | 10 + src/command/control/types.rs | 16 +- src/config.rs | 16 +- 26 files changed, 1082 insertions(+), 423 deletions(-) create mode 100644 examples/embassy-rp2040-example/.vscode/settings.json create mode 100644 examples/tokio-std-example/.cargo/config.toml create mode 100644 examples/tokio-std-example/.gitignore create mode 100644 examples/tokio-std-example/.vscode/settings.json create mode 100644 examples/tokio-std-example/Cargo.toml create mode 100644 examples/tokio-std-example/rust-toolchain.toml create mode 100644 examples/tokio-std-example/src/bin/embassy-internal-stack.rs create mode 100644 examples/tokio-std-example/src/bin/tokio-smoltcp-ppp.rs create mode 100644 src/command/control/responses.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index d19761f..7f9a29e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,6 +10,7 @@ ], "rust-analyzer.cargo.features": [ "lara-r6", + "embassy-embedded-hal" ], "rust-analyzer.cargo.target": "thumbv7em-none-eabihf", "rust-analyzer.diagnostics.disabled": [ diff --git a/Cargo.toml b/Cargo.toml index 7d7f783..917ad7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,14 +43,10 @@ embassy-net = { version = "0.4", features = [ "proto-ipv4", "medium-ip", ], optional = true } +embassy-embedded-hal = { version = "0.1", optional = true } -embedded-io = "0.6" embedded-io-async = "0.6" -[dev-dependencies] -atat = { version = "*", features = ["heapless"] } - - [features] default = ["socket-udp", "socket-tcp", "ppp"] diff --git a/examples/embassy-rp2040-example/.vscode/settings.json b/examples/embassy-rp2040-example/.vscode/settings.json new file mode 100644 index 0000000..b51df5c --- /dev/null +++ b/examples/embassy-rp2040-example/.vscode/settings.json @@ -0,0 +1,18 @@ +{ + // override the default setting (`cargo check --all-targets`) which produces the following error + // "can't find crate for `test`" when the default compilation target is a no_std target + // with these changes RA will call `cargo check --bins` on save + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.procMacro.enable": true, + "rust-analyzer.cargo.target": "thumbv6m-none-eabi", + // "rust-analyzer.cargo.target": "thumbv7em-none-eabihf", + "rust-analyzer.cargo.features": [ + "ppp", + ], + "rust-analyzer.checkOnSave.command": "clippy", + "rust-analyzer.cargoRunner": null, + "rust-analyzer.experimental.procAttrMacros": false, + "rust-analyzer.diagnostics.disabled": [ + "macro-error" + ], +} \ No newline at end of file diff --git a/examples/embassy-rp2040-example/Cargo.toml b/examples/embassy-rp2040-example/Cargo.toml index 56cc77c..e2ce233 100644 --- a/examples/embassy-rp2040-example/Cargo.toml +++ b/examples/embassy-rp2040-example/Cargo.toml @@ -4,16 +4,44 @@ version = "0.1.0" edition = "2021" [dependencies] -embassy-rp = { version = "0.1.0", features = ["defmt", "time-driver", "unstable-pac", "rom-v2-intrinsics", "critical-section-impl"] } -embassy-executor = { version = "0.5.0", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers", "nightly"] } -embassy-time = { version = "0.3", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-rp = { version = "0.1.0", features = [ + "defmt", + "time-driver", + "unstable-pac", + "rom-v2-intrinsics", + "critical-section-impl", +] } +embassy-executor = { version = "0.5.0", features = [ + "arch-cortex-m", + "executor-thread", + "defmt", + "integrated-timers", + "nightly", +] } +embassy-time = { version = "0.3", features = [ + "defmt", + "defmt-timestamp-uptime", +] } embassy-futures = { version = "0.1", features = ["defmt"] } embassy-sync = { version = "0.5", features = ["defmt"] } -embassy-net = { version = "0.4", features = ["defmt", "proto-ipv4", "medium-ip", "tcp", "udp"] } +embassy-net = { version = "0.4", features = [ + "defmt", + "packet-trace", + "proto-ipv4", + "medium-ip", + "tcp", + "udp", + "dns", +] } embassy-net-ppp = { version = "0.1", features = ["defmt"] } -embassy-at-cmux = { path = "../../../embassy/embassy-at-cmux", features = ["defmt"] } -embedded-tls = { path = "../../../embedded-tls", default-features = false, features = ["defmt"] } +embassy-at-cmux = { path = "../../../embassy/embassy-at-cmux", features = [ + "defmt", +] } + +embedded-tls = { path = "https://github.com/drogue-iot/embedded-tls", rev = "f788e02", default-features = false, features = [ + "defmt", +] } embedded-io-async = { version = "0.6" } heapless = "0.8" @@ -26,10 +54,21 @@ defmt = "0.3.5" defmt-rtt = "0.4.0" panic-probe = { version = "0.3.1", features = ["print-defmt"] } -static_cell = { version = "2.0", features = []} +static_cell = { version = "2.0", features = [] } atat = { version = "0.21.0", features = ["derive", "bytes", "defmt"] } -ublox-cellular-rs = {version = "0.4.0", path = "../..", features = ["lara-r6", "defmt"]} +ublox-cellular-rs = { version = "0.4.0", path = "../..", features = [ + "lara-r6", + "defmt", +] } +reqwless = { git = "https://github.com/drogue-iot/reqwless", features = [ + "defmt", +] } +smoltcp = { version = "*", default-features = false, features = [ + "dns-max-server-count-4", +] } +rand_chacha = { version = "0.3", default-features = false } + [features] ppp = ["ublox-cellular-rs/ppp"] @@ -58,11 +97,8 @@ embassy-executor = { path = "../../../embassy/embassy-executor" } atat = { path = "../../../atat/atat" } -#ublox-sockets = { path = "../../../ublox-sockets" } -#atat = { path = "../../../atat/atat" } - [profile.dev] opt-level = "s" [profile.release] -opt-level = "s" \ No newline at end of file +opt-level = "s" diff --git a/examples/embassy-rp2040-example/rust-toolchain.toml b/examples/embassy-rp2040-example/rust-toolchain.toml index 25d771e..d1bbca4 100644 --- a/examples/embassy-rp2040-example/rust-toolchain.toml +++ b/examples/embassy-rp2040-example/rust-toolchain.toml @@ -1,14 +1,8 @@ # Before upgrading check that everything is available on all tier1 targets here: # https://rust-lang.github.io/rustup-components-history [toolchain] -channel = "1.75" +channel = "nightly-2024-02-01" components = [ "rust-src", "rustfmt", "llvm-tools" ] targets = [ - "thumbv7em-none-eabi", - "thumbv7m-none-eabi", "thumbv6m-none-eabi", - "thumbv7em-none-eabihf", - "thumbv8m.main-none-eabihf", - "riscv32imac-unknown-none-elf", - "wasm32-unknown-unknown", ] \ No newline at end of file diff --git a/examples/embassy-rp2040-example/src/bin/embassy-smoltcp-ppp.rs b/examples/embassy-rp2040-example/src/bin/embassy-smoltcp-ppp.rs index 4082e70..8f8b287 100644 --- a/examples/embassy-rp2040-example/src/bin/embassy-smoltcp-ppp.rs +++ b/examples/embassy-rp2040-example/src/bin/embassy-smoltcp-ppp.rs @@ -1,5 +1,4 @@ #![cfg(feature = "ppp")] - #![no_std] #![no_main] #![allow(stable_features)] @@ -7,8 +6,10 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_net::dns::DnsSocket; +use embassy_net::tcp::client::TcpClient; +use embassy_net::tcp::client::TcpClientState; use embassy_net::tcp::TcpSocket; -use embassy_net::Ipv4Address; use embassy_net::Stack; use embassy_net::StackResources; use embassy_rp::gpio; @@ -17,11 +18,29 @@ use embassy_rp::gpio::Input; use embassy_rp::gpio::OutputOpenDrain; use embassy_rp::uart::BufferedUart; use embassy_rp::{bind_interrupts, peripherals::UART0, uart::BufferedInterruptHandler}; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_time::Duration; +use embassy_time::Timer; +use embedded_mqtt::transport::embedded_tls::TlsNalTransport; +use embedded_mqtt::transport::embedded_tls::TlsState; +use embedded_mqtt::DomainBroker; +use embedded_tls::Aes128GcmSha256; +use embedded_tls::Certificate; +use embedded_tls::TlsConfig; +use embedded_tls::TlsConnection; +use embedded_tls::TlsContext; +use embedded_tls::UnsecureProvider; +use rand_chacha::rand_core::SeedableRng; +use rand_chacha::ChaCha8Rng; +use reqwless::headers::ContentType; +use reqwless::request::Request; +use reqwless::request::RequestBuilder as _; +use reqwless::response::Response; use static_cell::StaticCell; use ublox_cellular::asynch::state::OperationState; use ublox_cellular::asynch::PPPRunner; use ublox_cellular::asynch::Resources; +use ublox_cellular::config::NoPin; use {defmt_rtt as _, panic_probe as _}; use ublox_cellular::config::{Apn, CellularConfig}; @@ -82,8 +101,8 @@ async fn main(spawner: Spawner) { embassy_rp::init(config) }; - static TX_BUF: StaticCell<[u8; 16]> = StaticCell::new(); - static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new(); + static TX_BUF: StaticCell<[u8; 256]> = StaticCell::new(); + static RX_BUF: StaticCell<[u8; 256]> = StaticCell::new(); let cell_uart = BufferedUart::new_with_rtscts( p.UART0, @@ -92,8 +111,8 @@ async fn main(spawner: Spawner) { p.PIN_1, p.PIN_3, p.PIN_2, - TX_BUF.init([0; 16]), - RX_BUF.init([0; 16]), + TX_BUF.init([0; 256]), + RX_BUF.init([0; 256]), embassy_rp::uart::Config::default(), ); @@ -103,15 +122,12 @@ async fn main(spawner: Spawner) { static RESOURCES: StaticCell> = StaticCell::new(); - - let (net_device, mut control, runner) = ublox_cellular::asynch::new_ppp( - RESOURCES.init(Resources::new()), - MyCelullarConfig { + let (net_device, mut cell_control, mut runner) = + ublox_cellular::asynch::new_ppp(RESOURCES.init(Resources::new()), MyCelullarConfig { reset_pin: Some(cell_nrst), power_pin: Some(cell_pwr), - vint_pin: Some(cell_vint), - }, - ); + vint_pin: Some(cell_vint) + }); // Generate random seed let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. @@ -127,43 +143,93 @@ async fn main(spawner: Spawner) { seed, )); - spawner.spawn(net_task(stack)).unwrap(); - spawner.spawn(ppp_task(runner, cell_uart, &stack)).unwrap(); - - control.set_desired_state(OperationState::Connected).await; - - stack.wait_config_up().await; - - info!("We have network!"); - - // Then we can use it! - let mut rx_buffer = [0; 4096]; - let mut tx_buffer = [0; 4096]; - let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); - socket.set_timeout(Some(Duration::from_secs(10))); - - let remote_endpoint = (Ipv4Address::new(93, 184, 216, 34), 80); - info!("connecting to {:?}...", remote_endpoint); - let r = socket.connect(remote_endpoint).await; - if let Err(e) = r { - warn!("connect error: {:?}", e); - return; - } - info!("TCP connected!"); -} - -#[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await -} + let http_fut = async { + stack.wait_config_up().await; + + info!("We have network!"); + + let mut rx_buffer = [0; 4096]; + let mut tx_buffer = [0; 4096]; + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); + socket.set_timeout(Some(Duration::from_secs(10))); + + let hostname = "ecdsa-test.germancoding.com"; + + let mut remote = stack + .dns_query(hostname, smoltcp::wire::DnsQueryType::A) + .await + .unwrap(); + let remote_endpoint = (remote.pop().unwrap(), 443); + info!("connecting to {:?}...", remote_endpoint); + let r = socket.connect(remote_endpoint).await; + if let Err(e) = r { + warn!("connect error: {:?}", e); + return; + } + info!("TCP connected!"); + + let mut read_record_buffer = [0; 16384]; + let mut write_record_buffer = [0; 16384]; + let config = TlsConfig::new().with_server_name(hostname); + let mut tls = TlsConnection::new(socket, &mut read_record_buffer, &mut write_record_buffer); + + tls.open(TlsContext::new( + &config, + UnsecureProvider::new::(ChaCha8Rng::seed_from_u64(seed)), + )) + .await + .expect("error establishing TLS connection"); + + info!("TLS Established!"); + + let request = Request::get("/") + .host(hostname) + .content_type(ContentType::TextPlain) + .build(); + request.write(&mut tls).await.unwrap(); + + let mut rx_buf = [0; 4096]; + let response = Response::read(&mut tls, reqwless::request::Method::GET, &mut rx_buf) + .await + .unwrap(); + + // let mut buf = vec![0; 16384]; + // let len = response + // .body() + // .reader() + // .read_to_end(&mut buf) + // .await + // .unwrap(); + // info!("{:?}", core::str::from_utf8(&buf[..len])); + }; -#[embassy_executor::task] -async fn ppp_task( - mut runner: PPPRunner<'static, MyCelullarConfig, INGRESS_BUF_SIZE, URC_CAPACITY>, - interface: BufferedUart<'static, UART0>, - stack: &'static embassy_net::Stack>, -) -> ! { - let (rx, tx) = interface.split(); - runner.run(rx, tx, stack).await + let (rx, tx) = cell_uart.split(); + embassy_futures::join::join3( + stack.run(), + runner.run(rx, tx, |ipv4| { + let Some(addr) = ipv4.address else { + warn!("PPP did not provide an IP address."); + return; + }; + let mut dns_servers = heapless::Vec::new(); + for s in ipv4.dns_servers.iter().flatten() { + let _ = dns_servers.push(embassy_net::Ipv4Address::from_bytes(&s.0)); + } + let config = embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { + address: embassy_net::Ipv4Cidr::new( + embassy_net::Ipv4Address::from_bytes(&addr.0), + 0, + ), + gateway: None, + dns_servers, + }); + + stack.set_config_v4(config); + }), + http_fut, + ) + .await; + + core::unreachable!(); } diff --git a/examples/tokio-std-example/.cargo/config.toml b/examples/tokio-std-example/.cargo/config.toml new file mode 100644 index 0000000..38c661e --- /dev/null +++ b/examples/tokio-std-example/.cargo/config.toml @@ -0,0 +1,5 @@ +[build] +target = "x86_64-unknown-linux-gnu" + +[env] +RUST_LOG = "trace,embassy_hal_internal=error" diff --git a/examples/tokio-std-example/.gitignore b/examples/tokio-std-example/.gitignore new file mode 100644 index 0000000..092e4d3 --- /dev/null +++ b/examples/tokio-std-example/.gitignore @@ -0,0 +1,9 @@ +**/*.rs.bk +.#* +.gdb_history +*.fifo +target/ +*.o +**/*secrets* + +.DS_Store diff --git a/examples/tokio-std-example/.vscode/settings.json b/examples/tokio-std-example/.vscode/settings.json new file mode 100644 index 0000000..64a95fd --- /dev/null +++ b/examples/tokio-std-example/.vscode/settings.json @@ -0,0 +1,17 @@ +{ + // override the default setting (`cargo check --all-targets`) which produces the following error + // "can't find crate for `test`" when the default compilation target is a no_std target + // with these changes RA will call `cargo check --bins` on save + "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.procMacro.enable": true, + "rust-analyzer.cargo.target": "x86_64-unknown-linux-gnu", + "rust-analyzer.cargo.features": [ + "ppp", + ], + "rust-analyzer.checkOnSave.command": "clippy", + "rust-analyzer.cargoRunner": null, + "rust-analyzer.experimental.procAttrMacros": false, + "rust-analyzer.diagnostics.disabled": [ + "macro-error" + ], +} \ No newline at end of file diff --git a/examples/tokio-std-example/Cargo.toml b/examples/tokio-std-example/Cargo.toml new file mode 100644 index 0000000..e264ceb --- /dev/null +++ b/examples/tokio-std-example/Cargo.toml @@ -0,0 +1,81 @@ +[package] +name = "tokio-std-example" +version = "0.1.0" +edition = "2021" + +[dependencies] +tokio = { version = "1", features = ["full"] } +tokio-serial = "5.4.1" + +embassy-time = { version = "0.3", features = ["std", "generic-queue"] } +embassy-futures = { version = "0.1", features = ["log"] } +embassy-sync = { version = "0.5", features = ["log"] } + +embassy-net = { version = "0.4", features = [ + "log", + "packet-trace", + "proto-ipv4", + "medium-ip", + "tcp", + "udp", + "dns", +] } +embassy-net-ppp = { version = "0.1", features = ["log"] } +embassy-at-cmux = { path = "../../../embassy/embassy-at-cmux", features = [ + "log", +] } + +embedded-tls = { git = "https://github.com/drogue-iot/embedded-tls", rev = "f788e02", default-features = false, features = [ + "log", +] } + +embedded-io-adapters = { version = "0.6", features = ["tokio-1"] } +embedded-io-async = { version = "0.6" } +heapless = "0.8" + +env_logger = "0.11" +log = "0.4.21" + +static_cell = { version = "2.0" } + +atat = { version = "0.21.0", features = ["derive", "bytes", "log"] } +ublox-cellular-rs = { version = "0.4.0", path = "../..", features = [ + "lara-r6", + "log", +] } +reqwless = { git = "https://github.com/drogue-iot/reqwless", features = [ + "log", +] } +smoltcp = { version = "*", default-features = false, features = [ + "dns-max-server-count-4", +] } +rand_chacha = { version = "0.3", default-features = false } + +[features] +ppp = ["ublox-cellular-rs/ppp"] +internal-network-stack = ["ublox-cellular-rs/internal-network-stack"] + +[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 = { git = "https://github.com/embassy-rs/embassy", branch = "main" } +# embassy-sync = { git = "https://github.com/embassy-rs/embassy", branch = "main" } +# embassy-net = { git = "https://github.com/embassy-rs/embassy", branch = "main" } +# embassy-net-ppp = { 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-net = { path = "../../../embassy/embassy-net" } +embassy-net-ppp = { path = "../../../embassy/embassy-net-ppp" } +embassy-futures = { path = "../../../embassy/embassy-futures" } + +atat = { path = "../../../atat/atat" } + +[profile.dev] +opt-level = "s" + +[profile.release] +opt-level = "s" diff --git a/examples/tokio-std-example/rust-toolchain.toml b/examples/tokio-std-example/rust-toolchain.toml new file mode 100644 index 0000000..f39e558 --- /dev/null +++ b/examples/tokio-std-example/rust-toolchain.toml @@ -0,0 +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-2024-02-01" +components = [ "rust-src", "rustfmt", "llvm-tools" ] +targets = [ + "x86_64-unknown-linux-gnu", +] \ No newline at end of file diff --git a/examples/tokio-std-example/src/bin/embassy-internal-stack.rs b/examples/tokio-std-example/src/bin/embassy-internal-stack.rs new file mode 100644 index 0000000..3429b73 --- /dev/null +++ b/examples/tokio-std-example/src/bin/embassy-internal-stack.rs @@ -0,0 +1,188 @@ +#![no_std] +#![no_main] +#![allow(stable_features)] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::gpio; +use embassy_rp::gpio::Input; + +use embassy_rp::gpio::OutputOpenDrain; +use embassy_rp::uart::BufferedUart; +use embassy_rp::uart::BufferedUartRx; +use embassy_rp::uart::BufferedUartTx; +use embassy_rp::{bind_interrupts, peripherals::UART0, uart::BufferedInterruptHandler}; +use embassy_time::{Duration, Timer}; +use static_cell::StaticCell; +use ublox_cellular::asynch::InternalRunner; +use ublox_cellular::asynch::Resources; +use {defmt_rtt as _, panic_probe as _}; + +use ublox_cellular::config::{Apn, CellularConfig}; + +use ublox_cellular::asynch::state::OperationState; + +bind_interrupts!(struct Irqs { + UART0_IRQ => BufferedInterruptHandler; +}); + +const CMD_BUF_SIZE: usize = 128; +const INGRESS_BUF_SIZE: usize = 1024; +const URC_CAPACITY: usize = 2; + +struct MyCelullarConfig { + reset_pin: Option>, + power_pin: Option>, + vint_pin: Option>, +} + +impl<'a> CellularConfig<'a> for MyCelullarConfig { + type ResetPin = OutputOpenDrain<'static>; + type PowerPin = OutputOpenDrain<'static>; + type VintPin = Input<'static>; + + const FLOW_CONTROL: bool = true; + const HEX_MODE: bool = true; + const APN: Apn<'a> = Apn::Given { + name: "em", + username: None, + password: None, + }; + fn reset_pin(&mut self) -> Option<&mut Self::ResetPin> { + info!("reset_pin"); + self.reset_pin.as_mut() + } + fn power_pin(&mut self) -> Option<&mut Self::PowerPin> { + info!("power_pin"); + self.power_pin.as_mut() + } + fn vint_pin(&mut self) -> Option<&mut Self::VintPin> { + info!("vint_pin = {}", self.vint_pin.as_mut()?.is_high()); + self.vint_pin.as_mut() + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = { + let config = + embassy_rp::config::Config::new(embassy_rp::clocks::ClockConfig::crystal(12_000_000)); + embassy_rp::init(config) + }; + + static TX_BUF: StaticCell<[u8; 16]> = StaticCell::new(); + static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new(); + + let cell_uart = BufferedUart::new_with_rtscts( + p.UART0, + Irqs, + p.PIN_0, + p.PIN_1, + p.PIN_3, + p.PIN_2, + TX_BUF.init([0; 16]), + RX_BUF.init([0; 16]), + embassy_rp::uart::Config::default(), + ); + + let (uart_rx, uart_tx) = cell_uart.split(); + let cell_nrst = gpio::OutputOpenDrain::new(p.PIN_4, gpio::Level::High); + let cell_pwr = gpio::OutputOpenDrain::new(p.PIN_5, gpio::Level::High); + let cell_vint = gpio::Input::new(p.PIN_6, gpio::Pull::None); + + static RESOURCES: StaticCell< + Resources, CMD_BUF_SIZE, INGRESS_BUF_SIZE, URC_CAPACITY>, + > = StaticCell::new(); + + let (_net_device, mut control, runner) = ublox_cellular::asynch::new_internal( + uart_rx, + uart_tx, + RESOURCES.init(Resources::new()), + MyCelullarConfig { + reset_pin: Some(cell_nrst), + power_pin: Some(cell_pwr), + vint_pin: Some(cell_vint), + }, + ); + + // defmt::info!("{:?}", runner.init().await); + // control.set_desired_state(PowerState::Connected).await; + // control + // .send(&crate::command::network_service::SetOperatorSelection { + // mode: crate::command::network_service::types::OperatorSelectionMode::Automatic, + // format: Some(0), + // }) + // .await; + + defmt::unwrap!(spawner.spawn(cell_task(runner))); + + Timer::after(Duration::from_millis(1000)).await; + loop { + control + .set_desired_state(OperationState::DataEstablished) + .await; + info!("set_desired_state(PowerState::Alive)"); + while control.power_state() != OperationState::DataEstablished { + Timer::after(Duration::from_millis(1000)).await; + } + Timer::after(Duration::from_millis(10000)).await; + + loop { + Timer::after(Duration::from_millis(1000)).await; + let operator = control.get_operator().await; + info!("{}", operator); + let signal_quality = control.get_signal_quality().await; + info!("{}", signal_quality); + if signal_quality.is_err() { + let desired_state = control.desired_state(); + control.set_desired_state(desired_state).await + } + if let Ok(sq) = signal_quality { + if let Ok(op) = operator { + if op.oper.is_none() { + continue; + } + } + if sq.rxlev > 0 && sq.rsrp != 255 { + break; + } + } + } + let dns = control + .send(&ublox_cellular::command::dns::ResolveNameIp { + resolution_type: + ublox_cellular::command::dns::types::ResolutionType::DomainNameToIp, + ip_domain_string: "www.google.com", + }) + .await; + info!("dns: {:?}", dns); + Timer::after(Duration::from_millis(10000)).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; + } +} + +// #[embassy_executor::task] +// async fn net_task(stack: &'static Stack>) -> ! { +// stack.run().await +// } + +#[embassy_executor::task] +async fn cell_task( + mut runner: InternalRunner< + 'static, + BufferedUartRx<'static, UART0>, + BufferedUartTx<'static, UART0>, + MyCelullarConfig, + INGRESS_BUF_SIZE, + URC_CAPACITY, + >, +) -> ! { + runner.run().await +} diff --git a/examples/tokio-std-example/src/bin/tokio-smoltcp-ppp.rs b/examples/tokio-std-example/src/bin/tokio-smoltcp-ppp.rs new file mode 100644 index 0000000..77e7ba6 --- /dev/null +++ b/examples/tokio-std-example/src/bin/tokio-smoltcp-ppp.rs @@ -0,0 +1,198 @@ +#![cfg(feature = "ppp")] + +use atat::asynch::AtatClient as _; +use atat::asynch::SimpleClient; +use atat::AtatIngress as _; +use embassy_net::dns::DnsSocket; +use embassy_net::tcp::client::TcpClient; +use embassy_net::tcp::client::TcpClientState; +use embassy_net::tcp::TcpSocket; +use embassy_net::Stack; +use embassy_net::StackResources; + +use embassy_sync::blocking_mutex::raw::NoopRawMutex; +use embassy_time::Duration; +use embassy_time::Instant; +use embassy_time::Timer; +use embedded_mqtt::transport::embedded_tls::TlsNalTransport; +use embedded_mqtt::transport::embedded_tls::TlsState; +use embedded_mqtt::DomainBroker; +use embedded_tls::Aes128GcmSha256; +use embedded_tls::Certificate; +use embedded_tls::TlsConfig; +use embedded_tls::TlsConnection; +use embedded_tls::TlsContext; +use embedded_tls::UnsecureProvider; +use log::*; +use rand_chacha::rand_core::SeedableRng; +use rand_chacha::ChaCha8Rng; +use reqwless::headers::ContentType; +use reqwless::request::Request; +use reqwless::request::RequestBuilder as _; +use reqwless::response::Response; +use static_cell::StaticCell; +use tokio_serial::SerialPort; +use tokio_serial::SerialPortBuilderExt; +use ublox_cellular::asynch::state::OperationState; +use ublox_cellular::asynch::Resources; + +use ublox_cellular::command::control::SetDataRate; +use ublox_cellular::command::control::SetFlowControl; +use ublox_cellular::command::general::GetModelId; +use ublox_cellular::command::ipc::SetMultiplexing; +use ublox_cellular::command::psn::DeactivatePDPContext; +use ublox_cellular::command::psn::EnterPPP; +use ublox_cellular::command::Urc; +use ublox_cellular::command::AT; +use ublox_cellular::config::NoPin; +use ublox_cellular::config::{Apn, CellularConfig}; + +const CMD_BUF_SIZE: usize = 128; +const INGRESS_BUF_SIZE: usize = 512; +const URC_CAPACITY: usize = 2; + +struct MyCelullarConfig; + +impl<'a> CellularConfig<'a> for MyCelullarConfig { + type ResetPin = NoPin; + type PowerPin = NoPin; + type VintPin = NoPin; + + const FLOW_CONTROL: bool = true; + + const APN: Apn<'a> = Apn::Given { + name: "em", + username: None, + password: None, + }; + + const PPP_CONFIG: embassy_net_ppp::Config<'a> = embassy_net_ppp::Config { + username: b"", + password: b"", + }; +} + +const TTY: &str = "/dev/ttyUSB0"; + +#[tokio::main] +async fn main() -> Result<(), Box> { + env_logger::init(); + + info!("HELLO"); + + let mut ppp_iface = tokio_serial::new(TTY, 115200).open_native_async()?; + ppp_iface + .set_flow_control(tokio_serial::FlowControl::Hardware) + .unwrap(); + + static RESOURCES: StaticCell> = + StaticCell::new(); + + let (net_device, mut cell_control, mut runner) = + ublox_cellular::asynch::new_ppp(RESOURCES.init(Resources::new()), MyCelullarConfig); + + // Generate random seed + let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. + + // Init network stack + static STACK: StaticCell>> = StaticCell::new(); + static STACK_RESOURCES: StaticCell> = StaticCell::new(); + + let stack = &*STACK.init(Stack::new( + net_device, + embassy_net::Config::default(), + STACK_RESOURCES.init(StackResources::new()), + seed, + )); + + let http_fut = async { + stack.wait_config_up().await; + + info!("We have network!"); + + let mut rx_buffer = [0; 4096]; + let mut tx_buffer = [0; 4096]; + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); + socket.set_timeout(Some(Duration::from_secs(10))); + + let hostname = "ecdsa-test.germancoding.com"; + + let mut remote = stack + .dns_query(hostname, smoltcp::wire::DnsQueryType::A) + .await + .unwrap(); + let remote_endpoint = (remote.pop().unwrap(), 443); + info!("connecting to {:?}...", remote_endpoint); + let r = socket.connect(remote_endpoint).await; + if let Err(e) = r { + warn!("connect error: {:?}", e); + return; + } + info!("TCP connected!"); + + let mut read_record_buffer = [0; 16384]; + let mut write_record_buffer = [0; 16384]; + let config = TlsConfig::new().with_server_name(hostname); + let mut tls = TlsConnection::new(socket, &mut read_record_buffer, &mut write_record_buffer); + + tls.open(TlsContext::new( + &config, + UnsecureProvider::new::(ChaCha8Rng::seed_from_u64(seed)), + )) + .await + .expect("error establishing TLS connection"); + + info!("TLS Established!"); + + let request = Request::get("/") + .host(hostname) + .content_type(ContentType::TextPlain) + .build(); + request.write(&mut tls).await.unwrap(); + + let mut rx_buf = [0; 4096]; + let response = Response::read(&mut tls, reqwless::request::Method::GET, &mut rx_buf) + .await + .unwrap(); + + let mut buf = vec![0; 16384]; + let len = response + .body() + .reader() + .read_to_end(&mut buf) + .await + .unwrap(); + info!("{:?}", core::str::from_utf8(&buf[..len])); + }; + + let (rx, tx) = tokio::io::split(ppp_iface); + let rx = embedded_io_adapters::tokio_1::FromTokio::new(tokio::io::BufReader::new(rx)); + let tx = embedded_io_adapters::tokio_1::FromTokio::new(tx); + embassy_futures::join::join3( + stack.run(), + runner.run(rx, tx, |ipv4| { + let Some(addr) = ipv4.address else { + warn!("PPP did not provide an IP address."); + return; + }; + let mut dns_servers = heapless::Vec::new(); + for s in ipv4.dns_servers.iter().flatten() { + let _ = dns_servers.push(embassy_net::Ipv4Address::from_bytes(&s.0)); + } + let config = embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { + address: embassy_net::Ipv4Cidr::new( + embassy_net::Ipv4Address::from_bytes(&addr.0), + 0, + ), + gateway: None, + dns_servers, + }); + + stack.set_config_v4(config); + }), + http_fut, + ) + .await; + + unreachable!(); +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index cab8465..696df2c 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] channel = "1.75" -components = [ "rust-src", "rustfmt", "llvm-tools-preview", "clippy" ] +components = [ "rust-src", "rustfmt", "llvm-tools", "clippy" ] targets = [ "x86_64-unknown-linux-gnu", "thumbv7em-none-eabihf" diff --git a/src/asynch/control.rs b/src/asynch/control.rs index 98c52e7..562b960 100644 --- a/src/asynch/control.rs +++ b/src/asynch/control.rs @@ -37,6 +37,13 @@ impl<'a, AT: AtatClient> Control<'a, AT> { self.state_ch.set_desired_state(ps).await; } + pub async fn wait_for_desired_state( + &mut self, + ps: OperationState, + ) -> Result { + self.state_ch.wait_for_desired_state(ps).await + } + pub async fn get_signal_quality( &mut self, ) -> Result { diff --git a/src/asynch/internal_stack.rs b/src/asynch/internal_stack.rs index 18a4b87..23f8609 100644 --- a/src/asynch/internal_stack.rs +++ b/src/asynch/internal_stack.rs @@ -10,7 +10,11 @@ use crate::{command::Urc, config::CellularConfig}; pub use super::resources::UbxResources as Resources; -use super::{control::Control, runner::Runner, state, AtHandle}; +use super::{ + control::Control, + runner::{Runner, URC_SUBSCRIBERS}, + state, AtHandle, +}; pub fn new_internal< 'a, @@ -87,7 +91,14 @@ pub struct InternalRunner< const URC_CAPACITY: usize, > { pub cellular_runner: Runner<'a, Client<'a, W, INGRESS_BUF_SIZE>, C, URC_CAPACITY>, - pub ingress: atat::Ingress<'a, atat::AtDigester, Urc, INGRESS_BUF_SIZE, URC_CAPACITY, 2>, + pub ingress: atat::Ingress< + 'a, + atat::AtDigester, + Urc, + INGRESS_BUF_SIZE, + URC_CAPACITY, + URC_SUBSCRIBERS, + >, pub reader: R, } diff --git a/src/asynch/mod.rs b/src/asynch/mod.rs index aede837..d0cd66a 100644 --- a/src/asynch/mod.rs +++ b/src/asynch/mod.rs @@ -13,6 +13,16 @@ mod ppp; #[cfg(feature = "ppp")] pub use ppp::{new_ppp, PPPRunner, Resources}; +#[cfg(feature = "ppp")] +pub type Control<'d, const INGRESS_BUF_SIZE: usize> = control::Control< + 'd, + atat::asynch::Client< + 'd, + embassy_at_cmux::ChannelTx<'d, { ppp::CMUX_CHANNEL_SIZE }>, + INGRESS_BUF_SIZE, + >, +>; + use atat::asynch::AtatClient; use embassy_sync::{blocking_mutex::raw::NoopRawMutex, mutex::Mutex}; diff --git a/src/asynch/ppp.rs b/src/asynch/ppp.rs index 02828b0..affb3c3 100644 --- a/src/asynch/ppp.rs +++ b/src/asynch/ppp.rs @@ -2,16 +2,12 @@ use core::mem::MaybeUninit; use crate::{ command::{ - control::{types::FlowControl, SetFlowControl}, ipc::SetMultiplexing, - mobile_control::{ - types::{Functionality, ResetMode, TerminationErrorMode}, - SetModuleFunctionality, SetReportMobileTerminationError, - }, - psn::{DeactivatePDPContext, EnterPPP, SetPDPContextDefinition}, + psn::{DeactivatePDPContext, EnterPPP}, Urc, }, - config::{Apn, CellularConfig}, + config::CellularConfig, + module_timing::boot_time, }; use atat::{ asynch::{AtatClient, Client, SimpleClient}, @@ -19,17 +15,25 @@ use atat::{ }; use embassy_sync::{blocking_mutex::raw::NoopRawMutex, mutex::Mutex}; use embassy_time::{Duration, Instant, Timer}; -use embedded_io::Error; -use embedded_io_async::{BufRead, Read, Write}; +use embedded_io_async::{BufRead, Error, ErrorKind, Read, Write}; -use super::{control::Control, resources::UbxResources, runner::Runner, state, AtHandle}; +use super::{ + control::Control, + resources::UbxResources, + runner::{Runner, URC_SUBSCRIBERS}, + state, AtHandle, +}; + +pub const CMUX_MAX_FRAME_SIZE: usize = 512; +pub const CMUX_CHANNEL_SIZE: usize = CMUX_MAX_FRAME_SIZE * 2; +pub const CMUX_CHANNELS: usize = 2; // AT Control + PPP data pub type Resources< const CMD_BUF_SIZE: usize, const INGRESS_BUF_SIZE: usize, const URC_CAPACITY: usize, > = UbxResources< - embassy_at_cmux::ChannelTx<'static, 256>, + embassy_at_cmux::ChannelTx<'static, CMUX_CHANNEL_SIZE>, CMD_BUF_SIZE, INGRESS_BUF_SIZE, URC_CAPACITY, @@ -46,25 +50,32 @@ pub fn new_ppp< config: C, ) -> ( embassy_net_ppp::Device<'a>, - Control<'a, Client<'a, embassy_at_cmux::ChannelTx<'a, 256>, INGRESS_BUF_SIZE>>, + Control<'a, Client<'a, embassy_at_cmux::ChannelTx<'a, CMUX_CHANNEL_SIZE>, INGRESS_BUF_SIZE>>, PPPRunner<'a, C, INGRESS_BUF_SIZE, URC_CAPACITY>, ) { let ch_runner = state::new_ppp(&mut resources.ch); let state_ch = ch_runner.state_runner(); - let (mux_runner, [ppp_channel, control_channel]) = resources.mux.start(); + let (mux_runner, [control_channel, ppp_channel]) = resources.mux.start(); let (control_rx, control_tx, _) = control_channel.split(); // safety: this is a self-referential struct, however: // - it can't move while the `'a` borrow is active. // - when the borrow ends, the dangling references inside the MaybeUninit will never be used again. let at_client_uninit: *mut MaybeUninit< - Mutex, INGRESS_BUF_SIZE>>, + Mutex< + NoopRawMutex, + Client<'a, embassy_at_cmux::ChannelTx<'a, CMUX_CHANNEL_SIZE>, INGRESS_BUF_SIZE>, + >, > = (&mut resources.at_client as *mut MaybeUninit< Mutex< NoopRawMutex, - Client<'static, embassy_at_cmux::ChannelTx<'static, 256>, INGRESS_BUF_SIZE>, + Client< + 'static, + embassy_at_cmux::ChannelTx<'static, CMUX_CHANNEL_SIZE>, + INGRESS_BUF_SIZE, + >, >, >) .cast(); @@ -97,6 +108,7 @@ pub fn new_ppp< let (net_device, ppp_runner) = embassy_net_ppp::new(&mut resources.ppp_state); let runner = PPPRunner { + powered: false, ppp_runner, cellular_runner, ingress, @@ -114,87 +126,69 @@ pub struct PPPRunner< const INGRESS_BUF_SIZE: usize, const URC_CAPACITY: usize, > { + pub powered: bool, pub ppp_runner: embassy_net_ppp::Runner<'a>, pub cellular_runner: Runner< 'a, - Client<'a, embassy_at_cmux::ChannelTx<'a, 256>, INGRESS_BUF_SIZE>, + Client<'a, embassy_at_cmux::ChannelTx<'a, CMUX_CHANNEL_SIZE>, INGRESS_BUF_SIZE>, C, URC_CAPACITY, >, - pub ingress: atat::Ingress<'a, atat::AtDigester, Urc, INGRESS_BUF_SIZE, URC_CAPACITY, 2>, - pub ppp_channel: embassy_at_cmux::Channel<'a, 256>, - pub control_rx: embassy_at_cmux::ChannelRx<'a, 256>, - pub mux_runner: embassy_at_cmux::Runner<'a, 2, 256>, + pub ingress: atat::Ingress< + 'a, + atat::AtDigester, + Urc, + INGRESS_BUF_SIZE, + URC_CAPACITY, + URC_SUBSCRIBERS, + >, + pub ppp_channel: embassy_at_cmux::Channel<'a, CMUX_CHANNEL_SIZE>, + pub control_rx: embassy_at_cmux::ChannelRx<'a, CMUX_CHANNEL_SIZE>, + pub mux_runner: embassy_at_cmux::Runner<'a, CMUX_CHANNELS, CMUX_CHANNEL_SIZE>, } impl<'a, C: CellularConfig<'a>, const INGRESS_BUF_SIZE: usize, const URC_CAPACITY: usize> PPPRunner<'a, C, INGRESS_BUF_SIZE, URC_CAPACITY> { - async fn configure_apn(at_client: &mut A) -> Result<(), atat::Error> { - at_client - .send(&SetModuleFunctionality { - fun: Functionality::Minimum, - rst: Some(ResetMode::DontReset), - }) - .await?; - - let apn = match C::APN { - Apn::None => "", - Apn::Given { name, .. } => name, - }; - - at_client - .send(&SetPDPContextDefinition { - cid: C::CONTEXT_ID, - pdp_type: "IP", - apn, - }) - .await?; - - at_client - .send(&SetModuleFunctionality { - fun: Functionality::Full, - rst: Some(ResetMode::DontReset), - }) - .await?; - Ok(()) - } - - async fn init(rx: &mut R, tx: &mut W) -> Result<(), atat::Error> { + async fn init_multiplexer( + rx: &mut R, + tx: &mut W, + ) -> Result<(), crate::error::Error> { let mut buf = [0u8; 64]; + let mut interface = ReadWriteAdapter(rx, tx); let mut at_client = SimpleClient::new( - ReadWriteAdapter(rx, tx), + &mut interface, atat::AtDigester::::new(), &mut buf, atat::Config::default(), ); - at_client - .send(&SetReportMobileTerminationError { - n: TerminationErrorMode::Enabled, - }) - .await?; - - at_client - .send(&SetFlowControl { - value: FlowControl::RtsCts, - }) - .await?; + super::runner::init_at(&mut at_client, C::FLOW_CONTROL).await?; at_client .send(&SetMultiplexing { mode: 0, - subset: None, - port_speed: None, - n1: None, - t1: None, - n2: None, - t2: None, - t3: None, - k: None, + subset: Some(0), + port_speed: Some(5), + n1: Some(CMUX_MAX_FRAME_SIZE as u16), + t1: None, //Some(10), + n2: None, //Some(3), + t2: None, //Some(30), + t3: None, //Some(10), + k: None, //Some(2), }) .await?; + drop(at_client); + + // Drain the UART of any leftover AT stuff before setting up multiplexer + let _ = embassy_time::with_timeout(Duration::from_millis(100), async { + loop { + let _ = interface.read(&mut buf).await; + } + }) + .await; + Ok(()) } @@ -202,32 +196,36 @@ impl<'a, C: CellularConfig<'a>, const INGRESS_BUF_SIZE: usize, const URC_CAPACIT &mut self, mut rx: R, mut tx: W, - stack: &embassy_net::Stack>, + on_ipv4_up: impl FnMut(embassy_net_ppp::Ipv4Status) + Copy, ) -> ! { loop { - // Reset modem - // if self.cellular_runner.init().await.is_err() { - // Timer::after(Duration::from_secs(5)).await; - // continue; - // } - - // Timer::after(Duration::from_secs(5)).await; + if !self.powered { + // Reset modem + self.cellular_runner + .change_state_to_desired_state(state::OperationState::PowerDown) + .await; + self.cellular_runner + .change_state_to_desired_state(state::OperationState::PowerUp) + .await; + + Timer::after(boot_time()).await; + } // Do AT init and enter CMUX mode using interface - if Self::init(&mut rx, &mut tx).await.is_err() { + if Self::init_multiplexer(&mut rx, &mut tx).await.is_err() { Timer::after(Duration::from_secs(5)).await; continue; }; - Timer::after(Duration::from_secs(1)).await; + self.cellular_runner + .change_state_to_desired_state(state::OperationState::DataEstablished) + .await; let ppp_fut = async { let mut fails = 0; let mut last_start = None; loop { - Timer::after(Duration::from_secs(15)).await; - if let Some(last_start) = last_start { Timer::at(last_start + Duration::from_secs(10)).await; // Do not attempt to start too fast. @@ -245,63 +243,37 @@ impl<'a, C: CellularConfig<'a>, const INGRESS_BUF_SIZE: usize, const URC_CAPACIT } last_start = Some(Instant::now()); - let mut buf = [0u8; 64]; - let mut at_client = SimpleClient::new( - &mut self.ppp_channel, - atat::AtDigester::::new(), - &mut buf, - atat::Config::default(), - ); - - if let Err(e) = Self::configure_apn(&mut at_client).await { - warn!("modem: configure failed {:?}", e); - continue; - } - - Timer::after(Duration::from_secs(2)).await; - - // hangup just in case a call was already in progress. - // Ignore errors because this fails if it wasn't. - let _ = at_client.send(&DeactivatePDPContext).await; - - // Send AT command to enter PPP mode - let res = at_client.send(&EnterPPP { cid: C::CONTEXT_ID }).await; + { + let mut buf = [0u8; 16]; // Enough room for "ATD*99***1#\r\n" + let mut at_client = SimpleClient::new( + &mut self.ppp_channel, + atat::AtDigester::::new(), + &mut buf, + atat::Config::default(), + ); + + // hangup just in case a call was already in progress. + // Ignore errors because this fails if it wasn't. + let _ = at_client.send(&DeactivatePDPContext).await; + + // Send AT command to enter PPP mode + let res = at_client.send(&EnterPPP { cid: C::CONTEXT_ID }).await; + + if let Err(e) = res { + warn!("ppp dial failed {:?}", e); + continue; + } - if let Err(e) = res { - warn!("ppp dial failed {:?}", e); - continue; + Timer::after(Duration::from_millis(100)).await; } - drop(at_client); - // Check for CTS low (bit 2) - self.ppp_channel.set_hangup_detection(0x04, 0x00); + // self.ppp_channel.set_hangup_detection(0x04, 0x00); info!("RUNNING PPP"); let res = self .ppp_runner - .run(&mut self.ppp_channel, C::PPP_CONFIG, |ipv4| { - let Some(addr) = ipv4.address else { - warn!("PPP did not provide an IP address."); - return; - }; - let mut dns_servers = heapless::Vec::new(); - for s in ipv4.dns_servers.iter().flatten() { - let _ = - dns_servers.push(embassy_net::Ipv4Address::from_bytes(&s.0)); - } - let config = - embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { - address: embassy_net::Ipv4Cidr::new( - embassy_net::Ipv4Address::from_bytes(&addr.0), - 0, - ), - gateway: None, - dns_servers, - }); - - stack.set_config_v4(config); - }) + .run(&mut self.ppp_channel, C::PPP_CONFIG, on_ipv4_up) .await; info!("ppp failed: {:?}", res); @@ -309,27 +281,25 @@ impl<'a, C: CellularConfig<'a>, const INGRESS_BUF_SIZE: usize, const URC_CAPACIT self.ppp_channel.clear_hangup_detection(); // escape back to data mode. - self.ppp_channel.set_lines(0x44); + self.ppp_channel + .set_lines(embassy_at_cmux::Control::from_bits(0x44 << 1), None); Timer::after(Duration::from_millis(100)).await; - self.ppp_channel.set_lines(0x46); + self.ppp_channel + .set_lines(embassy_at_cmux::Control::from_bits(0x46 << 1), None); } }; - let ingress_fut = async { - self.ingress.read_from(&mut self.control_rx).await; - }; - - let mux_fut = async { - self.mux_runner.run(&mut rx, &mut tx).await; - }; + self.ingress.clear(); embassy_futures::select::select4( + self.mux_runner.run(&mut rx, &mut tx, CMUX_MAX_FRAME_SIZE), ppp_fut, - ingress_fut, + self.ingress.read_from(&mut self.control_rx), self.cellular_runner.run(), - mux_fut, ) .await; + + self.powered = false; } } } @@ -337,7 +307,7 @@ impl<'a, C: CellularConfig<'a>, const INGRESS_BUF_SIZE: usize, const URC_CAPACIT pub struct ReadWriteAdapter(pub R, pub W); impl embedded_io_async::ErrorType for ReadWriteAdapter { - type Error = embedded_io::ErrorKind; + type Error = ErrorKind; } impl Read for ReadWriteAdapter { diff --git a/src/asynch/resources.rs b/src/asynch/resources.rs index 5b2d7a8..3698c74 100644 --- a/src/asynch/resources.rs +++ b/src/asynch/resources.rs @@ -6,7 +6,7 @@ use embedded_io_async::Write; use crate::command::Urc; -use super::state; +use super::{runner::URC_SUBSCRIBERS, state}; pub struct UbxResources< W: Write, @@ -17,7 +17,7 @@ pub struct UbxResources< pub(crate) ch: state::State, pub(crate) res_slot: ResponseSlot, - pub(crate) urc_channel: UrcChannel, + pub(crate) urc_channel: UrcChannel, pub(crate) cmd_buf: [u8; CMD_BUF_SIZE], pub(crate) ingress_buf: [u8; INGRESS_BUF_SIZE], @@ -27,7 +27,8 @@ pub struct UbxResources< pub(crate) ppp_state: embassy_net_ppp::State<2, 2>, #[cfg(feature = "ppp")] - pub(crate) mux: embassy_at_cmux::Mux<2, 256>, + pub(crate) mux: + embassy_at_cmux::Mux<{ super::ppp::CMUX_CHANNELS }, { super::ppp::CMUX_CHANNEL_SIZE }>, } impl< diff --git a/src/asynch/runner.rs b/src/asynch/runner.rs index 1d979dc..df4f7d3 100644 --- a/src/asynch/runner.rs +++ b/src/asynch/runner.rs @@ -1,3 +1,5 @@ +use crate::command::control::types::Echo; +use crate::command::control::SetEcho; use crate::command::psn::GetGPRSAttached; use crate::command::psn::GetPDPContextState; use crate::command::psn::SetPDPContextState; @@ -34,6 +36,12 @@ use embassy_futures::select::Either; use super::AtHandle; +#[cfg(feature = "ppp")] +pub(crate) const URC_SUBSCRIBERS: usize = 2; + +#[cfg(feature = "internal-network-stack")] +pub(crate) const URC_SUBSCRIBERS: usize = 2; + /// Background runner for the Ublox Module. /// /// You must call `.run()` in a background task for the Ublox Module to operate. @@ -41,7 +49,7 @@ pub struct Runner<'d, AT: AtatClient, C: CellularConfig<'d>, const URC_CAPACITY: ch: state::Runner<'d>, at: AtHandle<'d, AT>, config: C, - urc_subscription: UrcSubscription<'d, Urc, URC_CAPACITY, 2>, + urc_subscription: UrcSubscription<'d, Urc, URC_CAPACITY, URC_SUBSCRIBERS>, } impl<'d, AT: AtatClient, C: CellularConfig<'d>, const URC_CAPACITY: usize> @@ -51,7 +59,7 @@ impl<'d, AT: AtatClient, C: CellularConfig<'d>, const URC_CAPACITY: usize> ch: state::Runner<'d>, at: AtHandle<'d, AT>, config: C, - urc_subscription: UrcSubscription<'d, Urc, URC_CAPACITY, 2>, + urc_subscription: UrcSubscription<'d, Urc, URC_CAPACITY, URC_SUBSCRIBERS>, ) -> Self { Self { ch, @@ -71,7 +79,6 @@ impl<'d, AT: AtatClient, C: CellularConfig<'d>, const URC_CAPACITY: usize> self.power_up().await?; }; self.reset().await?; - // self.is_alive().await?; Ok(()) } @@ -119,6 +126,13 @@ impl<'d, AT: AtatClient, C: CellularConfig<'d>, const URC_CAPACITY: usize> } } + pub async fn wait_for_desired_state( + &mut self, + ps: OperationState, + ) -> Result { + self.ch.state_runner().wait_for_desired_state(ps).await + } + pub async fn power_down(&mut self) -> Result<(), Error> { if self.has_power().await? { if let Some(pin) = self.config.power_pin() { @@ -127,6 +141,10 @@ impl<'d, AT: AtatClient, C: CellularConfig<'d>, const URC_CAPACITY: usize> pin.set_high().map_err(|_| Error::IoPin)?; self.ch.set_power_state(OperationState::PowerDown); debug!("Powered down"); + + // FIXME: Is this needed? + Timer::after(Duration::from_millis(1000)).await; + Ok(()) } else { warn!("No power pin configured"); @@ -137,103 +155,6 @@ impl<'d, AT: AtatClient, C: CellularConfig<'d>, const URC_CAPACITY: usize> } } - pub async fn init_at(&mut self) -> Result<(), Error> { - if !self.is_alive().await? { - return Err(Error::PoweredDown); - } - - // Extended errors on - self.at - .send(&SetReportMobileTerminationError { - n: TerminationErrorMode::Enabled, - }) - .await?; - - // Select SIM - self.at - .send(&SetGpioConfiguration { - gpio_id: 25, - gpio_mode: GpioMode::Output(GpioOutValue::High), - }) - .await?; - - #[cfg(any(feature = "lara-r6"))] - self.at - .send(&SetGpioConfiguration { - gpio_id: 42, - gpio_mode: GpioMode::Input(GpioInPull::NoPull), - }) - .await?; - - let _model_id = self.at.send(&GetModelId).await?; - - // self.at.send( - // &IdentificationInformation { - // n: 9 - // }, - // ).await?; - - self.at.send(&GetFirmwareVersion).await?; - - self.select_sim_card().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 { - value: Circuit109Behaviour::ChangesWithCarrier, - }) - .await?; - - // Ignore changes to DTR - self.at - .send(&SetCircuit108Behaviour { - value: Circuit108Behaviour::Ignore, - }) - .await?; - - // Switch off UART power saving until it is integrated into this API - self.at - .send(&SetPowerSavingControl { - mode: PowerSavingMode::Disabled, - timeout: None, - }) - .await?; - - #[cfg(feature = "internal-network-stack")] - if C::HEX_MODE { - self.at - .send(&crate::command::ip_transport_layer::SetHexMode { - hex_mode_disable: crate::command::ip_transport_layer::types::HexMode::Enabled, - }) - .await?; - } else { - self.at - .send(&crate::command::ip_transport_layer::SetHexMode { - hex_mode_disable: crate::command::ip_transport_layer::types::HexMode::Disabled, - }) - .await?; - } - - // Tell module whether we support flow control - // FIXME: Use AT+IFC=2,2 instead of AT&K here - if C::FLOW_CONTROL { - self.at - .send(&SetFlowControl { - value: FlowControl::RtsCts, - }) - .await?; - } else { - self.at - .send(&SetFlowControl { - value: FlowControl::Disabled, - }) - .await?; - } - Ok(()) - } /// Initializes the network only valid after `init_at`. /// /// # Errors @@ -331,42 +252,6 @@ impl<'d, AT: AtatClient, C: CellularConfig<'d>, const URC_CAPACITY: usize> 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(()); - } - _ => {} - } - - Timer::after(Duration::from_secs(1)).await; - } - - // There was an error initializing the SIM - // 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 { - fun: Functionality::Minimum, - // 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?; - self.at - .send(&SetModuleFunctionality { - fun: Functionality::Full, - rst: Some(ResetMode::DontReset), - }) - .await?; - - Ok(()) - } - /// Reset the module by driving it's `RESET_N` pin low for 50 ms /// /// **NOTE** This function will reset NVM settings! @@ -460,13 +345,10 @@ impl<'d, AT: AtatClient, C: CellularConfig<'d>, 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 => { + Some(false) | None => { self.ch.set_power_state(OperationState::PowerDown); } } @@ -493,7 +375,7 @@ impl<'d, AT: AtatClient, C: CellularConfig<'d>, const URC_CAPACITY: usize> } } - async fn change_state_to_desired_state( + pub async fn change_state_to_desired_state( &mut self, desired_state: OperationState, ) -> Result<(), Error> { @@ -527,26 +409,9 @@ impl<'d, AT: AtatClient, C: CellularConfig<'d>, const URC_CAPACITY: usize> return Err(err); } }, - 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); - return Err(Error::PoweredDown); - } - Err(err) => { - error!("Error in is_alive: {:?}", err); - return Err(Error::StateTimeout); - } - } - } Ok(OperationState::Initialized) => { #[cfg(not(feature = "ppp"))] - match self.init_at().await { + match init_at(&mut self.at, C::FLOW_CONTROL).await { Ok(_) => { self.ch.set_power_state(OperationState::Initialized); } @@ -585,7 +450,6 @@ impl<'d, AT: AtatClient, C: CellularConfig<'d>, const URC_CAPACITY: usize> return Err(err); } }, - #[cfg(not(feature = "ppp"))] Ok(OperationState::DataEstablished) => { match self.connect(C::APN, C::PROFILE_ID, C::CONTEXT_ID).await { Ok(_) => { @@ -631,7 +495,6 @@ impl<'d, AT: AtatClient, C: CellularConfig<'d>, const URC_CAPACITY: usize> } #[allow(unused_variables)] - #[cfg(not(feature = "ppp"))] async fn connect( &mut self, apn_info: crate::config::Apn<'_>, @@ -668,7 +531,7 @@ impl<'d, AT: AtatClient, C: CellularConfig<'d>, const URC_CAPACITY: usize> // Make sure we are attached to the cellular network. async fn is_network_attached(&mut self) -> Result { // Check for AT+CGATT to return 1 - let GPRSAttached { state } = self.at.send(&GetGPRSAttached).await.map_err(Error::from)?; + let GPRSAttached { state } = self.at.send(&GetGPRSAttached).await?; if state == GPRSAttachedState::Attached { return Ok(true); @@ -897,3 +760,142 @@ impl<'d, AT: AtatClient, C: CellularConfig<'d>, const URC_CAPACITY: usize> return Err(Error::ContextActivationTimeout); } } + +pub(crate) async fn init_at( + at_client: &mut A, + enable_flow_control: bool, +) -> Result<(), Error> { + // Allow auto bauding to kick in + embassy_time::with_timeout(boot_time() * 2, async { + loop { + if let Ok(alive) = at_client.send(&AT).await { + break alive; + } + Timer::after(Duration::from_millis(100)).await; + } + }) + .await + .map_err(|_| Error::PoweredDown)?; + + // Extended errors on + at_client + .send(&SetReportMobileTerminationError { + n: TerminationErrorMode::Enabled, + }) + .await?; + + // Echo off + at_client.send(&SetEcho { enabled: Echo::Off }).await?; + + // Select SIM + at_client + .send(&SetGpioConfiguration { + gpio_id: 25, + gpio_mode: GpioMode::Output(GpioOutValue::High), + }) + .await?; + + #[cfg(any(feature = "lara-r6"))] + at_client + .send(&SetGpioConfiguration { + gpio_id: 42, + gpio_mode: GpioMode::Input(GpioInPull::NoPull), + }) + .await?; + + let _model_id = at_client.send(&GetModelId).await?; + + // at_client.send( + // &IdentificationInformation { + // n: 9 + // }, + // ).await?; + + at_client.send(&GetFirmwareVersion).await?; + + select_sim_card(at_client).await?; + + let ccid = at_client.send(&GetCCID).await?; + info!("CCID: {}", ccid.ccid); + + // DCD circuit (109) changes in accordance with the carrier + at_client + .send(&SetCircuit109Behaviour { + value: Circuit109Behaviour::ChangesWithCarrier, + }) + .await?; + + // Ignore changes to DTR + at_client + .send(&SetCircuit108Behaviour { + value: Circuit108Behaviour::Ignore, + }) + .await?; + + // Switch off UART power saving until it is integrated into this API + at_client + .send(&SetPowerSavingControl { + mode: PowerSavingMode::Disabled, + timeout: None, + }) + .await?; + + #[cfg(feature = "internal-network-stack")] + if C::HEX_MODE { + at_client + .send(&crate::command::ip_transport_layer::SetHexMode { + hex_mode_disable: crate::command::ip_transport_layer::types::HexMode::Enabled, + }) + .await?; + } else { + at_client + .send(&crate::command::ip_transport_layer::SetHexMode { + hex_mode_disable: crate::command::ip_transport_layer::types::HexMode::Disabled, + }) + .await?; + } + + // Tell module whether we support flow control + if enable_flow_control { + at_client.send(&SetFlowControl).await?; + } else { + at_client.send(&SetFlowControl).await?; + } + Ok(()) +} + +pub(crate) async fn select_sim_card(at_client: &mut A) -> Result<(), Error> { + for _ in 0..2 { + match at_client.send(&GetPinStatus).await { + Ok(PinStatus { code }) if code == PinStatusCode::Ready => { + debug!("SIM is ready"); + return Ok(()); + } + _ => {} + } + + Timer::after(Duration::from_secs(1)).await; + } + + // There was an error initializing the SIM + // We've seen issues on uBlox-based devices, as a precation, we'll cycle + // the modem here through minimal/full functional state. + at_client + .send(&SetModuleFunctionality { + fun: Functionality::Minimum, + // 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?; + at_client + .send(&SetModuleFunctionality { + fun: Functionality::Full, + rst: Some(ResetMode::DontReset), + }) + .await?; + + Ok(()) +} diff --git a/src/asynch/state.rs b/src/asynch/state.rs index dd1995b..e02ecd6 100644 --- a/src/asynch/state.rs +++ b/src/asynch/state.rs @@ -23,15 +23,13 @@ pub enum LinkState { } /// If the celular modem is up and responding to AT. -#[derive(PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum OperationState { PowerDown = 0, PowerUp, - Alive, Initialized, Connected, - #[cfg(not(feature = "ppp"))] DataEstablished, } @@ -40,11 +38,9 @@ impl TryFrom for OperationState { match state { 0 => Ok(OperationState::PowerDown), 1 => Ok(OperationState::PowerUp), - 2 => Ok(OperationState::Alive), - 3 => Ok(OperationState::Initialized), - 4 => Ok(OperationState::Connected), - #[cfg(not(feature = "ppp"))] - 5 => Ok(OperationState::DataEstablished), + 2 => Ok(OperationState::Initialized), + 3 => Ok(OperationState::Connected), + 4 => Ok(OperationState::DataEstablished), _ => Err(()), } } diff --git a/src/asynch/ublox_stack/tcp.rs b/src/asynch/ublox_stack/tcp.rs index 52c9cc3..b01fff1 100644 --- a/src/asynch/ublox_stack/tcp.rs +++ b/src/asynch/ublox_stack/tcp.rs @@ -292,23 +292,22 @@ impl<'d> TcpIo<'d> { } } -// #[cfg(feature = "nightly")] mod embedded_io_impls { use super::*; - impl embedded_io::Error for ConnectError { - fn kind(&self) -> embedded_io::ErrorKind { - embedded_io::ErrorKind::Other + impl embedded_io_async::Error for ConnectError { + fn kind(&self) -> embedded_io_async::ErrorKind { + embedded_io_async::ErrorKind::Other } } - impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { - embedded_io::ErrorKind::Other + impl embedded_io_async::Error for Error { + fn kind(&self) -> embedded_io_async::ErrorKind { + embedded_io_async::ErrorKind::Other } } - impl<'d> embedded_io::ErrorType for TcpSocket<'d> { + impl<'d> embedded_io_async::ErrorType for TcpSocket<'d> { type Error = Error; } @@ -328,7 +327,7 @@ mod embedded_io_impls { } } - impl<'d> embedded_io::ErrorType for TcpReader<'d> { + impl<'d> embedded_io_async::ErrorType for TcpReader<'d> { type Error = Error; } @@ -338,7 +337,7 @@ mod embedded_io_impls { } } - impl<'d> embedded_io::ErrorType for TcpWriter<'d> { + impl<'d> embedded_io_async::ErrorType for TcpWriter<'d> { type Error = Error; } @@ -459,7 +458,7 @@ pub mod client { } } - impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_io::ErrorType + impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_io_async::ErrorType for TcpConnection<'d, N, TX_SZ, RX_SZ> { type Error = Error; diff --git a/src/command/control/mod.rs b/src/command/control/mod.rs index 6d75312..6a3bef9 100644 --- a/src/command/control/mod.rs +++ b/src/command/control/mod.rs @@ -2,13 +2,15 @@ //! These commands, unless specifically stated, do not implement set syntax using "=", read ("?"), or test ("=?"). //! If such commands are used, the "+CME ERROR: unknown" or "+CME ERROR: 100" error result code is provided //! (depending on the +CMEE AT command setting). -// pub mod responses; +pub mod responses; pub mod types; -use atat::atat_derive::AtatCmd; -use types::{BaudRate, Circuit108Behaviour, Circuit109Behaviour, FlowControl, SoftwareFlowControl}; - use super::NoResponse; +use atat::atat_derive::AtatCmd; +use responses::DataRate; +use types::{ + BaudRate, Circuit108Behaviour, Circuit109Behaviour, Echo, FlowControl, SoftwareFlowControl, +}; /// 15.2 Circuit 109 behavior &C /// @@ -44,11 +46,8 @@ pub struct SetCircuit108Behaviour { /// - HW flow control also referred with RTS / CTS flow control /// - SW flow control also referred with XON / XOFF flow control #[derive(Clone, AtatCmd)] -#[at_cmd("&K", NoResponse, value_sep = false)] -pub struct SetFlowControl { - #[at_arg(position = 0)] - pub value: FlowControl, -} +#[at_cmd("+IFC=2,2", NoResponse, value_sep = false)] +pub struct SetFlowControl; /// 15.8 Set flow control \Q /// @@ -81,6 +80,14 @@ pub struct SetDataRate { pub rate: BaudRate, } +/// 15.9 UART data rate configuration +IPR +/// +/// Specifies the data rate at which the DCE accepts commands on the UART +/// interface. The full range of data rates depends on HW or other criteria. +#[derive(Clone, AtatCmd)] +#[at_cmd("+IPR?", DataRate)] +pub struct GetDataRate; + /// 15.25 Set to factory defined configuration &F /// /// Resets the current profile to factory-programmed setting. Other NVM @@ -92,3 +99,18 @@ pub struct SetDataRate { #[derive(Clone, AtatCmd)] #[at_cmd("&F", NoResponse)] pub struct FactoryResetConfig; + +/// 15.25 Set to factory defined configuration &F +/// +/// Resets the current profile to factory-programmed setting. Other NVM +/// settings, not included in the profiles, are not affected. In case of +/// success, the response is issued using the configuration of the result codes +/// format (Q, V, S3, S4 AT commands) loaded from the factory-programmed +/// profile. The other DCE settings are applied after the response has been +/// sent. +#[derive(Clone, AtatCmd)] +#[at_cmd("E", NoResponse, value_sep = false)] +pub struct SetEcho { + #[at_arg(position = 0)] + pub enabled: Echo, +} diff --git a/src/command/control/responses.rs b/src/command/control/responses.rs new file mode 100644 index 0000000..0c16269 --- /dev/null +++ b/src/command/control/responses.rs @@ -0,0 +1,10 @@ +//! Responses for Control Commands +use super::types::BaudRate; +use atat::atat_derive::AtatResp; + +#[derive(Clone, Debug, PartialEq, Eq, AtatResp)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct DataRate { + #[at_arg(position = 0)] + pub rate: BaudRate, +} diff --git a/src/command/control/types.rs b/src/command/control/types.rs index a035b83..f3dc135 100644 --- a/src/command/control/types.rs +++ b/src/command/control/types.rs @@ -13,6 +13,14 @@ pub enum Circuit109Behaviour { ChangesWithCarrier = 1, } +#[derive(Clone, PartialEq, Eq, AtatEnum)] +pub enum Echo { + /// 0: Echo off + Off = 0, + /// 1 (default value and factory-programmed value): Echo on + On = 1, +} + /// Indicates the behavior of circuit 108 #[derive(Clone, PartialEq, Eq, AtatEnum)] pub enum Circuit108Behaviour { @@ -51,7 +59,8 @@ pub enum SoftwareFlowControl { Circuit105_106 = 3, } -#[derive(Clone, PartialEq, Eq, AtatEnum)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, AtatEnum)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[at_enum(u32)] pub enum BaudRate { #[cfg(any( @@ -100,6 +109,7 @@ pub enum BaudRate { feature = "sara-u2", feature = "toby-r2", feature = "lara-r2", + feature = "lara-r6", feature = "toby-l4", ))] B230400 = 230_400, @@ -111,6 +121,7 @@ pub enum BaudRate { feature = "sara-u2", feature = "toby-r2", feature = "lara-r2", + feature = "lara-r6", feature = "toby-l4", ))] B460800 = 460_800, @@ -122,10 +133,11 @@ pub enum BaudRate { feature = "sara-u2", feature = "toby-r2", feature = "lara-r2", + feature = "lara-r6", feature = "toby-l4", ))] B921600 = 921_600, - #[cfg(any(feature = "toby-r2", feature = "lara-r2",))] + #[cfg(any(feature = "toby-r2", feature = "lara-r2", feature = "lara-r6"))] B3000000 = 3_000_000, #[cfg(any(feature = "toby-r2", feature = "lara-r2",))] B3250000 = 3_250_000, diff --git a/src/config.rs b/src/config.rs index e6b8d0b..2e5f41c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -73,9 +73,6 @@ pub trait CellularConfig<'a> { type PowerPin: OutputPin; type VintPin: InputPin; - // const INGRESS_BUF_SIZE: usize; - // const URC_CAPACITY: usize; - const FLOW_CONTROL: bool = false; #[cfg(feature = "internal-network-stack")] @@ -84,7 +81,6 @@ pub trait CellularConfig<'a> { const OPERATOR_FORMAT: OperatorFormat = OperatorFormat::Long; const PROFILE_ID: ProfileId = ProfileId(1); - // #[cfg(not(feature = "upsd-context-activation"))] const CONTEXT_ID: ContextId = ContextId(1); const APN: Apn<'a> = Apn::None; @@ -92,9 +88,15 @@ pub trait CellularConfig<'a> { #[cfg(feature = "ppp")] const PPP_CONFIG: embassy_net_ppp::Config<'a>; - 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>; + fn reset_pin(&mut self) -> Option<&mut Self::ResetPin> { + None + } + fn power_pin(&mut self) -> Option<&mut Self::PowerPin> { + None + } + fn vint_pin(&mut self) -> Option<&mut Self::VintPin> { + None + } } #[repr(u8)]