Andrew Fox / BLE_API

Fork of BLE_API by Bluetooth Low Energy

Committer:
vcoubard
Date:
Mon Jan 11 08:51:49 2016 +0000
Revision:
1088:709ebced28ab
Parent:
1052:b55e1ad3e1b3
Synchronized with git rev 0781293b
Author: Andres Amaya Garcia
Add onShutdown to register callbacks

Add an onShutdown() function to Gap, GattClient, GattServer and
SecurityManager. The callbacks are added to a private callback chain in each of
the instances. The callbacks will be executed inside each object's reset()
function BEFORE the state of the instance is cleared. The developers of the
platform-specific implementation must call the parent class' reset() function
for the callbacks to be executed.

Finally, an onShutdown() function that returns the shutdown callchain is added
to allow detaching callbacks.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rgrover1 710:b2e1a2660ec2 1 /* mbed Microcontroller Library
rgrover1 710:b2e1a2660ec2 2 * Copyright (c) 2006-2013 ARM Limited
rgrover1 710:b2e1a2660ec2 3 *
rgrover1 710:b2e1a2660ec2 4 * Licensed under the Apache License, Version 2.0 (the "License");
rgrover1 710:b2e1a2660ec2 5 * you may not use this file except in compliance with the License.
rgrover1 710:b2e1a2660ec2 6 * You may obtain a copy of the License at
rgrover1 710:b2e1a2660ec2 7 *
rgrover1 710:b2e1a2660ec2 8 * http://www.apache.org/licenses/LICENSE-2.0
rgrover1 710:b2e1a2660ec2 9 *
rgrover1 710:b2e1a2660ec2 10 * Unless required by applicable law or agreed to in writing, software
rgrover1 710:b2e1a2660ec2 11 * distributed under the License is distributed on an "AS IS" BASIS,
rgrover1 710:b2e1a2660ec2 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rgrover1 710:b2e1a2660ec2 13 * See the License for the specific language governing permissions and
rgrover1 710:b2e1a2660ec2 14 * limitations under the License.
rgrover1 710:b2e1a2660ec2 15 */
rgrover1 710:b2e1a2660ec2 16 #ifndef MBED_CALLCHAIN_OF_FUNCTION_POINTERS_WITH_CONTEXT_H
rgrover1 710:b2e1a2660ec2 17 #define MBED_CALLCHAIN_OF_FUNCTION_POINTERS_WITH_CONTEXT_H
rgrover1 710:b2e1a2660ec2 18
rgrover1 710:b2e1a2660ec2 19 #include <string.h>
rgrover1 710:b2e1a2660ec2 20 #include "FunctionPointerWithContext.h"
vcoubard 1052:b55e1ad3e1b3 21 #include "SafeBool.h"
rgrover1 710:b2e1a2660ec2 22
rgrover1 710:b2e1a2660ec2 23
rgrover1 710:b2e1a2660ec2 24 /** Group one or more functions in an instance of a CallChainOfFunctionPointersWithContext, then call them in
rgrover1 710:b2e1a2660ec2 25 * sequence using CallChainOfFunctionPointersWithContext::call(). Used mostly by the interrupt chaining code,
rgrover1 710:b2e1a2660ec2 26 * but can be used for other purposes.
rgrover1 710:b2e1a2660ec2 27 *
rgrover1 710:b2e1a2660ec2 28 * Example:
rgrover1 710:b2e1a2660ec2 29 * @code
rgrover1 710:b2e1a2660ec2 30 *
rgrover1 710:b2e1a2660ec2 31 * CallChainOfFunctionPointersWithContext<void *> chain;
rgrover1 710:b2e1a2660ec2 32 *
rgrover1 710:b2e1a2660ec2 33 * void first(void *context) {
rgrover1 710:b2e1a2660ec2 34 * printf("'first' function.\n");
rgrover1 710:b2e1a2660ec2 35 * }
rgrover1 710:b2e1a2660ec2 36 *
rgrover1 710:b2e1a2660ec2 37 * void second(void *context) {
rgrover1 710:b2e1a2660ec2 38 * printf("'second' function.\n");
rgrover1 710:b2e1a2660ec2 39 * }
rgrover1 710:b2e1a2660ec2 40 *
rgrover1 710:b2e1a2660ec2 41 * class Test {
rgrover1 710:b2e1a2660ec2 42 * public:
rgrover1 710:b2e1a2660ec2 43 * void f(void *context) {
rgrover1 710:b2e1a2660ec2 44 * printf("A::f (class member).\n");
rgrover1 710:b2e1a2660ec2 45 * }
rgrover1 710:b2e1a2660ec2 46 * };
rgrover1 710:b2e1a2660ec2 47 *
rgrover1 710:b2e1a2660ec2 48 * int main() {
rgrover1 710:b2e1a2660ec2 49 * Test test;
rgrover1 710:b2e1a2660ec2 50 *
rgrover1 710:b2e1a2660ec2 51 * chain.add(second);
rgrover1 710:b2e1a2660ec2 52 * chain.add_front(first);
rgrover1 710:b2e1a2660ec2 53 * chain.add(&test, &Test::f);
rgrover1 710:b2e1a2660ec2 54 * chain.call();
rgrover1 710:b2e1a2660ec2 55 * }
rgrover1 710:b2e1a2660ec2 56 * @endcode
rgrover1 710:b2e1a2660ec2 57 */
rgrover1 710:b2e1a2660ec2 58
rgrover1 710:b2e1a2660ec2 59 template <typename ContextType>
vcoubard 1052:b55e1ad3e1b3 60 class CallChainOfFunctionPointersWithContext : public SafeBool<CallChainOfFunctionPointersWithContext<ContextType> > {
rgrover1 710:b2e1a2660ec2 61 public:
rgrover1 710:b2e1a2660ec2 62 typedef FunctionPointerWithContext<ContextType> *pFunctionPointerWithContext_t;
rgrover1 710:b2e1a2660ec2 63
rgrover1 710:b2e1a2660ec2 64 public:
vcoubard 1048:efb29faf12fc 65 /** Create an empty chain.
rgrover1 710:b2e1a2660ec2 66 *
vcoubard 1048:efb29faf12fc 67 * @param size (optional) Initial size of the chain.
rgrover1 710:b2e1a2660ec2 68 */
rgrover1 710:b2e1a2660ec2 69 CallChainOfFunctionPointersWithContext() : chainHead(NULL) {
rgrover1 710:b2e1a2660ec2 70 /* empty */
rgrover1 710:b2e1a2660ec2 71 }
rgrover1 710:b2e1a2660ec2 72
rgrover1 710:b2e1a2660ec2 73 virtual ~CallChainOfFunctionPointersWithContext() {
rgrover1 710:b2e1a2660ec2 74 clear();
rgrover1 710:b2e1a2660ec2 75 }
rgrover1 710:b2e1a2660ec2 76
vcoubard 1048:efb29faf12fc 77 /** Add a function at the front of the chain.
rgrover1 710:b2e1a2660ec2 78 *
vcoubard 1048:efb29faf12fc 79 * @param function A pointer to a void function.
rgrover1 710:b2e1a2660ec2 80 *
rgrover1 710:b2e1a2660ec2 81 * @returns
vcoubard 1048:efb29faf12fc 82 * The function object created for 'function'.
rgrover1 710:b2e1a2660ec2 83 */
rgrover1 710:b2e1a2660ec2 84 pFunctionPointerWithContext_t add(void (*function)(ContextType context)) {
rgrover1 710:b2e1a2660ec2 85 return common_add(new FunctionPointerWithContext<ContextType>(function));
rgrover1 710:b2e1a2660ec2 86 }
rgrover1 710:b2e1a2660ec2 87
vcoubard 1048:efb29faf12fc 88 /** Add a function at the front of the chain.
rgrover1 710:b2e1a2660ec2 89 *
vcoubard 1048:efb29faf12fc 90 * @param tptr Pointer to the object to call the member function on.
vcoubard 1048:efb29faf12fc 91 * @param mptr Pointer to the member function to be called.
rgrover1 710:b2e1a2660ec2 92 *
rgrover1 710:b2e1a2660ec2 93 * @returns
vcoubard 1048:efb29faf12fc 94 * The function object created for 'tptr' and 'mptr'.
rgrover1 710:b2e1a2660ec2 95 */
rgrover1 710:b2e1a2660ec2 96 template<typename T>
rgrover1 710:b2e1a2660ec2 97 pFunctionPointerWithContext_t add(T *tptr, void (T::*mptr)(ContextType context)) {
rgrover1 710:b2e1a2660ec2 98 return common_add(new FunctionPointerWithContext<ContextType>(tptr, mptr));
rgrover1 710:b2e1a2660ec2 99 }
rgrover1 710:b2e1a2660ec2 100
vcoubard 1052:b55e1ad3e1b3 101 /** Add a function at the front of the chain.
vcoubard 1052:b55e1ad3e1b3 102 *
vcoubard 1052:b55e1ad3e1b3 103 * @param func The FunctionPointerWithContext to add.
vcoubard 1052:b55e1ad3e1b3 104 */
vcoubard 1052:b55e1ad3e1b3 105 pFunctionPointerWithContext_t add(const FunctionPointerWithContext<ContextType>& func) {
vcoubard 1052:b55e1ad3e1b3 106 return common_add(new FunctionPointerWithContext<ContextType>(func));
vcoubard 1052:b55e1ad3e1b3 107 }
vcoubard 1052:b55e1ad3e1b3 108
vcoubard 1052:b55e1ad3e1b3 109 /**
vcoubard 1052:b55e1ad3e1b3 110 * Detach a function pointer from a callchain
vcoubard 1052:b55e1ad3e1b3 111 *
vcoubard 1052:b55e1ad3e1b3 112 * @oaram toDetach FunctionPointerWithContext to detach from this callchain
vcoubard 1052:b55e1ad3e1b3 113 *
vcoubard 1052:b55e1ad3e1b3 114 * @return true if a function pointer has been detached and false otherwise
vcoubard 1052:b55e1ad3e1b3 115 */
vcoubard 1052:b55e1ad3e1b3 116 bool detach(const FunctionPointerWithContext<ContextType>& toDetach) {
vcoubard 1052:b55e1ad3e1b3 117 pFunctionPointerWithContext_t current = chainHead;
vcoubard 1052:b55e1ad3e1b3 118 pFunctionPointerWithContext_t previous = NULL;
vcoubard 1052:b55e1ad3e1b3 119
vcoubard 1052:b55e1ad3e1b3 120 while (current) {
vcoubard 1052:b55e1ad3e1b3 121 if(*current == toDetach) {
vcoubard 1052:b55e1ad3e1b3 122 if(previous == NULL) {
vcoubard 1052:b55e1ad3e1b3 123 if(currentCalled == current) {
vcoubard 1052:b55e1ad3e1b3 124 currentCalled = NULL;
vcoubard 1052:b55e1ad3e1b3 125 }
vcoubard 1052:b55e1ad3e1b3 126 chainHead = current->getNext();
vcoubard 1052:b55e1ad3e1b3 127 } else {
vcoubard 1052:b55e1ad3e1b3 128 if(currentCalled == current) {
vcoubard 1052:b55e1ad3e1b3 129 currentCalled = previous;
vcoubard 1052:b55e1ad3e1b3 130 }
vcoubard 1052:b55e1ad3e1b3 131 previous->chainAsNext(current->getNext());
vcoubard 1052:b55e1ad3e1b3 132 }
vcoubard 1052:b55e1ad3e1b3 133 delete current;
vcoubard 1052:b55e1ad3e1b3 134 return true;
vcoubard 1052:b55e1ad3e1b3 135 }
vcoubard 1052:b55e1ad3e1b3 136
vcoubard 1052:b55e1ad3e1b3 137 previous = current;
vcoubard 1052:b55e1ad3e1b3 138 current = current->getNext();
vcoubard 1052:b55e1ad3e1b3 139 }
vcoubard 1052:b55e1ad3e1b3 140
vcoubard 1052:b55e1ad3e1b3 141 return false;
vcoubard 1052:b55e1ad3e1b3 142 }
vcoubard 1052:b55e1ad3e1b3 143
rgrover1 710:b2e1a2660ec2 144 /** Clear the call chain (remove all functions in the chain).
rgrover1 710:b2e1a2660ec2 145 */
rgrover1 710:b2e1a2660ec2 146 void clear(void) {
rgrover1 710:b2e1a2660ec2 147 pFunctionPointerWithContext_t fptr = chainHead;
rgrover1 710:b2e1a2660ec2 148 while (fptr) {
rgrover1 710:b2e1a2660ec2 149 pFunctionPointerWithContext_t deadPtr = fptr;
rgrover1 710:b2e1a2660ec2 150 fptr = deadPtr->getNext();
rgrover1 710:b2e1a2660ec2 151 delete deadPtr;
rgrover1 710:b2e1a2660ec2 152 }
rgrover1 710:b2e1a2660ec2 153
rgrover1 710:b2e1a2660ec2 154 chainHead = NULL;
rgrover1 710:b2e1a2660ec2 155 }
rgrover1 710:b2e1a2660ec2 156
rgrover1 710:b2e1a2660ec2 157 bool hasCallbacksAttached(void) const {
rgrover1 710:b2e1a2660ec2 158 return (chainHead != NULL);
rgrover1 710:b2e1a2660ec2 159 }
rgrover1 710:b2e1a2660ec2 160
rgrover1 710:b2e1a2660ec2 161 /** Call all the functions in the chain in sequence
rgrover1 710:b2e1a2660ec2 162 */
rgrover1 710:b2e1a2660ec2 163 void call(ContextType context) {
vcoubard 1052:b55e1ad3e1b3 164 ((const CallChainOfFunctionPointersWithContext*) this)->call(context);
vcoubard 1052:b55e1ad3e1b3 165 }
vcoubard 1052:b55e1ad3e1b3 166
vcoubard 1052:b55e1ad3e1b3 167 /**
vcoubard 1052:b55e1ad3e1b3 168 * @brief same as above but const
vcoubard 1052:b55e1ad3e1b3 169 */
vcoubard 1052:b55e1ad3e1b3 170 void call(ContextType context) const {
vcoubard 1052:b55e1ad3e1b3 171 currentCalled = chainHead;
vcoubard 1052:b55e1ad3e1b3 172
vcoubard 1052:b55e1ad3e1b3 173 while(currentCalled) {
vcoubard 1052:b55e1ad3e1b3 174 currentCalled->call(context);
vcoubard 1052:b55e1ad3e1b3 175 // if this was the head and the call removed the head
vcoubard 1052:b55e1ad3e1b3 176 if(currentCalled == NULL) {
vcoubard 1052:b55e1ad3e1b3 177 currentCalled = chainHead;
vcoubard 1052:b55e1ad3e1b3 178 } else {
vcoubard 1052:b55e1ad3e1b3 179 currentCalled = currentCalled->getNext();
vcoubard 1052:b55e1ad3e1b3 180 }
rgrover1 953:f6eb43f524b2 181 }
rgrover1 953:f6eb43f524b2 182 }
rgrover1 953:f6eb43f524b2 183
vcoubard 1052:b55e1ad3e1b3 184 /**
vcoubard 1052:b55e1ad3e1b3 185 * @brief same as above but with function call operator
vcoubard 1052:b55e1ad3e1b3 186 * \code
vcoubard 1052:b55e1ad3e1b3 187 *
vcoubard 1052:b55e1ad3e1b3 188 * void first(bool);
vcoubard 1052:b55e1ad3e1b3 189 * void second(bool);
vcoubard 1052:b55e1ad3e1b3 190 *
vcoubard 1052:b55e1ad3e1b3 191 * CallChainOfFunctionPointerWithContext<bool> foo;
vcoubard 1052:b55e1ad3e1b3 192 *
vcoubard 1052:b55e1ad3e1b3 193 * foo.attach(first);
vcoubard 1052:b55e1ad3e1b3 194 * foo.attach(second);
vcoubard 1052:b55e1ad3e1b3 195 *
vcoubard 1052:b55e1ad3e1b3 196 * // call the callchain like a function
vcoubard 1052:b55e1ad3e1b3 197 * foo(true);
vcoubard 1052:b55e1ad3e1b3 198 *
vcoubard 1052:b55e1ad3e1b3 199 * \endcode
vcoubard 1052:b55e1ad3e1b3 200 */
vcoubard 1052:b55e1ad3e1b3 201 void operator()(ContextType context) const {
vcoubard 1052:b55e1ad3e1b3 202 call(context);
vcoubard 1052:b55e1ad3e1b3 203 }
vcoubard 1052:b55e1ad3e1b3 204
vcoubard 1052:b55e1ad3e1b3 205 /**
vcoubard 1052:b55e1ad3e1b3 206 * @brief bool conversion operation
vcoubard 1052:b55e1ad3e1b3 207 */
vcoubard 1052:b55e1ad3e1b3 208 bool toBool() const {
vcoubard 1052:b55e1ad3e1b3 209 return chainHead != NULL;
vcoubard 1052:b55e1ad3e1b3 210 }
vcoubard 1052:b55e1ad3e1b3 211
rgrover1 710:b2e1a2660ec2 212 private:
rgrover1 710:b2e1a2660ec2 213 pFunctionPointerWithContext_t common_add(pFunctionPointerWithContext_t pf) {
rgrover1 710:b2e1a2660ec2 214 if (chainHead == NULL) {
rgrover1 710:b2e1a2660ec2 215 chainHead = pf;
rgrover1 710:b2e1a2660ec2 216 } else {
rgrover1 710:b2e1a2660ec2 217 pf->chainAsNext(chainHead);
rgrover1 710:b2e1a2660ec2 218 chainHead = pf;
rgrover1 710:b2e1a2660ec2 219 }
rgrover1 710:b2e1a2660ec2 220
rgrover1 710:b2e1a2660ec2 221 return chainHead;
rgrover1 710:b2e1a2660ec2 222 }
rgrover1 710:b2e1a2660ec2 223
rgrover1 710:b2e1a2660ec2 224 private:
rgrover1 710:b2e1a2660ec2 225 pFunctionPointerWithContext_t chainHead;
vcoubard 1052:b55e1ad3e1b3 226 // iterator during a function call, this has to be mutable because the call function is const.
vcoubard 1052:b55e1ad3e1b3 227 // Note: mutable is the correct behaviour here, the iterator never leak outside the object.
vcoubard 1052:b55e1ad3e1b3 228 // So the object can still be seen as logically const even if it change its internal state
vcoubard 1052:b55e1ad3e1b3 229 mutable pFunctionPointerWithContext_t currentCalled;
vcoubard 1052:b55e1ad3e1b3 230
rgrover1 990:53ac0ac3aa39 231
vcoubard 1048:efb29faf12fc 232 /* Disallow copy constructor and assignment operators. */
rgrover1 710:b2e1a2660ec2 233 private:
rgrover1 710:b2e1a2660ec2 234 CallChainOfFunctionPointersWithContext(const CallChainOfFunctionPointersWithContext &);
rgrover1 710:b2e1a2660ec2 235 CallChainOfFunctionPointersWithContext & operator = (const CallChainOfFunctionPointersWithContext &);
rgrover1 710:b2e1a2660ec2 236 };
rgrover1 710:b2e1a2660ec2 237
rgrover1 710:b2e1a2660ec2 238 #endif