Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Examples: Add support for overriding lorawan keys during build via LORA_APPKEY, LORA_DEVEUI.. values #232

Merged
merged 1 commit into from Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions examples/nrf52840/Cargo.toml
Expand Up @@ -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"]
69 changes: 66 additions & 3 deletions examples/nrf52840/build.rs
Expand Up @@ -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<Vec<u8>> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hex::encode?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I initially didn't want to include extra dependency for just a single semi-trivial function (left-pad 🗡️ )..

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<String> {
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()),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps implement DevEui/AppEui/AppKey::from_str? Feature-gated behind std being enabled in lorawan-encoding.

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()
Expand Down
2 changes: 1 addition & 1 deletion examples/nrf52840/src/bin/lora_cad.rs
Expand Up @@ -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 _};
Expand Down
21 changes: 16 additions & 5 deletions examples/nrf52840/src/bin/lora_lorawan.rs
Expand Up @@ -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;
Expand All @@ -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<peripherals::TWISPI1>;
RNG => rng::InterruptHandler<peripherals::RNG>;
Expand Down Expand Up @@ -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();
}
2 changes: 1 addition & 1 deletion examples/nrf52840/src/bin/lora_p2p_receive.rs
Expand Up @@ -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 _};
Expand Down
2 changes: 1 addition & 1 deletion examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs
Expand Up @@ -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 _};
Expand Down
2 changes: 1 addition & 1 deletion examples/nrf52840/src/bin/lora_p2p_send.rs
Expand Up @@ -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 _};
Expand Down