Revised to disable BLE for radio communication as needed.

Dependencies:   BLE_API nRF51822 mbed-dev-bin

Dependents:   microbit

Committer:
tsfarber
Date:
Tue Nov 26 04:12:46 2019 +0000
Revision:
74:26717338739d
Parent:
41:da05ec75cd5d
This program combines samples programs radio TX and radio RX so that both units can send or receive depending on which unit's buttons are pressed. Tested successfully. MicroBitConfig.h has been edited to disable BLE.

Who changed what in which revision?

UserRevisionLine numberNew 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 /**
Jonathan Austin 1:8aa5cdb4ab67 27 * Class definition for the MicroBitMessageBus.
Jonathan Austin 1:8aa5cdb4ab67 28 *
Jonathan Austin 1:8aa5cdb4ab67 29 * The MicroBitMessageBus is the common mechanism to deliver asynchronous events on the
Jonathan Austin 1:8aa5cdb4ab67 30 * MicroBit platform. It serves a number of purposes:
Jonathan Austin 1:8aa5cdb4ab67 31 *
Jonathan Austin 1:8aa5cdb4ab67 32 * 1) It provides an eventing abstraction that is independent of the underlying substrate.
Jonathan Austin 1:8aa5cdb4ab67 33 *
Jonathan Austin 1:8aa5cdb4ab67 34 * 2) It provides a mechanism to decouple user code from trusted system code
Jonathan Austin 1:8aa5cdb4ab67 35 * i.e. the basis of a message passing nano kernel.
Jonathan Austin 1:8aa5cdb4ab67 36 *
Jonathan Austin 1:8aa5cdb4ab67 37 * 3) It allows a common high level eventing abstraction across a range of hardware types.e.g. buttons, BLE...
Jonathan Austin 1:8aa5cdb4ab67 38 *
Jonathan Austin 1:8aa5cdb4ab67 39 * 4) It provides a mechanim for extensibility - new devices added via I/O pins can have OO based
Jonathan Austin 1:8aa5cdb4ab67 40 * drivers and communicate via the message bus with minima impact on user level languages.
Jonathan Austin 1:8aa5cdb4ab67 41 *
Jonathan Austin 1:8aa5cdb4ab67 42 * 5) It allows for the possiblility of event / data aggregation, which in turn can save energy.
Jonathan Austin 1:8aa5cdb4ab67 43 *
Jonathan Austin 1:8aa5cdb4ab67 44 * It has the following design principles:
Jonathan Austin 1:8aa5cdb4ab67 45 *
Jonathan Austin 1:8aa5cdb4ab67 46 * 1) Maintain a low RAM footprint where possible
Jonathan Austin 1:8aa5cdb4ab67 47 *
Jonathan Austin 1:8aa5cdb4ab67 48 * 2) Make few assumptions about the underlying platform, but allow optimizations where possible.
Jonathan Austin 1:8aa5cdb4ab67 49 */
Jonathan Austin 1:8aa5cdb4ab67 50 #include "MicroBitConfig.h"
Jonathan Austin 1:8aa5cdb4ab67 51 #include "MicroBitMessageBus.h"
Jonathan Austin 1:8aa5cdb4ab67 52 #include "MicroBitFiber.h"
Jonathan Austin 1:8aa5cdb4ab67 53 #include "ErrorNo.h"
Jonathan Austin 1:8aa5cdb4ab67 54
Jonathan Austin 1:8aa5cdb4ab67 55 /**
Jonathan Austin 1:8aa5cdb4ab67 56 * Default constructor.
Jonathan Austin 1:8aa5cdb4ab67 57 *
Jonathan Austin 1:8aa5cdb4ab67 58 * Adds itself as a fiber component, and also configures itself to be the
Jonathan Austin 1:8aa5cdb4ab67 59 * default EventModel if defaultEventBus is NULL.
Jonathan Austin 1:8aa5cdb4ab67 60 */
Jonathan Austin 1:8aa5cdb4ab67 61 MicroBitMessageBus::MicroBitMessageBus()
Jonathan Austin 1:8aa5cdb4ab67 62 {
Jonathan Austin 1:8aa5cdb4ab67 63 this->listeners = NULL;
Jonathan Austin 1:8aa5cdb4ab67 64 this->evt_queue_head = NULL;
Jonathan Austin 1:8aa5cdb4ab67 65 this->evt_queue_tail = NULL;
Jonathan Austin 1:8aa5cdb4ab67 66 this->queueLength = 0;
Jonathan Austin 1:8aa5cdb4ab67 67
Jonathan Austin 1:8aa5cdb4ab67 68 fiber_add_idle_component(this);
Jonathan Austin 1:8aa5cdb4ab67 69
Jonathan Austin 1:8aa5cdb4ab67 70 if(EventModel::defaultEventBus == NULL)
Jonathan Austin 1:8aa5cdb4ab67 71 EventModel::defaultEventBus = this;
Jonathan Austin 1:8aa5cdb4ab67 72 }
Jonathan Austin 1:8aa5cdb4ab67 73
Jonathan Austin 1:8aa5cdb4ab67 74 /**
Jonathan Austin 1:8aa5cdb4ab67 75 * Invokes a callback on a given MicroBitListener
Jonathan Austin 1:8aa5cdb4ab67 76 *
Jonathan Austin 1:8aa5cdb4ab67 77 * Internal wrapper function, used to enable
Jonathan Austin 1:8aa5cdb4ab67 78 * parameterised callbacks through the fiber scheduler.
Jonathan Austin 1:8aa5cdb4ab67 79 */
Jonathan Austin 1:8aa5cdb4ab67 80 void async_callback(void *param)
Jonathan Austin 1:8aa5cdb4ab67 81 {
Jonathan Austin 1:8aa5cdb4ab67 82 MicroBitListener *listener = (MicroBitListener *)param;
Jonathan Austin 1:8aa5cdb4ab67 83
Jonathan Austin 1:8aa5cdb4ab67 84 // OK, now we need to decide how to behave depending on our configuration.
Jonathan Austin 1:8aa5cdb4ab67 85 // If this a fiber f already active within this listener then check our
Jonathan Austin 1:8aa5cdb4ab67 86 // configuration to determine the correct course of action.
Jonathan Austin 1:8aa5cdb4ab67 87 //
Jonathan Austin 1:8aa5cdb4ab67 88
Jonathan Austin 1:8aa5cdb4ab67 89 if (listener->flags & MESSAGE_BUS_LISTENER_BUSY)
Jonathan Austin 1:8aa5cdb4ab67 90 {
Jonathan Austin 1:8aa5cdb4ab67 91 // Drop this event, if that's how we've been configured.
Jonathan Austin 1:8aa5cdb4ab67 92 if (listener->flags & MESSAGE_BUS_LISTENER_DROP_IF_BUSY)
Jonathan Austin 1:8aa5cdb4ab67 93 return;
Jonathan Austin 1:8aa5cdb4ab67 94
Jonathan Austin 1:8aa5cdb4ab67 95 // Queue this event up for later, if that's how we've been configured.
Jonathan Austin 1:8aa5cdb4ab67 96 if (listener->flags & MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY)
Jonathan Austin 1:8aa5cdb4ab67 97 {
Jonathan Austin 1:8aa5cdb4ab67 98 listener->queue(listener->evt);
Jonathan Austin 1:8aa5cdb4ab67 99 return;
Jonathan Austin 1:8aa5cdb4ab67 100 }
Jonathan Austin 1:8aa5cdb4ab67 101 }
Jonathan Austin 1:8aa5cdb4ab67 102
Jonathan Austin 1:8aa5cdb4ab67 103 // Determine the calling convention for the callback, and invoke...
Jonathan Austin 1:8aa5cdb4ab67 104 // C++ is really bad at this! Especially as the ARM compiler is yet to support C++ 11 :-/
Jonathan Austin 1:8aa5cdb4ab67 105
Jonathan Austin 1:8aa5cdb4ab67 106 // Record that we have a fiber going into this listener...
Jonathan Austin 1:8aa5cdb4ab67 107 listener->flags |= MESSAGE_BUS_LISTENER_BUSY;
Jonathan Austin 1:8aa5cdb4ab67 108
Jonathan Austin 1:8aa5cdb4ab67 109 while (1)
Jonathan Austin 1:8aa5cdb4ab67 110 {
Jonathan Austin 1:8aa5cdb4ab67 111 // Firstly, check for a method callback into an object.
Jonathan Austin 1:8aa5cdb4ab67 112 if (listener->flags & MESSAGE_BUS_LISTENER_METHOD)
Jonathan Austin 1:8aa5cdb4ab67 113 listener->cb_method->fire(listener->evt);
Jonathan Austin 1:8aa5cdb4ab67 114
Jonathan Austin 1:8aa5cdb4ab67 115 // Now a parameterised C function
Jonathan Austin 1:8aa5cdb4ab67 116 else if (listener->flags & MESSAGE_BUS_LISTENER_PARAMETERISED)
Jonathan Austin 1:8aa5cdb4ab67 117 listener->cb_param(listener->evt, listener->cb_arg);
Jonathan Austin 1:8aa5cdb4ab67 118
Jonathan Austin 1:8aa5cdb4ab67 119 // We must have a plain C function
Jonathan Austin 1:8aa5cdb4ab67 120 else
Jonathan Austin 1:8aa5cdb4ab67 121 listener->cb(listener->evt);
Jonathan Austin 1:8aa5cdb4ab67 122
Jonathan Austin 1:8aa5cdb4ab67 123 // If there are more events to process, dequeue the next one and process it.
Jonathan Austin 1:8aa5cdb4ab67 124 if ((listener->flags & MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY) && listener->evt_queue)
Jonathan Austin 1:8aa5cdb4ab67 125 {
Jonathan Austin 1:8aa5cdb4ab67 126 MicroBitEventQueueItem *item = listener->evt_queue;
Jonathan Austin 1:8aa5cdb4ab67 127
Jonathan Austin 1:8aa5cdb4ab67 128 listener->evt = item->evt;
Jonathan Austin 1:8aa5cdb4ab67 129 listener->evt_queue = listener->evt_queue->next;
Jonathan Austin 1:8aa5cdb4ab67 130 delete item;
Jonathan Austin 1:8aa5cdb4ab67 131
Jonathan Austin 1:8aa5cdb4ab67 132 // We spin the scheduler here, to preven any particular event handler from continuously holding onto resources.
Jonathan Austin 1:8aa5cdb4ab67 133 schedule();
Jonathan Austin 1:8aa5cdb4ab67 134 }
Jonathan Austin 1:8aa5cdb4ab67 135 else
Jonathan Austin 1:8aa5cdb4ab67 136 break;
Jonathan Austin 1:8aa5cdb4ab67 137 }
Jonathan Austin 1:8aa5cdb4ab67 138
Jonathan Austin 1:8aa5cdb4ab67 139 // The fiber of exiting... clear our state.
Jonathan Austin 1:8aa5cdb4ab67 140 listener->flags &= ~MESSAGE_BUS_LISTENER_BUSY;
Jonathan Austin 1:8aa5cdb4ab67 141 }
Jonathan Austin 1:8aa5cdb4ab67 142
Jonathan Austin 1:8aa5cdb4ab67 143 /**
Jonathan Austin 1:8aa5cdb4ab67 144 * Queue the given event for processing at a later time.
Jonathan Austin 1:8aa5cdb4ab67 145 * Add the given event at the tail of our queue.
Jonathan Austin 1:8aa5cdb4ab67 146 *
Jonathan Austin 1:8aa5cdb4ab67 147 * @param The event to queue.
Jonathan Austin 1:8aa5cdb4ab67 148 */
Jonathan Austin 1:8aa5cdb4ab67 149 void MicroBitMessageBus::queueEvent(MicroBitEvent &evt)
Jonathan Austin 1:8aa5cdb4ab67 150 {
Jonathan Austin 1:8aa5cdb4ab67 151 int processingComplete;
Jonathan Austin 1:8aa5cdb4ab67 152
Jonathan Austin 1:8aa5cdb4ab67 153 MicroBitEventQueueItem *prev = evt_queue_tail;
Jonathan Austin 1:8aa5cdb4ab67 154
Jonathan Austin 1:8aa5cdb4ab67 155 // Now process all handler regsitered as URGENT.
Jonathan Austin 1:8aa5cdb4ab67 156 // These pre-empt the queue, and are useful for fast, high priority services.
Jonathan Austin 1:8aa5cdb4ab67 157 processingComplete = this->process(evt, true);
Jonathan Austin 1:8aa5cdb4ab67 158
Jonathan Austin 1:8aa5cdb4ab67 159 // If we've already processed all event handlers, we're all done.
Jonathan Austin 1:8aa5cdb4ab67 160 // No need to queue the event.
Jonathan Austin 1:8aa5cdb4ab67 161 if (processingComplete)
Jonathan Austin 1:8aa5cdb4ab67 162 return;
Jonathan Austin 1:8aa5cdb4ab67 163
Jonathan Austin 1:8aa5cdb4ab67 164 // If we need to queue, but there is no space, then there's nothg we can do.
Jonathan Austin 1:8aa5cdb4ab67 165 if (queueLength >= MESSAGE_BUS_LISTENER_MAX_QUEUE_DEPTH)
Jonathan Austin 1:8aa5cdb4ab67 166 return;
Jonathan Austin 1:8aa5cdb4ab67 167
Jonathan Austin 1:8aa5cdb4ab67 168 // Otherwise, we need to queue this event for later processing...
Jonathan Austin 1:8aa5cdb4ab67 169 // We queue this event at the tail of the queue at the point where we entered queueEvent()
Jonathan Austin 1:8aa5cdb4ab67 170 // This is important as the processing above *may* have generated further events, and
Jonathan Austin 1:8aa5cdb4ab67 171 // we want to maintain ordering of events.
Jonathan Austin 1:8aa5cdb4ab67 172 MicroBitEventQueueItem *item = new MicroBitEventQueueItem(evt);
Jonathan Austin 1:8aa5cdb4ab67 173
Jonathan Austin 1:8aa5cdb4ab67 174 // The queue was empty when we entered this function, so queue our event at the start of the queue.
Jonathan Austin 1:8aa5cdb4ab67 175 __disable_irq();
Jonathan Austin 1:8aa5cdb4ab67 176
Jonathan Austin 1:8aa5cdb4ab67 177 if (prev == NULL)
Jonathan Austin 1:8aa5cdb4ab67 178 {
Jonathan Austin 1:8aa5cdb4ab67 179 item->next = evt_queue_head;
Jonathan Austin 1:8aa5cdb4ab67 180 evt_queue_head = item;
Jonathan Austin 1:8aa5cdb4ab67 181 }
Jonathan Austin 1:8aa5cdb4ab67 182 else
Jonathan Austin 1:8aa5cdb4ab67 183 {
Jonathan Austin 1:8aa5cdb4ab67 184 item->next = prev->next;
Jonathan Austin 1:8aa5cdb4ab67 185 prev->next = item;
Jonathan Austin 1:8aa5cdb4ab67 186 }
Jonathan Austin 1:8aa5cdb4ab67 187
Jonathan Austin 1:8aa5cdb4ab67 188 if (item->next == NULL)
Jonathan Austin 1:8aa5cdb4ab67 189 evt_queue_tail = item;
Jonathan Austin 1:8aa5cdb4ab67 190
Jonathan Austin 1:8aa5cdb4ab67 191 queueLength++;
Jonathan Austin 1:8aa5cdb4ab67 192
Jonathan Austin 1:8aa5cdb4ab67 193 __enable_irq();
Jonathan Austin 1:8aa5cdb4ab67 194 }
Jonathan Austin 1:8aa5cdb4ab67 195
Jonathan Austin 1:8aa5cdb4ab67 196 /**
Jonathan Austin 1:8aa5cdb4ab67 197 * Extract the next event from the front of the event queue (if present).
Jonathan Austin 1:8aa5cdb4ab67 198 *
Jonathan Austin 1:8aa5cdb4ab67 199 * @return a pointer to the MicroBitEventQueueItem that is at the head of the list.
Jonathan Austin 1:8aa5cdb4ab67 200 */
Jonathan Austin 1:8aa5cdb4ab67 201 MicroBitEventQueueItem* MicroBitMessageBus::dequeueEvent()
Jonathan Austin 1:8aa5cdb4ab67 202 {
Jonathan Austin 1:8aa5cdb4ab67 203 MicroBitEventQueueItem *item = NULL;
Jonathan Austin 1:8aa5cdb4ab67 204
Jonathan Austin 1:8aa5cdb4ab67 205 __disable_irq();
Jonathan Austin 1:8aa5cdb4ab67 206
Jonathan Austin 1:8aa5cdb4ab67 207 if (evt_queue_head != NULL)
Jonathan Austin 1:8aa5cdb4ab67 208 {
Jonathan Austin 1:8aa5cdb4ab67 209 item = evt_queue_head;
Jonathan Austin 1:8aa5cdb4ab67 210 evt_queue_head = item->next;
Jonathan Austin 1:8aa5cdb4ab67 211
Jonathan Austin 1:8aa5cdb4ab67 212 if (evt_queue_head == NULL)
Jonathan Austin 1:8aa5cdb4ab67 213 evt_queue_tail = NULL;
Jonathan Austin 1:8aa5cdb4ab67 214
Jonathan Austin 1:8aa5cdb4ab67 215 queueLength--;
Jonathan Austin 1:8aa5cdb4ab67 216 }
Jonathan Austin 1:8aa5cdb4ab67 217
Jonathan Austin 1:8aa5cdb4ab67 218 __enable_irq();
Jonathan Austin 1:8aa5cdb4ab67 219
Jonathan Austin 1:8aa5cdb4ab67 220
Jonathan Austin 1:8aa5cdb4ab67 221 return item;
Jonathan Austin 1:8aa5cdb4ab67 222 }
Jonathan Austin 1:8aa5cdb4ab67 223
Jonathan Austin 1:8aa5cdb4ab67 224 /**
Jonathan Austin 1:8aa5cdb4ab67 225 * Cleanup any MicroBitListeners marked for deletion from the list.
Jonathan Austin 1:8aa5cdb4ab67 226 *
Jonathan Austin 1:8aa5cdb4ab67 227 * @return The number of listeners removed from the list.
Jonathan Austin 1:8aa5cdb4ab67 228 */
Jonathan Austin 1:8aa5cdb4ab67 229 int MicroBitMessageBus::deleteMarkedListeners()
Jonathan Austin 1:8aa5cdb4ab67 230 {
Jonathan Austin 1:8aa5cdb4ab67 231 MicroBitListener *l, *p;
Jonathan Austin 1:8aa5cdb4ab67 232 int removed = 0;
Jonathan Austin 1:8aa5cdb4ab67 233
Jonathan Austin 1:8aa5cdb4ab67 234 l = listeners;
Jonathan Austin 1:8aa5cdb4ab67 235 p = NULL;
Jonathan Austin 1:8aa5cdb4ab67 236
Jonathan Austin 1:8aa5cdb4ab67 237 // Walk this list of event handlers. Delete any that match the given listener.
Jonathan Austin 1:8aa5cdb4ab67 238 while (l != NULL)
Jonathan Austin 1:8aa5cdb4ab67 239 {
LancasterUniversity 37:b624ae5e94a5 240 if ((l->flags & MESSAGE_BUS_LISTENER_DELETING) && !(l->flags & MESSAGE_BUS_LISTENER_BUSY))
Jonathan Austin 1:8aa5cdb4ab67 241 {
Jonathan Austin 1:8aa5cdb4ab67 242 if (p == NULL)
Jonathan Austin 1:8aa5cdb4ab67 243 listeners = l->next;
Jonathan Austin 1:8aa5cdb4ab67 244 else
Jonathan Austin 1:8aa5cdb4ab67 245 p->next = l->next;
Jonathan Austin 1:8aa5cdb4ab67 246
Jonathan Austin 1:8aa5cdb4ab67 247 // delete the listener.
Jonathan Austin 1:8aa5cdb4ab67 248 MicroBitListener *t = l;
Jonathan Austin 1:8aa5cdb4ab67 249 l = l->next;
Jonathan Austin 1:8aa5cdb4ab67 250
Jonathan Austin 1:8aa5cdb4ab67 251 delete t;
Jonathan Austin 1:8aa5cdb4ab67 252 removed++;
Jonathan Austin 1:8aa5cdb4ab67 253
Jonathan Austin 1:8aa5cdb4ab67 254 continue;
Jonathan Austin 1:8aa5cdb4ab67 255 }
Jonathan Austin 1:8aa5cdb4ab67 256
Jonathan Austin 1:8aa5cdb4ab67 257 p = l;
Jonathan Austin 1:8aa5cdb4ab67 258 l = l->next;
Jonathan Austin 1:8aa5cdb4ab67 259 }
Jonathan Austin 1:8aa5cdb4ab67 260
Jonathan Austin 1:8aa5cdb4ab67 261 return removed;
Jonathan Austin 1:8aa5cdb4ab67 262 }
Jonathan Austin 1:8aa5cdb4ab67 263
Jonathan Austin 1:8aa5cdb4ab67 264 /**
Jonathan Austin 1:8aa5cdb4ab67 265 * Periodic callback from MicroBit.
Jonathan Austin 1:8aa5cdb4ab67 266 *
Jonathan Austin 1:8aa5cdb4ab67 267 * Process at least one event from the event queue, if it is not empty.
Jonathan Austin 1:8aa5cdb4ab67 268 * We then continue processing events until something appears on the runqueue.
Jonathan Austin 1:8aa5cdb4ab67 269 */
Jonathan Austin 1:8aa5cdb4ab67 270 void MicroBitMessageBus::idleTick()
Jonathan Austin 1:8aa5cdb4ab67 271 {
Jonathan Austin 1:8aa5cdb4ab67 272 // Clear out any listeners marked for deletion
Jonathan Austin 1:8aa5cdb4ab67 273 this->deleteMarkedListeners();
Jonathan Austin 1:8aa5cdb4ab67 274
Jonathan Austin 1:8aa5cdb4ab67 275 MicroBitEventQueueItem *item = this->dequeueEvent();
Jonathan Austin 1:8aa5cdb4ab67 276
Jonathan Austin 1:8aa5cdb4ab67 277 // Whilst there are events to process and we have no useful other work to do, pull them off the queue and process them.
Jonathan Austin 1:8aa5cdb4ab67 278 while (item)
Jonathan Austin 1:8aa5cdb4ab67 279 {
Jonathan Austin 1:8aa5cdb4ab67 280 // send the event to all standard event listeners.
Jonathan Austin 1:8aa5cdb4ab67 281 this->process(item->evt);
Jonathan Austin 1:8aa5cdb4ab67 282
Jonathan Austin 1:8aa5cdb4ab67 283 // Free the queue item.
Jonathan Austin 1:8aa5cdb4ab67 284 delete item;
Jonathan Austin 1:8aa5cdb4ab67 285
Jonathan Austin 1:8aa5cdb4ab67 286 // If we have created some useful work to do, we stop processing.
Jonathan Austin 1:8aa5cdb4ab67 287 // This helps to minimise the number of blocked fibers we create at any point in time, therefore
Jonathan Austin 1:8aa5cdb4ab67 288 // also reducing the RAM footprint.
Jonathan Austin 1:8aa5cdb4ab67 289 if(!scheduler_runqueue_empty())
Jonathan Austin 1:8aa5cdb4ab67 290 break;
Jonathan Austin 1:8aa5cdb4ab67 291
Jonathan Austin 1:8aa5cdb4ab67 292 // Pull the next event to process, if there is one.
Jonathan Austin 1:8aa5cdb4ab67 293 item = this->dequeueEvent();
Jonathan Austin 1:8aa5cdb4ab67 294 }
Jonathan Austin 1:8aa5cdb4ab67 295 }
Jonathan Austin 1:8aa5cdb4ab67 296
Jonathan Austin 1:8aa5cdb4ab67 297 /**
Jonathan Austin 1:8aa5cdb4ab67 298 * Queues the given event to be sent to all registered recipients.
Jonathan Austin 1:8aa5cdb4ab67 299 *
Jonathan Austin 1:8aa5cdb4ab67 300 * @param evt The event to send.
Jonathan Austin 1:8aa5cdb4ab67 301 *
Jonathan Austin 1:8aa5cdb4ab67 302 * @code
Jonathan Austin 1:8aa5cdb4ab67 303 * MicroBitMessageBus bus;
Jonathan Austin 1:8aa5cdb4ab67 304 *
Jonathan Austin 1:8aa5cdb4ab67 305 * // Creates and sends the MicroBitEvent using bus.
Jonathan Austin 1:8aa5cdb4ab67 306 * MicrobitEvent evt(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK);
Jonathan Austin 1:8aa5cdb4ab67 307 *
Jonathan Austin 1:8aa5cdb4ab67 308 * // Creates the MicrobitEvent, but delays the sending of that event.
Jonathan Austin 1:8aa5cdb4ab67 309 * MicrobitEvent evt1(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, CREATE_ONLY);
Jonathan Austin 1:8aa5cdb4ab67 310 *
Jonathan Austin 1:8aa5cdb4ab67 311 * bus.send(evt1);
Jonathan Austin 1:8aa5cdb4ab67 312 *
Jonathan Austin 1:8aa5cdb4ab67 313 * // This has the same effect!
Jonathan Austin 1:8aa5cdb4ab67 314 * evt1.fire()
Jonathan Austin 1:8aa5cdb4ab67 315 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 316 */
Jonathan Austin 1:8aa5cdb4ab67 317 int MicroBitMessageBus::send(MicroBitEvent evt)
Jonathan Austin 1:8aa5cdb4ab67 318 {
Jonathan Austin 1:8aa5cdb4ab67 319 // We simply queue processing of the event until we're scheduled in normal thread context.
Jonathan Austin 1:8aa5cdb4ab67 320 // We do this to avoid the possibility of executing event handler code in IRQ context, which may bring
Jonathan Austin 1:8aa5cdb4ab67 321 // hidden race conditions to kids code. Queuing all events ensures causal ordering (total ordering in fact).
Jonathan Austin 1:8aa5cdb4ab67 322 this->queueEvent(evt);
Jonathan Austin 1:8aa5cdb4ab67 323 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 324 }
Jonathan Austin 1:8aa5cdb4ab67 325
Jonathan Austin 1:8aa5cdb4ab67 326 /**
Jonathan Austin 1:8aa5cdb4ab67 327 * Internal function, used to deliver the given event to all relevant recipients.
Jonathan Austin 1:8aa5cdb4ab67 328 * Normally, this is called once an event has been removed from the event queue.
Jonathan Austin 1:8aa5cdb4ab67 329 *
Jonathan Austin 1:8aa5cdb4ab67 330 * @param evt The event to send.
Jonathan Austin 1:8aa5cdb4ab67 331 *
Jonathan Austin 1:8aa5cdb4ab67 332 * @param urgent The type of listeners to process (optional). If set to true, only listeners defined as urgent and non-blocking will be processed
Jonathan Austin 1:8aa5cdb4ab67 333 * otherwise, all other (standard) listeners will be processed. Defaults to false.
Jonathan Austin 1:8aa5cdb4ab67 334 *
Jonathan Austin 1:8aa5cdb4ab67 335 * @return 1 if all matching listeners were processed, 0 if further processing is required.
Jonathan Austin 1:8aa5cdb4ab67 336 *
Jonathan Austin 1:8aa5cdb4ab67 337 * @note It is recommended that all external code uses the send() function instead of this function,
Jonathan Austin 1:8aa5cdb4ab67 338 * or the constructors provided by MicrobitEvent.
Jonathan Austin 1:8aa5cdb4ab67 339 */
Jonathan Austin 1:8aa5cdb4ab67 340 int MicroBitMessageBus::process(MicroBitEvent &evt, bool urgent)
Jonathan Austin 1:8aa5cdb4ab67 341 {
Jonathan Austin 1:8aa5cdb4ab67 342 MicroBitListener *l;
Jonathan Austin 1:8aa5cdb4ab67 343 int complete = 1;
Jonathan Austin 1:8aa5cdb4ab67 344 bool listenerUrgent;
Jonathan Austin 1:8aa5cdb4ab67 345
Jonathan Austin 1:8aa5cdb4ab67 346 l = listeners;
Jonathan Austin 1:8aa5cdb4ab67 347 while (l != NULL)
Jonathan Austin 1:8aa5cdb4ab67 348 {
Jonathan Austin 1:8aa5cdb4ab67 349 if((l->id == evt.source || l->id == MICROBIT_ID_ANY) && (l->value == evt.value || l->value == MICROBIT_EVT_ANY))
Jonathan Austin 1:8aa5cdb4ab67 350 {
LancasterUniversity 5:f0f1cecd65d8 351 // If we're running under the fiber scheduler, then derive the THREADING_MODE for the callback based on the
LancasterUniversity 5:f0f1cecd65d8 352 // metadata in the listener itself.
LancasterUniversity 5:f0f1cecd65d8 353 if (fiber_scheduler_running())
LancasterUniversity 5:f0f1cecd65d8 354 listenerUrgent = (l->flags & MESSAGE_BUS_LISTENER_IMMEDIATE) == MESSAGE_BUS_LISTENER_IMMEDIATE;
LancasterUniversity 5:f0f1cecd65d8 355 else
LancasterUniversity 5:f0f1cecd65d8 356 listenerUrgent = true;
LancasterUniversity 5:f0f1cecd65d8 357
LancasterUniversity 5:f0f1cecd65d8 358 // If we should process this event hander in this pass, then activate the listener.
Jonathan Austin 1:8aa5cdb4ab67 359 if(listenerUrgent == urgent && !(l->flags & MESSAGE_BUS_LISTENER_DELETING))
Jonathan Austin 1:8aa5cdb4ab67 360 {
Jonathan Austin 1:8aa5cdb4ab67 361 l->evt = evt;
Jonathan Austin 1:8aa5cdb4ab67 362
Jonathan Austin 1:8aa5cdb4ab67 363 // OK, if this handler has regisitered itself as non-blocking, we just execute it directly...
Jonathan Austin 1:8aa5cdb4ab67 364 // This is normally only done for trusted system components.
Jonathan Austin 1:8aa5cdb4ab67 365 // Otherwise, we invoke it in a 'fork on block' context, that will automatically create a fiber
Jonathan Austin 1:8aa5cdb4ab67 366 // should the event handler attempt a blocking operation, but doesn't have the overhead
Jonathan Austin 1:8aa5cdb4ab67 367 // of creating a fiber needlessly. (cool huh?)
LancasterUniversity 25:27299423d813 368 if (l->flags & MESSAGE_BUS_LISTENER_NONBLOCKING || !fiber_scheduler_running())
LancasterUniversity 25:27299423d813 369 async_callback(l);
LancasterUniversity 25:27299423d813 370 else
LancasterUniversity 25:27299423d813 371 invoke(async_callback, l);
Jonathan Austin 1:8aa5cdb4ab67 372 }
Jonathan Austin 1:8aa5cdb4ab67 373 else
Jonathan Austin 1:8aa5cdb4ab67 374 {
Jonathan Austin 1:8aa5cdb4ab67 375 complete = 0;
Jonathan Austin 1:8aa5cdb4ab67 376 }
Jonathan Austin 1:8aa5cdb4ab67 377 }
Jonathan Austin 1:8aa5cdb4ab67 378
Jonathan Austin 1:8aa5cdb4ab67 379 l = l->next;
Jonathan Austin 1:8aa5cdb4ab67 380 }
Jonathan Austin 1:8aa5cdb4ab67 381
Jonathan Austin 1:8aa5cdb4ab67 382 return complete;
Jonathan Austin 1:8aa5cdb4ab67 383 }
Jonathan Austin 1:8aa5cdb4ab67 384
Jonathan Austin 1:8aa5cdb4ab67 385 /**
Jonathan Austin 1:8aa5cdb4ab67 386 * Add the given MicroBitListener to the list of event handlers, unconditionally.
Jonathan Austin 1:8aa5cdb4ab67 387 *
Jonathan Austin 1:8aa5cdb4ab67 388 * @param listener The MicroBitListener to add.
Jonathan Austin 1:8aa5cdb4ab67 389 *
Jonathan Austin 1:8aa5cdb4ab67 390 * @return MICROBIT_OK if the listener is valid, MICROBIT_INVALID_PARAMETER otherwise.
Jonathan Austin 1:8aa5cdb4ab67 391 */
Jonathan Austin 1:8aa5cdb4ab67 392 int MicroBitMessageBus::add(MicroBitListener *newListener)
Jonathan Austin 1:8aa5cdb4ab67 393 {
Jonathan Austin 1:8aa5cdb4ab67 394 MicroBitListener *l, *p;
Jonathan Austin 1:8aa5cdb4ab67 395 int methodCallback;
Jonathan Austin 1:8aa5cdb4ab67 396
Jonathan Austin 1:8aa5cdb4ab67 397 //handler can't be NULL!
Jonathan Austin 1:8aa5cdb4ab67 398 if (newListener == NULL)
Jonathan Austin 1:8aa5cdb4ab67 399 return MICROBIT_INVALID_PARAMETER;
Jonathan Austin 1:8aa5cdb4ab67 400
Jonathan Austin 1:8aa5cdb4ab67 401 l = listeners;
Jonathan Austin 1:8aa5cdb4ab67 402
Jonathan Austin 1:8aa5cdb4ab67 403 // Firstly, we treat a listener as an idempotent operation. Ensure we don't already have this handler
Jonathan Austin 1:8aa5cdb4ab67 404 // registered in a that will already capture these events. If we do, silently ignore.
Jonathan Austin 1:8aa5cdb4ab67 405
Jonathan Austin 1:8aa5cdb4ab67 406 // We always check the ID, VALUE and CB_METHOD fields.
Jonathan Austin 1:8aa5cdb4ab67 407 // If we have a callback to a method, check the cb_method class. Otherwise, the cb function point is sufficient.
Jonathan Austin 1:8aa5cdb4ab67 408 while (l != NULL)
Jonathan Austin 1:8aa5cdb4ab67 409 {
Jonathan Austin 1:8aa5cdb4ab67 410 methodCallback = (newListener->flags & MESSAGE_BUS_LISTENER_METHOD) && (l->flags & MESSAGE_BUS_LISTENER_METHOD);
Jonathan Austin 1:8aa5cdb4ab67 411
Jonathan Austin 1:8aa5cdb4ab67 412 if (l->id == newListener->id && l->value == newListener->value && (methodCallback ? *l->cb_method == *newListener->cb_method : l->cb == newListener->cb))
Jonathan Austin 1:8aa5cdb4ab67 413 {
Jonathan Austin 1:8aa5cdb4ab67 414 // We have a perfect match for this event listener already registered.
Jonathan Austin 1:8aa5cdb4ab67 415 // If it's marked for deletion, we simply resurrect the listener, and we're done.
Jonathan Austin 1:8aa5cdb4ab67 416 // Either way, we return an error code, as the *new* listener should be released...
Jonathan Austin 1:8aa5cdb4ab67 417 if(l->flags & MESSAGE_BUS_LISTENER_DELETING)
Jonathan Austin 1:8aa5cdb4ab67 418 l->flags &= ~MESSAGE_BUS_LISTENER_DELETING;
Jonathan Austin 1:8aa5cdb4ab67 419
Jonathan Austin 1:8aa5cdb4ab67 420 return MICROBIT_NOT_SUPPORTED;
Jonathan Austin 1:8aa5cdb4ab67 421 }
Jonathan Austin 1:8aa5cdb4ab67 422
Jonathan Austin 1:8aa5cdb4ab67 423 l = l->next;
Jonathan Austin 1:8aa5cdb4ab67 424 }
Jonathan Austin 1:8aa5cdb4ab67 425
Jonathan Austin 1:8aa5cdb4ab67 426 // We have a valid, new event handler. Add it to the list.
Jonathan Austin 1:8aa5cdb4ab67 427 // if listeners is null - we can automatically add this listener to the list at the beginning...
Jonathan Austin 1:8aa5cdb4ab67 428 if (listeners == NULL)
Jonathan Austin 1:8aa5cdb4ab67 429 {
Jonathan Austin 1:8aa5cdb4ab67 430 listeners = newListener;
Jonathan Austin 1:8aa5cdb4ab67 431 MicroBitEvent(MICROBIT_ID_MESSAGE_BUS_LISTENER, newListener->id);
Jonathan Austin 1:8aa5cdb4ab67 432
Jonathan Austin 1:8aa5cdb4ab67 433 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 434 }
Jonathan Austin 1:8aa5cdb4ab67 435
Jonathan Austin 1:8aa5cdb4ab67 436 // We maintain an ordered list of listeners.
Jonathan Austin 1:8aa5cdb4ab67 437 // The chain is held stictly in increasing order of ID (first level), then value code (second level).
Jonathan Austin 1:8aa5cdb4ab67 438 // Find the correct point in the chain for this event.
Jonathan Austin 1:8aa5cdb4ab67 439 // Adding a listener is a rare occurance, so we just walk the list...
Jonathan Austin 1:8aa5cdb4ab67 440
Jonathan Austin 1:8aa5cdb4ab67 441 p = listeners;
Jonathan Austin 1:8aa5cdb4ab67 442 l = listeners;
Jonathan Austin 1:8aa5cdb4ab67 443
Jonathan Austin 1:8aa5cdb4ab67 444 while (l != NULL && l->id < newListener->id)
Jonathan Austin 1:8aa5cdb4ab67 445 {
Jonathan Austin 1:8aa5cdb4ab67 446 p = l;
Jonathan Austin 1:8aa5cdb4ab67 447 l = l->next;
Jonathan Austin 1:8aa5cdb4ab67 448 }
Jonathan Austin 1:8aa5cdb4ab67 449
Jonathan Austin 1:8aa5cdb4ab67 450 while (l != NULL && l->id == newListener->id && l->value < newListener->value)
Jonathan Austin 1:8aa5cdb4ab67 451 {
Jonathan Austin 1:8aa5cdb4ab67 452 p = l;
Jonathan Austin 1:8aa5cdb4ab67 453 l = l->next;
Jonathan Austin 1:8aa5cdb4ab67 454 }
Jonathan Austin 1:8aa5cdb4ab67 455
Jonathan Austin 1:8aa5cdb4ab67 456 //add at front of list
Jonathan Austin 1:8aa5cdb4ab67 457 if (p == listeners && (newListener->id < p->id || (p->id == newListener->id && p->value > newListener->value)))
Jonathan Austin 1:8aa5cdb4ab67 458 {
Jonathan Austin 1:8aa5cdb4ab67 459 newListener->next = p;
Jonathan Austin 1:8aa5cdb4ab67 460
Jonathan Austin 1:8aa5cdb4ab67 461 //this new listener is now the front!
Jonathan Austin 1:8aa5cdb4ab67 462 listeners = newListener;
Jonathan Austin 1:8aa5cdb4ab67 463 }
Jonathan Austin 1:8aa5cdb4ab67 464
Jonathan Austin 1:8aa5cdb4ab67 465 //add after p
Jonathan Austin 1:8aa5cdb4ab67 466 else
Jonathan Austin 1:8aa5cdb4ab67 467 {
Jonathan Austin 1:8aa5cdb4ab67 468 newListener->next = p->next;
Jonathan Austin 1:8aa5cdb4ab67 469 p->next = newListener;
Jonathan Austin 1:8aa5cdb4ab67 470 }
Jonathan Austin 1:8aa5cdb4ab67 471
Jonathan Austin 1:8aa5cdb4ab67 472 MicroBitEvent(MICROBIT_ID_MESSAGE_BUS_LISTENER, newListener->id);
Jonathan Austin 1:8aa5cdb4ab67 473 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 474 }
Jonathan Austin 1:8aa5cdb4ab67 475
Jonathan Austin 1:8aa5cdb4ab67 476 /**
Jonathan Austin 1:8aa5cdb4ab67 477 * Remove the given MicroBitListener from the list of event handlers.
Jonathan Austin 1:8aa5cdb4ab67 478 *
Jonathan Austin 1:8aa5cdb4ab67 479 * @param listener The MicroBitListener to remove.
Jonathan Austin 1:8aa5cdb4ab67 480 *
Jonathan Austin 1:8aa5cdb4ab67 481 * @return MICROBIT_OK if the listener is valid, MICROBIT_INVALID_PARAMETER otherwise.
Jonathan Austin 1:8aa5cdb4ab67 482 */
Jonathan Austin 1:8aa5cdb4ab67 483 int MicroBitMessageBus::remove(MicroBitListener *listener)
Jonathan Austin 1:8aa5cdb4ab67 484 {
Jonathan Austin 1:8aa5cdb4ab67 485 MicroBitListener *l;
Jonathan Austin 1:8aa5cdb4ab67 486 int removed = 0;
Jonathan Austin 1:8aa5cdb4ab67 487
Jonathan Austin 1:8aa5cdb4ab67 488 //handler can't be NULL!
Jonathan Austin 1:8aa5cdb4ab67 489 if (listener == NULL)
Jonathan Austin 1:8aa5cdb4ab67 490 return MICROBIT_INVALID_PARAMETER;
Jonathan Austin 1:8aa5cdb4ab67 491
Jonathan Austin 1:8aa5cdb4ab67 492 l = listeners;
Jonathan Austin 1:8aa5cdb4ab67 493
Jonathan Austin 1:8aa5cdb4ab67 494 // Walk this list of event handlers. Delete any that match the given listener.
Jonathan Austin 1:8aa5cdb4ab67 495 while (l != NULL)
Jonathan Austin 1:8aa5cdb4ab67 496 {
Jonathan Austin 1:8aa5cdb4ab67 497 if ((listener->flags & MESSAGE_BUS_LISTENER_METHOD) == (l->flags & MESSAGE_BUS_LISTENER_METHOD))
Jonathan Austin 1:8aa5cdb4ab67 498 {
Jonathan Austin 1:8aa5cdb4ab67 499 if(((listener->flags & MESSAGE_BUS_LISTENER_METHOD) && (*l->cb_method == *listener->cb_method)) ||
Jonathan Austin 1:8aa5cdb4ab67 500 ((!(listener->flags & MESSAGE_BUS_LISTENER_METHOD) && l->cb == listener->cb)))
Jonathan Austin 1:8aa5cdb4ab67 501 {
Jonathan Austin 1:8aa5cdb4ab67 502 if ((listener->id == MICROBIT_ID_ANY || listener->id == l->id) && (listener->value == MICROBIT_EVT_ANY || listener->value == l->value))
Jonathan Austin 1:8aa5cdb4ab67 503 {
Jonathan Austin 1:8aa5cdb4ab67 504 // Found a match. mark this to be removed from the list.
Jonathan Austin 1:8aa5cdb4ab67 505 l->flags |= MESSAGE_BUS_LISTENER_DELETING;
Jonathan Austin 1:8aa5cdb4ab67 506 removed++;
Jonathan Austin 1:8aa5cdb4ab67 507 }
Jonathan Austin 1:8aa5cdb4ab67 508 }
Jonathan Austin 1:8aa5cdb4ab67 509 }
Jonathan Austin 1:8aa5cdb4ab67 510
Jonathan Austin 1:8aa5cdb4ab67 511 l = l->next;
Jonathan Austin 1:8aa5cdb4ab67 512 }
Jonathan Austin 1:8aa5cdb4ab67 513
Jonathan Austin 1:8aa5cdb4ab67 514 if (removed > 0)
Jonathan Austin 1:8aa5cdb4ab67 515 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 516 else
Jonathan Austin 1:8aa5cdb4ab67 517 return MICROBIT_INVALID_PARAMETER;
Jonathan Austin 1:8aa5cdb4ab67 518 }
Jonathan Austin 1:8aa5cdb4ab67 519
Jonathan Austin 1:8aa5cdb4ab67 520 /**
Jonathan Austin 1:8aa5cdb4ab67 521 * Returns the microBitListener with the given position in our list.
Jonathan Austin 1:8aa5cdb4ab67 522 *
Jonathan Austin 1:8aa5cdb4ab67 523 * @param n The position in the list to return.
Jonathan Austin 1:8aa5cdb4ab67 524 *
Jonathan Austin 1:8aa5cdb4ab67 525 * @return the MicroBitListener at postion n in the list, or NULL if the position is invalid.
Jonathan Austin 1:8aa5cdb4ab67 526 */
Jonathan Austin 1:8aa5cdb4ab67 527 MicroBitListener* MicroBitMessageBus::elementAt(int n)
Jonathan Austin 1:8aa5cdb4ab67 528 {
Jonathan Austin 1:8aa5cdb4ab67 529 MicroBitListener *l = listeners;
Jonathan Austin 1:8aa5cdb4ab67 530
Jonathan Austin 1:8aa5cdb4ab67 531 while (n > 0)
Jonathan Austin 1:8aa5cdb4ab67 532 {
Jonathan Austin 1:8aa5cdb4ab67 533 if (l == NULL)
Jonathan Austin 1:8aa5cdb4ab67 534 return NULL;
Jonathan Austin 1:8aa5cdb4ab67 535
Jonathan Austin 1:8aa5cdb4ab67 536 n--;
Jonathan Austin 1:8aa5cdb4ab67 537 l = l->next;
Jonathan Austin 1:8aa5cdb4ab67 538 }
Jonathan Austin 1:8aa5cdb4ab67 539
Jonathan Austin 1:8aa5cdb4ab67 540 return l;
Jonathan Austin 1:8aa5cdb4ab67 541 }
Jonathan Austin 1:8aa5cdb4ab67 542
Jonathan Austin 1:8aa5cdb4ab67 543 /**
Jonathan Austin 1:8aa5cdb4ab67 544 * Destructor for MicroBitMessageBus, where we deregister this instance from the array of fiber components.
Jonathan Austin 1:8aa5cdb4ab67 545 */
Jonathan Austin 1:8aa5cdb4ab67 546 MicroBitMessageBus::~MicroBitMessageBus()
Jonathan Austin 1:8aa5cdb4ab67 547 {
Jonathan Austin 1:8aa5cdb4ab67 548 fiber_remove_idle_component(this);
LancasterUniversity 5:f0f1cecd65d8 549 }