2022-09-28 04:55:41 +02:00
|
|
|
//! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio.
|
2022-10-10 19:35:42 +02:00
|
|
|
//! Other nrf/sx126x combinations may work with appropriate pin modifications.
|
|
|
|
//! It demonstates LORA P2P functionality in conjunction with example lora_p2p_report.rs.
|
2022-09-28 04:55:41 +02:00
|
|
|
#![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::*;
|
2022-10-10 19:35:42 +02:00
|
|
|
use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
|
2022-09-28 04:55:41 +02:00
|
|
|
use embassy_nrf::{interrupt, 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 _};
|
|
|
|
|
|
|
|
// Message bus: queue of 2, 1 subscriber (Lora P2P), 2 publishers (temperature, motion detection)
|
|
|
|
static MESSAGE_BUS: PubSubChannel<CriticalSectionRawMutex, Message, 2, 1, 2> = PubSubChannel::new();
|
|
|
|
|
|
|
|
#[derive(Clone, defmt::Format)]
|
|
|
|
enum Message {
|
|
|
|
Temperature(i32),
|
|
|
|
MotionDetected,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[embassy_executor::task]
|
2022-10-10 19:35:42 +02:00
|
|
|
async fn temperature_task(publisher: Publisher<'static, CriticalSectionRawMutex, Message, 2, 1, 2>) {
|
|
|
|
// Publish a fake temperature every 43 seconds, minimizing LORA traffic.
|
2022-09-28 04:55:41 +02:00
|
|
|
loop {
|
2022-10-10 19:35:42 +02:00
|
|
|
Timer::after(Duration::from_secs(43)).await;
|
|
|
|
publisher.publish(Message::Temperature(9)).await;
|
2022-09-28 04:55:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[embassy_executor::task]
|
2022-10-10 19:35:42 +02:00
|
|
|
async fn motion_detection_task(publisher: Publisher<'static, CriticalSectionRawMutex, Message, 2, 1, 2>) {
|
|
|
|
// Publish a fake motion detection every 79 seconds, minimizing LORA traffic.
|
2022-09-28 04:55:41 +02:00
|
|
|
loop {
|
2022-10-10 19:35:42 +02:00
|
|
|
Timer::after(Duration::from_secs(79)).await;
|
2022-09-28 04:55:41 +02:00
|
|
|
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();
|
2022-10-10 19:35:42 +02:00
|
|
|
spi_config.frequency = spim::Frequency::M16;
|
2022-09-28 04:55:41 +02:00
|
|
|
|
|
|
|
let mut radio = {
|
|
|
|
let irq = interrupt::take!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
|
|
|
|
let spim = spim::Spim::new(p.TWISPI1, irq, p.P1_11, p.P1_13, p.P1_12, spi_config);
|
|
|
|
|
2022-10-08 21:32:22 +02:00
|
|
|
let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
|
|
|
|
let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
|
2022-09-28 04:55:41 +02:00
|
|
|
let dio1 = Input::new(p.P1_15.degrade(), Pull::Down);
|
|
|
|
let busy = Input::new(p.P1_14.degrade(), Pull::Down);
|
2022-10-08 21:32:22 +02:00
|
|
|
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);
|
2022-09-28 04:55:41 +02:00
|
|
|
|
|
|
|
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),
|
|
|
|
}
|
|
|
|
|
2022-10-10 19:35:42 +02:00
|
|
|
unwrap!(spawner.spawn(temperature_task(temperature_publisher)));
|
|
|
|
unwrap!(spawner.spawn(motion_detection_task(motion_detection_publisher)));
|
2022-09-28 04:55:41 +02:00
|
|
|
|
|
|
|
loop {
|
|
|
|
let message = lora_tx_subscriber.next_message_pure().await;
|
|
|
|
|
|
|
|
let tx_config = TxConfig {
|
|
|
|
// 11 byte maximum payload for Bandwidth 125 and SF 10
|
2022-10-10 19:35:42 +02:00
|
|
|
pw: 10, // up to 20
|
2022-09-28 04:55:41 +02:00
|
|
|
rf: RfConfig {
|
|
|
|
frequency: 903900000, // channel in Hz, not MHz
|
|
|
|
bandwidth: Bandwidth::_250KHz,
|
|
|
|
spreading_factor: SpreadingFactor::_10,
|
|
|
|
coding_rate: CodingRate::_4_8,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2022-10-10 19:35:42 +02:00
|
|
|
let mut buffer = [0x00u8];
|
2022-09-28 04:55:41 +02:00
|
|
|
match message {
|
2022-10-10 19:35:42 +02:00
|
|
|
Message::Temperature(temperature) => buffer[0] = temperature as u8,
|
|
|
|
Message::MotionDetected => buffer[0] = 0x01u8,
|
2022-09-28 04:55:41 +02:00
|
|
|
};
|
|
|
|
|
2022-10-10 19:35:42 +02:00
|
|
|
// unencrypted
|
2022-09-28 04:55:41 +02:00
|
|
|
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),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|