From 02c86bca5275328a15376176ff44487ab7655866 Mon Sep 17 00:00:00 2001 From: ceekdee Date: Fri, 21 Apr 2023 01:20:46 -0500 Subject: Add external LoRa physical layer functionality. --- examples/nrf52840/src/bin/lora_cad.rs | 92 +++++++++++++++ .../src/bin/lora_p2p_receive_duty_cycle.rs | 124 +++++++++++++++++++++ examples/nrf52840/src/bin/lora_p2p_report.rs | 81 -------------- 3 files changed, 216 insertions(+), 81 deletions(-) create mode 100644 examples/nrf52840/src/bin/lora_cad.rs create mode 100644 examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs delete mode 100644 examples/nrf52840/src/bin/lora_p2p_report.rs (limited to 'examples/nrf52840/src') diff --git a/examples/nrf52840/src/bin/lora_cad.rs b/examples/nrf52840/src/bin/lora_cad.rs new file mode 100644 index 000000000..8899c1b23 --- /dev/null +++ b/examples/nrf52840/src/bin/lora_cad.rs @@ -0,0 +1,92 @@ +//! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio. +//! Other nrf/sx126x combinations may work with appropriate pin modifications. +//! It demonstates LORA CAD functionality. +#![no_std] +#![no_main] +#![macro_use] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_lora::iv::GenericSx126xInterfaceVariant; +use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull}; +use embassy_nrf::{bind_interrupts, peripherals, spim}; +use embassy_time::{Delay, Duration, Timer}; +use lora_phy::mod_params::*; +use lora_phy::sx1261_2::SX1261_2; +use lora_phy::LoRa; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + let mut spi_config = spim::Config::default(); + spi_config.frequency = spim::Frequency::M16; + + let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config); + + let nss = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard); + let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard); + let dio1 = Input::new(p.P1_15.degrade(), Pull::Down); + let busy = Input::new(p.P1_14.degrade(), Pull::Down); + let rf_switch_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard); + let rf_switch_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard); + + let iv = + GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap(); + + let mut delay = Delay; + + let mut lora = { + match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, &mut delay).await { + Ok(l) => l, + Err(err) => { + info!("Radio error = {}", err); + return; + } + } + }; + + let mut debug_indicator = Output::new(p.P1_03, Level::Low, OutputDrive::Standard); + let mut start_indicator = Output::new(p.P1_04, Level::Low, OutputDrive::Standard); + + start_indicator.set_high(); + Timer::after(Duration::from_secs(5)).await; + start_indicator.set_low(); + + let mdltn_params = { + match lora.create_modulation_params(SpreadingFactor::_10, Bandwidth::_250KHz, CodingRate::_4_8, 903900000) { + Ok(mp) => mp, + Err(err) => { + info!("Radio error = {}", err); + return; + } + } + }; + + match lora.prepare_for_cad(&mdltn_params, true).await { + Ok(()) => {} + Err(err) => { + info!("Radio error = {}", err); + return; + } + }; + + match lora.cad().await { + Ok(cad_activity_detected) => { + if cad_activity_detected { + info!("cad successful with activity detected") + } else { + info!("cad successful without activity detected") + } + debug_indicator.set_high(); + Timer::after(Duration::from_secs(15)).await; + debug_indicator.set_low(); + } + Err(err) => info!("cad unsuccessful = {}", err), + } +} diff --git a/examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs b/examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs new file mode 100644 index 000000000..d84701742 --- /dev/null +++ b/examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs @@ -0,0 +1,124 @@ +//! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio. +//! Other nrf/sx126x combinations may work with appropriate pin modifications. +//! It demonstates LoRa Rx duty cycle functionality. +#![no_std] +#![no_main] +#![macro_use] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_lora::iv::GenericSx126xInterfaceVariant; +use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull}; +use embassy_nrf::{bind_interrupts, peripherals, spim}; +use embassy_time::{Delay, Duration, Timer}; +use lora_phy::mod_params::*; +use lora_phy::sx1261_2::SX1261_2; +use lora_phy::LoRa; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + let mut spi_config = spim::Config::default(); + spi_config.frequency = spim::Frequency::M16; + + let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config); + + let nss = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard); + let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard); + let dio1 = Input::new(p.P1_15.degrade(), Pull::Down); + let busy = Input::new(p.P1_14.degrade(), Pull::Down); + let rf_switch_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard); + let rf_switch_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard); + + let iv = + GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap(); + + let mut delay = Delay; + + let mut lora = { + match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, &mut delay).await { + Ok(l) => l, + Err(err) => { + info!("Radio error = {}", err); + return; + } + } + }; + + let mut debug_indicator = Output::new(p.P1_03, Level::Low, OutputDrive::Standard); + let mut start_indicator = Output::new(p.P1_04, Level::Low, OutputDrive::Standard); + + start_indicator.set_high(); + Timer::after(Duration::from_secs(5)).await; + start_indicator.set_low(); + + let mut receiving_buffer = [00u8; 100]; + + let mdltn_params = { + match lora.create_modulation_params(SpreadingFactor::_10, Bandwidth::_250KHz, CodingRate::_4_8, 903900000) { + Ok(mp) => mp, + Err(err) => { + info!("Radio error = {}", err); + return; + } + } + }; + + let rx_pkt_params = { + match lora.create_rx_packet_params(4, false, receiving_buffer.len() as u8, true, false, &mdltn_params) { + Ok(pp) => pp, + Err(err) => { + info!("Radio error = {}", err); + return; + } + } + }; + + // See "RM0453 Reference manual STM32WL5x advanced ArmĀ®-based 32-bit MCUs with sub-GHz radio solution" for the best explanation of Rx duty cycle processing. + match lora + .prepare_for_rx( + &mdltn_params, + &rx_pkt_params, + Some(&DutyCycleParams { + rx_time: 300_000, // 300_000 units * 15.625 us/unit = 4.69 s + sleep_time: 200_000, // 200_000 units * 15.625 us/unit = 3.13 s + }), + false, + false, + 0, + 0, + ) + .await + { + Ok(()) => {} + Err(err) => { + info!("Radio error = {}", err); + return; + } + }; + + receiving_buffer = [00u8; 100]; + match lora.rx(&rx_pkt_params, &mut receiving_buffer).await { + Ok((received_len, _rx_pkt_status)) => { + if (received_len == 3) + && (receiving_buffer[0] == 0x01u8) + && (receiving_buffer[1] == 0x02u8) + && (receiving_buffer[2] == 0x03u8) + { + info!("rx successful"); + debug_indicator.set_high(); + Timer::after(Duration::from_secs(5)).await; + debug_indicator.set_low(); + } else { + info!("rx unknown packet") + } + } + Err(err) => info!("rx unsuccessful = {}", err), + } +} diff --git a/examples/nrf52840/src/bin/lora_p2p_report.rs b/examples/nrf52840/src/bin/lora_p2p_report.rs deleted file mode 100644 index e24f0db03..000000000 --- a/examples/nrf52840/src/bin/lora_p2p_report.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio. -//! Other nrf/sx126x combinations may work with appropriate pin modifications. -//! It demonstates LORA P2P functionality in conjunction with example lora_p2p_sense.rs. -#![no_std] -#![no_main] -#![macro_use] -#![allow(dead_code)] -#![feature(type_alias_impl_trait)] - -use defmt::*; -use embassy_executor::Spawner; -use embassy_lora::sx126x::*; -use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull}; -use embassy_nrf::{bind_interrupts, peripherals, spim}; -use embassy_time::{Duration, Timer}; -use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor}; -use {defmt_rtt as _, panic_probe as _}; - -bind_interrupts!(struct Irqs { - SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler; -}); - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = embassy_nrf::init(Default::default()); - let mut spi_config = spim::Config::default(); - spi_config.frequency = spim::Frequency::M16; - - let mut radio = { - let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config); - - let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard); - let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard); - let dio1 = Input::new(p.P1_15.degrade(), Pull::Down); - let busy = Input::new(p.P1_14.degrade(), Pull::Down); - let antenna_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard); - let antenna_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard); - - match Sx126xRadio::new(spim, cs, reset, antenna_rx, antenna_tx, dio1, busy, false).await { - Ok(r) => r, - Err(err) => { - info!("Sx126xRadio error = {}", err); - return; - } - } - }; - - let mut debug_indicator = Output::new(p.P1_03, Level::Low, OutputDrive::Standard); - let mut start_indicator = Output::new(p.P1_04, Level::Low, OutputDrive::Standard); - - start_indicator.set_high(); - Timer::after(Duration::from_secs(5)).await; - start_indicator.set_low(); - - loop { - let rf_config = RfConfig { - frequency: 903900000, // channel in Hz - bandwidth: Bandwidth::_250KHz, - spreading_factor: SpreadingFactor::_10, - coding_rate: CodingRate::_4_8, - }; - - let mut buffer = [00u8; 100]; - - // P2P receive - match radio.rx(rf_config, &mut buffer).await { - Ok((buffer_len, rx_quality)) => info!( - "RX received = {:?} with length = {} rssi = {} snr = {}", - &buffer[0..buffer_len], - buffer_len, - rx_quality.rssi(), - rx_quality.snr() - ), - Err(err) => info!("RX error = {}", err), - } - - debug_indicator.set_high(); - Timer::after(Duration::from_secs(2)).await; - debug_indicator.set_low(); - } -} -- cgit From 73f25093c7793ad2e8bd6fceeca46d9b5b1031ad Mon Sep 17 00:00:00 2001 From: ceekdee Date: Sun, 23 Apr 2023 18:32:34 -0500 Subject: Add lora-phy examples. --- examples/nrf52840/src/bin/lora_cad.rs | 13 ++- examples/nrf52840/src/bin/lora_lorawan.rs | 83 +++++++++++++ examples/nrf52840/src/bin/lora_p2p_receive.rs | 121 +++++++++++++++++++ .../src/bin/lora_p2p_receive_duty_cycle.rs | 11 +- examples/nrf52840/src/bin/lora_p2p_send.rs | 104 +++++++++++++++++ examples/nrf52840/src/bin/lora_p2p_sense.rs | 128 --------------------- 6 files changed, 327 insertions(+), 133 deletions(-) create mode 100644 examples/nrf52840/src/bin/lora_lorawan.rs create mode 100644 examples/nrf52840/src/bin/lora_p2p_receive.rs create mode 100644 examples/nrf52840/src/bin/lora_p2p_send.rs delete mode 100644 examples/nrf52840/src/bin/lora_p2p_sense.rs (limited to 'examples/nrf52840/src') diff --git a/examples/nrf52840/src/bin/lora_cad.rs b/examples/nrf52840/src/bin/lora_cad.rs index 8899c1b23..beca061ed 100644 --- a/examples/nrf52840/src/bin/lora_cad.rs +++ b/examples/nrf52840/src/bin/lora_cad.rs @@ -1,6 +1,6 @@ //! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio. //! Other nrf/sx126x combinations may work with appropriate pin modifications. -//! It demonstates LORA CAD functionality. +//! It demonstrates LORA CAD functionality. #![no_std] #![no_main] #![macro_use] @@ -17,6 +17,8 @@ use lora_phy::sx1261_2::SX1261_2; use lora_phy::LoRa; use {defmt_rtt as _, panic_probe as _}; +const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region + bind_interrupts!(struct Irqs { SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler; }); @@ -59,7 +61,12 @@ async fn main(_spawner: Spawner) { start_indicator.set_low(); let mdltn_params = { - match lora.create_modulation_params(SpreadingFactor::_10, Bandwidth::_250KHz, CodingRate::_4_8, 903900000) { + match lora.create_modulation_params( + SpreadingFactor::_10, + Bandwidth::_250KHz, + CodingRate::_4_8, + LORA_FREQUENCY_IN_HZ, + ) { Ok(mp) => mp, Err(err) => { info!("Radio error = {}", err); @@ -84,7 +91,7 @@ async fn main(_spawner: Spawner) { info!("cad successful without activity detected") } debug_indicator.set_high(); - Timer::after(Duration::from_secs(15)).await; + Timer::after(Duration::from_secs(5)).await; debug_indicator.set_low(); } Err(err) => info!("cad unsuccessful = {}", err), diff --git a/examples/nrf52840/src/bin/lora_lorawan.rs b/examples/nrf52840/src/bin/lora_lorawan.rs new file mode 100644 index 000000000..c953680c6 --- /dev/null +++ b/examples/nrf52840/src/bin/lora_lorawan.rs @@ -0,0 +1,83 @@ +//! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio. +//! Other nrf/sx126x combinations may work with appropriate pin modifications. +//! It demonstrates LoRaWAN join functionality. +#![no_std] +#![no_main] +#![macro_use] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_lora::iv::GenericSx126xInterfaceVariant; +use embassy_lora::LoraTimer; +use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull}; +use embassy_nrf::rng::Rng; +use embassy_nrf::{bind_interrupts, peripherals, rng, spim}; +use embassy_time::Delay; +use lora_phy::mod_params::*; +use lora_phy::sx1261_2::SX1261_2; +use lora_phy::LoRa; +use lorawan::default_crypto::DefaultFactory as Crypto; +use lorawan_device::async_device::lora_radio::LoRaRadio; +use lorawan_device::async_device::{region, Device, JoinMode}; +use {defmt_rtt as _, panic_probe as _}; + +const LORAWAN_REGION: region::Region = region::Region::EU868; // warning: set this appropriately for the region + +bind_interrupts!(struct Irqs { + SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler; + RNG => rng::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + let mut spi_config = spim::Config::default(); + spi_config.frequency = spim::Frequency::M16; + + let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config); + + let nss = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard); + let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard); + let dio1 = Input::new(p.P1_15.degrade(), Pull::Down); + let busy = Input::new(p.P1_14.degrade(), Pull::Down); + let rf_switch_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard); + let rf_switch_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard); + + let iv = + GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap(); + + let mut delay = Delay; + + let lora = { + match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), true, &mut delay).await { + Ok(l) => l, + Err(err) => { + info!("Radio error = {}", err); + return; + } + } + }; + + let radio = LoRaRadio::new(lora); + let region: region::Configuration = region::Configuration::new(LORAWAN_REGION); + let mut device: Device<_, Crypto, _, _> = Device::new(region, radio, LoraTimer::new(), Rng::new(p.RNG, Irqs)); + + defmt::info!("Joining LoRaWAN network"); + + // TODO: Adjust the EUI and Keys according to your network credentials + match device + .join(&JoinMode::OTAA { + deveui: [0, 0, 0, 0, 0, 0, 0, 0], + appeui: [0, 0, 0, 0, 0, 0, 0, 0], + appkey: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + }) + .await + { + Ok(()) => defmt::info!("LoRaWAN network joined"), + Err(err) => { + info!("Radio error = {}", err); + return; + } + }; +} diff --git a/examples/nrf52840/src/bin/lora_p2p_receive.rs b/examples/nrf52840/src/bin/lora_p2p_receive.rs new file mode 100644 index 000000000..563fe42ec --- /dev/null +++ b/examples/nrf52840/src/bin/lora_p2p_receive.rs @@ -0,0 +1,121 @@ +//! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio. +//! Other nrf/sx126x combinations may work with appropriate pin modifications. +//! It demonstrates LORA P2P receive functionality in conjunction with the lora_p2p_send example. +#![no_std] +#![no_main] +#![macro_use] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_lora::iv::GenericSx126xInterfaceVariant; +use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull}; +use embassy_nrf::{bind_interrupts, peripherals, spim}; +use embassy_time::{Delay, Duration, Timer}; +use lora_phy::mod_params::*; +use lora_phy::sx1261_2::SX1261_2; +use lora_phy::LoRa; +use {defmt_rtt as _, panic_probe as _}; + +const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region + +bind_interrupts!(struct Irqs { + SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + let mut spi_config = spim::Config::default(); + spi_config.frequency = spim::Frequency::M16; + + let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config); + + let nss = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard); + let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard); + let dio1 = Input::new(p.P1_15.degrade(), Pull::Down); + let busy = Input::new(p.P1_14.degrade(), Pull::Down); + let rf_switch_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard); + let rf_switch_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard); + + let iv = + GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap(); + + let mut delay = Delay; + + let mut lora = { + match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, &mut delay).await { + Ok(l) => l, + Err(err) => { + info!("Radio error = {}", err); + return; + } + } + }; + + let mut debug_indicator = Output::new(p.P1_03, Level::Low, OutputDrive::Standard); + let mut start_indicator = Output::new(p.P1_04, Level::Low, OutputDrive::Standard); + + start_indicator.set_high(); + Timer::after(Duration::from_secs(5)).await; + start_indicator.set_low(); + + let mut receiving_buffer = [00u8; 100]; + + let mdltn_params = { + match lora.create_modulation_params( + SpreadingFactor::_10, + Bandwidth::_250KHz, + CodingRate::_4_8, + LORA_FREQUENCY_IN_HZ, + ) { + Ok(mp) => mp, + Err(err) => { + info!("Radio error = {}", err); + return; + } + } + }; + + let rx_pkt_params = { + match lora.create_rx_packet_params(4, false, receiving_buffer.len() as u8, true, false, &mdltn_params) { + Ok(pp) => pp, + Err(err) => { + info!("Radio error = {}", err); + return; + } + } + }; + + match lora + .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, true, false, 0, 0x00ffffffu32) + .await + { + Ok(()) => {} + Err(err) => { + info!("Radio error = {}", err); + return; + } + }; + + loop { + receiving_buffer = [00u8; 100]; + match lora.rx(&rx_pkt_params, &mut receiving_buffer).await { + Ok((received_len, _rx_pkt_status)) => { + if (received_len == 3) + && (receiving_buffer[0] == 0x01u8) + && (receiving_buffer[1] == 0x02u8) + && (receiving_buffer[2] == 0x03u8) + { + info!("rx successful"); + debug_indicator.set_high(); + Timer::after(Duration::from_secs(5)).await; + debug_indicator.set_low(); + } else { + info!("rx unknown packet"); + } + } + Err(err) => info!("rx unsuccessful = {}", err), + } + } +} 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 d84701742..1fd8f61a2 100644 --- a/examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs +++ b/examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs @@ -1,6 +1,6 @@ //! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio. //! Other nrf/sx126x combinations may work with appropriate pin modifications. -//! It demonstates LoRa Rx duty cycle functionality. +//! It demonstrates LoRa Rx duty cycle functionality in conjunction with the lora_p2p_send example. #![no_std] #![no_main] #![macro_use] @@ -17,6 +17,8 @@ use lora_phy::sx1261_2::SX1261_2; use lora_phy::LoRa; use {defmt_rtt as _, panic_probe as _}; +const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region + bind_interrupts!(struct Irqs { SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler; }); @@ -61,7 +63,12 @@ async fn main(_spawner: Spawner) { let mut receiving_buffer = [00u8; 100]; let mdltn_params = { - match lora.create_modulation_params(SpreadingFactor::_10, Bandwidth::_250KHz, CodingRate::_4_8, 903900000) { + match lora.create_modulation_params( + SpreadingFactor::_10, + Bandwidth::_250KHz, + CodingRate::_4_8, + LORA_FREQUENCY_IN_HZ, + ) { Ok(mp) => mp, Err(err) => { info!("Radio error = {}", err); diff --git a/examples/nrf52840/src/bin/lora_p2p_send.rs b/examples/nrf52840/src/bin/lora_p2p_send.rs new file mode 100644 index 000000000..1c8bbc27a --- /dev/null +++ b/examples/nrf52840/src/bin/lora_p2p_send.rs @@ -0,0 +1,104 @@ +//! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio. +//! Other nrf/sx126x combinations may work with appropriate pin modifications. +//! It demonstrates LORA P2P send functionality. +#![no_std] +#![no_main] +#![macro_use] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_lora::iv::GenericSx126xInterfaceVariant; +use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull}; +use embassy_nrf::{bind_interrupts, peripherals, spim}; +use embassy_time::Delay; +use lora_phy::mod_params::*; +use lora_phy::sx1261_2::SX1261_2; +use lora_phy::LoRa; +use {defmt_rtt as _, panic_probe as _}; + +const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region + +bind_interrupts!(struct Irqs { + SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + let mut spi_config = spim::Config::default(); + spi_config.frequency = spim::Frequency::M16; + + let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config); + + let nss = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard); + let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard); + let dio1 = Input::new(p.P1_15.degrade(), Pull::Down); + let busy = Input::new(p.P1_14.degrade(), Pull::Down); + let rf_switch_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard); + let rf_switch_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard); + + let iv = + GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap(); + + let mut delay = Delay; + + let mut lora = { + match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, &mut delay).await { + Ok(l) => l, + Err(err) => { + info!("Radio error = {}", err); + return; + } + } + }; + + let mdltn_params = { + match lora.create_modulation_params( + SpreadingFactor::_10, + Bandwidth::_250KHz, + CodingRate::_4_8, + LORA_FREQUENCY_IN_HZ, + ) { + Ok(mp) => mp, + Err(err) => { + info!("Radio error = {}", err); + return; + } + } + }; + + let mut tx_pkt_params = { + match lora.create_tx_packet_params(4, false, true, false, &mdltn_params) { + Ok(pp) => pp, + Err(err) => { + info!("Radio error = {}", err); + return; + } + } + }; + + match lora.prepare_for_tx(&mdltn_params, 20, false).await { + Ok(()) => {} + Err(err) => { + info!("Radio error = {}", err); + return; + } + }; + + let buffer = [0x01u8, 0x02u8, 0x03u8]; + match lora.tx(&mdltn_params, &mut tx_pkt_params, &buffer, 0xffffff).await { + Ok(()) => { + info!("TX DONE"); + } + Err(err) => { + info!("Radio error = {}", err); + return; + } + }; + + match lora.sleep(&mut delay).await { + Ok(()) => info!("Sleep successful"), + Err(err) => info!("Sleep unsuccessful = {}", err), + } +} diff --git a/examples/nrf52840/src/bin/lora_p2p_sense.rs b/examples/nrf52840/src/bin/lora_p2p_sense.rs deleted file mode 100644 index b6f41ffcc..000000000 --- a/examples/nrf52840/src/bin/lora_p2p_sense.rs +++ /dev/null @@ -1,128 +0,0 @@ -//! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio. -//! Other nrf/sx126x combinations may work with appropriate pin modifications. -//! It demonstates LORA P2P functionality in conjunction with example lora_p2p_report.rs. -#![no_std] -#![no_main] -#![macro_use] -#![feature(type_alias_impl_trait)] -#![feature(alloc_error_handler)] -#![allow(incomplete_features)] - -use defmt::*; -use embassy_executor::Spawner; -use embassy_lora::sx126x::*; -use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull}; -use embassy_nrf::{bind_interrupts, peripherals, spim}; -use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use embassy_sync::pubsub::{PubSubChannel, Publisher}; -use embassy_time::{Duration, Timer}; -use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor, TxConfig}; -use {defmt_rtt as _, panic_probe as _, panic_probe as _}; - -bind_interrupts!(struct Irqs { - SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler; -}); - -// Message bus: queue of 2, 1 subscriber (Lora P2P), 2 publishers (temperature, motion detection) -static MESSAGE_BUS: PubSubChannel = PubSubChannel::new(); - -#[derive(Clone, defmt::Format)] -enum Message { - Temperature(i32), - MotionDetected, -} - -#[embassy_executor::task] -async fn temperature_task(publisher: Publisher<'static, CriticalSectionRawMutex, Message, 2, 1, 2>) { - // Publish a fake temperature every 43 seconds, minimizing LORA traffic. - loop { - Timer::after(Duration::from_secs(43)).await; - publisher.publish(Message::Temperature(9)).await; - } -} - -#[embassy_executor::task] -async fn motion_detection_task(publisher: Publisher<'static, CriticalSectionRawMutex, Message, 2, 1, 2>) { - // Publish a fake motion detection every 79 seconds, minimizing LORA traffic. - loop { - Timer::after(Duration::from_secs(79)).await; - publisher.publish(Message::MotionDetected).await; - } -} - -#[embassy_executor::main] -async fn main(spawner: Spawner) { - let p = embassy_nrf::init(Default::default()); - // set up to funnel temperature and motion detection events to the Lora Tx task - let mut lora_tx_subscriber = unwrap!(MESSAGE_BUS.subscriber()); - let temperature_publisher = unwrap!(MESSAGE_BUS.publisher()); - let motion_detection_publisher = unwrap!(MESSAGE_BUS.publisher()); - - let mut spi_config = spim::Config::default(); - spi_config.frequency = spim::Frequency::M16; - - let mut radio = { - let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config); - - let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard); - let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard); - let dio1 = Input::new(p.P1_15.degrade(), Pull::Down); - let busy = Input::new(p.P1_14.degrade(), Pull::Down); - let antenna_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard); - let antenna_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard); - - match Sx126xRadio::new(spim, cs, reset, antenna_rx, antenna_tx, dio1, busy, false).await { - Ok(r) => r, - Err(err) => { - info!("Sx126xRadio error = {}", err); - return; - } - } - }; - - let mut start_indicator = Output::new(p.P1_04, Level::Low, OutputDrive::Standard); - - start_indicator.set_high(); - Timer::after(Duration::from_secs(5)).await; - start_indicator.set_low(); - - match radio.lora.sleep().await { - Ok(()) => info!("Sleep successful"), - Err(err) => info!("Sleep unsuccessful = {}", err), - } - - unwrap!(spawner.spawn(temperature_task(temperature_publisher))); - unwrap!(spawner.spawn(motion_detection_task(motion_detection_publisher))); - - loop { - let message = lora_tx_subscriber.next_message_pure().await; - - let tx_config = TxConfig { - // 11 byte maximum payload for Bandwidth 125 and SF 10 - pw: 10, // up to 20 - rf: RfConfig { - frequency: 903900000, // channel in Hz, not MHz - bandwidth: Bandwidth::_250KHz, - spreading_factor: SpreadingFactor::_10, - coding_rate: CodingRate::_4_8, - }, - }; - - let mut buffer = [0x00u8]; - match message { - Message::Temperature(temperature) => buffer[0] = temperature as u8, - Message::MotionDetected => buffer[0] = 0x01u8, - }; - - // unencrypted - match radio.tx(tx_config, &buffer).await { - Ok(ret_val) => info!("TX ret_val = {}", ret_val), - Err(err) => info!("TX error = {}", err), - } - - match radio.lora.sleep().await { - Ok(()) => info!("Sleep successful"), - Err(err) => info!("Sleep unsuccessful = {}", err), - } - } -} -- cgit