@@ -30,7 +30,7 @@ pub struct Radio<'c> {
30
30
pub const DEFAULT_CCA : Cca = Cca :: CarrierSense ;
31
31
32
32
/// Default radio channel = Channel 20 (`2_450` MHz)
33
- pub const DEFAULT_CHANNEL : Channel = Channel :: _20 ;
33
+ pub const DEFAULT_CHANNEL : Channel = Channel :: _18 ; // _17 todo undo; set this to interfere with my wifi
34
34
35
35
/// Default TX power = 0 dBm
36
36
pub const DEFAULT_TXPOWER : TxPower = TxPower :: _0dBm;
@@ -43,6 +43,15 @@ pub const DEFAULT_SFD: u8 = 0xA7;
43
43
pub enum Cca {
44
44
/// Carrier sense
45
45
CarrierSense ,
46
+ /// Energy Detection / Energy Above Threshold
47
+ EnergyDetection {
48
+ /// Energy measurements above this value mean that the channel is assumed to be busy.
49
+ /// Note the the measurement range is 0..0xFF - where 0 means that the received power was
50
+ /// less than 10 dB above the selected receiver sensitivity. This value is not given in dBm,
51
+ /// but can be converted. See the nrf52840 Product Specification Section 6.20.12.4
52
+ /// for details.
53
+ ed_threshold : u8 ,
54
+ } ,
46
55
}
47
56
48
57
/// IEEE 802.15.4 channels
@@ -203,8 +212,8 @@ impl<'c> Radio<'c> {
203
212
}
204
213
205
214
// set default settings
206
- radio. set_cca ( DEFAULT_CCA ) ;
207
215
radio. set_channel ( DEFAULT_CHANNEL ) ;
216
+ radio. set_cca ( DEFAULT_CCA ) ;
208
217
radio. set_sfd ( DEFAULT_SFD ) ;
209
218
radio. set_txpower ( DEFAULT_TXPOWER ) ;
210
219
@@ -226,6 +235,13 @@ impl<'c> Radio<'c> {
226
235
self . needs_enable = true ;
227
236
match cca {
228
237
Cca :: CarrierSense => self . radio . ccactrl . write ( |w| w. ccamode ( ) . carrier_mode ( ) ) ,
238
+ Cca :: EnergyDetection { ed_threshold } => {
239
+ // "[ED] is enabled by first configuring the field CCAMODE=EdMode in CCACTRL
240
+ // and writing the CCAEDTHRES field to a chosen value."
241
+ self . radio
242
+ . ccactrl
243
+ . write ( |w| unsafe { w. ccamode ( ) . ed_mode ( ) . ccaedthres ( ) . bits ( ed_threshold) } ) ;
244
+ }
229
245
}
230
246
}
231
247
@@ -243,6 +259,48 @@ impl<'c> Radio<'c> {
243
259
. write ( |w| w. txpower ( ) . variant ( power. _into ( ) ) ) ;
244
260
}
245
261
262
+ /// Sample the received signal power (i.e. the presence of possibly interfering signals)
263
+ /// within the bandwidth of the currently used channel for sample_cycles iterations.
264
+ /// Note that one iteration has a sample time of 128μs, and that each iteration produces the
265
+ /// average RSSI value measured during this sample time.
266
+ ///
267
+ /// Returns the *maximum* measurement recorded during sampling as reported by the hardware (not in dBm!).
268
+ /// The result can be used to find a suitable ED threshold for Energy Detection-based CCA mechanisms.
269
+ ///
270
+ /// For details, see Section 6.20.12.3 Energy detection (ED) of the PS.
271
+ /// RSSI samples are averaged over a measurement time of 8 symbol periods (128 μs).
272
+ pub fn energy_detection_scan ( & mut self , sample_cycles : u32 ) -> u8 {
273
+ unsafe {
274
+ // Increase the time spent listening
275
+ self . radio . edcnt . write ( |w| w. edcnt ( ) . bits ( sample_cycles) ) ;
276
+ }
277
+
278
+ // ensure that the shortcut between READY event and START task is disabled before putting
279
+ // the radio into recv mode
280
+ self . radio . shorts . reset ( ) ;
281
+ self . put_in_rx_mode ( ) ;
282
+
283
+ // clear related events
284
+ self . radio . events_edend . reset ( ) ;
285
+
286
+ // start energy detection sampling
287
+ self . radio
288
+ . tasks_edstart
289
+ . write ( |w| w. tasks_edstart ( ) . set_bit ( ) ) ;
290
+
291
+ loop {
292
+ if self . radio . events_edend . read ( ) . events_edend ( ) . bit_is_set ( ) {
293
+ // sampling period is over; collect value
294
+ self . radio . events_edend . reset ( ) ;
295
+
296
+ // note that since we have increased EDCNT, the EDSAMPLE register contains the
297
+ // maximumrecorded value, not the average
298
+ let read_lvl = self . radio . edsample . read ( ) . edlvl ( ) . bits ( ) ;
299
+ return read_lvl;
300
+ }
301
+ }
302
+ }
303
+
246
304
/// Recevies one radio packet and copies its contents into the given `packet` buffer
247
305
///
248
306
/// This methods returns the `Ok` variant if the CRC included the packet was successfully
@@ -356,6 +414,7 @@ impl<'c> Radio<'c> {
356
414
/// packet is transmitted and the `Err` variant is returned
357
415
// NOTE we do NOT check the address of `packet`; see comment in `Packet::new` for details
358
416
pub fn try_send ( & mut self , packet : & Packet ) -> Result < ( ) , ( ) > {
417
+ // enable radio to perform cca
359
418
self . put_in_rx_mode ( ) ;
360
419
361
420
// clear related events
@@ -369,15 +428,15 @@ impl<'c> Radio<'c> {
369
428
. write ( |w| w. packetptr ( ) . bits ( packet. buffer . as_ptr ( ) as u32 ) ) ;
370
429
}
371
430
372
- // immediately start transmission if the channel is idle
431
+ // configure radio to immediately start transmission if the channel is idle
373
432
self . radio
374
433
. shorts
375
434
. modify ( |_, w| w. ccaidle_txen ( ) . set_bit ( ) . txready_start ( ) . set_bit ( ) ) ;
376
435
377
436
// the DMA transfer will start at some point after the following write operation so
378
437
// we place the compiler fence here
379
438
dma_start_fence ( ) ;
380
- // start CCA
439
+ // start CCA. In case the channel is clear, the data at packetptr will be sent automatically
381
440
self . radio
382
441
. tasks_ccastart
383
442
. write ( |w| w. tasks_ccastart ( ) . set_bit ( ) ) ;
@@ -413,6 +472,7 @@ impl<'c> Radio<'c> {
413
472
/// CCA attempts to be spec compliant
414
473
// NOTE we do NOT check the address of `packet`; see comment in `Packet::new` for details
415
474
pub fn send ( & mut self , packet : & Packet ) {
475
+ // enable radio to perform cca
416
476
self . put_in_rx_mode ( ) ;
417
477
418
478
// clear related events
@@ -435,7 +495,7 @@ impl<'c> Radio<'c> {
435
495
}
436
496
437
497
' cca: loop {
438
- // start CCA
498
+ // start CCA (+ sending if channel is clear)
439
499
self . radio
440
500
. tasks_ccastart
441
501
. write ( |w| w. tasks_ccastart ( ) . set_bit ( ) ) ;
0 commit comments