diff options
| author | ceekdee <[email protected]> | 2022-09-27 21:55:41 -0500 |
|---|---|---|
| committer | ceekdee <[email protected]> | 2022-09-27 21:55:41 -0500 |
| commit | a89a0c2f122759a7e743e75152f7af7f67b4387b (patch) | |
| tree | 52ea198c2a28cf405c651b9a73a3a87eccab1e37 /examples | |
| parent | 9bb43ffe9adddb3497bb08d0730635fbd66cff94 (diff) | |
Initial add for sx126x
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/nrf/Cargo.toml | 7 | ||||
| -rw-r--r-- | examples/nrf/src/bin/lora_p2p_report.rs | 84 | ||||
| -rw-r--r-- | examples/nrf/src/bin/lora_p2p_sense.rs | 173 |
3 files changed, 263 insertions, 1 deletions
diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml index a5d340c69..54df16ba0 100644 --- a/examples/nrf/Cargo.toml +++ b/examples/nrf/Cargo.toml | |||
| @@ -5,7 +5,8 @@ version = "0.1.0" | |||
| 5 | 5 | ||
| 6 | [features] | 6 | [features] |
| 7 | default = ["nightly"] | 7 | default = ["nightly"] |
| 8 | nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embedded-io/async", "embassy-net"] | 8 | nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embedded-io/async", "embassy-net", |
| 9 | "embassy-lora", "lorawan-device", "lorawan"] | ||
| 9 | 10 | ||
| 10 | [dependencies] | 11 | [dependencies] |
| 11 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 12 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| @@ -16,6 +17,10 @@ embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defm | |||
| 16 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true } | 17 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true } |
| 17 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } | 18 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } |
| 18 | embedded-io = "0.3.0" | 19 | embedded-io = "0.3.0" |
| 20 | embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["rak4631", "time", "defmt"], optional = true } | ||
| 21 | |||
| 22 | lorawan-device = { version = "0.8.0", default-features = false, features = ["async"], optional = true } | ||
| 23 | lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"], optional = true } | ||
| 19 | 24 | ||
| 20 | defmt = "0.3" | 25 | defmt = "0.3" |
| 21 | defmt-rtt = "0.3" | 26 | defmt-rtt = "0.3" |
diff --git a/examples/nrf/src/bin/lora_p2p_report.rs b/examples/nrf/src/bin/lora_p2p_report.rs new file mode 100644 index 000000000..46cb848b1 --- /dev/null +++ b/examples/nrf/src/bin/lora_p2p_report.rs | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | //! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio. | ||
| 2 | #![no_std] | ||
| 3 | #![no_main] | ||
| 4 | #![macro_use] | ||
| 5 | #![allow(dead_code)] | ||
| 6 | #![feature(type_alias_impl_trait)] | ||
| 7 | |||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_lora::sx126x::*; | ||
| 11 | use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull}; | ||
| 12 | use embassy_nrf::{interrupt, spim}; | ||
| 13 | use embassy_time::{Duration, Timer}; | ||
| 14 | use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor}; | ||
| 15 | use {defmt_rtt as _, panic_probe as _}; | ||
| 16 | |||
| 17 | #[embassy_executor::main] | ||
| 18 | async fn main(_spawner: Spawner) { | ||
| 19 | let p = embassy_nrf::init(Default::default()); | ||
| 20 | let mut spi_config = spim::Config::default(); | ||
| 21 | spi_config.frequency = spim::Frequency::M1; // M16 ??? | ||
| 22 | |||
| 23 | let mut radio = { | ||
| 24 | let irq = interrupt::take!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||
| 25 | let spim = spim::Spim::new(p.TWISPI1, irq, p.P1_11, p.P1_13, p.P1_12, spi_config); | ||
| 26 | |||
| 27 | let cs = Output::new(p.P1_10, Level::High, OutputDrive::Standard); | ||
| 28 | let reset = Output::new(p.P1_06, Level::High, OutputDrive::Standard); | ||
| 29 | let dio1 = Input::new(p.P1_15.degrade(), Pull::Down); | ||
| 30 | let busy = Input::new(p.P1_14.degrade(), Pull::Down); | ||
| 31 | let antenna_rx = Output::new(p.P1_05, Level::Low, OutputDrive::Standard); | ||
| 32 | let antenna_tx = Output::new(p.P1_07, Level::Low, OutputDrive::Standard); | ||
| 33 | |||
| 34 | match Sx126xRadio::new(spim, cs, reset, antenna_rx, antenna_tx, dio1, busy, false).await { | ||
| 35 | Ok(r) => r, | ||
| 36 | Err(err) => { | ||
| 37 | info!("Sx126xRadio error = {}", err); | ||
| 38 | return; | ||
| 39 | } | ||
| 40 | } | ||
| 41 | }; | ||
| 42 | |||
| 43 | let mut debug_indicator = Output::new(p.P1_03, Level::Low, OutputDrive::Standard); | ||
| 44 | let mut start_indicator = Output::new(p.P1_04, Level::Low, OutputDrive::Standard); | ||
| 45 | |||
| 46 | start_indicator.set_high(); | ||
| 47 | Timer::after(Duration::from_secs(5)).await; | ||
| 48 | start_indicator.set_low(); | ||
| 49 | |||
| 50 | match radio.lora.sleep().await { | ||
| 51 | Ok(()) => info!("Sleep successful"), | ||
| 52 | Err(err) => info!("Sleep unsuccessful = {}", err), | ||
| 53 | } | ||
| 54 | |||
| 55 | let rf_config = RfConfig { | ||
| 56 | frequency: 903900000, // channel in Hz | ||
| 57 | bandwidth: Bandwidth::_250KHz, | ||
| 58 | spreading_factor: SpreadingFactor::_10, | ||
| 59 | coding_rate: CodingRate::_4_8, | ||
| 60 | }; | ||
| 61 | |||
| 62 | let mut buffer = [00u8; 100]; | ||
| 63 | |||
| 64 | // P2P receive | ||
| 65 | match radio.rx(rf_config, &mut buffer).await { | ||
| 66 | Ok((buffer_len, rx_quality)) => info!( | ||
| 67 | "RX received = {:?} with length = {} rssi = {} snr = {}", | ||
| 68 | &buffer[0..buffer_len], | ||
| 69 | buffer_len, | ||
| 70 | rx_quality.rssi(), | ||
| 71 | rx_quality.snr() | ||
| 72 | ), | ||
| 73 | Err(err) => info!("RX error = {}", err), | ||
| 74 | } | ||
| 75 | |||
| 76 | match radio.lora.sleep().await { | ||
| 77 | Ok(()) => info!("Sleep successful"), | ||
| 78 | Err(err) => info!("Sleep unsuccessful = {}", err), | ||
| 79 | } | ||
| 80 | |||
| 81 | debug_indicator.set_high(); | ||
| 82 | Timer::after(Duration::from_secs(5)).await; | ||
| 83 | debug_indicator.set_low(); | ||
| 84 | } | ||
diff --git a/examples/nrf/src/bin/lora_p2p_sense.rs b/examples/nrf/src/bin/lora_p2p_sense.rs new file mode 100644 index 000000000..57aaea665 --- /dev/null +++ b/examples/nrf/src/bin/lora_p2p_sense.rs | |||
| @@ -0,0 +1,173 @@ | |||
| 1 | //! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio. | ||
| 2 | #![no_std] | ||
| 3 | #![no_main] | ||
| 4 | #![macro_use] | ||
| 5 | #![feature(type_alias_impl_trait)] | ||
| 6 | #![feature(alloc_error_handler)] | ||
| 7 | #![allow(incomplete_features)] | ||
| 8 | |||
| 9 | use defmt::*; | ||
| 10 | use embassy_executor::Spawner; | ||
| 11 | use embassy_lora::sx126x::*; | ||
| 12 | use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin as _, Pull}; | ||
| 13 | use embassy_nrf::temp::Temp; | ||
| 14 | use embassy_nrf::{interrupt, spim}; | ||
| 15 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 16 | use embassy_sync::pubsub::{PubSubChannel, Publisher}; | ||
| 17 | use embassy_time::{Duration, Timer}; | ||
| 18 | use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor, TxConfig}; | ||
| 19 | use {defmt_rtt as _, panic_probe as _, panic_probe as _}; | ||
| 20 | |||
| 21 | // Sensor packet constants | ||
| 22 | const TEMPERATURE_UID: u8 = 0x01; | ||
| 23 | const MOTION_UID: u8 = 0x02; | ||
| 24 | |||
| 25 | // Message bus: queue of 2, 1 subscriber (Lora P2P), 2 publishers (temperature, motion detection) | ||
| 26 | static MESSAGE_BUS: PubSubChannel<CriticalSectionRawMutex, Message, 2, 1, 2> = PubSubChannel::new(); | ||
| 27 | |||
| 28 | #[derive(Clone, defmt::Format)] | ||
| 29 | enum Message { | ||
| 30 | Temperature(i32), | ||
| 31 | MotionDetected, | ||
| 32 | } | ||
| 33 | |||
| 34 | #[embassy_executor::task] | ||
| 35 | async fn temperature_task( | ||
| 36 | mut temperature: Temp<'static>, | ||
| 37 | publisher: Publisher<'static, CriticalSectionRawMutex, Message, 2, 1, 2>, | ||
| 38 | ) { | ||
| 39 | Timer::after(Duration::from_secs(45)).await; // stabilize for 45 seconds | ||
| 40 | |||
| 41 | let mut temperature_reporting_threshhold = 10; | ||
| 42 | |||
| 43 | loop { | ||
| 44 | let value = temperature.read().await; | ||
| 45 | let mut temperature_val = value.to_num::<i32>(); | ||
| 46 | |||
| 47 | info!("Temperature: {}", temperature_val); // debug ??? | ||
| 48 | |||
| 49 | // only report every 2 degree Celsius drops, from 9 through 5, but starting at 3 always report | ||
| 50 | |||
| 51 | if temperature_val == 8 || temperature_val == 6 || temperature_val == 4 { | ||
| 52 | temperature_val += 1; | ||
| 53 | } | ||
| 54 | |||
| 55 | if temperature_reporting_threshhold > temperature_val | ||
| 56 | && (temperature_val == 9 || temperature_val == 7 || temperature_val == 5) | ||
| 57 | { | ||
| 58 | temperature_reporting_threshhold = temperature_val; | ||
| 59 | publisher.publish(Message::Temperature(temperature_val)).await; | ||
| 60 | } else if temperature_val <= 3 { | ||
| 61 | publisher.publish(Message::Temperature(temperature_val)).await; | ||
| 62 | } | ||
| 63 | |||
| 64 | Timer::after(Duration::from_secs(20 * 60)).await; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | #[embassy_executor::task] | ||
| 69 | async fn motion_detection_task( | ||
| 70 | mut pir_pin: Input<'static, AnyPin>, | ||
| 71 | publisher: Publisher<'static, CriticalSectionRawMutex, Message, 2, 1, 2>, | ||
| 72 | ) { | ||
| 73 | Timer::after(Duration::from_secs(30)).await; // stabilize for 30 seconds | ||
| 74 | |||
| 75 | loop { | ||
| 76 | // wait for motion detection | ||
| 77 | pir_pin.wait_for_low().await; | ||
| 78 | publisher.publish(Message::MotionDetected).await; | ||
| 79 | |||
| 80 | // wait a minute before setting up for more motion detection | ||
| 81 | Timer::after(Duration::from_secs(60)).await; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | #[embassy_executor::main] | ||
| 86 | async fn main(spawner: Spawner) { | ||
| 87 | let p = embassy_nrf::init(Default::default()); | ||
| 88 | // set up to funnel temperature and motion detection events to the Lora Tx task | ||
| 89 | let mut lora_tx_subscriber = unwrap!(MESSAGE_BUS.subscriber()); | ||
| 90 | let temperature_publisher = unwrap!(MESSAGE_BUS.publisher()); | ||
| 91 | let motion_detection_publisher = unwrap!(MESSAGE_BUS.publisher()); | ||
| 92 | |||
| 93 | let mut spi_config = spim::Config::default(); | ||
| 94 | spi_config.frequency = spim::Frequency::M1; // M16 ??? | ||
| 95 | |||
| 96 | let mut radio = { | ||
| 97 | let irq = interrupt::take!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||
| 98 | let spim = spim::Spim::new(p.TWISPI1, irq, p.P1_11, p.P1_13, p.P1_12, spi_config); | ||
| 99 | |||
| 100 | let cs = Output::new(p.P1_10, Level::High, OutputDrive::Standard); | ||
| 101 | let reset = Output::new(p.P1_06, Level::High, OutputDrive::Standard); | ||
| 102 | let dio1 = Input::new(p.P1_15.degrade(), Pull::Down); | ||
| 103 | let busy = Input::new(p.P1_14.degrade(), Pull::Down); | ||
| 104 | let antenna_rx = Output::new(p.P1_05, Level::Low, OutputDrive::Standard); | ||
| 105 | let antenna_tx = Output::new(p.P1_07, Level::Low, OutputDrive::Standard); | ||
| 106 | |||
| 107 | match Sx126xRadio::new(spim, cs, reset, antenna_rx, antenna_tx, dio1, busy, false).await { | ||
| 108 | Ok(r) => r, | ||
| 109 | Err(err) => { | ||
| 110 | info!("Sx126xRadio error = {}", err); | ||
| 111 | return; | ||
| 112 | } | ||
| 113 | } | ||
| 114 | }; | ||
| 115 | |||
| 116 | // set up for the temperature task | ||
| 117 | let temperature_irq = interrupt::take!(TEMP); | ||
| 118 | let temperature = Temp::new(p.TEMP, temperature_irq); | ||
| 119 | |||
| 120 | // set the motion detection pin | ||
| 121 | let pir_pin = Input::new(p.P0_10.degrade(), Pull::Up); | ||
| 122 | |||
| 123 | let mut start_indicator = Output::new(p.P1_04, Level::Low, OutputDrive::Standard); | ||
| 124 | let mut debug_indicator = Output::new(p.P1_03, Level::Low, OutputDrive::Standard); | ||
| 125 | |||
| 126 | start_indicator.set_high(); | ||
| 127 | Timer::after(Duration::from_secs(5)).await; | ||
| 128 | start_indicator.set_low(); | ||
| 129 | |||
| 130 | match radio.lora.sleep().await { | ||
| 131 | Ok(()) => info!("Sleep successful"), | ||
| 132 | Err(err) => info!("Sleep unsuccessful = {}", err), | ||
| 133 | } | ||
| 134 | |||
| 135 | unwrap!(spawner.spawn(temperature_task(temperature, temperature_publisher))); | ||
| 136 | unwrap!(spawner.spawn(motion_detection_task(pir_pin, motion_detection_publisher))); | ||
| 137 | |||
| 138 | loop { | ||
| 139 | let message = lora_tx_subscriber.next_message_pure().await; | ||
| 140 | |||
| 141 | let tx_config = TxConfig { | ||
| 142 | // 11 byte maximum payload for Bandwidth 125 and SF 10 | ||
| 143 | pw: 20, // up to 20 // 5 ??? | ||
| 144 | rf: RfConfig { | ||
| 145 | frequency: 903900000, // channel in Hz, not MHz | ||
| 146 | bandwidth: Bandwidth::_250KHz, | ||
| 147 | spreading_factor: SpreadingFactor::_10, | ||
| 148 | coding_rate: CodingRate::_4_8, | ||
| 149 | }, | ||
| 150 | }; | ||
| 151 | |||
| 152 | let mut buffer = [TEMPERATURE_UID, 0xffu8, MOTION_UID, 0x00u8]; | ||
| 153 | match message { | ||
| 154 | Message::Temperature(temperature) => buffer[1] = temperature as u8, | ||
| 155 | Message::MotionDetected => buffer[3] = 0x01u8, | ||
| 156 | }; | ||
| 157 | |||
| 158 | // crypto for text ??? | ||
| 159 | match radio.tx(tx_config, &buffer).await { | ||
| 160 | Ok(ret_val) => info!("TX ret_val = {}", ret_val), | ||
| 161 | Err(err) => info!("TX error = {}", err), | ||
| 162 | } | ||
| 163 | |||
| 164 | match radio.lora.sleep().await { | ||
| 165 | Ok(()) => info!("Sleep successful"), | ||
| 166 | Err(err) => info!("Sleep unsuccessful = {}", err), | ||
| 167 | } | ||
| 168 | |||
| 169 | debug_indicator.set_high(); | ||
| 170 | Timer::after(Duration::from_secs(5)).await; | ||
| 171 | debug_indicator.set_low(); | ||
| 172 | } | ||
| 173 | } | ||
