Updated

Fork of BLE_API by Bluetooth Low Energy

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?

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"
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