Eddystone test using modified DAL

Dependencies:   BLE_API mbed-dev-bin nRF51822

Dependents:   microbit-eddystone

Fork of microbit-dal by Lancaster University

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MicroBitMessageBus.cpp Source File

MicroBitMessageBus.cpp

00001 /*
00002 The MIT License (MIT)
00003 
00004 Copyright (c) 2016 British Broadcasting Corporation.
00005 This software is provided by Lancaster University by arrangement with the BBC.
00006 
00007 Permission is hereby granted, free of charge, to any person obtaining a
00008 copy of this software and associated documentation files (the "Software"),
00009 to deal in the Software without restriction, including without limitation
00010 the rights to use, copy, modify, merge, publish, distribute, sublicense,
00011 and/or sell copies of the Software, and to permit persons to whom the
00012 Software is furnished to do so, subject to the following conditions:
00013 
00014 The above copyright notice and this permission notice shall be included in
00015 all copies or substantial portions of the Software.
00016 
00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00020 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00021 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00022 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00023 DEALINGS IN THE SOFTWARE.
00024 */
00025 
00026 /**
00027   * Class definition for the MicroBitMessageBus.
00028   *
00029   * The MicroBitMessageBus is the common mechanism to deliver asynchronous events on the
00030   * MicroBit platform. It serves a number of purposes:
00031   *
00032   * 1) It provides an eventing abstraction that is independent of the underlying substrate.
00033   *
00034   * 2) It provides a mechanism to decouple user code from trusted system code
00035   *    i.e. the basis of a message passing nano kernel.
00036   *
00037   * 3) It allows a common high level eventing abstraction across a range of hardware types.e.g. buttons, BLE...
00038   *
00039   * 4) It provides a mechanim for extensibility - new devices added via I/O pins can have OO based
00040   *    drivers and communicate via the message bus with minima impact on user level languages.
00041   *
00042   * 5) It allows for the possiblility of event / data aggregation, which in turn can save energy.
00043   *
00044   * It has the following design principles:
00045   *
00046   * 1) Maintain a low RAM footprint where possible
00047   *
00048   * 2) Make few assumptions about the underlying platform, but allow optimizations where possible.
00049   */
00050 #include "MicroBitConfig.h"
00051 #include "MicroBitMessageBus.h"
00052 #include "MicroBitFiber.h"
00053 #include "ErrorNo.h"
00054 
00055 /**
00056   * Default constructor.
00057   *
00058   * Adds itself as a fiber component, and also configures itself to be the
00059   * default EventModel if defaultEventBus is NULL.
00060   */
00061 MicroBitMessageBus::MicroBitMessageBus()
00062 {
00063     this->listeners = NULL;
00064     this->evt_queue_head = NULL;
00065     this->evt_queue_tail = NULL;
00066     this->queueLength = 0;
00067 
00068     fiber_add_idle_component(this);
00069 
00070     if(EventModel::defaultEventBus == NULL)
00071         EventModel::defaultEventBus = this;
00072 }
00073 
00074 /**
00075   * Invokes a callback on a given MicroBitListener
00076   *
00077   * Internal wrapper function, used to enable
00078   * parameterised callbacks through the fiber scheduler.
00079   */
00080 void async_callback(void *param)
00081 {
00082     MicroBitListener *listener = (MicroBitListener *)param;
00083 
00084     // OK, now we need to decide how to behave depending on our configuration.
00085     // If this a fiber f already active within this listener then check our
00086     // configuration to determine the correct course of action.
00087     //
00088 
00089     if (listener->flags & MESSAGE_BUS_LISTENER_BUSY)
00090     {
00091         // Drop this event, if that's how we've been configured.
00092         if (listener->flags & MESSAGE_BUS_LISTENER_DROP_IF_BUSY)
00093             return;
00094 
00095         // Queue this event up for later, if that's how we've been configured.
00096         if (listener->flags & MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY)
00097         {
00098             listener->queue(listener->evt);
00099             return;
00100         }
00101     }
00102 
00103     // Determine the calling convention for the callback, and invoke...
00104     // C++ is really bad at this! Especially as the ARM compiler is yet to support C++ 11 :-/
00105 
00106     // Record that we have a fiber going into this listener...
00107     listener->flags |= MESSAGE_BUS_LISTENER_BUSY;
00108 
00109     while (1)
00110     {
00111         // Firstly, check for a method callback into an object.
00112         if (listener->flags & MESSAGE_BUS_LISTENER_METHOD)
00113             listener->cb_method->fire(listener->evt);
00114 
00115         // Now a parameterised C function
00116         else if (listener->flags & MESSAGE_BUS_LISTENER_PARAMETERISED)
00117             listener->cb_param(listener->evt, listener->cb_arg);
00118 
00119         // We must have a plain C function
00120         else
00121             listener->cb(listener->evt);
00122 
00123         // If there are more events to process, dequeue the next one and process it.
00124         if ((listener->flags & MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY) && listener->evt_queue)
00125         {
00126             MicroBitEventQueueItem *item = listener->evt_queue;
00127 
00128             listener->evt = item->evt;
00129             listener->evt_queue = listener->evt_queue->next;
00130             delete item;
00131 
00132             // We spin the scheduler here, to preven any particular event handler from continuously holding onto resources.
00133             schedule();
00134         }
00135         else
00136             break;
00137     }
00138 
00139     // The fiber of exiting... clear our state.
00140     listener->flags &= ~MESSAGE_BUS_LISTENER_BUSY;
00141 }
00142 
00143 /**
00144   * Queue the given event for processing at a later time.
00145   * Add the given event at the tail of our queue.
00146   *
00147   * @param The event to queue.
00148   */
00149 void MicroBitMessageBus::queueEvent(MicroBitEvent &evt)
00150 {
00151     int processingComplete;
00152 
00153     MicroBitEventQueueItem *prev = evt_queue_tail;
00154 
00155     // Now process all handler regsitered as URGENT.
00156     // These pre-empt the queue, and are useful for fast, high priority services.
00157     processingComplete = this->process(evt, true);
00158 
00159     // If we've already processed all event handlers, we're all done.
00160     // No need to queue the event.
00161     if (processingComplete)
00162         return;
00163 
00164     // If we need to queue, but there is no space, then there's nothg we can do.
00165     if (queueLength >= MESSAGE_BUS_LISTENER_MAX_QUEUE_DEPTH)
00166         return;
00167 
00168     // Otherwise, we need to queue this event for later processing...
00169     // We queue this event at the tail of the queue at the point where we entered queueEvent()
00170     // This is important as the processing above *may* have generated further events, and
00171     // we want to maintain ordering of events.
00172     MicroBitEventQueueItem *item = new MicroBitEventQueueItem(evt);
00173 
00174     // The queue was empty when we entered this function, so queue our event at the start of the queue.
00175     __disable_irq();
00176 
00177     if (prev == NULL)
00178     {
00179         item->next = evt_queue_head;
00180         evt_queue_head = item;
00181     }
00182     else
00183     {
00184         item->next = prev->next;
00185         prev->next = item;
00186     }
00187 
00188     if (item->next == NULL)
00189         evt_queue_tail = item;
00190 
00191     queueLength++;
00192 
00193     __enable_irq();
00194 }
00195 
00196 /**
00197   * Extract the next event from the front of the event queue (if present).
00198   *
00199   * @return a pointer to the MicroBitEventQueueItem that is at the head of the list.
00200   */
00201 MicroBitEventQueueItem* MicroBitMessageBus::dequeueEvent()
00202 {
00203     MicroBitEventQueueItem *item = NULL;
00204 
00205     __disable_irq();
00206 
00207     if (evt_queue_head != NULL)
00208     {
00209         item = evt_queue_head;
00210         evt_queue_head = item->next;
00211 
00212         if (evt_queue_head == NULL)
00213             evt_queue_tail = NULL;
00214 
00215         queueLength--;
00216     }
00217 
00218     __enable_irq();
00219 
00220 
00221     return item;
00222 }
00223 
00224 /**
00225   * Cleanup any MicroBitListeners marked for deletion from the list.
00226   *
00227   * @return The number of listeners removed from the list.
00228   */
00229 int MicroBitMessageBus::deleteMarkedListeners()
00230 {
00231     MicroBitListener *l, *p;
00232     int removed = 0;
00233 
00234     l = listeners;
00235     p = NULL;
00236 
00237     // Walk this list of event handlers. Delete any that match the given listener.
00238     while (l != NULL)
00239     {
00240         if ((l->flags & MESSAGE_BUS_LISTENER_DELETING) && !(l->flags & MESSAGE_BUS_LISTENER_BUSY))
00241         {
00242             if (p == NULL)
00243                 listeners = l->next;
00244             else
00245                 p->next = l->next;
00246 
00247             // delete the listener.
00248             MicroBitListener *t = l;
00249             l = l->next;
00250 
00251             delete t;
00252             removed++;
00253 
00254             continue;
00255         }
00256 
00257         p = l;
00258         l = l->next;
00259     }
00260 
00261     return removed;
00262 }
00263 
00264 /**
00265   * Periodic callback from MicroBit.
00266   *
00267   * Process at least one event from the event queue, if it is not empty.
00268   * We then continue processing events until something appears on the runqueue.
00269   */
00270 void MicroBitMessageBus::idleTick()
00271 {
00272     // Clear out any listeners marked for deletion
00273     this->deleteMarkedListeners();
00274 
00275     MicroBitEventQueueItem *item = this->dequeueEvent();
00276 
00277     // Whilst there are events to process and we have no useful other work to do, pull them off the queue and process them.
00278     while (item)
00279     {
00280         // send the event to all standard event listeners.
00281         this->process(item->evt);
00282 
00283         // Free the queue item.
00284         delete item;
00285 
00286         // If we have created some useful work to do, we stop processing.
00287         // This helps to minimise the number of blocked fibers we create at any point in time, therefore
00288         // also reducing the RAM footprint.
00289         if(!scheduler_runqueue_empty())
00290             break;
00291 
00292         // Pull the next event to process, if there is one.
00293         item = this->dequeueEvent();
00294     }
00295 }
00296 
00297 /**
00298   * Queues the given event to be sent to all registered recipients.
00299   *
00300   * @param evt The event to send.
00301   *
00302   * @code
00303   * MicroBitMessageBus bus;
00304   *
00305   * // Creates and sends the MicroBitEvent using bus.
00306   * MicrobitEvent evt(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK);
00307   *
00308   * // Creates the MicrobitEvent, but delays the sending of that event.
00309   * MicrobitEvent evt1(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, CREATE_ONLY);
00310   *
00311   * bus.send(evt1);
00312   *
00313   * // This has the same effect!
00314   * evt1.fire()
00315   * @endcode
00316   */
00317 int MicroBitMessageBus::send(MicroBitEvent evt)
00318 {
00319     // We simply queue processing of the event until we're scheduled in normal thread context.
00320     // We do this to avoid the possibility of executing event handler code in IRQ context, which may bring
00321     // hidden race conditions to kids code. Queuing all events ensures causal ordering (total ordering in fact).
00322     this->queueEvent(evt);
00323     return MICROBIT_OK;
00324 }
00325 
00326 /**
00327   * Internal function, used to deliver the given event to all relevant recipients.
00328   * Normally, this is called once an event has been removed from the event queue.
00329   *
00330   * @param evt The event to send.
00331   *
00332   * @param urgent The type of listeners to process (optional). If set to true, only listeners defined as urgent and non-blocking will be processed
00333   *               otherwise, all other (standard) listeners will be processed. Defaults to false.
00334   *
00335   * @return 1 if all matching listeners were processed, 0 if further processing is required.
00336   *
00337   * @note It is recommended that all external code uses the send() function instead of this function,
00338   *       or the constructors provided by MicrobitEvent.
00339   */
00340 int MicroBitMessageBus::process(MicroBitEvent &evt, bool urgent)
00341 {
00342     MicroBitListener *l;
00343     int complete = 1;
00344     bool listenerUrgent;
00345 
00346     l = listeners;
00347     while (l != NULL)
00348     {
00349         if((l->id == evt.source || l->id == MICROBIT_ID_ANY) && (l->value == evt.value || l->value == MICROBIT_EVT_ANY))
00350         {
00351             // If we're running under the fiber scheduler, then derive the THREADING_MODE for the callback based on the
00352             // metadata in the listener itself.
00353             if (fiber_scheduler_running())
00354                 listenerUrgent = (l->flags & MESSAGE_BUS_LISTENER_IMMEDIATE) == MESSAGE_BUS_LISTENER_IMMEDIATE;
00355             else
00356                 listenerUrgent = true;
00357 
00358             // If we should process this event hander in this pass, then activate the listener.
00359             if(listenerUrgent == urgent && !(l->flags & MESSAGE_BUS_LISTENER_DELETING))
00360             {
00361                 l->evt = evt;
00362 
00363                 // OK, if this handler has regisitered itself as non-blocking, we just execute it directly...
00364                 // This is normally only done for trusted system components.
00365                 // Otherwise, we invoke it in a 'fork on block' context, that will automatically create a fiber
00366                 // should the event handler attempt a blocking operation, but doesn't have the overhead
00367                 // of creating a fiber needlessly. (cool huh?)
00368                 if (l->flags & MESSAGE_BUS_LISTENER_NONBLOCKING || !fiber_scheduler_running())
00369                     async_callback(l);
00370                 else
00371                     invoke(async_callback, l);
00372             }
00373             else
00374             {
00375                 complete = 0;
00376             }
00377         }
00378 
00379         l = l->next;
00380     }
00381 
00382     return complete;
00383 }
00384 
00385 /**
00386   * Add the given MicroBitListener to the list of event handlers, unconditionally.
00387   *
00388   * @param listener The MicroBitListener to add.
00389   *
00390   * @return MICROBIT_OK if the listener is valid, MICROBIT_INVALID_PARAMETER otherwise.
00391   */
00392 int MicroBitMessageBus::add(MicroBitListener *newListener)
00393 {
00394     MicroBitListener *l, *p;
00395     int methodCallback;
00396 
00397     //handler can't be NULL!
00398     if (newListener == NULL)
00399         return MICROBIT_INVALID_PARAMETER;
00400 
00401     l = listeners;
00402 
00403     // Firstly, we treat a listener as an idempotent operation. Ensure we don't already have this handler
00404     // registered in a that will already capture these events. If we do, silently ignore.
00405 
00406     // We always check the ID, VALUE and CB_METHOD fields.
00407     // If we have a callback to a method, check the cb_method class. Otherwise, the cb function point is sufficient.
00408     while (l != NULL)
00409     {
00410         methodCallback = (newListener->flags & MESSAGE_BUS_LISTENER_METHOD) && (l->flags & MESSAGE_BUS_LISTENER_METHOD);
00411 
00412         if (l->id == newListener->id && l->value == newListener->value && (methodCallback ? *l->cb_method == *newListener->cb_method : l->cb == newListener->cb))
00413         {
00414             // We have a perfect match for this event listener already registered.
00415             // If it's marked for deletion, we simply resurrect the listener, and we're done.
00416             // Either way, we return an error code, as the *new* listener should be released...
00417             if(l->flags & MESSAGE_BUS_LISTENER_DELETING)
00418                 l->flags &= ~MESSAGE_BUS_LISTENER_DELETING;
00419 
00420             return MICROBIT_NOT_SUPPORTED;
00421         }
00422 
00423         l = l->next;
00424     }
00425 
00426     // We have a valid, new event handler. Add it to the list.
00427     // if listeners is null - we can automatically add this listener to the list at the beginning...
00428     if (listeners == NULL)
00429     {
00430         listeners = newListener;
00431         MicroBitEvent(MICROBIT_ID_MESSAGE_BUS_LISTENER, newListener->id);
00432 
00433         return MICROBIT_OK;
00434     }
00435 
00436     // We maintain an ordered list of listeners.
00437     // The chain is held stictly in increasing order of ID (first level), then value code (second level).
00438     // Find the correct point in the chain for this event.
00439     // Adding a listener is a rare occurance, so we just walk the list...
00440 
00441     p = listeners;
00442     l = listeners;
00443 
00444     while (l != NULL && l->id < newListener->id)
00445     {
00446         p = l;
00447         l = l->next;
00448     }
00449 
00450     while (l != NULL && l->id == newListener->id && l->value < newListener->value)
00451     {
00452         p = l;
00453         l = l->next;
00454     }
00455 
00456     //add at front of list
00457     if (p == listeners && (newListener->id < p->id || (p->id == newListener->id && p->value > newListener->value)))
00458     {
00459         newListener->next = p;
00460 
00461         //this new listener is now the front!
00462         listeners = newListener;
00463     }
00464 
00465     //add after p
00466     else
00467     {
00468         newListener->next = p->next;
00469         p->next = newListener;
00470     }
00471 
00472     MicroBitEvent(MICROBIT_ID_MESSAGE_BUS_LISTENER, newListener->id);
00473     return MICROBIT_OK;
00474 }
00475 
00476 /**
00477   * Remove the given MicroBitListener from the list of event handlers.
00478   *
00479   * @param listener The MicroBitListener to remove.
00480   *
00481   * @return MICROBIT_OK if the listener is valid, MICROBIT_INVALID_PARAMETER otherwise.
00482   */
00483 int MicroBitMessageBus::remove(MicroBitListener *listener)
00484 {
00485     MicroBitListener *l;
00486     int removed = 0;
00487 
00488     //handler can't be NULL!
00489     if (listener == NULL)
00490         return MICROBIT_INVALID_PARAMETER;
00491 
00492     l = listeners;
00493 
00494     // Walk this list of event handlers. Delete any that match the given listener.
00495     while (l != NULL)
00496     {
00497         if ((listener->flags & MESSAGE_BUS_LISTENER_METHOD) == (l->flags & MESSAGE_BUS_LISTENER_METHOD))
00498         {
00499             if(((listener->flags & MESSAGE_BUS_LISTENER_METHOD) && (*l->cb_method == *listener->cb_method)) ||
00500               ((!(listener->flags & MESSAGE_BUS_LISTENER_METHOD) && l->cb == listener->cb)))
00501             {
00502                 if ((listener->id == MICROBIT_ID_ANY || listener->id == l->id) && (listener->value == MICROBIT_EVT_ANY || listener->value == l->value))
00503                 {
00504                     // Found a match. mark this to be removed from the list.
00505                     l->flags |= MESSAGE_BUS_LISTENER_DELETING;
00506                     removed++;
00507                 }
00508             }
00509         }
00510 
00511         l = l->next;
00512     }
00513 
00514     if (removed > 0)
00515         return MICROBIT_OK;
00516     else
00517         return MICROBIT_INVALID_PARAMETER;
00518 }
00519 
00520 /**
00521   * Returns the microBitListener with the given position in our list.
00522   *
00523   * @param n The position in the list to return.
00524   *
00525   * @return the MicroBitListener at postion n in the list, or NULL if the position is invalid.
00526   */
00527 MicroBitListener* MicroBitMessageBus::elementAt(int n)
00528 {
00529     MicroBitListener *l = listeners;
00530 
00531     while (n > 0)
00532     {
00533         if (l == NULL)
00534             return NULL;
00535 
00536         n--;
00537         l = l->next;
00538     }
00539 
00540     return l;
00541 }
00542 
00543 /**
00544   * Destructor for MicroBitMessageBus, where we deregister this instance from the array of fiber components.
00545   */
00546 MicroBitMessageBus::~MicroBitMessageBus()
00547 {
00548     fiber_remove_idle_component(this);
00549 }