Microbug / MicroBitDAL_SB2_TEST

Fork of MicroBitDALImageRewrite by Joe Finney

Committer:
finneyj
Date:
Tue Apr 28 18:32:34 2015 +0000
Revision:
2:6597fe50dc94
Parent:
1:3e0360107f98
Integrated a Cortex M0 Fiber scheduler.; Updated MessageBus to generated events to decouple event handlers from interrupt context through use of scheduled fibers.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
finneyj 1:3e0360107f98 1 /**
finneyj 1:3e0360107f98 2 * Class definition for a MicroBitImage.
finneyj 1:3e0360107f98 3 *
finneyj 1:3e0360107f98 4 * An MicroBitImage is a simple bitmap representation of an image.
finneyj 1:3e0360107f98 5 */
finneyj 1:3e0360107f98 6
finneyj 1:3e0360107f98 7 #include "MicroBitMessageBus.h"
finneyj 2:6597fe50dc94 8 #include "MicroBitFiber.h"
finneyj 1:3e0360107f98 9
finneyj 1:3e0360107f98 10 /**
finneyj 1:3e0360107f98 11 * Constructor.
finneyj 1:3e0360107f98 12 * Create a new Message Bus Listener.
finneyj 1:3e0360107f98 13 */
finneyj 2:6597fe50dc94 14 MicroBitListener::MicroBitListener(int id, int value, void (*handler)(void))
finneyj 1:3e0360107f98 15 {
finneyj 1:3e0360107f98 16 this->id = id;
finneyj 1:3e0360107f98 17 this->value = value;
finneyj 1:3e0360107f98 18 this->cb = handler;
finneyj 1:3e0360107f98 19 this->next = NULL;
finneyj 1:3e0360107f98 20 }
finneyj 1:3e0360107f98 21
finneyj 1:3e0360107f98 22 /**
finneyj 1:3e0360107f98 23 * Constructor.
finneyj 1:3e0360107f98 24 * Create a new Message Bus.
finneyj 1:3e0360107f98 25 */
finneyj 1:3e0360107f98 26 MicroBitMessageBus::MicroBitMessageBus()
finneyj 1:3e0360107f98 27 {
finneyj 1:3e0360107f98 28 this->listeners = NULL;
finneyj 1:3e0360107f98 29 this->seq = 0;
finneyj 1:3e0360107f98 30 }
finneyj 1:3e0360107f98 31
finneyj 1:3e0360107f98 32 /**
finneyj 1:3e0360107f98 33 * Send the given event to all regstered recipients.
finneyj 1:3e0360107f98 34 *
finneyj 1:3e0360107f98 35 * @param The event to send. This structure is assumed to be heap allocated, and will
finneyj 1:3e0360107f98 36 * be automatically freed once all recipients have been notified.
finneyj 1:3e0360107f98 37 */
finneyj 1:3e0360107f98 38 void MicroBitMessageBus::send(MicroBitEvent *evt)
finneyj 1:3e0360107f98 39 {
finneyj 1:3e0360107f98 40 this->send(evt, NULL);
finneyj 1:3e0360107f98 41 }
finneyj 1:3e0360107f98 42
finneyj 1:3e0360107f98 43 /**
finneyj 1:3e0360107f98 44 * Send the given event to all regstered recipients, using a cached entry to minimize lookups.
finneyj 1:3e0360107f98 45 * This is particularly useful for optimizing sensors that frequently send to the same channel.
finneyj 1:3e0360107f98 46 *
finneyj 1:3e0360107f98 47 * @param evt The event to send. This structure is assumed to be heap allocated, and will
finneyj 1:3e0360107f98 48 * be automatically freed once all recipients have been notified.
finneyj 1:3e0360107f98 49 * @param c Cache entry to reduce lookups for commonly used channels.
finneyj 1:3e0360107f98 50 *
finneyj 1:3e0360107f98 51 * TODO: For now, this is unbuffered. We should consider scheduling events here, and operating
finneyj 1:3e0360107f98 52 * a different thread that empties the queue. This would perhaps provide greater opportunities
finneyj 1:3e0360107f98 53 * for aggregation.
finneyj 1:3e0360107f98 54 */
finneyj 1:3e0360107f98 55 void MicroBitMessageBus::send(MicroBitEvent *evt, MicroBitMessageBusCache *c)
finneyj 1:3e0360107f98 56 {
finneyj 1:3e0360107f98 57 MicroBitListener *l;
finneyj 1:3e0360107f98 58 MicroBitListener *start;
finneyj 1:3e0360107f98 59
finneyj 1:3e0360107f98 60 // Find the start of the sublist where we'll send this event.
finneyj 1:3e0360107f98 61 // Ideally, we'll have a valid, cached entry. Use it if we do.
finneyj 1:3e0360107f98 62 if ( c != NULL && c->seq == this->seq)
finneyj 1:3e0360107f98 63 {
finneyj 1:3e0360107f98 64 l = c->ptr;
finneyj 1:3e0360107f98 65 }
finneyj 1:3e0360107f98 66 else
finneyj 1:3e0360107f98 67 {
finneyj 1:3e0360107f98 68 l = listeners;
finneyj 1:3e0360107f98 69 while (l != NULL && l->id != evt->source)
finneyj 1:3e0360107f98 70 l = l->next;
finneyj 1:3e0360107f98 71 }
finneyj 1:3e0360107f98 72
finneyj 1:3e0360107f98 73 start = l;
finneyj 1:3e0360107f98 74
finneyj 1:3e0360107f98 75 // Now, send the event to all listeners registered for this event.
finneyj 1:3e0360107f98 76 while (l != NULL && l->id == evt->source)
finneyj 1:3e0360107f98 77 {
finneyj 1:3e0360107f98 78 if(l->value == MICROBIT_BUS_VALUE_ANY || l->value == evt->value)
finneyj 2:6597fe50dc94 79 //l->cb();
finneyj 2:6597fe50dc94 80 create_fiber(l->cb);
finneyj 1:3e0360107f98 81
finneyj 1:3e0360107f98 82 l = l->next;
finneyj 1:3e0360107f98 83 }
finneyj 1:3e0360107f98 84
finneyj 1:3e0360107f98 85 // Next, send to any listeners registered for ALL event sources.
finneyj 1:3e0360107f98 86 l = listeners;
finneyj 1:3e0360107f98 87 while (l != NULL && l->id == MICROBIT_BUS_ID_ANY)
finneyj 1:3e0360107f98 88 {
finneyj 2:6597fe50dc94 89 //l->cb();
finneyj 2:6597fe50dc94 90 create_fiber(l->cb);
finneyj 1:3e0360107f98 91 l = l->next;
finneyj 1:3e0360107f98 92 }
finneyj 1:3e0360107f98 93
finneyj 1:3e0360107f98 94 // Finally, if we were given a cached entry that's now invalid, update it.
finneyj 1:3e0360107f98 95 if ( c != NULL && c->seq != this->seq)
finneyj 1:3e0360107f98 96 {
finneyj 1:3e0360107f98 97 c->ptr = start;
finneyj 1:3e0360107f98 98 c->seq = this->seq;
finneyj 1:3e0360107f98 99 }
finneyj 1:3e0360107f98 100 }
finneyj 1:3e0360107f98 101
finneyj 1:3e0360107f98 102 /**
finneyj 1:3e0360107f98 103 * Register a listener function.
finneyj 1:3e0360107f98 104 *
finneyj 1:3e0360107f98 105 * @param id The source of messages to listen for. Events sent from any other IDs will be filtered.
finneyj 1:3e0360107f98 106 * Use MICROBIT_ID_ANY to receive events from all components.
finneyj 1:3e0360107f98 107 *
finneyj 1:3e0360107f98 108 * @param value The value of messages to listen for. Events with any other values will be filtered.
finneyj 1:3e0360107f98 109 * Use MICROBIT_VALUE_ANY to receive events of any value.
finneyj 1:3e0360107f98 110 *
finneyj 1:3e0360107f98 111 * @param hander The function to call when an event is received.
finneyj 1:3e0360107f98 112 *
finneyj 1:3e0360107f98 113 * TODO: We currently don't support C++ member functions as callbacks, which we should.
finneyj 1:3e0360107f98 114 */
finneyj 1:3e0360107f98 115
finneyj 2:6597fe50dc94 116 void MicroBitMessageBus::listen(int id, int value, void (*handler)(void))
finneyj 1:3e0360107f98 117 {
finneyj 1:3e0360107f98 118 MicroBitListener *l, *p;
finneyj 1:3e0360107f98 119 MicroBitListener *newListener = new MicroBitListener(id, value, handler);
finneyj 1:3e0360107f98 120
finneyj 1:3e0360107f98 121 // Firstly, we treat a listener as an idempotent operation. Ensure we don't already have this handler
finneyj 1:3e0360107f98 122 // registered in a that will already capture these events. If we do, silently ignore.
finneyj 1:3e0360107f98 123 l = listeners;
finneyj 1:3e0360107f98 124
finneyj 1:3e0360107f98 125 while (l != NULL && l->id <= id)
finneyj 1:3e0360107f98 126 {
finneyj 1:3e0360107f98 127 if (l->cb == handler && (l->id == id || l->id == MICROBIT_BUS_ID_ANY) && (l->value == value || l->value == MICROBIT_BUS_VALUE_ANY))
finneyj 1:3e0360107f98 128 return;
finneyj 1:3e0360107f98 129
finneyj 1:3e0360107f98 130 l = l->next;
finneyj 1:3e0360107f98 131 }
finneyj 1:3e0360107f98 132
finneyj 1:3e0360107f98 133 // Maintain an ordered list of listeners.
finneyj 1:3e0360107f98 134 // Chain is held stictly in increasing order of ID (first level), then value code (second level).
finneyj 1:3e0360107f98 135 // Find the correct point in the chain for this event.
finneyj 1:3e0360107f98 136 // Adding a listener is a rare occurance, so we just walk the list.
finneyj 1:3e0360107f98 137 p = NULL;
finneyj 1:3e0360107f98 138 l = listeners;
finneyj 1:3e0360107f98 139
finneyj 1:3e0360107f98 140 while (l != NULL && l->id <= id && l->value <= value)
finneyj 1:3e0360107f98 141 {
finneyj 1:3e0360107f98 142 p=l;
finneyj 1:3e0360107f98 143 l = l->next;
finneyj 1:3e0360107f98 144 }
finneyj 1:3e0360107f98 145
finneyj 1:3e0360107f98 146 // Add the listener at this point in the chain.
finneyj 1:3e0360107f98 147 if (p == NULL)
finneyj 1:3e0360107f98 148 listeners = newListener;
finneyj 1:3e0360107f98 149 else
finneyj 1:3e0360107f98 150 {
finneyj 1:3e0360107f98 151 newListener->next = p->next;
finneyj 1:3e0360107f98 152 p->next = newListener;
finneyj 1:3e0360107f98 153 }
finneyj 1:3e0360107f98 154
finneyj 1:3e0360107f98 155 // Increase our sequence number and we're done.
finneyj 1:3e0360107f98 156 // This will lazily invalidate any cached entries to the listener list.
finneyj 1:3e0360107f98 157 this->seq++;
finneyj 1:3e0360107f98 158 }
finneyj 1:3e0360107f98 159