https://github.com/WebBluetoothCG/demos/pull/42
Dependencies: BLE_API mbed-dev-bin nRF51822
Fork of microbit-dal by
source/drivers/MicroBitRadio.cpp@18:e2f92ac26450, 2016-07-13 (annotated)
- Committer:
- LancasterUniversity
- Date:
- Wed Jul 13 12:17:48 2016 +0100
- Revision:
- 18:e2f92ac26450
- Parent:
- 1:8aa5cdb4ab67
- Child:
- 19:ebc07f856999
Synchronized with git rev a82254b9
Author: Joe Finney
microbit: MicroBitRadio support for multiple enable/disable operations
MicroBitRadio::disable neglected to reset the internal status flag indicating
that the radio has bene initialised, which prevent subsequent enable()
operations completing properly.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Jonathan Austin |
1:8aa5cdb4ab67 | 1 | /* |
Jonathan Austin |
1:8aa5cdb4ab67 | 2 | The MIT License (MIT) |
Jonathan Austin |
1:8aa5cdb4ab67 | 3 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 4 | Copyright (c) 2016 British Broadcasting Corporation. |
Jonathan Austin |
1:8aa5cdb4ab67 | 5 | This software is provided by Lancaster University by arrangement with the BBC. |
Jonathan Austin |
1:8aa5cdb4ab67 | 6 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 7 | Permission is hereby granted, free of charge, to any person obtaining a |
Jonathan Austin |
1:8aa5cdb4ab67 | 8 | copy of this software and associated documentation files (the "Software"), |
Jonathan Austin |
1:8aa5cdb4ab67 | 9 | to deal in the Software without restriction, including without limitation |
Jonathan Austin |
1:8aa5cdb4ab67 | 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, |
Jonathan Austin |
1:8aa5cdb4ab67 | 11 | and/or sell copies of the Software, and to permit persons to whom the |
Jonathan Austin |
1:8aa5cdb4ab67 | 12 | Software is furnished to do so, subject to the following conditions: |
Jonathan Austin |
1:8aa5cdb4ab67 | 13 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 14 | The above copyright notice and this permission notice shall be included in |
Jonathan Austin |
1:8aa5cdb4ab67 | 15 | all copies or substantial portions of the Software. |
Jonathan Austin |
1:8aa5cdb4ab67 | 16 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
Jonathan Austin |
1:8aa5cdb4ab67 | 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
Jonathan Austin |
1:8aa5cdb4ab67 | 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
Jonathan Austin |
1:8aa5cdb4ab67 | 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
Jonathan Austin |
1:8aa5cdb4ab67 | 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
Jonathan Austin |
1:8aa5cdb4ab67 | 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
Jonathan Austin |
1:8aa5cdb4ab67 | 23 | DEALINGS IN THE SOFTWARE. |
Jonathan Austin |
1:8aa5cdb4ab67 | 24 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 25 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 26 | #include "MicroBitConfig.h" |
Jonathan Austin |
1:8aa5cdb4ab67 | 27 | #include "MicroBitRadio.h" |
Jonathan Austin |
1:8aa5cdb4ab67 | 28 | #include "MicroBitComponent.h" |
Jonathan Austin |
1:8aa5cdb4ab67 | 29 | #include "EventModel.h" |
Jonathan Austin |
1:8aa5cdb4ab67 | 30 | #include "MicroBitDevice.h" |
Jonathan Austin |
1:8aa5cdb4ab67 | 31 | #include "ErrorNo.h" |
Jonathan Austin |
1:8aa5cdb4ab67 | 32 | #include "MicroBitFiber.h" |
Jonathan Austin |
1:8aa5cdb4ab67 | 33 | #include "MicroBitBLEManager.h" |
Jonathan Austin |
1:8aa5cdb4ab67 | 34 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 35 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 36 | * Provides a simple broadcast radio abstraction, built upon the raw nrf51822 RADIO module. |
Jonathan Austin |
1:8aa5cdb4ab67 | 37 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 38 | * The nrf51822 RADIO module supports a number of proprietary modes of operation oher than the typical BLE usage. |
Jonathan Austin |
1:8aa5cdb4ab67 | 39 | * This class uses one of these modes to enable simple, point to multipoint communication directly between micro:bits. |
Jonathan Austin |
1:8aa5cdb4ab67 | 40 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 41 | * TODO: The protocols implemented here do not currently perform any significant form of energy management, |
Jonathan Austin |
1:8aa5cdb4ab67 | 42 | * which means that they will consume far more energy than their BLE equivalent. Later versions of the protocol |
Jonathan Austin |
1:8aa5cdb4ab67 | 43 | * should look to address this through energy efficient broadcast techbiques / sleep scheduling. In particular, the GLOSSY |
Jonathan Austin |
1:8aa5cdb4ab67 | 44 | * approach to efficient rebroadcast and network synchronisation would likely provide an effective future step. |
Jonathan Austin |
1:8aa5cdb4ab67 | 45 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 46 | * TODO: Meshing should also be considered - again a GLOSSY approach may be effective here, and highly complementary to |
Jonathan Austin |
1:8aa5cdb4ab67 | 47 | * the master/slave arachitecture of BLE. |
Jonathan Austin |
1:8aa5cdb4ab67 | 48 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 49 | * TODO: This implementation may only operated whilst the BLE stack is disabled. The nrf51822 provides a timeslot API to allow |
Jonathan Austin |
1:8aa5cdb4ab67 | 50 | * BLE to cohabit with other protocols. Future work to allow this colocation would be benefical, and would also allow for the |
Jonathan Austin |
1:8aa5cdb4ab67 | 51 | * creation of wireless BLE bridges. |
Jonathan Austin |
1:8aa5cdb4ab67 | 52 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 53 | * NOTE: This API does not contain any form of encryption, authentication or authorisation. Its purpose is solely for use as a |
Jonathan Austin |
1:8aa5cdb4ab67 | 54 | * teaching aid to demonstrate how simple communications operates, and to provide a sandpit through which learning can take place. |
Jonathan Austin |
1:8aa5cdb4ab67 | 55 | * For serious applications, BLE should be considered a substantially more secure alternative. |
Jonathan Austin |
1:8aa5cdb4ab67 | 56 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 57 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 58 | MicroBitRadio* MicroBitRadio::instance = NULL; |
Jonathan Austin |
1:8aa5cdb4ab67 | 59 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 60 | extern "C" void RADIO_IRQHandler(void) |
Jonathan Austin |
1:8aa5cdb4ab67 | 61 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 62 | // Move on to the next buffer, if possible. |
Jonathan Austin |
1:8aa5cdb4ab67 | 63 | MicroBitRadio::instance->queueRxBuf(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 64 | NRF_RADIO->PACKETPTR = (uint32_t) MicroBitRadio::instance->getRxBuf(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 65 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 66 | if(NRF_RADIO->EVENTS_READY) |
Jonathan Austin |
1:8aa5cdb4ab67 | 67 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 68 | NRF_RADIO->EVENTS_READY = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 69 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 70 | // Start listening and wait for the END event |
Jonathan Austin |
1:8aa5cdb4ab67 | 71 | NRF_RADIO->TASKS_START = 1; |
Jonathan Austin |
1:8aa5cdb4ab67 | 72 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 73 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 74 | if(NRF_RADIO->EVENTS_END) |
Jonathan Austin |
1:8aa5cdb4ab67 | 75 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 76 | NRF_RADIO->EVENTS_END = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 77 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 78 | if(NRF_RADIO->CRCSTATUS == 1) |
Jonathan Austin |
1:8aa5cdb4ab67 | 79 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 80 | uint8_t sample = NRF_RADIO->RSSISAMPLE; |
Jonathan Austin |
1:8aa5cdb4ab67 | 81 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 82 | MicroBitRadio::instance->setRSSI(sample); |
Jonathan Austin |
1:8aa5cdb4ab67 | 83 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 84 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 85 | // Start listening and wait for the END event |
Jonathan Austin |
1:8aa5cdb4ab67 | 86 | NRF_RADIO->TASKS_START = 1; |
Jonathan Austin |
1:8aa5cdb4ab67 | 87 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 88 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 89 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 90 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 91 | * Constructor. |
Jonathan Austin |
1:8aa5cdb4ab67 | 92 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 93 | * Initialise the MicroBitRadio. |
Jonathan Austin |
1:8aa5cdb4ab67 | 94 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 95 | * @note This class is demand activated, as a result most resources are only |
Jonathan Austin |
1:8aa5cdb4ab67 | 96 | * committed if send/recv or event registrations calls are made. |
Jonathan Austin |
1:8aa5cdb4ab67 | 97 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 98 | MicroBitRadio::MicroBitRadio(uint16_t id) : datagram(*this), event (*this) |
Jonathan Austin |
1:8aa5cdb4ab67 | 99 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 100 | this->id = id; |
Jonathan Austin |
1:8aa5cdb4ab67 | 101 | this->status = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 102 | this->group = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 103 | this->queueDepth = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 104 | this->rssi = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 105 | this->rxQueue = NULL; |
Jonathan Austin |
1:8aa5cdb4ab67 | 106 | this->rxBuf = NULL; |
Jonathan Austin |
1:8aa5cdb4ab67 | 107 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 108 | instance = this; |
Jonathan Austin |
1:8aa5cdb4ab67 | 109 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 110 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 111 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 112 | * Change the output power level of the transmitter to the given value. |
Jonathan Austin |
1:8aa5cdb4ab67 | 113 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 114 | * @param power a value in the range 0..7, where 0 is the lowest power and 7 is the highest. |
Jonathan Austin |
1:8aa5cdb4ab67 | 115 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 116 | * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the value is out of range. |
Jonathan Austin |
1:8aa5cdb4ab67 | 117 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 118 | int MicroBitRadio::setTransmitPower(int power) |
Jonathan Austin |
1:8aa5cdb4ab67 | 119 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 120 | if (power < 0 || power >= MICROBIT_BLE_POWER_LEVELS) |
Jonathan Austin |
1:8aa5cdb4ab67 | 121 | return MICROBIT_INVALID_PARAMETER; |
Jonathan Austin |
1:8aa5cdb4ab67 | 122 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 123 | NRF_RADIO->TXPOWER = (uint32_t)MICROBIT_BLE_POWER_LEVEL[power]; |
Jonathan Austin |
1:8aa5cdb4ab67 | 124 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 125 | return MICROBIT_OK; |
Jonathan Austin |
1:8aa5cdb4ab67 | 126 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 127 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 128 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 129 | * Change the transmission and reception band of the radio to the given channel |
Jonathan Austin |
1:8aa5cdb4ab67 | 130 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 131 | * @param band a frequency band in the range 0 - 100. Each step is 1MHz wide, based at 2400MHz. |
Jonathan Austin |
1:8aa5cdb4ab67 | 132 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 133 | * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the value is out of range, |
Jonathan Austin |
1:8aa5cdb4ab67 | 134 | * or MICROBIT_NOT_SUPPORTED if the BLE stack is running. |
Jonathan Austin |
1:8aa5cdb4ab67 | 135 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 136 | int MicroBitRadio::setFrequencyBand(int band) |
Jonathan Austin |
1:8aa5cdb4ab67 | 137 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 138 | if (ble_running()) |
Jonathan Austin |
1:8aa5cdb4ab67 | 139 | return MICROBIT_NOT_SUPPORTED; |
Jonathan Austin |
1:8aa5cdb4ab67 | 140 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 141 | if (band < 0 || band > 100) |
Jonathan Austin |
1:8aa5cdb4ab67 | 142 | return MICROBIT_INVALID_PARAMETER; |
Jonathan Austin |
1:8aa5cdb4ab67 | 143 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 144 | NRF_RADIO->FREQUENCY = (uint32_t)band; |
Jonathan Austin |
1:8aa5cdb4ab67 | 145 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 146 | return MICROBIT_OK; |
Jonathan Austin |
1:8aa5cdb4ab67 | 147 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 148 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 149 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 150 | * Retrieve a pointer to the currently allocated receive buffer. This is the area of memory |
Jonathan Austin |
1:8aa5cdb4ab67 | 151 | * actively being used by the radio hardware to store incoming data. |
Jonathan Austin |
1:8aa5cdb4ab67 | 152 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 153 | * @return a pointer to the current receive buffer. |
Jonathan Austin |
1:8aa5cdb4ab67 | 154 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 155 | FrameBuffer* MicroBitRadio::getRxBuf() |
Jonathan Austin |
1:8aa5cdb4ab67 | 156 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 157 | return rxBuf; |
Jonathan Austin |
1:8aa5cdb4ab67 | 158 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 159 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 160 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 161 | * Attempt to queue a buffer received by the radio hardware, if sufficient space is available. |
Jonathan Austin |
1:8aa5cdb4ab67 | 162 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 163 | * @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if a replacement receiver buffer |
Jonathan Austin |
1:8aa5cdb4ab67 | 164 | * could not be allocated (either by policy or memory exhaustion). |
Jonathan Austin |
1:8aa5cdb4ab67 | 165 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 166 | int MicroBitRadio::queueRxBuf() |
Jonathan Austin |
1:8aa5cdb4ab67 | 167 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 168 | if (rxBuf == NULL) |
Jonathan Austin |
1:8aa5cdb4ab67 | 169 | return MICROBIT_INVALID_PARAMETER; |
Jonathan Austin |
1:8aa5cdb4ab67 | 170 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 171 | if (queueDepth >= MICROBIT_RADIO_MAXIMUM_RX_BUFFERS) |
Jonathan Austin |
1:8aa5cdb4ab67 | 172 | return MICROBIT_NO_RESOURCES; |
Jonathan Austin |
1:8aa5cdb4ab67 | 173 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 174 | // Store the received RSSI value in the frame |
Jonathan Austin |
1:8aa5cdb4ab67 | 175 | rxBuf->rssi = getRSSI(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 176 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 177 | // Ensure that a replacement buffer is available before queuing. |
Jonathan Austin |
1:8aa5cdb4ab67 | 178 | FrameBuffer *newRxBuf = new FrameBuffer(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 179 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 180 | if (newRxBuf == NULL) |
Jonathan Austin |
1:8aa5cdb4ab67 | 181 | return MICROBIT_NO_RESOURCES; |
Jonathan Austin |
1:8aa5cdb4ab67 | 182 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 183 | // We add to the tail of the queue to preserve causal ordering. |
Jonathan Austin |
1:8aa5cdb4ab67 | 184 | rxBuf->next = NULL; |
Jonathan Austin |
1:8aa5cdb4ab67 | 185 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 186 | if (rxQueue == NULL) |
Jonathan Austin |
1:8aa5cdb4ab67 | 187 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 188 | rxQueue = rxBuf; |
Jonathan Austin |
1:8aa5cdb4ab67 | 189 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 190 | else |
Jonathan Austin |
1:8aa5cdb4ab67 | 191 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 192 | FrameBuffer *p = rxQueue; |
Jonathan Austin |
1:8aa5cdb4ab67 | 193 | while (p->next != NULL) |
Jonathan Austin |
1:8aa5cdb4ab67 | 194 | p = p->next; |
Jonathan Austin |
1:8aa5cdb4ab67 | 195 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 196 | p->next = rxBuf; |
Jonathan Austin |
1:8aa5cdb4ab67 | 197 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 198 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 199 | // Increase our received packet count |
Jonathan Austin |
1:8aa5cdb4ab67 | 200 | queueDepth++; |
Jonathan Austin |
1:8aa5cdb4ab67 | 201 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 202 | // Allocate a new buffer for the receiver hardware to use. the old on will be passed on to higher layer protocols/apps. |
Jonathan Austin |
1:8aa5cdb4ab67 | 203 | rxBuf = newRxBuf; |
Jonathan Austin |
1:8aa5cdb4ab67 | 204 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 205 | return MICROBIT_OK; |
Jonathan Austin |
1:8aa5cdb4ab67 | 206 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 207 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 208 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 209 | * Sets the RSSI for the most recent packet. |
Jonathan Austin |
1:8aa5cdb4ab67 | 210 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 211 | * @param rssi the new rssi value. |
Jonathan Austin |
1:8aa5cdb4ab67 | 212 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 213 | * @note should only be called from RADIO_IRQHandler... |
Jonathan Austin |
1:8aa5cdb4ab67 | 214 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 215 | int MicroBitRadio::setRSSI(uint8_t rssi) |
Jonathan Austin |
1:8aa5cdb4ab67 | 216 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 217 | if (!(status & MICROBIT_RADIO_STATUS_INITIALISED)) |
Jonathan Austin |
1:8aa5cdb4ab67 | 218 | return MICROBIT_NOT_SUPPORTED; |
Jonathan Austin |
1:8aa5cdb4ab67 | 219 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 220 | this->rssi = rssi; |
Jonathan Austin |
1:8aa5cdb4ab67 | 221 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 222 | return MICROBIT_OK; |
Jonathan Austin |
1:8aa5cdb4ab67 | 223 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 224 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 225 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 226 | * Retrieves the current RSSI for the most recent packet. |
Jonathan Austin |
1:8aa5cdb4ab67 | 227 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 228 | * @return the most recent RSSI value or MICROBIT_NOT_SUPPORTED if the BLE stack is running. |
Jonathan Austin |
1:8aa5cdb4ab67 | 229 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 230 | int MicroBitRadio::getRSSI() |
Jonathan Austin |
1:8aa5cdb4ab67 | 231 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 232 | if (!(status & MICROBIT_RADIO_STATUS_INITIALISED)) |
Jonathan Austin |
1:8aa5cdb4ab67 | 233 | return MICROBIT_NOT_SUPPORTED; |
Jonathan Austin |
1:8aa5cdb4ab67 | 234 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 235 | return this->rssi; |
Jonathan Austin |
1:8aa5cdb4ab67 | 236 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 237 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 238 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 239 | * Initialises the radio for use as a multipoint sender/receiver |
Jonathan Austin |
1:8aa5cdb4ab67 | 240 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 241 | * @return MICROBIT_OK on success, MICROBIT_NOT_SUPPORTED if the BLE stack is running. |
Jonathan Austin |
1:8aa5cdb4ab67 | 242 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 243 | int MicroBitRadio::enable() |
Jonathan Austin |
1:8aa5cdb4ab67 | 244 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 245 | // If the device is already initialised, then there's nothing to do. |
Jonathan Austin |
1:8aa5cdb4ab67 | 246 | if (status & MICROBIT_RADIO_STATUS_INITIALISED) |
Jonathan Austin |
1:8aa5cdb4ab67 | 247 | return MICROBIT_OK; |
Jonathan Austin |
1:8aa5cdb4ab67 | 248 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 249 | // Only attempt to enable this radio mode if BLE is disabled. |
Jonathan Austin |
1:8aa5cdb4ab67 | 250 | if (ble_running()) |
Jonathan Austin |
1:8aa5cdb4ab67 | 251 | return MICROBIT_NOT_SUPPORTED; |
Jonathan Austin |
1:8aa5cdb4ab67 | 252 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 253 | // If this is the first time we've been enable, allocate out receive buffers. |
Jonathan Austin |
1:8aa5cdb4ab67 | 254 | if (rxBuf == NULL) |
Jonathan Austin |
1:8aa5cdb4ab67 | 255 | rxBuf = new FrameBuffer(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 256 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 257 | if (rxBuf == NULL) |
Jonathan Austin |
1:8aa5cdb4ab67 | 258 | return MICROBIT_NO_RESOURCES; |
Jonathan Austin |
1:8aa5cdb4ab67 | 259 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 260 | // Enable the High Frequency clock on the processor. This is a pre-requisite for |
Jonathan Austin |
1:8aa5cdb4ab67 | 261 | // the RADIO module. Without this clock, no communication is possible. |
Jonathan Austin |
1:8aa5cdb4ab67 | 262 | NRF_CLOCK->EVENTS_HFCLKSTARTED = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 263 | NRF_CLOCK->TASKS_HFCLKSTART = 1; |
Jonathan Austin |
1:8aa5cdb4ab67 | 264 | while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0); |
Jonathan Austin |
1:8aa5cdb4ab67 | 265 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 266 | // Bring up the nrf51822 RADIO module in Nordic's proprietary 1MBps packet radio mode. |
Jonathan Austin |
1:8aa5cdb4ab67 | 267 | setTransmitPower(MICROBIT_RADIO_DEFAULT_TX_POWER); |
Jonathan Austin |
1:8aa5cdb4ab67 | 268 | setFrequencyBand(MICROBIT_RADIO_DEFAULT_FREQUENCY); |
Jonathan Austin |
1:8aa5cdb4ab67 | 269 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 270 | // Configure for 1Mbps throughput. |
Jonathan Austin |
1:8aa5cdb4ab67 | 271 | // This may sound excessive, but running a high data rates reduces the chances of collisions... |
Jonathan Austin |
1:8aa5cdb4ab67 | 272 | NRF_RADIO->MODE = RADIO_MODE_MODE_Nrf_1Mbit; |
Jonathan Austin |
1:8aa5cdb4ab67 | 273 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 274 | // Configure the addresses we use for this protocol. We run ANONYMOUSLY at the core. |
Jonathan Austin |
1:8aa5cdb4ab67 | 275 | // A 40 bit addresses is used. The first 32 bits match the ASCII character code for "uBit". |
Jonathan Austin |
1:8aa5cdb4ab67 | 276 | // Statistically, this provides assurance to avoid other similar 2.4GHz protocols that may be in the vicinity. |
Jonathan Austin |
1:8aa5cdb4ab67 | 277 | // We also map the assigned 8-bit GROUP id into the PREFIX field. This allows the RADIO hardware to perform |
Jonathan Austin |
1:8aa5cdb4ab67 | 278 | // address matching for us, and only generate an interrupt when a packet matching our group is received. |
Jonathan Austin |
1:8aa5cdb4ab67 | 279 | NRF_RADIO->BASE0 = MICROBIT_RADIO_BASE_ADDRESS; |
Jonathan Austin |
1:8aa5cdb4ab67 | 280 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 281 | // Join the default group. This will configure the remaining byte in the RADIO hardware module. |
Jonathan Austin |
1:8aa5cdb4ab67 | 282 | setGroup(MICROBIT_RADIO_DEFAULT_GROUP); |
Jonathan Austin |
1:8aa5cdb4ab67 | 283 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 284 | // The RADIO hardware module supports the use of multiple addresses, but as we're running anonymously, we only need one. |
Jonathan Austin |
1:8aa5cdb4ab67 | 285 | // Configure the RADIO module to use the default address (address 0) for both send and receive operations. |
Jonathan Austin |
1:8aa5cdb4ab67 | 286 | NRF_RADIO->TXADDRESS = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 287 | NRF_RADIO->RXADDRESSES = 1; |
Jonathan Austin |
1:8aa5cdb4ab67 | 288 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 289 | // Packet layout configuration. The nrf51822 has a highly capable and flexible RADIO module that, in addition to transmission |
Jonathan Austin |
1:8aa5cdb4ab67 | 290 | // and reception of data, also contains a LENGTH field, two optional additional 1 byte fields (S0 and S1) and a CRC calculation. |
Jonathan Austin |
1:8aa5cdb4ab67 | 291 | // Configure the packet format for a simple 8 bit length field and no additional fields. |
Jonathan Austin |
1:8aa5cdb4ab67 | 292 | NRF_RADIO->PCNF0 = 0x00000008; |
Jonathan Austin |
1:8aa5cdb4ab67 | 293 | NRF_RADIO->PCNF1 = 0x02040000 | MICROBIT_RADIO_MAX_PACKET_SIZE; |
Jonathan Austin |
1:8aa5cdb4ab67 | 294 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 295 | // Most communication channels contain some form of checksum - a mathematical calculation taken based on all the data |
Jonathan Austin |
1:8aa5cdb4ab67 | 296 | // in a packet, that is also sent as part of the packet. When received, this calculation can be repeated, and the results |
Jonathan Austin |
1:8aa5cdb4ab67 | 297 | // from the sender and receiver compared. If they are different, then some corruption of the data ahas happened in transit, |
Jonathan Austin |
1:8aa5cdb4ab67 | 298 | // and we know we can't trust it. The nrf51822 RADIO uses a CRC for this - a very effective checksum calculation. |
Jonathan Austin |
1:8aa5cdb4ab67 | 299 | // |
Jonathan Austin |
1:8aa5cdb4ab67 | 300 | // Enable automatic 16bit CRC generation and checking, and configure how the CRC is calculated. |
Jonathan Austin |
1:8aa5cdb4ab67 | 301 | NRF_RADIO->CRCCNF = RADIO_CRCCNF_LEN_Two; |
Jonathan Austin |
1:8aa5cdb4ab67 | 302 | NRF_RADIO->CRCINIT = 0xFFFF; |
Jonathan Austin |
1:8aa5cdb4ab67 | 303 | NRF_RADIO->CRCPOLY = 0x11021; |
Jonathan Austin |
1:8aa5cdb4ab67 | 304 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 305 | // Set the start random value of the data whitening algorithm. This can be any non zero number. |
Jonathan Austin |
1:8aa5cdb4ab67 | 306 | NRF_RADIO->DATAWHITEIV = 0x18; |
Jonathan Austin |
1:8aa5cdb4ab67 | 307 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 308 | // Set up the RADIO module to read and write from our internal buffer. |
Jonathan Austin |
1:8aa5cdb4ab67 | 309 | NRF_RADIO->PACKETPTR = (uint32_t)rxBuf; |
Jonathan Austin |
1:8aa5cdb4ab67 | 310 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 311 | // Configure the hardware to issue an interrupt whenever a task is complete (e.g. send/receive). |
Jonathan Austin |
1:8aa5cdb4ab67 | 312 | NRF_RADIO->INTENSET = 0x00000008; |
Jonathan Austin |
1:8aa5cdb4ab67 | 313 | NVIC_ClearPendingIRQ(RADIO_IRQn); |
Jonathan Austin |
1:8aa5cdb4ab67 | 314 | NVIC_EnableIRQ(RADIO_IRQn); |
Jonathan Austin |
1:8aa5cdb4ab67 | 315 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 316 | NRF_RADIO->SHORTS |= RADIO_SHORTS_ADDRESS_RSSISTART_Msk; |
Jonathan Austin |
1:8aa5cdb4ab67 | 317 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 318 | // Start listening for the next packet |
Jonathan Austin |
1:8aa5cdb4ab67 | 319 | NRF_RADIO->EVENTS_READY = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 320 | NRF_RADIO->TASKS_RXEN = 1; |
Jonathan Austin |
1:8aa5cdb4ab67 | 321 | while(NRF_RADIO->EVENTS_READY == 0); |
Jonathan Austin |
1:8aa5cdb4ab67 | 322 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 323 | NRF_RADIO->EVENTS_END = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 324 | NRF_RADIO->TASKS_START = 1; |
Jonathan Austin |
1:8aa5cdb4ab67 | 325 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 326 | // register ourselves for a callback event, in order to empty the receive queue. |
Jonathan Austin |
1:8aa5cdb4ab67 | 327 | fiber_add_idle_component(this); |
Jonathan Austin |
1:8aa5cdb4ab67 | 328 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 329 | // Done. Record that our RADIO is configured. |
Jonathan Austin |
1:8aa5cdb4ab67 | 330 | status |= MICROBIT_RADIO_STATUS_INITIALISED; |
Jonathan Austin |
1:8aa5cdb4ab67 | 331 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 332 | return MICROBIT_OK; |
Jonathan Austin |
1:8aa5cdb4ab67 | 333 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 334 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 335 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 336 | * Disables the radio for use as a multipoint sender/receiver. |
Jonathan Austin |
1:8aa5cdb4ab67 | 337 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 338 | * @return MICROBIT_OK on success, MICROBIT_NOT_SUPPORTED if the BLE stack is running. |
Jonathan Austin |
1:8aa5cdb4ab67 | 339 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 340 | int MicroBitRadio::disable() |
Jonathan Austin |
1:8aa5cdb4ab67 | 341 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 342 | // Only attempt to enable.disable the radio if the protocol is alreayd running. |
Jonathan Austin |
1:8aa5cdb4ab67 | 343 | if (ble_running()) |
Jonathan Austin |
1:8aa5cdb4ab67 | 344 | return MICROBIT_NOT_SUPPORTED; |
Jonathan Austin |
1:8aa5cdb4ab67 | 345 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 346 | if (!(status & MICROBIT_RADIO_STATUS_INITIALISED)) |
Jonathan Austin |
1:8aa5cdb4ab67 | 347 | return MICROBIT_OK; |
Jonathan Austin |
1:8aa5cdb4ab67 | 348 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 349 | // Disable interrupts and STOP any ongoing packet reception. |
Jonathan Austin |
1:8aa5cdb4ab67 | 350 | NVIC_DisableIRQ(RADIO_IRQn); |
Jonathan Austin |
1:8aa5cdb4ab67 | 351 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 352 | NRF_RADIO->EVENTS_DISABLED = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 353 | NRF_RADIO->TASKS_DISABLE = 1; |
Jonathan Austin |
1:8aa5cdb4ab67 | 354 | while(NRF_RADIO->EVENTS_DISABLED == 0); |
Jonathan Austin |
1:8aa5cdb4ab67 | 355 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 356 | // deregister ourselves from the callback event used to empty the receive queue. |
Jonathan Austin |
1:8aa5cdb4ab67 | 357 | fiber_remove_idle_component(this); |
Jonathan Austin |
1:8aa5cdb4ab67 | 358 | |
LancasterUniversity | 18:e2f92ac26450 | 359 | // record that the radio is now disabled |
LancasterUniversity | 18:e2f92ac26450 | 360 | status &= ~MICROBIT_RADIO_STATUS_INITIALISED; |
LancasterUniversity | 18:e2f92ac26450 | 361 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 362 | return MICROBIT_OK; |
Jonathan Austin |
1:8aa5cdb4ab67 | 363 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 364 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 365 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 366 | * Sets the radio to listen to packets sent with the given group id. |
Jonathan Austin |
1:8aa5cdb4ab67 | 367 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 368 | * @param group The group to join. A micro:bit can only listen to one group ID at any time. |
Jonathan Austin |
1:8aa5cdb4ab67 | 369 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 370 | * @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the BLE stack is running. |
Jonathan Austin |
1:8aa5cdb4ab67 | 371 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 372 | int MicroBitRadio::setGroup(uint8_t group) |
Jonathan Austin |
1:8aa5cdb4ab67 | 373 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 374 | if (ble_running()) |
Jonathan Austin |
1:8aa5cdb4ab67 | 375 | return MICROBIT_NOT_SUPPORTED; |
Jonathan Austin |
1:8aa5cdb4ab67 | 376 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 377 | // Record our group id locally |
Jonathan Austin |
1:8aa5cdb4ab67 | 378 | this->group = group; |
Jonathan Austin |
1:8aa5cdb4ab67 | 379 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 380 | // Also append it to the address of this device, to allow the RADIO module to filter for us. |
Jonathan Austin |
1:8aa5cdb4ab67 | 381 | NRF_RADIO->PREFIX0 = (uint32_t)group; |
Jonathan Austin |
1:8aa5cdb4ab67 | 382 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 383 | return MICROBIT_OK; |
Jonathan Austin |
1:8aa5cdb4ab67 | 384 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 385 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 386 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 387 | * A background, low priority callback that is triggered whenever the processor is idle. |
Jonathan Austin |
1:8aa5cdb4ab67 | 388 | * Here, we empty our queue of received packets, and pass them onto higher level protocol handlers. |
Jonathan Austin |
1:8aa5cdb4ab67 | 389 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 390 | void MicroBitRadio::idleTick() |
Jonathan Austin |
1:8aa5cdb4ab67 | 391 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 392 | // Walk the list of packets and process each one. |
Jonathan Austin |
1:8aa5cdb4ab67 | 393 | while(rxQueue) |
Jonathan Austin |
1:8aa5cdb4ab67 | 394 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 395 | FrameBuffer *p = rxQueue; |
Jonathan Austin |
1:8aa5cdb4ab67 | 396 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 397 | switch (p->protocol) |
Jonathan Austin |
1:8aa5cdb4ab67 | 398 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 399 | case MICROBIT_RADIO_PROTOCOL_DATAGRAM: |
Jonathan Austin |
1:8aa5cdb4ab67 | 400 | datagram.packetReceived(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 401 | break; |
Jonathan Austin |
1:8aa5cdb4ab67 | 402 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 403 | case MICROBIT_RADIO_PROTOCOL_EVENTBUS: |
Jonathan Austin |
1:8aa5cdb4ab67 | 404 | event.packetReceived(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 405 | break; |
Jonathan Austin |
1:8aa5cdb4ab67 | 406 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 407 | default: |
Jonathan Austin |
1:8aa5cdb4ab67 | 408 | MicroBitEvent(MICROBIT_ID_RADIO_DATA_READY, p->protocol); |
Jonathan Austin |
1:8aa5cdb4ab67 | 409 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 410 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 411 | // If the packet was processed, it will have been recv'd, and taken from the queue. |
Jonathan Austin |
1:8aa5cdb4ab67 | 412 | // If this was a packet for an unknown protocol, it will still be there, so simply free it. |
Jonathan Austin |
1:8aa5cdb4ab67 | 413 | if (p == rxQueue) |
Jonathan Austin |
1:8aa5cdb4ab67 | 414 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 415 | recv(); |
Jonathan Austin |
1:8aa5cdb4ab67 | 416 | delete p; |
Jonathan Austin |
1:8aa5cdb4ab67 | 417 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 418 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 419 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 420 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 421 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 422 | * Determines the number of packets ready to be processed. |
Jonathan Austin |
1:8aa5cdb4ab67 | 423 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 424 | * @return The number of packets in the receive buffer. |
Jonathan Austin |
1:8aa5cdb4ab67 | 425 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 426 | int MicroBitRadio::dataReady() |
Jonathan Austin |
1:8aa5cdb4ab67 | 427 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 428 | return queueDepth; |
Jonathan Austin |
1:8aa5cdb4ab67 | 429 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 430 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 431 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 432 | * Retrieves the next packet from the receive buffer. |
Jonathan Austin |
1:8aa5cdb4ab67 | 433 | * If a data packet is available, then it will be returned immediately to |
Jonathan Austin |
1:8aa5cdb4ab67 | 434 | * the caller. This call will also dequeue the buffer. |
Jonathan Austin |
1:8aa5cdb4ab67 | 435 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 436 | * @return The buffer containing the the packet. If no data is available, NULL is returned. |
Jonathan Austin |
1:8aa5cdb4ab67 | 437 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 438 | * @note Once recv() has been called, it is the callers resposibility to |
Jonathan Austin |
1:8aa5cdb4ab67 | 439 | * delete the buffer when appropriate. |
Jonathan Austin |
1:8aa5cdb4ab67 | 440 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 441 | FrameBuffer* MicroBitRadio::recv() |
Jonathan Austin |
1:8aa5cdb4ab67 | 442 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 443 | FrameBuffer *p = rxQueue; |
Jonathan Austin |
1:8aa5cdb4ab67 | 444 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 445 | if (p) |
Jonathan Austin |
1:8aa5cdb4ab67 | 446 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 447 | rxQueue = rxQueue->next; |
Jonathan Austin |
1:8aa5cdb4ab67 | 448 | queueDepth--; |
Jonathan Austin |
1:8aa5cdb4ab67 | 449 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 450 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 451 | return p; |
Jonathan Austin |
1:8aa5cdb4ab67 | 452 | } |
Jonathan Austin |
1:8aa5cdb4ab67 | 453 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 454 | /** |
Jonathan Austin |
1:8aa5cdb4ab67 | 455 | * Transmits the given buffer onto the broadcast radio. |
Jonathan Austin |
1:8aa5cdb4ab67 | 456 | * The call will wait until the transmission of the packet has completed before returning. |
Jonathan Austin |
1:8aa5cdb4ab67 | 457 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 458 | * @param data The packet contents to transmit. |
Jonathan Austin |
1:8aa5cdb4ab67 | 459 | * |
Jonathan Austin |
1:8aa5cdb4ab67 | 460 | * @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the BLE stack is running. |
Jonathan Austin |
1:8aa5cdb4ab67 | 461 | */ |
Jonathan Austin |
1:8aa5cdb4ab67 | 462 | int MicroBitRadio::send(FrameBuffer *buffer) |
Jonathan Austin |
1:8aa5cdb4ab67 | 463 | { |
Jonathan Austin |
1:8aa5cdb4ab67 | 464 | if (ble_running()) |
Jonathan Austin |
1:8aa5cdb4ab67 | 465 | return MICROBIT_NOT_SUPPORTED; |
Jonathan Austin |
1:8aa5cdb4ab67 | 466 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 467 | if (buffer == NULL) |
Jonathan Austin |
1:8aa5cdb4ab67 | 468 | return MICROBIT_INVALID_PARAMETER; |
Jonathan Austin |
1:8aa5cdb4ab67 | 469 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 470 | if (buffer->length > MICROBIT_RADIO_MAX_PACKET_SIZE + MICROBIT_RADIO_HEADER_SIZE - 1) |
Jonathan Austin |
1:8aa5cdb4ab67 | 471 | return MICROBIT_INVALID_PARAMETER; |
Jonathan Austin |
1:8aa5cdb4ab67 | 472 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 473 | // Firstly, disable the Radio interrupt. We want to wait until the trasmission completes. |
Jonathan Austin |
1:8aa5cdb4ab67 | 474 | NVIC_DisableIRQ(RADIO_IRQn); |
Jonathan Austin |
1:8aa5cdb4ab67 | 475 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 476 | // Turn off the transceiver. |
Jonathan Austin |
1:8aa5cdb4ab67 | 477 | NRF_RADIO->EVENTS_DISABLED = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 478 | NRF_RADIO->TASKS_DISABLE = 1; |
Jonathan Austin |
1:8aa5cdb4ab67 | 479 | while(NRF_RADIO->EVENTS_DISABLED == 0); |
Jonathan Austin |
1:8aa5cdb4ab67 | 480 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 481 | // Configure the radio to send the buffer provided. |
Jonathan Austin |
1:8aa5cdb4ab67 | 482 | NRF_RADIO->PACKETPTR = (uint32_t) buffer; |
Jonathan Austin |
1:8aa5cdb4ab67 | 483 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 484 | // Turn on the transmitter, and wait for it to signal that it's ready to use. |
Jonathan Austin |
1:8aa5cdb4ab67 | 485 | NRF_RADIO->EVENTS_READY = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 486 | NRF_RADIO->TASKS_TXEN = 1; |
Jonathan Austin |
1:8aa5cdb4ab67 | 487 | while (NRF_RADIO->EVENTS_READY == 0); |
Jonathan Austin |
1:8aa5cdb4ab67 | 488 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 489 | // Start transmission and wait for end of packet. |
Jonathan Austin |
1:8aa5cdb4ab67 | 490 | NRF_RADIO->TASKS_START = 1; |
Jonathan Austin |
1:8aa5cdb4ab67 | 491 | NRF_RADIO->EVENTS_END = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 492 | while(NRF_RADIO->EVENTS_END == 0); |
Jonathan Austin |
1:8aa5cdb4ab67 | 493 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 494 | // Return the radio to using the default receive buffer |
Jonathan Austin |
1:8aa5cdb4ab67 | 495 | NRF_RADIO->PACKETPTR = (uint32_t) rxBuf; |
Jonathan Austin |
1:8aa5cdb4ab67 | 496 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 497 | // Turn off the transmitter. |
Jonathan Austin |
1:8aa5cdb4ab67 | 498 | NRF_RADIO->EVENTS_DISABLED = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 499 | NRF_RADIO->TASKS_DISABLE = 1; |
Jonathan Austin |
1:8aa5cdb4ab67 | 500 | while(NRF_RADIO->EVENTS_DISABLED == 0); |
Jonathan Austin |
1:8aa5cdb4ab67 | 501 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 502 | // Start listening for the next packet |
Jonathan Austin |
1:8aa5cdb4ab67 | 503 | NRF_RADIO->EVENTS_READY = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 504 | NRF_RADIO->TASKS_RXEN = 1; |
Jonathan Austin |
1:8aa5cdb4ab67 | 505 | while(NRF_RADIO->EVENTS_READY == 0); |
Jonathan Austin |
1:8aa5cdb4ab67 | 506 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 507 | NRF_RADIO->EVENTS_END = 0; |
Jonathan Austin |
1:8aa5cdb4ab67 | 508 | NRF_RADIO->TASKS_START = 1; |
Jonathan Austin |
1:8aa5cdb4ab67 | 509 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 510 | // Re-enable the Radio interrupt. |
Jonathan Austin |
1:8aa5cdb4ab67 | 511 | NVIC_ClearPendingIRQ(RADIO_IRQn); |
Jonathan Austin |
1:8aa5cdb4ab67 | 512 | NVIC_EnableIRQ(RADIO_IRQn); |
Jonathan Austin |
1:8aa5cdb4ab67 | 513 | |
Jonathan Austin |
1:8aa5cdb4ab67 | 514 | return MICROBIT_OK; |
LancasterUniversity | 18:e2f92ac26450 | 515 | } |