aboutsummaryrefslogtreecommitdiff
path: root/examples/nrf
diff options
context:
space:
mode:
authorceekdee <[email protected]>2022-09-27 21:55:41 -0500
committerceekdee <[email protected]>2022-09-27 21:55:41 -0500
commita89a0c2f122759a7e743e75152f7af7f67b4387b (patch)
tree52ea198c2a28cf405c651b9a73a3a87eccab1e37 /examples/nrf
parent9bb43ffe9adddb3497bb08d0730635fbd66cff94 (diff)
Initial add for sx126x
Diffstat (limited to 'examples/nrf')
-rw-r--r--examples/nrf/Cargo.toml7
-rw-r--r--examples/nrf/src/bin/lora_p2p_report.rs84
-rw-r--r--examples/nrf/src/bin/lora_p2p_sense.rs173
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]
7default = ["nightly"] 7default = ["nightly"]
8nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embedded-io/async", "embassy-net"] 8nightly = ["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]
11embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 12embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
@@ -16,6 +17,10 @@ embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defm
16embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true } 17embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true }
17embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } 18embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true }
18embedded-io = "0.3.0" 19embedded-io = "0.3.0"
20embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["rak4631", "time", "defmt"], optional = true }
21
22lorawan-device = { version = "0.8.0", default-features = false, features = ["async"], optional = true }
23lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"], optional = true }
19 24
20defmt = "0.3" 25defmt = "0.3"
21defmt-rtt = "0.3" 26defmt-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
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_lora::sx126x::*;
11use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
12use embassy_nrf::{interrupt, spim};
13use embassy_time::{Duration, Timer};
14use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor};
15use {defmt_rtt as _, panic_probe as _};
16
17#[embassy_executor::main]
18async 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
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_lora::sx126x::*;
12use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin as _, Pull};
13use embassy_nrf::temp::Temp;
14use embassy_nrf::{interrupt, spim};
15use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
16use embassy_sync::pubsub::{PubSubChannel, Publisher};
17use embassy_time::{Duration, Timer};
18use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor, TxConfig};
19use {defmt_rtt as _, panic_probe as _, panic_probe as _};
20
21// Sensor packet constants
22const TEMPERATURE_UID: u8 = 0x01;
23const MOTION_UID: u8 = 0x02;
24
25// Message bus: queue of 2, 1 subscriber (Lora P2P), 2 publishers (temperature, motion detection)
26static MESSAGE_BUS: PubSubChannel<CriticalSectionRawMutex, Message, 2, 1, 2> = PubSubChannel::new();
27
28#[derive(Clone, defmt::Format)]
29enum Message {
30 Temperature(i32),
31 MotionDetected,
32}
33
34#[embassy_executor::task]
35async 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]
69async 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]
86async 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}