microbit: Added support to remove MicroBitListener event handlers.
This commit is contained in:
parent
8ea2e953c8
commit
51493092ff
6 changed files with 253 additions and 18 deletions
|
@ -53,7 +53,7 @@ template <typename T>
|
|||
MemberFunctionCallback::MemberFunctionCallback(T* object, void (T::*method)(MicroBitEvent e))
|
||||
{
|
||||
this->object = object;
|
||||
memclr(this->method, sizeof(method));
|
||||
memclr(this->method, sizeof(this->method));
|
||||
memcpy(this->method, &method, sizeof(method));
|
||||
invoke = &MemberFunctionCallback::methodCall<T>;
|
||||
}
|
||||
|
|
|
@ -54,6 +54,11 @@ struct MicroBitListener
|
|||
*/
|
||||
template <typename T>
|
||||
MicroBitListener(uint16_t id, uint16_t value, T* object, void (T::*method)(MicroBitEvent));
|
||||
|
||||
/**
|
||||
* Destructor. Ensures all resources used by this listener are freed.
|
||||
*/
|
||||
~MicroBitListener();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -110,20 +110,116 @@ class MicroBitMessageBus : public MicroBitComponent
|
|||
/**
|
||||
* Register a listener function.
|
||||
*
|
||||
* Same as above, except the listener function is passed an extra argument in addition to the
|
||||
* MicroBitEvent, when called.
|
||||
* @param id The source of messages to listen for. Events sent from any other IDs will be filtered.
|
||||
* Use MICROBIT_ID_ANY to receive events from all components.
|
||||
*
|
||||
* @param value The value of messages to listen for. Events with any other values will be filtered.
|
||||
* Use MICROBIT_EVT_ANY to receive events of any value.
|
||||
*
|
||||
* @param hander The function to call when an event is received.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* void onButtonBClick(void *arg)
|
||||
* {
|
||||
* //do something
|
||||
* }
|
||||
* uBit.MessageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick); // call function when ever a click event is detected.
|
||||
* @endcode
|
||||
*/
|
||||
void listen(int id, int value, void (*handler)(MicroBitEvent, void*), void* arg);
|
||||
|
||||
/**
|
||||
* Register a listener function.
|
||||
*
|
||||
* @param id The source of messages to listen for. Events sent from any other IDs will be filtered.
|
||||
* Use MICROBIT_ID_ANY to receive events from all components.
|
||||
*
|
||||
* @param value The value of messages to listen for. Events with any other values will be filtered.
|
||||
* Use MICROBIT_EVT_ANY to receive events of any value.
|
||||
*
|
||||
* @param hander The function to call when an event is received.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* void SomeClass::onButtonBClick()
|
||||
* {
|
||||
* //do something
|
||||
* }
|
||||
*
|
||||
* As above, but allows callbacks into member functions within a C++ object.
|
||||
* This one is a bit more complex, but hey, that's C++ for you!
|
||||
* SomeClass s = new SomeClass();
|
||||
* uBit.MessageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick);
|
||||
* @endcode
|
||||
*/
|
||||
template <typename T>
|
||||
void listen(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent));
|
||||
|
||||
|
||||
/**
|
||||
* Unregister a listener function.
|
||||
* Listners are identified by the Event ID, Event VALUE and handler registered using listen().
|
||||
*
|
||||
* @param id The Event ID used to register the listener.
|
||||
* @param value The Event VALUE used to register the listener.
|
||||
* @param handler The function used to register the listener.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* void onButtonBClick()
|
||||
* {
|
||||
* //do something
|
||||
* }
|
||||
*
|
||||
* uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick);
|
||||
* @endcode
|
||||
*/
|
||||
void ignore(int id, int value, void (*handler)(MicroBitEvent));
|
||||
|
||||
/**
|
||||
* Unregister a listener function.
|
||||
* Listners are identified by the Event ID, Event VALUE and handler registered using listen().
|
||||
*
|
||||
* @param id The Event ID used to register the listener.
|
||||
* @param value The Event VALUE used to register the listener.
|
||||
* @param handler The function used to register the listener.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* void onButtonBClick(void *arg)
|
||||
* {
|
||||
* //do something
|
||||
* }
|
||||
*
|
||||
* uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick);
|
||||
* @endcode
|
||||
*/
|
||||
void ignore(int id, int value, void (*handler)(MicroBitEvent, void*), void* arg);
|
||||
|
||||
/**
|
||||
* Unregister a listener function.
|
||||
* Listners are identified by the Event ID, Event VALUE and handler registered using listen().
|
||||
*
|
||||
* @param id The Event ID used to register the listener.
|
||||
* @param value The Event VALUE used to register the listener.
|
||||
* @param handler The function used to register the listener.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
*
|
||||
* void SomeClass::onButtonBClick()
|
||||
* {
|
||||
* //do something
|
||||
* }
|
||||
*
|
||||
* SomeClass s = new SomeClass();
|
||||
* uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick);
|
||||
* @endcode
|
||||
*/
|
||||
template <typename T>
|
||||
void ignore(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent));
|
||||
private:
|
||||
|
||||
/**
|
||||
|
@ -132,6 +228,7 @@ class MicroBitMessageBus : public MicroBitComponent
|
|||
* @return 1 if the listener is valid, 0 otherwise.
|
||||
*/
|
||||
int add(MicroBitListener *newListener);
|
||||
int remove(MicroBitListener *newListener);
|
||||
|
||||
MicroBitListener *listeners; // Chain of active listeners.
|
||||
MicroBitEventQueueItem *evt_queue_head; // Head of queued events to be processed.
|
||||
|
@ -166,13 +263,39 @@ void MicroBitMessageBus::listen(uint16_t id, uint16_t value, T* object, void (T:
|
|||
MicroBitListener *newListener = new MicroBitListener(id, value, object, handler);
|
||||
|
||||
if(!add(newListener))
|
||||
{
|
||||
delete newListener->cb_method;
|
||||
delete newListener;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a listener function.
|
||||
* Listners are identified by the Event ID, Event VALUE and handler registered using listen().
|
||||
*
|
||||
* @param id The Event ID used to register the listener.
|
||||
* @param value The Event VALUE used to register the listener.
|
||||
* @param handler The function used to register the listener.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* void onButtonBClick(void *arg)
|
||||
* {
|
||||
* //do something
|
||||
* }
|
||||
*
|
||||
* uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick);
|
||||
* @endcode
|
||||
*/
|
||||
template <typename T>
|
||||
void MicroBitMessageBus::ignore(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent))
|
||||
{
|
||||
if (handler == NULL)
|
||||
return;
|
||||
|
||||
MicroBitListener listener(id, value, object, handler);
|
||||
remove(&listener);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ void MemberFunctionCallback::fire(MicroBitEvent e)
|
|||
*/
|
||||
bool MemberFunctionCallback::operator==(const MemberFunctionCallback &mfc)
|
||||
{
|
||||
return (object == mfc.object && memcmp(method,mfc.method,sizeof(method))==0);
|
||||
return (object == mfc.object && (memcmp(method,mfc.method,sizeof(method))==0));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -43,3 +43,11 @@ MicroBitListener::MicroBitListener(uint16_t id, uint16_t value, void (*handler)(
|
|||
this->next = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor. Ensures all resources used by this listener are freed.
|
||||
*/
|
||||
MicroBitListener::~MicroBitListener()
|
||||
{
|
||||
if(this->flags & MESSAGE_BUS_LISTENER_METHOD)
|
||||
delete cb_method;
|
||||
}
|
||||
|
|
|
@ -245,10 +245,7 @@ void MicroBitMessageBus::listen(int id, int value, void (*handler)(MicroBitEvent
|
|||
MicroBitListener *newListener = new MicroBitListener(id, value, handler);
|
||||
|
||||
if(!add(newListener))
|
||||
{
|
||||
delete newListener;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void MicroBitMessageBus::listen(int id, int value, void (*handler)(MicroBitEvent, void*), void* arg)
|
||||
|
@ -259,10 +256,63 @@ void MicroBitMessageBus::listen(int id, int value, void (*handler)(MicroBitEvent
|
|||
MicroBitListener *newListener = new MicroBitListener(id, value, handler, arg);
|
||||
|
||||
if(!add(newListener))
|
||||
{
|
||||
delete newListener;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a listener function.
|
||||
* Listners are identified by the Event ID, Event VALUE and handler registered using listen().
|
||||
*
|
||||
* @param id The Event ID used to register the listener.
|
||||
* @param value The Event VALUE used to register the listener.
|
||||
* @param handler The function used to register the listener.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* void onButtonBClick()
|
||||
* {
|
||||
* //do something
|
||||
* }
|
||||
*
|
||||
* uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick);
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitMessageBus::ignore(int id, int value, void (*handler)(MicroBitEvent))
|
||||
{
|
||||
if (handler == NULL)
|
||||
return;
|
||||
|
||||
MicroBitListener listener(id, value, handler);
|
||||
remove(&listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a listener function.
|
||||
* Listners are identified by the Event ID, Event VALUE and handler registered using listen().
|
||||
*
|
||||
* @param id The Event ID used to register the listener.
|
||||
* @param value The Event VALUE used to register the listener.
|
||||
* @param handler The function used to register the listener.
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* void onButtonBClick(void *arg)
|
||||
* {
|
||||
* //do something
|
||||
* }
|
||||
*
|
||||
* uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick);
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitMessageBus::ignore(int id, int value, void (*handler)(MicroBitEvent, void*), void* arg)
|
||||
{
|
||||
if (handler == NULL)
|
||||
return;
|
||||
|
||||
MicroBitListener listener(id, value, handler, arg);
|
||||
remove(&listener);
|
||||
}
|
||||
|
||||
|
||||
|
@ -280,7 +330,6 @@ int MicroBitMessageBus::add(MicroBitListener *newListener)
|
|||
if (newListener == NULL)
|
||||
return 0;
|
||||
|
||||
methodCallback = newListener->flags & MESSAGE_BUS_LISTENER_METHOD;
|
||||
|
||||
l = listeners;
|
||||
|
||||
|
@ -291,6 +340,8 @@ int MicroBitMessageBus::add(MicroBitListener *newListener)
|
|||
// If we have a callback to a method, check the cb_method class. Otherwise, the cb function point is sufficient.
|
||||
while (l != NULL)
|
||||
{
|
||||
methodCallback = (newListener->flags & MESSAGE_BUS_LISTENER_METHOD) && (l->flags & MESSAGE_BUS_LISTENER_METHOD);
|
||||
|
||||
if (l->id == newListener->id && l->value == newListener->value && (methodCallback ? *l->cb_method == *newListener->cb_method : l->cb == newListener->cb))
|
||||
return 0;
|
||||
|
||||
|
@ -344,3 +395,52 @@ int MicroBitMessageBus::add(MicroBitListener *newListener)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a MicroBitListener from the list that matches the given listener.
|
||||
* @param listener The MicroBitListener to validate.
|
||||
* @return The number of listeners removed from the list.
|
||||
*/
|
||||
int MicroBitMessageBus::remove(MicroBitListener *listener)
|
||||
{
|
||||
MicroBitListener *l, *p;
|
||||
int removed = 0;
|
||||
|
||||
//handler can't be NULL!
|
||||
if (listener == NULL)
|
||||
return 0;
|
||||
|
||||
l = listeners;
|
||||
p = NULL;
|
||||
|
||||
// Walk this list of event handlers. Delete any that match the given listener.
|
||||
while (l != NULL)
|
||||
{
|
||||
if (l->id == listener->id && l->value == listener->value && ((listener->flags & MESSAGE_BUS_LISTENER_METHOD) == (l->flags & MESSAGE_BUS_LISTENER_METHOD)))
|
||||
{
|
||||
if(((listener->flags & MESSAGE_BUS_LISTENER_METHOD) && (*l->cb_method == *listener->cb_method)) ||
|
||||
((!(listener->flags & MESSAGE_BUS_LISTENER_METHOD) && l->cb == listener->cb)))
|
||||
{
|
||||
// Found a match. Remove from the list.
|
||||
if (p == NULL)
|
||||
listeners = l->next;
|
||||
else
|
||||
p->next = l->next;
|
||||
|
||||
// delete the listener.
|
||||
MicroBitListener *t = l;
|
||||
l = l->next;
|
||||
|
||||
delete t;
|
||||
removed++;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
p = l;
|
||||
l = l->next;
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue