From 57c1c13021c33ea7f0a6daaaa13fee3d758e1fb5 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Thu, 21 Mar 2024 16:09:31 +0200 Subject: [PATCH] examples: nrf52840: Support customising LoRaWAN keys via ENV Add possibility to overriding LoRaWAN keys from env during compile. --- examples/nrf52840/Cargo.toml | 5 +- examples/nrf52840/build.rs | 69 ++++++++++++++++++- examples/nrf52840/src/bin/lora_cad.rs | 2 +- examples/nrf52840/src/bin/lora_lorawan.rs | 21 ++++-- examples/nrf52840/src/bin/lora_p2p_receive.rs | 2 +- .../src/bin/lora_p2p_receive_duty_cycle.rs | 2 +- examples/nrf52840/src/bin/lora_p2p_send.rs | 2 +- 7 files changed, 89 insertions(+), 14 deletions(-) diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index a5eb68ec..64ff7336 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -26,6 +26,7 @@ debug = 2 [features] default = [] - -## Customize target binary to make it runnable from RAM (ie via teleprobe) +## Customize target binary to make it runnable from RAM link-to-ram = [] +# Add teleprobe specific hooks to code +teleprobe = ["link-to-ram"] diff --git a/examples/nrf52840/build.rs b/examples/nrf52840/build.rs index 4091ce3f..62a8124c 100644 --- a/examples/nrf52840/build.rs +++ b/examples/nrf52840/build.rs @@ -10,14 +10,77 @@ use std::env; use std::fs::File; -use std::io::Write; +use std::io::{BufWriter, Write}; use std::path::PathBuf; +fn hex_to_bytes(s: &str) -> Option> { + if s.len() % 2 == 0 { + (0..s.len()) + .step_by(2) + .map(|i| s.get(i..i + 2).and_then(|sub| u8::from_str_radix(sub, 16).ok())) + .collect() + } else { + None + } +} + +/// Read and parse LoRaWAN keys as HEX strings from an environment variable +fn parse_lorawan_id(val: Option<&str>, var: &str, len: usize) -> Option { + if let Some(s) = val { + let l = s.len(); + // Allow empty keys + if l == 0 { + return None; + } + if l % 2 == 1 || l != 2 * len { + panic!( + "Environment variable {} has invalid length: {}, expecting: {}", + &var, + l, + 2 * len + ); + } + if let Some(v) = hex_to_bytes(s) { + return Some(format!("Some({:?})", v)); + } else { + panic!( + "Unable to parse {} from environment, make sure it's a valid hex string with length {}", + &var, + 2 * len + ); + } + } + None +} + fn main() { - // Put linker configuration in our output directory and ensure it's - // on the linker search path. let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + // Generate LoRaWAN eui and key overrides from environment variables + { + let path = &out.join("lorawan_keys.rs"); + let mut file = BufWriter::new(File::create(&path).unwrap()); + + // TODO: Figure out how to not generate this file every time... + write!( + &mut file, + "{}", + format_args!( + "\ + // Generated by build.rs\n\ + const DEVEUI: Option<[u8; 8]> = {};\n\ + const APPEUI: Option<[u8; 8]> = {};\n\ + const APPKEY: Option<[u8; 16]> = {};\n", + parse_lorawan_id(option_env!("LORA_DEVEUI"), "LORA_DEVEUI", 8).unwrap_or("None".to_string()), + parse_lorawan_id(option_env!("LORA_APPEUI"), "LORA_APPEUI", 8).unwrap_or("None".to_string()), + parse_lorawan_id(option_env!("LORA_APPKEY"), "LORA_APPKEY", 16).unwrap_or("None".to_string()), + ) + ) + .unwrap(); + } + + // Put linker configuration in our output directory and ensure it's + // on the linker search path. if cfg!(feature = "link-to-ram") { File::create(out.join("link_ram_cortex_m.x")) .unwrap() diff --git a/examples/nrf52840/src/bin/lora_cad.rs b/examples/nrf52840/src/bin/lora_cad.rs index 5a601308..51a5d051 100644 --- a/examples/nrf52840/src/bin/lora_cad.rs +++ b/examples/nrf52840/src/bin/lora_cad.rs @@ -11,7 +11,7 @@ use embassy_nrf::{bind_interrupts, peripherals, spim}; use embassy_time::{Delay, Timer}; use embedded_hal_bus::spi::ExclusiveDevice; use lora_phy::iv::GenericSx126xInterfaceVariant; -use lora_phy::sx126x::{Sx126xVariant, TcxoCtrlVoltage, Sx126x}; +use lora_phy::sx126x::{Sx126x, Sx126xVariant, TcxoCtrlVoltage}; use lora_phy::LoRa; use lora_phy::{mod_params::*, sx126x}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/nrf52840/src/bin/lora_lorawan.rs b/examples/nrf52840/src/bin/lora_lorawan.rs index f32861f6..900e8070 100644 --- a/examples/nrf52840/src/bin/lora_lorawan.rs +++ b/examples/nrf52840/src/bin/lora_lorawan.rs @@ -13,7 +13,7 @@ use embassy_time::Delay; use embedded_hal_bus::spi::ExclusiveDevice; use lora_phy::iv::GenericSx126xInterfaceVariant; use lora_phy::lorawan_radio::LorawanRadio; -use lora_phy::sx126x::{self, Sx126xVariant, TcxoCtrlVoltage, Sx126x}; +use lora_phy::sx126x::{self, Sx126x, Sx126xVariant, TcxoCtrlVoltage}; use lora_phy::LoRa; use lorawan_device::async_device::{region, Device, EmbassyTimer, JoinMode}; use lorawan_device::default_crypto::DefaultFactory as Crypto; @@ -24,6 +24,15 @@ use {defmt_rtt as _, panic_probe as _}; const LORAWAN_REGION: region::Region = region::Region::EU868; const MAX_TX_POWER: u8 = 14; +// Load optional override values for EUIs and APPKEY generated by build.rs from +// environment values +include!(concat!(env!("OUT_DIR"), "/lorawan_keys.rs")); + +// Fallback values +const DEFAULT_DEVEUI: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0]; +const DEFAULT_APPEUI: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0]; +const DEFAULT_APPKEY: [u8; 16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + bind_interrupts!(struct Irqs { SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler; RNG => rng::InterruptHandler; @@ -60,15 +69,17 @@ async fn main(_spawner: Spawner) { defmt::info!("Joining LoRaWAN network"); - // TODO: Adjust the EUI and Keys according to your network credentials let resp = device .join(&JoinMode::OTAA { - deveui: DevEui::from([0, 0, 0, 0, 0, 0, 0, 0]), - appeui: AppEui::from([0, 0, 0, 0, 0, 0, 0, 0]), - appkey: AppKey::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + deveui: DevEui::from(DEVEUI.unwrap_or(DEFAULT_DEVEUI)), + appeui: AppEui::from(APPEUI.unwrap_or(DEFAULT_APPEUI)), + appkey: AppKey::from(APPKEY.unwrap_or(DEFAULT_APPKEY)), }) .await .unwrap(); info!("LoRaWAN network joined: {:?}", resp); + + #[cfg(feature = "teleprobe")] + cortex_m::asm::bkpt(); } diff --git a/examples/nrf52840/src/bin/lora_p2p_receive.rs b/examples/nrf52840/src/bin/lora_p2p_receive.rs index 6b1313af..b380d68c 100644 --- a/examples/nrf52840/src/bin/lora_p2p_receive.rs +++ b/examples/nrf52840/src/bin/lora_p2p_receive.rs @@ -11,7 +11,7 @@ use embassy_nrf::{bind_interrupts, peripherals, spim}; use embassy_time::{Delay, Timer}; use embedded_hal_bus::spi::ExclusiveDevice; use lora_phy::iv::GenericSx126xInterfaceVariant; -use lora_phy::sx126x::{Sx126xVariant, TcxoCtrlVoltage, Sx126x}; +use lora_phy::sx126x::{Sx126x, Sx126xVariant, TcxoCtrlVoltage}; use lora_phy::{mod_params::*, sx126x}; use lora_phy::{LoRa, RxMode}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs b/examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs index be79f6b1..385b3486 100644 --- a/examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs +++ b/examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs @@ -11,7 +11,7 @@ use embassy_nrf::{bind_interrupts, peripherals, spim}; use embassy_time::{Delay, Timer}; use embedded_hal_bus::spi::ExclusiveDevice; use lora_phy::iv::GenericSx126xInterfaceVariant; -use lora_phy::sx126x::{Sx126xVariant, TcxoCtrlVoltage, Sx126x}; +use lora_phy::sx126x::{Sx126x, Sx126xVariant, TcxoCtrlVoltage}; use lora_phy::{mod_params::*, sx126x}; use lora_phy::{LoRa, RxMode}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/nrf52840/src/bin/lora_p2p_send.rs b/examples/nrf52840/src/bin/lora_p2p_send.rs index 9d65c362..ae87ab56 100644 --- a/examples/nrf52840/src/bin/lora_p2p_send.rs +++ b/examples/nrf52840/src/bin/lora_p2p_send.rs @@ -11,7 +11,7 @@ use embassy_nrf::{bind_interrupts, peripherals, spim}; use embassy_time::Delay; use embedded_hal_bus::spi::ExclusiveDevice; use lora_phy::iv::GenericSx126xInterfaceVariant; -use lora_phy::sx126x::{Sx126xVariant, TcxoCtrlVoltage, Sx126x}; +use lora_phy::sx126x::{Sx126x, Sx126xVariant, TcxoCtrlVoltage}; use lora_phy::LoRa; use lora_phy::{mod_params::*, sx126x}; use {defmt_rtt as _, panic_probe as _};