High level Bluetooth Low Energy API and radio abstraction layer
Fork of BLE_API by
ble/CallChainOfFunctionPointersWithContext.h@993:4d62b7967c11, 2015-12-02 (annotated)
- Committer:
- rgrover1
- Date:
- Wed Dec 02 10:29:44 2015 +0000
- Revision:
- 993:4d62b7967c11
- Parent:
- 992:ca834f7ae8ed
- Child:
- 1042:21a86ac7f5b1
Synchronized with git rev 12e27cd4
Author: Rohit Grover
Release 2.1.3
=============
* Improvements to CallChainOfFunctionPointerswithContext:
- add a `detach` function to be able to remove callbacks.
- detach function now return true if a function has been detached and
false otherwise.
- add a function call operator.
- use safe-bool idiom. see : http://www.artima.com/cppsource/safebool.html
* Add SafeBool class which allow to easily declare a safe bool operator in
c++03.
* Improvements to FunctionPointerWithContext:
- fix call propagation
- use safe bool idiom
* Add config file for generating Doxygen.
* Setup for onRadioNotification callback does not call initRadioNotification
anymore.
* GapAdvertisementData now handles replacement and appending of data fields
based on type. Some fields can be replaced with new values, and others
require the payload to be appended.
Who changed what in which revision?
User | Revision | Line number | New 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" |
rgrover1 | 993:4d62b7967c11 | 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> |
rgrover1 | 993:4d62b7967c11 | 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: |
rgrover1 | 993:4d62b7967c11 | 65 | /** Create an empty chain. |
rgrover1 | 710:b2e1a2660ec2 | 66 | * |
rgrover1 | 993:4d62b7967c11 | 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 | |
rgrover1 | 993:4d62b7967c11 | 77 | /** Add a function at the front of the chain. |
rgrover1 | 710:b2e1a2660ec2 | 78 | * |
rgrover1 | 993:4d62b7967c11 | 79 | * @param function A pointer to a void function. |
rgrover1 | 710:b2e1a2660ec2 | 80 | * |
rgrover1 | 710:b2e1a2660ec2 | 81 | * @returns |
rgrover1 | 993:4d62b7967c11 | 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 | |
rgrover1 | 993:4d62b7967c11 | 88 | /** Add a function at the front of the chain. |
rgrover1 | 710:b2e1a2660ec2 | 89 | * |
rgrover1 | 993:4d62b7967c11 | 90 | * @param tptr Pointer to the object to call the member function on. |
rgrover1 | 993:4d62b7967c11 | 91 | * @param mptr Pointer to the member function to be called. |
rgrover1 | 710:b2e1a2660ec2 | 92 | * |
rgrover1 | 710:b2e1a2660ec2 | 93 | * @returns |
rgrover1 | 993:4d62b7967c11 | 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 | |
rgrover1 | 993:4d62b7967c11 | 101 | /** Add a function at the front of the chain. |
rgrover1 | 993:4d62b7967c11 | 102 | * |
rgrover1 | 993:4d62b7967c11 | 103 | * @param func The FunctionPointerWithContext to add. |
rgrover1 | 993:4d62b7967c11 | 104 | */ |
rgrover1 | 993:4d62b7967c11 | 105 | pFunctionPointerWithContext_t add(const FunctionPointerWithContext<ContextType>& func) { |
rgrover1 | 993:4d62b7967c11 | 106 | return common_add(new FunctionPointerWithContext<ContextType>(func)); |
rgrover1 | 993:4d62b7967c11 | 107 | } |
rgrover1 | 993:4d62b7967c11 | 108 | |
rgrover1 | 993:4d62b7967c11 | 109 | /** |
rgrover1 | 993:4d62b7967c11 | 110 | * Detach a function pointer from a callchain |
rgrover1 | 993:4d62b7967c11 | 111 | * |
rgrover1 | 993:4d62b7967c11 | 112 | * @oaram toDetach FunctionPointerWithContext to detach from this callchain |
rgrover1 | 993:4d62b7967c11 | 113 | * |
rgrover1 | 993:4d62b7967c11 | 114 | * @return true if a function pointer has been detached and false otherwise |
rgrover1 | 993:4d62b7967c11 | 115 | */ |
rgrover1 | 993:4d62b7967c11 | 116 | bool detach(const FunctionPointerWithContext<ContextType>& toDetach) { |
rgrover1 | 993:4d62b7967c11 | 117 | pFunctionPointerWithContext_t current = chainHead; |
rgrover1 | 993:4d62b7967c11 | 118 | pFunctionPointerWithContext_t previous = NULL; |
rgrover1 | 993:4d62b7967c11 | 119 | |
rgrover1 | 993:4d62b7967c11 | 120 | while (current) { |
rgrover1 | 993:4d62b7967c11 | 121 | if(*current == toDetach) { |
rgrover1 | 993:4d62b7967c11 | 122 | if(previous == NULL) { |
rgrover1 | 993:4d62b7967c11 | 123 | if(currentCalled == current) { |
rgrover1 | 993:4d62b7967c11 | 124 | currentCalled = NULL; |
rgrover1 | 993:4d62b7967c11 | 125 | } |
rgrover1 | 993:4d62b7967c11 | 126 | chainHead = current->getNext(); |
rgrover1 | 993:4d62b7967c11 | 127 | } else { |
rgrover1 | 993:4d62b7967c11 | 128 | if(currentCalled == current) { |
rgrover1 | 993:4d62b7967c11 | 129 | currentCalled = previous; |
rgrover1 | 993:4d62b7967c11 | 130 | } |
rgrover1 | 993:4d62b7967c11 | 131 | previous->chainAsNext(current->getNext()); |
rgrover1 | 993:4d62b7967c11 | 132 | } |
rgrover1 | 993:4d62b7967c11 | 133 | delete current; |
rgrover1 | 993:4d62b7967c11 | 134 | return true; |
rgrover1 | 993:4d62b7967c11 | 135 | } |
rgrover1 | 993:4d62b7967c11 | 136 | |
rgrover1 | 993:4d62b7967c11 | 137 | previous = current; |
rgrover1 | 993:4d62b7967c11 | 138 | current = current->getNext(); |
rgrover1 | 993:4d62b7967c11 | 139 | } |
rgrover1 | 993:4d62b7967c11 | 140 | |
rgrover1 | 993:4d62b7967c11 | 141 | return false; |
rgrover1 | 993:4d62b7967c11 | 142 | } |
rgrover1 | 993:4d62b7967c11 | 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) { |
rgrover1 | 993:4d62b7967c11 | 164 | ((const CallChainOfFunctionPointersWithContext*) this)->call(context); |
rgrover1 | 993:4d62b7967c11 | 165 | } |
rgrover1 | 993:4d62b7967c11 | 166 | |
rgrover1 | 993:4d62b7967c11 | 167 | /** |
rgrover1 | 993:4d62b7967c11 | 168 | * @brief same as above but const |
rgrover1 | 993:4d62b7967c11 | 169 | */ |
rgrover1 | 993:4d62b7967c11 | 170 | void call(ContextType context) const { |
rgrover1 | 993:4d62b7967c11 | 171 | currentCalled = chainHead; |
rgrover1 | 993:4d62b7967c11 | 172 | |
rgrover1 | 993:4d62b7967c11 | 173 | while(currentCalled) { |
rgrover1 | 993:4d62b7967c11 | 174 | currentCalled->call(context); |
rgrover1 | 993:4d62b7967c11 | 175 | // if this was the head and the call removed the head |
rgrover1 | 993:4d62b7967c11 | 176 | if(currentCalled == NULL) { |
rgrover1 | 993:4d62b7967c11 | 177 | currentCalled = chainHead; |
rgrover1 | 993:4d62b7967c11 | 178 | } else { |
rgrover1 | 993:4d62b7967c11 | 179 | currentCalled = currentCalled->getNext(); |
rgrover1 | 993:4d62b7967c11 | 180 | } |
rgrover1 | 953:f6eb43f524b2 | 181 | } |
rgrover1 | 953:f6eb43f524b2 | 182 | } |
rgrover1 | 953:f6eb43f524b2 | 183 | |
rgrover1 | 993:4d62b7967c11 | 184 | /** |
rgrover1 | 993:4d62b7967c11 | 185 | * @brief same as above but with function call operator |
rgrover1 | 993:4d62b7967c11 | 186 | * \code |
rgrover1 | 993:4d62b7967c11 | 187 | * |
rgrover1 | 993:4d62b7967c11 | 188 | * void first(bool); |
rgrover1 | 993:4d62b7967c11 | 189 | * void second(bool); |
rgrover1 | 993:4d62b7967c11 | 190 | * |
rgrover1 | 993:4d62b7967c11 | 191 | * CallChainOfFunctionPointerWithContext<bool> foo; |
rgrover1 | 993:4d62b7967c11 | 192 | * |
rgrover1 | 993:4d62b7967c11 | 193 | * foo.attach(first); |
rgrover1 | 993:4d62b7967c11 | 194 | * foo.attach(second); |
rgrover1 | 993:4d62b7967c11 | 195 | * |
rgrover1 | 993:4d62b7967c11 | 196 | * // call the callchain like a function |
rgrover1 | 993:4d62b7967c11 | 197 | * foo(true); |
rgrover1 | 993:4d62b7967c11 | 198 | * |
rgrover1 | 993:4d62b7967c11 | 199 | * \endcode |
rgrover1 | 993:4d62b7967c11 | 200 | */ |
rgrover1 | 993:4d62b7967c11 | 201 | void operator()(ContextType context) const { |
rgrover1 | 993:4d62b7967c11 | 202 | call(context); |
rgrover1 | 993:4d62b7967c11 | 203 | } |
rgrover1 | 993:4d62b7967c11 | 204 | |
rgrover1 | 993:4d62b7967c11 | 205 | /** |
rgrover1 | 993:4d62b7967c11 | 206 | * @brief bool conversion operation |
rgrover1 | 993:4d62b7967c11 | 207 | */ |
rgrover1 | 993:4d62b7967c11 | 208 | bool toBool() const { |
rgrover1 | 993:4d62b7967c11 | 209 | return chainHead != NULL; |
rgrover1 | 993:4d62b7967c11 | 210 | } |
rgrover1 | 993:4d62b7967c11 | 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; |
rgrover1 | 993:4d62b7967c11 | 226 | // iterator during a function call, this has to be mutable because the call function is const. |
rgrover1 | 993:4d62b7967c11 | 227 | // Note: mutable is the correct behaviour here, the iterator never leak outside the object. |
rgrover1 | 993:4d62b7967c11 | 228 | // So the object can still be seen as logically const even if it change its internal state |
rgrover1 | 993:4d62b7967c11 | 229 | mutable pFunctionPointerWithContext_t currentCalled; |
rgrover1 | 990:53ac0ac3aa39 | 230 | |
rgrover1 | 993:4d62b7967c11 | 231 | |
rgrover1 | 993:4d62b7967c11 | 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 |