From 5e654f03300e2e58981a489df398406e876c308d Mon Sep 17 00:00:00 2001 From: Mathias Koch Date: Thu, 15 Feb 2024 11:11:38 +0100 Subject: [PATCH] enhancement(example): rp2040 + lara-r6 example (#100) * add APNInfo to config as const * change apn settings to enum * update dependencies to new embassy release * can establish psd context and a dns request works * move statemachine out of main runner select loop * a bit of formatting * update to newest atat changes * Add RP2040 example --------- Co-authored-by: Tobias Breitwieser --- .../embassy-rp2040-example/.cargo/config.toml | 8 + examples/embassy-rp2040-example/.gitignore | 9 + examples/embassy-rp2040-example/Cargo.toml | 47 ++++ examples/embassy-rp2040-example/build.rs | 6 + examples/embassy-rp2040-example/memory.x | 5 + .../rust-toolchain.toml | 14 ++ examples/embassy-rp2040-example/src/main.rs | 237 ++++++++++++++++++ examples/embassy-stm32-example/.gitignore | 9 + 8 files changed, 335 insertions(+) create mode 100644 examples/embassy-rp2040-example/.cargo/config.toml create mode 100644 examples/embassy-rp2040-example/.gitignore create mode 100644 examples/embassy-rp2040-example/Cargo.toml create mode 100644 examples/embassy-rp2040-example/build.rs create mode 100644 examples/embassy-rp2040-example/memory.x create mode 100644 examples/embassy-rp2040-example/rust-toolchain.toml create mode 100644 examples/embassy-rp2040-example/src/main.rs create mode 100644 examples/embassy-stm32-example/.gitignore diff --git a/examples/embassy-rp2040-example/.cargo/config.toml b/examples/embassy-rp2040-example/.cargo/config.toml new file mode 100644 index 0000000..ffed95e --- /dev/null +++ b/examples/embassy-rp2040-example/.cargo/config.toml @@ -0,0 +1,8 @@ +[target.thumbv6m-none-eabi] +runner = 'probe-rs run --chip RP2040' + +[build] +target = "thumbv6m-none-eabi" + +[env] +DEFMT_LOG = "trace,embassy_hal_internal=error" diff --git a/examples/embassy-rp2040-example/.gitignore b/examples/embassy-rp2040-example/.gitignore new file mode 100644 index 0000000..092e4d3 --- /dev/null +++ b/examples/embassy-rp2040-example/.gitignore @@ -0,0 +1,9 @@ +**/*.rs.bk +.#* +.gdb_history +*.fifo +target/ +*.o +**/*secrets* + +.DS_Store diff --git a/examples/embassy-rp2040-example/Cargo.toml b/examples/embassy-rp2040-example/Cargo.toml new file mode 100644 index 0000000..2c3ca35 --- /dev/null +++ b/examples/embassy-rp2040-example/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "embassy-rp2040-example" +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"] } +embassy-time = { version = "0.3", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-sync = { version = "0.5", features = ["defmt"] } +portable-atomic = { version = "1.5.1", features = ["critical-section"] } + +cortex-m = { version = "0.7.7", features = ["inline-asm"] } +cortex-m-rt = "0.7.3" + +defmt = "0.3.5" +defmt-rtt = "0.4.0" +panic-probe = { version = "0.3.1", features = ["print-defmt"] } + +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", "async"]} + +[patch.crates-io] +ublox-sockets = { git = "https://github.com/BlackbirdHQ/ublox-sockets", branch = "feature/async-borrowed-sockets" } +atat = { git = "https://github.com/BlackbirdHQ/atat", branch = "master" } +no-std-net = { git = "https://github.com/rushmorem/no-std-net", branch = "issue-15" } +embassy-rp = { git = "https://github.com/embassy-rs/embassy", branch = "main" } +embassy-time = { git = "https://github.com/embassy-rs/embassy", branch = "main" } +embassy-sync = { git = "https://github.com/embassy-rs/embassy", branch = "main" } +embassy-futures = { git = "https://github.com/embassy-rs/embassy", branch = "main" } +embassy-executor = { git = "https://github.com/embassy-rs/embassy", branch = "main" } + +#embassy-time = { path = "../../../embassy/embassy-time" } +#embassy-sync = { path = "../../../embassy/embassy-sync" } +#embassy-futures = { path = "../../../embassy/embassy-futures" } +#embassy-executor = { path = "../../../embassy/embassy-executor" } + +#ublox-sockets = { path = "../../../ublox-sockets" } +#atat = { path = "../../../atat/atat" } + +[profile.dev] +opt-level = "s" + +[profile.release] +opt-level = "s" \ No newline at end of file diff --git a/examples/embassy-rp2040-example/build.rs b/examples/embassy-rp2040-example/build.rs new file mode 100644 index 0000000..673f12e --- /dev/null +++ b/examples/embassy-rp2040-example/build.rs @@ -0,0 +1,6 @@ +fn main() { + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tlink-rp.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/embassy-rp2040-example/memory.x b/examples/embassy-rp2040-example/memory.x new file mode 100644 index 0000000..eb8c173 --- /dev/null +++ b/examples/embassy-rp2040-example/memory.x @@ -0,0 +1,5 @@ +MEMORY { + BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 + FLASH : ORIGIN = 0x10000100, LENGTH = 1024K - 0x100 + RAM : ORIGIN = 0x20000000, LENGTH = 256K +} \ No newline at end of file diff --git a/examples/embassy-rp2040-example/rust-toolchain.toml b/examples/embassy-rp2040-example/rust-toolchain.toml new file mode 100644 index 0000000..25d771e --- /dev/null +++ b/examples/embassy-rp2040-example/rust-toolchain.toml @@ -0,0 +1,14 @@ +# Before upgrading check that everything is available on all tier1 targets here: +# https://rust-lang.github.io/rustup-components-history +[toolchain] +channel = "1.75" +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/main.rs b/examples/embassy-rp2040-example/src/main.rs new file mode 100644 index 0000000..dff7b3d --- /dev/null +++ b/examples/embassy-rp2040-example/src/main.rs @@ -0,0 +1,237 @@ +#![no_std] +#![no_main] +#![allow(stable_features)] + +use atat::asynch::Client; + +use atat::ResponseSlot; +use atat::UrcChannel; + +use cortex_m_rt::entry; +use defmt::*; +use embassy_executor::{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 {defmt_rtt as _, panic_probe as _}; + +use ublox_cellular::config::{Apn, CellularConfig}; + +use atat::{AtatIngress, DefaultDigester, Ingress}; +use ublox_cellular::asynch::runner::Runner; +use ublox_cellular::asynch::state::OperationState; +use ublox_cellular::asynch::State; +use ublox_cellular::command; +use ublox_cellular::command::Urc; + +bind_interrupts!(struct Irqs { + UART0_IRQ => BufferedInterruptHandler; +}); + +const INGRESS_BUF_SIZE: usize = 1024; +const URC_CAPACITY: usize = 2; +const URC_SUBSCRIBERS: 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::task] +async fn main_task(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(); + static INGRESS_BUF: StaticCell<[u8; INGRESS_BUF_SIZE]> = StaticCell::new(); + + let mut cell_uart_config = embassy_rp::uart::Config::default(); + cell_uart_config.baudrate = 115200; + + 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]), + cell_uart_config, + ); + + 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); + + let celullar_config = MyCelullarConfig { + reset_pin: Some(cell_nrst), + power_pin: Some(cell_pwr), + vint_pin: Some(cell_vint), + }; + + static RES_SLOT: ResponseSlot = ResponseSlot::new(); + static URC_CHANNEL: UrcChannel = UrcChannel::new(); + let ingress = Ingress::new( + DefaultDigester::::default(), + INGRESS_BUF.init([0; INGRESS_BUF_SIZE]), + &RES_SLOT, + &URC_CHANNEL, + ); + static BUF: StaticCell<[u8; INGRESS_BUF_SIZE]> = StaticCell::new(); + let client = Client::new( + uart_tx, + &RES_SLOT, + BUF.init([0; INGRESS_BUF_SIZE]), + atat::Config::default(), + ); + + spawner.spawn(ingress_task(ingress, uart_rx)).unwrap(); + + static STATE: StaticCell, INGRESS_BUF_SIZE>>> = + StaticCell::new(); + let (_device, mut control, runner) = ublox_cellular::asynch::new( + STATE.init(State::new(client)), + &URC_CHANNEL, + celullar_config, + ) + .await; + // defmt::info!("{:?}", runner.init().await); + // control.set_desired_state(PowerState::Connected).await; + // control + // .send(&crate::command::network_service::SetOperatorSelection { + // mode: crate::command::network_service::types::OperatorSelectionMode::Automatic, + // format: Some(0), + // }) + // .await; + + defmt::unwrap!(spawner.spawn(cellular_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 ingress_task( + mut ingress: Ingress< + 'static, + DefaultDigester, + ublox_cellular::command::Urc, + { INGRESS_BUF_SIZE }, + { URC_CAPACITY }, + { URC_SUBSCRIBERS }, + >, + mut reader: BufferedUartRx<'static, UART0>, +) -> ! { + ingress.read_from(&mut reader).await +} + +#[embassy_executor::task] +async fn cellular_task( + runner: Runner< + 'static, + atat::asynch::Client<'_, BufferedUartTx<'static, UART0>, { INGRESS_BUF_SIZE }>, + MyCelullarConfig, + { URC_CAPACITY }, + >, +) -> ! { + runner.run().await +} + +static EXECUTOR: StaticCell = StaticCell::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let executor = EXECUTOR.init(Executor::new()); + + executor.run(|spawner| { + unwrap!(spawner.spawn(main_task(spawner))); + }) +} diff --git a/examples/embassy-stm32-example/.gitignore b/examples/embassy-stm32-example/.gitignore new file mode 100644 index 0000000..092e4d3 --- /dev/null +++ b/examples/embassy-stm32-example/.gitignore @@ -0,0 +1,9 @@ +**/*.rs.bk +.#* +.gdb_history +*.fifo +target/ +*.o +**/*secrets* + +.DS_Store