nrf52/ble_radio.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.
//! Radio driver, Bluetooth Low Energy, NRF52
//!
//! The generic radio configuration i.e., not specific to Bluetooth are functions and similar which
//! do not start with `ble`. Moreover, Bluetooth Low Energy specific radio configuration
//! starts with `ble`
//!
//! For more readability the Bluetooth specific configuration may be moved to separate trait
//!
//! ### Author
//! * Niklas Adolfsson <niklasadolfsson1@gmail.com>
//! * Date: July 18, 2017
//!
//! ### Packet Configuration
//! ```txt
//! +----------+------+--------+----+--------+----+---------+-----+
//! | Preamble | Base | Prefix | S0 | Length | S1 | Payload | CRC |
//! +----------+------+--------+----+--------+----+---------+-----+
//! ```
//!
//! * Preamble - 1 byte
//!
//! * Base and prefix forms together the access address
//!
//! * S0, an optional parameter that is configured to indicate how many bytes of
//! the payload is the PDU Type. Configured as 1 byte!
//!
//! * Length, an optional parameter that is configured to indicate how many bits of the
//! payload is the length field. Configured as 8 bits!
//!
//! * S1, Not used
//!
//! * Payload - 2 to 255 bytes
//!
//! * CRC - 3 bytes
use core::cell::Cell;
use core::ptr::addr_of;
use core::ptr::addr_of_mut;
use kernel::hil::ble_advertising;
use kernel::hil::ble_advertising::RadioChannel;
use kernel::utilities::cells::OptionalCell;
use kernel::utilities::cells::TakeCell;
use kernel::utilities::registers::interfaces::{Readable, Writeable};
use kernel::utilities::registers::{register_bitfields, ReadOnly, ReadWrite, WriteOnly};
use kernel::utilities::StaticRef;
use kernel::ErrorCode;
use nrf5x::constants::TxPower;
const RADIO_BASE: StaticRef<RadioRegisters> =
unsafe { StaticRef::new(0x40001000 as *const RadioRegisters) };
#[repr(C)]
struct RadioRegisters {
/// Enable Radio in TX mode
/// - Address: 0x000 - 0x004
task_txen: WriteOnly<u32, Task::Register>,
/// Enable Radio in RX mode
/// - Address: 0x004 - 0x008
task_rxen: WriteOnly<u32, Task::Register>,
/// Start Radio
/// - Address: 0x008 - 0x00c
task_start: WriteOnly<u32, Task::Register>,
/// Stop Radio
/// - Address: 0x00c - 0x010
task_stop: WriteOnly<u32, Task::Register>,
/// Disable Radio
/// - Address: 0x010 - 0x014
task_disable: WriteOnly<u32, Task::Register>,
/// Start the RSSI and take one single sample of the receive signal strength
/// - Address: 0x014- 0x018
task_rssistart: WriteOnly<u32, Task::Register>,
/// Stop the RSSI measurement
/// - Address: 0x018 - 0x01c
task_rssistop: WriteOnly<u32, Task::Register>,
/// Start the bit counter
/// - Address: 0x01c - 0x020
task_bcstart: WriteOnly<u32, Task::Register>,
/// Stop the bit counter
/// - Address: 0x020 - 0x024
task_bcstop: WriteOnly<u32, Task::Register>,
/// Reserved
_reserved1: [u32; 55],
/// Radio has ramped up and is ready to be started
/// - Address: 0x100 - 0x104
event_ready: ReadWrite<u32, Event::Register>,
/// Address sent or received
/// - Address: 0x104 - 0x108
event_address: ReadWrite<u32, Event::Register>,
/// Packet payload sent or received
/// - Address: 0x108 - 0x10c
event_payload: ReadWrite<u32, Event::Register>,
/// Packet sent or received
/// - Address: 0x10c - 0x110
event_end: ReadWrite<u32, Event::Register>,
/// Radio has been disabled
/// - Address: 0x110 - 0x114
event_disabled: ReadWrite<u32, Event::Register>,
/// A device address match occurred on the last received packet
/// - Address: 0x114 - 0x118
event_devmatch: ReadWrite<u32>,
/// No device address match occurred on the last received packet
/// - Address: 0x118 - 0x11c
event_devmiss: ReadWrite<u32, Event::Register>,
/// Sampling of receive signal strength complete
/// - Address: 0x11c - 0x120
event_rssiend: ReadWrite<u32, Event::Register>,
/// Reserved
_reserved2: [u32; 2],
/// Bit counter reached bit count value
/// - Address: 0x128 - 0x12c
event_bcmatch: ReadWrite<u32, Event::Register>,
/// Reserved
_reserved3: [u32; 1],
/// Packet received with CRC ok
/// - Address: 0x130 - 0x134
event_crcok: ReadWrite<u32, Event::Register>,
/// Packet received with CRC error
/// - Address: 0x134 - 0x138
crcerror: ReadWrite<u32, Event::Register>,
/// Reserved
_reserved4: [u32; 50],
/// Shortcut register
/// - Address: 0x200 - 0x204
shorts: ReadWrite<u32, Shortcut::Register>,
/// Reserved
_reserved5: [u32; 64],
/// Enable interrupt
/// - Address: 0x304 - 0x308
intenset: ReadWrite<u32, Interrupt::Register>,
/// Disable interrupt
/// - Address: 0x308 - 0x30c
intenclr: ReadWrite<u32, Interrupt::Register>,
/// Reserved
_reserved6: [u32; 61],
/// CRC status
/// - Address: 0x400 - 0x404
crcstatus: ReadOnly<u32, Event::Register>,
/// Reserved
_reserved7: [u32; 1],
/// Received address
/// - Address: 0x408 - 0x40c
rxmatch: ReadOnly<u32, ReceiveMatch::Register>,
/// CRC field of previously received packet
/// - Address: 0x40c - 0x410
rxcrc: ReadOnly<u32, ReceiveCrc::Register>,
/// Device address match index
/// - Address: 0x410 - 0x414
dai: ReadOnly<u32, DeviceAddressIndex::Register>,
/// Reserved
_reserved8: [u32; 60],
/// Packet pointer
/// - Address: 0x504 - 0x508
packetptr: ReadWrite<u32, PacketPointer::Register>,
/// Frequency
/// - Address: 0x508 - 0x50c
frequency: ReadWrite<u32, Frequency::Register>,
/// Output power
/// - Address: 0x50c - 0x510
txpower: ReadWrite<u32, TransmitPower::Register>,
/// Data rate and modulation
/// - Address: 0x510 - 0x514
mode: ReadWrite<u32, Mode::Register>,
/// Packet configuration register 0
/// - Address 0x514 - 0x518
pcnf0: ReadWrite<u32, PacketConfiguration0::Register>,
/// Packet configuration register 1
/// - Address: 0x518 - 0x51c
pcnf1: ReadWrite<u32, PacketConfiguration1::Register>,
/// Base address 0
/// - Address: 0x51c - 0x520
base0: ReadWrite<u32, BaseAddress::Register>,
/// Base address 1
/// - Address: 0x520 - 0x524
base1: ReadWrite<u32, BaseAddress::Register>,
/// Prefix bytes for logical addresses 0-3
/// - Address: 0x524 - 0x528
prefix0: ReadWrite<u32, Prefix0::Register>,
/// Prefix bytes for logical addresses 4-7
/// - Address: 0x528 - 0x52c
prefix1: ReadWrite<u32, Prefix1::Register>,
/// Transmit address select
/// - Address: 0x52c - 0x530
txaddress: ReadWrite<u32, TransmitAddress::Register>,
/// Receive address select
/// - Address: 0x530 - 0x534
rxaddresses: ReadWrite<u32, ReceiveAddresses::Register>,
/// CRC configuration
/// - Address: 0x534 - 0x538
crccnf: ReadWrite<u32, CrcConfiguration::Register>,
/// CRC polynomial
/// - Address: 0x538 - 0x53c
crcpoly: ReadWrite<u32, CrcPolynomial::Register>,
/// CRC initial value
/// - Address: 0x53c - 0x540
crcinit: ReadWrite<u32, CrcInitialValue::Register>,
/// Reserved
_reserved9: [u32; 1],
/// Interframe spacing in microseconds
/// - Address: 0x544 - 0x548
tifs: ReadWrite<u32, InterFrameSpacing::Register>,
/// RSSI sample
/// - Address: 0x548 - 0x54c
rssisample: ReadWrite<u32, RssiSample::Register>,
/// Reserved
_reserved10: [u32; 1],
/// Current radio state
/// - Address: 0x550 - 0x554
state: ReadOnly<u32, State::Register>,
/// Data whitening initial value
/// - Address: 0x554 - 0x558
datawhiteiv: ReadWrite<u32, DataWhiteIv::Register>,
/// Reserved
_reserved11: [u32; 2],
/// Bit counter compare
/// - Address: 0x560 - 0x564
bcc: ReadWrite<u32, BitCounterCompare::Register>,
/// Reserved
_reserved12: [u32; 39],
/// Device address base segments
/// - Address: 0x600 - 0x620
dab: [ReadWrite<u32, DeviceAddressBase::Register>; 8],
/// Device address prefix
/// - Address: 0x620 - 0x640
dap: [ReadWrite<u32, DeviceAddressPrefix::Register>; 8],
/// Device address match configuration
/// - Address: 0x640 - 0x644
dacnf: ReadWrite<u32, DeviceAddressMatch::Register>,
/// Reserved
_reserved13: [u32; 3],
/// Radio mode configuration register
/// - Address: 0x650 - 0x654
modecnf0: ReadWrite<u32, RadioModeConfig::Register>,
/// Reserved
_reserved14: [u32; 618],
/// Peripheral power control
/// - Address: 0xFFC - 0x1000
power: ReadWrite<u32, Task::Register>,
}
register_bitfields! [u32,
/// Task register
Task [
/// Enable task
ENABLE OFFSET(0) NUMBITS(1)
],
/// Event register
Event [
/// Ready event
READY OFFSET(0) NUMBITS(1)
],
/// Shortcut register
Shortcut [
/// Shortcut between READY event and START task
READY_START OFFSET(0) NUMBITS(1),
/// Shortcut between END event and DISABLE task
END_DISABLE OFFSET(1) NUMBITS(1),
/// Shortcut between DISABLED event and TXEN task
DISABLED_TXEN OFFSET(2) NUMBITS(1),
/// Shortcut between DISABLED event and RXEN task
DISABLED_RXEN OFFSET(3) NUMBITS(1),
/// Shortcut between ADDRESS event and RSSISTART task
ADDRESS_RSSISTART OFFSET(4) NUMBITS(1),
/// Shortcut between END event and START task
END_START OFFSET(5) NUMBITS(1),
/// Shortcut between ADDRESS event and BCSTART task
ADDRESS_BCSTART OFFSET(6) NUMBITS(1),
/// Shortcut between DISABLED event and RSSISTOP task
DISABLED_RSSISTOP OFFSET(8) NUMBITS(1)
],
/// Interrupt register
Interrupt [
/// READY event
READY OFFSET(0) NUMBITS(1),
/// ADDRESS event
ADDRESS OFFSET(1) NUMBITS(1),
/// PAYLOAD event
PAYLOAD OFFSET(2) NUMBITS(1),
/// END event
END OFFSET(3) NUMBITS(1),
/// DISABLED event
DISABLED OFFSET(4) NUMBITS(1),
/// DEVMATCH event
DEVMATCH OFFSET(5) NUMBITS(1),
/// DEVMISS event
DEVMISS OFFSET(6) NUMBITS(1),
/// RSSIEND event
RSSIEND OFFSET(7) NUMBITS(1),
/// BCMATCH event
BCMATCH OFFSET(10) NUMBITS(1),
/// CRCOK event
CRCOK OFFSET(12) NUMBITS(1),
/// CRCERROR event
CRCERROR OFFSET(13) NUMBITS(1)
],
/// Receive match register
ReceiveMatch [
/// Logical address of which previous packet was received
MATCH OFFSET(0) NUMBITS(3)
],
/// Received CRC register
ReceiveCrc [
/// CRC field of previously received packet
CRC OFFSET(0) NUMBITS(24)
],
/// Device address match index register
DeviceAddressIndex [
/// Device address match index
/// Index (n) of device address, see DAB\[n\] and DAP\[n\], that got an
/// address match
INDEX OFFSET(0) NUMBITS(3)
],
/// Packet pointer register
PacketPointer [
/// Packet address to be used for the next transmission or reception. When transmitting, the packet pointed to by this
/// address will be transmitted and when receiving, the received packet will be written to this address. This address is a byte
/// aligned ram address.
POINTER OFFSET(0) NUMBITS(32)
],
/// Frequency register
Frequency [
/// Radio channel frequency
/// Frequency = 2400 + FREQUENCY (MHz)
FREQUENCY OFFSET(0) NUMBITS(7) [],
/// Channel map selection.
/// Channel map between 2400 MHZ .. 2500 MHZ
MAP OFFSET(8) NUMBITS(1) [
DEFAULT = 0,
LOW = 1
]
],
/// Transmitting power register
TransmitPower [
/// Radio output power
POWER OFFSET(0) NUMBITS(8) [
POS4DBM = 4,
POS3DBM = 3,
ODBM = 0,
NEG4DBM = 0xfc,
NEG8DBM = 0xf8,
NEG12DBM = 0xf4,
NEG16DBM = 0xf0,
NEG20DBM = 0xec,
NEG40DBM = 0xd8
]
],
/// Data rate and modulation register
Mode [
/// Radio data rate and modulation setting.
/// The radio supports Frequency-shift Keying (FSK) modulation
MODE OFFSET(0) NUMBITS(4) [
NRF_1MBIT = 0,
NRF_2MBIT = 1,
NRF_250KBIT = 2,
BLE_1MBIT = 3
]
],
/// Packet configuration register 0
PacketConfiguration0 [
/// Length on air of LENGTH field in number of bits
LFLEN OFFSET(0) NUMBITS(4) [],
/// Length on air of S0 field in number of bytes
S0LEN OFFSET(8) NUMBITS(1) [],
/// Length on air of S1 field in number of bits.
S1LEN OFFSET(16) NUMBITS(4) [],
/// Include or exclude S1 field in RAM
S1INCL OFFSET(20) NUMBITS(1) [
AUTOMATIC = 0,
INCLUDE = 1
],
/// Length of preamble on air. Decision point: TASKS_START task
PLEN OFFSET(24) NUMBITS(1) [
EIGHT = 0,
SIXTEEN = 1
]
],
/// Packet configuration register 1
PacketConfiguration1 [
/// Maximum length of packet payload
MAXLEN OFFSET(0) NUMBITS(8) [],
/// Static length in number of bytes
STATLEN OFFSET(8) NUMBITS(8) [],
/// Base address length in number of bytes
BALEN OFFSET(16) NUMBITS(3) [],
/// On air endianness
ENDIAN OFFSET(24) NUMBITS(1) [
LITTLE = 0,
BIG = 1
],
/// Enable or disable packet whitening
WHITEEN OFFSET(25) NUMBITS(1) [
DISABLED = 0,
ENABLED = 1
]
],
/// Radio base address register
BaseAddress [
/// BASE0 or BASE1
BASE OFFSET(0) NUMBITS(32)
],
/// Radio prefix0 registers
Prefix0 [
/// Address prefix 0
AP0 OFFSET(0) NUMBITS(8),
/// Address prefix 1
AP1 OFFSET(8) NUMBITS(8),
/// Address prefix 2
AP2 OFFSET(16) NUMBITS(8),
/// Address prefix 3
AP3 OFFSET(24) NUMBITS(8)
],
/// Radio prefix0 registers
Prefix1 [
/// Address prefix 4
AP4 OFFSET(0) NUMBITS(8),
/// Address prefix 5
AP5 OFFSET(8) NUMBITS(8),
/// Address prefix 6
AP6 OFFSET(16) NUMBITS(8),
/// Address prefix 7
AP7 OFFSET(24) NUMBITS(8)
],
/// Transmit address register
TransmitAddress [
/// Logical address to be used when transmitting a packet
ADDRESS OFFSET(0) NUMBITS(3)
],
/// Receive addresses register
ReceiveAddresses [
/// Enable or disable reception on logical address 0-7
ADDRESS OFFSET(0) NUMBITS(8)
],
/// CRC configuration register
CrcConfiguration [
/// CRC length in bytes
LEN OFFSET(0) NUMBITS(2) [
DISABLED = 0,
ONE = 1,
TWO = 2,
THREE = 3
],
/// Include or exclude packet field from CRC calculation
SKIPADDR OFFSET(8) NUMBITS(1) [
INCLUDE = 0,
EXCLUDE = 1
]
],
/// CRC polynomial register
CrcPolynomial [
/// CRC polynomial
CRCPOLY OFFSET(0) NUMBITS(24)
],
/// CRC initial value register
CrcInitialValue [
/// Initial value for CRC calculation
CRCINIT OFFSET(0) NUMBITS(24)
],
/// Inter Frame Spacing in us register
InterFrameSpacing [
/// Inter Frame Spacing in us
/// Inter frame space is the time interval between two consecutive packets. It is defined as the time, in micro seconds, from the
/// end of the last bit of the previous packet to the start of the first bit of the subsequent packet
TIFS OFFSET(0) NUMBITS(8)
],
/// RSSI sample register
RssiSample [
/// RSSI sample result
RSSISAMPLE OFFSET(0) NUMBITS(7)
],
/// Radio state register
State [
/// Current radio state
STATE OFFSET(0) NUMBITS(4) [
DISABLED = 0,
RXRU = 1,
RXIDLE = 2,
RX = 3,
RXDISABLED = 4,
TXRU = 9,
TXIDLE = 10,
TX = 11,
TXDISABLED = 12
]
],
/// Data whitening initial value register
DataWhiteIv [
/// Data whitening initial value. Bit 6 is hard-wired to '1', writing '0'
/// to it has no effect, and it will always be read back and used by the device as '1'
DATEWHITEIV OFFSET(0) NUMBITS(7)
],
/// Bit counter compare register
BitCounterCompare [
/// Bit counter compare
BCC OFFSET(0) NUMBITS(32)
],
/// Device address base register
DeviceAddressBase [
/// Device address base 0-7
DAB OFFSET(0) NUMBITS(32)
],
/// Device address prefix register
DeviceAddressPrefix [
/// Device address prefix 0-7
DAP OFFSET(0) NUMBITS(32)
],
/// Device address match configuration register
DeviceAddressMatch [
/// Enable or disable device address matching on 0-7
ENA OFFSET(0) NUMBITS(8),
/// TxAdd for device address 0-7
TXADD OFFSET(8) NUMBITS(8)
],
/// Radio mode configuration register
RadioModeConfig [
/// Radio ramp-up time
RU OFFSET(0) NUMBITS(1) [
DEFAULT = 0,
FAST = 1
],
/// Default TX value
/// Specifies what the RADIO will transmit when it is not started, i.e. between:
/// RADIO.EVENTS_READY and RADIO.TASKS_START
/// RADIO.EVENTS_END and RADIO.TASKS_START
DTX OFFSET(8) NUMBITS(2) [
B1 = 0,
B0 = 1,
CENTER = 2
]
]
];
static mut PAYLOAD: [u8; nrf5x::constants::RADIO_PAYLOAD_LENGTH] =
[0x00; nrf5x::constants::RADIO_PAYLOAD_LENGTH];
pub struct Radio<'a> {
registers: StaticRef<RadioRegisters>,
tx_power: Cell<TxPower>,
rx_client: OptionalCell<&'a dyn ble_advertising::RxClient>,
tx_client: OptionalCell<&'a dyn ble_advertising::TxClient>,
buffer: TakeCell<'static, [u8]>,
}
impl<'a> Radio<'a> {
pub const fn new() -> Radio<'a> {
Radio {
registers: RADIO_BASE,
tx_power: Cell::new(TxPower::ZerodBm),
rx_client: OptionalCell::empty(),
tx_client: OptionalCell::empty(),
buffer: TakeCell::empty(),
}
}
pub fn is_enabled(&self) -> bool {
self.registers.mode.matches_all(Mode::MODE::BLE_1MBIT)
}
fn tx(&self) {
self.registers.event_ready.write(Event::READY::CLEAR);
self.registers.task_txen.write(Task::ENABLE::SET);
}
fn rx(&self) {
self.registers.event_ready.write(Event::READY::CLEAR);
self.registers.task_rxen.write(Task::ENABLE::SET);
}
fn set_rx_address(&self) {
self.registers
.rxaddresses
.write(ReceiveAddresses::ADDRESS.val(1));
}
fn set_tx_address(&self) {
self.registers
.txaddress
.write(TransmitAddress::ADDRESS.val(0));
}
fn radio_on(&self) {
// reset and enable power
self.registers.power.write(Task::ENABLE::CLEAR);
self.registers.power.write(Task::ENABLE::SET);
}
fn radio_off(&self) {
self.registers.power.write(Task::ENABLE::CLEAR);
}
fn set_tx_power(&self) {
self.registers.txpower.set(self.tx_power.get() as u32);
}
fn set_dma_ptr(&self) {
self.registers.packetptr.set(addr_of!(PAYLOAD) as u32);
}
#[inline(never)]
pub fn handle_interrupt(&self) {
self.disable_all_interrupts();
if self.registers.event_ready.is_set(Event::READY) {
self.registers.event_ready.write(Event::READY::CLEAR);
self.registers.event_end.write(Event::READY::CLEAR);
self.registers.task_start.write(Task::ENABLE::SET);
}
if self.registers.event_address.is_set(Event::READY) {
self.registers.event_address.write(Event::READY::CLEAR);
}
if self.registers.event_payload.is_set(Event::READY) {
self.registers.event_payload.write(Event::READY::CLEAR);
}
// tx or rx finished!
if self.registers.event_end.is_set(Event::READY) {
self.registers.event_end.write(Event::READY::CLEAR);
let result = if self.registers.crcstatus.is_set(Event::READY) {
Ok(())
} else {
Err(ErrorCode::FAIL)
};
match self.registers.state.get() {
nrf5x::constants::RADIO_STATE_TXRU
| nrf5x::constants::RADIO_STATE_TXIDLE
| nrf5x::constants::RADIO_STATE_TXDISABLE
| nrf5x::constants::RADIO_STATE_TX => {
self.radio_off();
self.tx_client
.map(|client| client.transmit_event(self.buffer.take().unwrap(), result));
}
nrf5x::constants::RADIO_STATE_RXRU
| nrf5x::constants::RADIO_STATE_RXIDLE
| nrf5x::constants::RADIO_STATE_RXDISABLE
| nrf5x::constants::RADIO_STATE_RX => {
self.radio_off();
unsafe {
self.rx_client.map(|client| {
// Length is: S0 (1 Byte) + Length (1 Byte) + S1 (0 Bytes) + Payload
// And because the length field is directly read from the packet
// We need to add 2 to length to get the total length
client.receive_event(
&mut *addr_of_mut!(PAYLOAD),
PAYLOAD[1] + 2,
result,
)
});
}
}
// Radio state - Disabled
_ => (),
}
}
self.enable_interrupts();
}
pub fn enable_interrupts(&self) {
self.registers.intenset.write(
Interrupt::READY::SET
+ Interrupt::ADDRESS::SET
+ Interrupt::PAYLOAD::SET
+ Interrupt::END::SET,
);
}
pub fn enable_interrupt(&self, intr: u32) {
self.registers.intenset.set(intr);
}
pub fn clear_interrupt(&self, intr: u32) {
self.registers.intenclr.set(intr);
}
pub fn disable_all_interrupts(&self) {
// disable all possible interrupts
self.registers.intenclr.set(0xffffffff);
}
fn replace_radio_buffer(&self, buf: &'static mut [u8]) -> &'static mut [u8] {
// set payload
for (i, c) in buf.as_ref().iter().enumerate() {
unsafe {
PAYLOAD[i] = *c;
}
}
buf
}
fn ble_initialize(&self, channel: RadioChannel) {
self.radio_on();
self.ble_set_tx_power();
self.ble_set_channel_rate();
self.ble_set_channel_freq(channel);
self.ble_set_data_whitening(channel);
self.set_tx_address();
self.set_rx_address();
self.ble_set_packet_config();
self.ble_set_advertising_access_address();
self.ble_set_crc_config();
self.set_dma_ptr();
}
// BLUETOOTH SPECIFICATION Version 4.2 [Vol 6, Part B], section 3.1.1 CRC Generation
fn ble_set_crc_config(&self) {
self.registers
.crccnf
.write(CrcConfiguration::LEN::THREE + CrcConfiguration::SKIPADDR::EXCLUDE);
self.registers
.crcinit
.set(nrf5x::constants::RADIO_CRCINIT_BLE);
self.registers
.crcpoly
.set(nrf5x::constants::RADIO_CRCPOLY_BLE);
}
// BLUETOOTH SPECIFICATION Version 4.2 [Vol 6, Part B], section 2.1.2 Access Address
// Set access address to 0x8E89BED6
fn ble_set_advertising_access_address(&self) {
self.registers.prefix0.set(0x0000008e);
self.registers.base0.set(0x89bed600);
}
// Packet configuration
// BLUETOOTH SPECIFICATION Version 4.2 [Vol 6, Part B], section 2.1 Packet Format
//
// LSB MSB
// +----------+ +----------------+ +---------------+ +------------+
// | Preamble | - | Access Address | - | PDU | - | CRC |
// | (1 byte) | | (4 bytes) | | (2-255 bytes) | | (3 bytes) |
// +----------+ +----------------+ +---------------+ +------------+
//
fn ble_set_packet_config(&self) {
// sets the header of PDU TYPE to 1 byte
// sets the header length to 1 byte
self.registers.pcnf0.write(
PacketConfiguration0::LFLEN.val(8)
+ PacketConfiguration0::S0LEN.val(1)
+ PacketConfiguration0::S1LEN::CLEAR
+ PacketConfiguration0::S1INCL::CLEAR
+ PacketConfiguration0::PLEN::EIGHT,
);
self.registers.pcnf1.write(
PacketConfiguration1::WHITEEN::ENABLED
+ PacketConfiguration1::ENDIAN::LITTLE
+ PacketConfiguration1::BALEN.val(3)
+ PacketConfiguration1::STATLEN::CLEAR
+ PacketConfiguration1::MAXLEN.val(255),
);
}
// BLUETOOTH SPECIFICATION Version 4.2 [Vol 6, Part A], 4.6 REFERENCE SIGNAL DEFINITION
// Bit Rate = 1 Mb/s ±1 ppm
fn ble_set_channel_rate(&self) {
self.registers.mode.write(Mode::MODE::BLE_1MBIT);
}
// BLUETOOTH SPECIFICATION Version 4.2 [Vol 6, Part B], section 3.2 Data Whitening
// Configure channel index to the LFSR and the hardware solves the rest
fn ble_set_data_whitening(&self, channel: RadioChannel) {
self.registers.datawhiteiv.set(channel.get_channel_index());
}
// BLUETOOTH SPECIFICATION Version 4.2 [Vol 6, Part B], section 1.4.1
// RF Channels: 0 - 39
// Data: 0 - 36
// Advertising: 37, 38, 39
fn ble_set_channel_freq(&self, channel: RadioChannel) {
self.registers
.frequency
.write(Frequency::FREQUENCY.val(channel as u32));
}
// BLUETOOTH SPECIFICATION Version 4.2 [Vol 6, Part B], section 3 TRANSMITTER CHARACTERISTICS
// Minimum Output Power : -20dBm
// Maximum Output Power : +10dBm
//
// no check is required because the BleConfig::set_tx_power() method ensures that only
// valid tranmitting power is configured!
fn ble_set_tx_power(&self) {
self.set_tx_power();
}
}
impl<'a> ble_advertising::BleAdvertisementDriver<'a> for Radio<'a> {
fn transmit_advertisement(&self, buf: &'static mut [u8], _len: usize, channel: RadioChannel) {
let res = self.replace_radio_buffer(buf);
self.buffer.replace(res);
self.ble_initialize(channel);
self.tx();
self.enable_interrupts();
}
fn receive_advertisement(&self, channel: RadioChannel) {
self.ble_initialize(channel);
self.rx();
self.enable_interrupts();
}
fn set_receive_client(&self, client: &'a dyn ble_advertising::RxClient) {
self.rx_client.set(client);
}
fn set_transmit_client(&self, client: &'a dyn ble_advertising::TxClient) {
self.tx_client.set(client);
}
}
impl ble_advertising::BleConfig for Radio<'_> {
// The BLE Advertising Driver validates that the `tx_power` is between -20 to 10 dBm but then
// underlying chip must validate if the current `tx_power` is supported as well
fn set_tx_power(&self, tx_power: u8) -> Result<(), ErrorCode> {
// Convert u8 to TxPower
match nrf5x::constants::TxPower::try_from(tx_power) {
// Invalid transmitting power, propogate error
Err(()) => Err(ErrorCode::NOSUPPORT),
// Valid transmitting power, propogate success
Ok(res) => {
self.tx_power.set(res);
Ok(())
}
}
}
}