Forked to avoid changing the publioc repo
Dependencies: BLE_API mbed-dev-bin nRF51822
Fork of microbit-dal by
source/drivers/MicroBitRadio.cpp@22:23d7b9a4b082, 2016-07-13 (annotated)
- Committer:
- LancasterUniversity
- Date:
- Wed Jul 13 12:17:54 2016 +0100
- Revision:
- 22:23d7b9a4b082
- Parent:
- 21:cab56b701601
- Child:
- 23:6055f6c19fa6
Synchronized with git rev 7cf98c22
Author: James Devine
microbit-dal: patch for fiber_wake_on_event
fiber_wake_on_event used to crash after forking a FOB fiber.
It would attempt to obtain a new fiber context, and would place it on the wait queue.
Then when that fiber was paged in, the context of that fiber would not have been
initialised, as the function presumed schedule would be called immediately after
fiber initialisation.
This patch catches that edge case.
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; |
LancasterUniversity | 22:23d7b9a4b082 | 102 | this->group = MICROBIT_RADIO_DEFAULT_GROUP; |
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. |
LancasterUniversity | 22:23d7b9a4b082 | 282 | setGroup(this->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 | 22:23d7b9a4b082 | 359 | // record that the radio is now disabled |
LancasterUniversity | 22:23d7b9a4b082 | 360 | status &= ~MICROBIT_RADIO_STATUS_INITIALISED; |
LancasterUniversity | 22:23d7b9a4b082 | 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 | } |