Various enhancement:
Add SafeBool class which allow to easily declare a safe bool operator in c++03. CallChainOfFunctionPointerswithContext: - unify syntax of add - detach function now return true if a function has been detached and false otherwise - Explanations about function call operator - use safe bool idiom - explanations about iterator and why it is mutable FunctionPointerWithContext: - fix call propagation - use safe bool idiom Gap: - add documentation - onRadioNotification does mot call initRadioNotification anymore GattClient: - documentation GattServer: - documentationmaster
parent
38e27c4a0a
commit
184d29c35b
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <string.h>
|
||||
#include "FunctionPointerWithContext.h"
|
||||
#include "SafeBool.h"
|
||||
|
||||
|
||||
/** Group one or more functions in an instance of a CallChainOfFunctionPointersWithContext, then call them in
|
||||
|
@ -56,7 +57,7 @@
|
|||
*/
|
||||
|
||||
template <typename ContextType>
|
||||
class CallChainOfFunctionPointersWithContext {
|
||||
class CallChainOfFunctionPointersWithContext : public SafeBool<CallChainOfFunctionPointersWithContext<ContextType> > {
|
||||
public:
|
||||
typedef FunctionPointerWithContext<ContextType> *pFunctionPointerWithContext_t;
|
||||
|
||||
|
@ -101,8 +102,8 @@ public:
|
|||
*
|
||||
* @param func The FunctionPointerWithContext to add.
|
||||
*/
|
||||
void add(const FunctionPointerWithContext<ContextType>& func) {
|
||||
common_add(new FunctionPointerWithContext<ContextType>(func));
|
||||
pFunctionPointerWithContext_t add(const FunctionPointerWithContext<ContextType>& func) {
|
||||
return common_add(new FunctionPointerWithContext<ContextType>(func));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,7 +113,7 @@ public:
|
|||
*
|
||||
* @return true if a function pointer has been detached and false otherwise
|
||||
*/
|
||||
void detach(const FunctionPointerWithContext<ContextType>& toDetach) {
|
||||
bool detach(const FunctionPointerWithContext<ContextType>& toDetach) {
|
||||
pFunctionPointerWithContext_t current = chainHead;
|
||||
pFunctionPointerWithContext_t previous = NULL;
|
||||
|
||||
|
@ -130,12 +131,14 @@ public:
|
|||
previous->chainAsNext(current->getNext());
|
||||
}
|
||||
delete current;
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
previous = current;
|
||||
current = current->getNext();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Clear the call chain (remove all functions in the chain).
|
||||
|
@ -156,9 +159,6 @@ public:
|
|||
}
|
||||
|
||||
/** Call all the functions in the chain in sequence
|
||||
* @Note: The stack frames of all the callbacks within the chained
|
||||
* FunctionPointers will stack up. Hopefully there won't be too many
|
||||
* chained FunctionPointers.
|
||||
*/
|
||||
void call(ContextType context) {
|
||||
((const CallChainOfFunctionPointersWithContext*) this)->call(context);
|
||||
|
@ -183,16 +183,30 @@ public:
|
|||
|
||||
/**
|
||||
* @brief same as above but with function call operator
|
||||
* \code
|
||||
*
|
||||
* void first(bool);
|
||||
* void second(bool);
|
||||
*
|
||||
* CallChainOfFunctionPointerWithContext<bool> foo;
|
||||
*
|
||||
* foo.attach(first);
|
||||
* foo.attach(second);
|
||||
*
|
||||
* // call the callchain like a function
|
||||
* foo(true);
|
||||
*
|
||||
* \endcode
|
||||
*/
|
||||
void operator()(ContextType context) const {
|
||||
call(context);
|
||||
}
|
||||
|
||||
typedef void (CallChainOfFunctionPointersWithContext::*bool_type)() const;
|
||||
void True() const {}
|
||||
|
||||
operator bool_type() const {
|
||||
return chainHead == NULL ? 0 : &CallChainOfFunctionPointersWithContext::True;
|
||||
/**
|
||||
* @brief bool conversion operation
|
||||
*/
|
||||
bool toBool() const {
|
||||
return chainHead != NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -209,6 +223,9 @@ private:
|
|||
|
||||
private:
|
||||
pFunctionPointerWithContext_t chainHead;
|
||||
// iterator during a function call, this has to be mutable because the call function is const.
|
||||
// Note: mutable is the correct behaviour here, the iterator never leak outside the object.
|
||||
// So the object can still be seen as logically const even if it change its internal state
|
||||
mutable pFunctionPointerWithContext_t currentCalled;
|
||||
|
||||
|
||||
|
|
|
@ -18,12 +18,13 @@
|
|||
#define MBED_FUNCTIONPOINTER_WITH_CONTEXT_H
|
||||
|
||||
#include <string.h>
|
||||
#include "SafeBool.h"
|
||||
|
||||
/** A class for storing and calling a pointer to a static or member void function
|
||||
* that takes a context.
|
||||
*/
|
||||
template <typename ContextType>
|
||||
class FunctionPointerWithContext {
|
||||
class FunctionPointerWithContext : public SafeBool<FunctionPointerWithContext<ContextType> > {
|
||||
public:
|
||||
typedef FunctionPointerWithContext<ContextType> *pFunctionPointerWithContext_t;
|
||||
typedef const FunctionPointerWithContext<ContextType> *cpFunctionPointerWithContext_t;
|
||||
|
@ -87,11 +88,6 @@ public:
|
|||
* many FunctionPointers in a chain. */
|
||||
void call(ContextType context) const {
|
||||
_caller(this, context);
|
||||
|
||||
/* Propagate the call to next in the chain. */
|
||||
if (_next) {
|
||||
_next->call(context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -103,7 +99,7 @@ public:
|
|||
|
||||
/** Same as above, workaround for mbed os FunctionPointer implementation. */
|
||||
void call(ContextType context) {
|
||||
_caller(this, context);
|
||||
((const FunctionPointerWithContext*) this)->call(context);
|
||||
}
|
||||
|
||||
typedef void (FunctionPointerWithContext::*bool_type)() const;
|
||||
|
@ -111,12 +107,8 @@ public:
|
|||
/**
|
||||
* implementation of safe bool operator
|
||||
*/
|
||||
operator bool_type() const {
|
||||
if(_function || _memberFunctionAndPointer._object) {
|
||||
return &FunctionPointerWithContext::trueValue;
|
||||
}
|
||||
|
||||
return 0;
|
||||
bool toBool() const {
|
||||
return (_function || _memberFunctionAndPointer._object);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -164,12 +156,6 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief True value used in conversion to bool, this function is useless
|
||||
* beside this usage
|
||||
*/
|
||||
void trueValue() const {}
|
||||
|
||||
struct MemberFunctionAndPtr {
|
||||
/*
|
||||
* Forward declaration of a class and a member function to this class.
|
||||
|
|
26
ble/Gap.h
26
ble/Gap.h
|
@ -897,35 +897,56 @@ public:
|
|||
/**
|
||||
* Set up a callback for timeout events. Refer to TimeoutSource_t for
|
||||
* possible event types.
|
||||
* @note It is possible to unregister callbacks using onTimeout().detach(callback)
|
||||
*/
|
||||
void onTimeout(TimeoutEventCallback_t callback) {
|
||||
timeoutCallbackChain.add(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief provide access to the callchain of timeout event callbacks
|
||||
* It is possible to register callbacks using onTimeout().add(callback);
|
||||
* It is possible to unregister callbacks using onTimeout().detach(callback)
|
||||
* @return The timeout event callbacks chain
|
||||
*/
|
||||
TimeoutEventCallbackChain_t& onTimeout() {
|
||||
return timeoutCallbackChain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append to a chain of callbacks to be invoked upon GAP connection.
|
||||
* @note It is possible to unregister callbacks using onConnection().detach(callback)
|
||||
*/
|
||||
void onConnection(ConnectionEventCallback_t callback) {connectionCallChain.add(callback);}
|
||||
|
||||
template<typename T>
|
||||
void onConnection(T *tptr, void (T::*mptr)(const ConnectionCallbackParams_t*)) {connectionCallChain.add(tptr, mptr);}
|
||||
|
||||
/**
|
||||
* @brief provide access to the callchain of connection event callbacks
|
||||
* It is possible to register callbacks using onConnection().add(callback);
|
||||
* It is possible to unregister callbacks using onConnection().detach(callback)
|
||||
* @return The connection event callbacks chain
|
||||
*/
|
||||
ConnectionEventCallbackChain_t& onconnection() {
|
||||
return connectionCallChain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append to a chain of callbacks to be invoked upon GAP disconnection.
|
||||
* @note It is possible to unregister callbacks using onDisconnection().detach(callback)
|
||||
*/
|
||||
void onDisconnection(DisconnectionEventCallback_t callback) {disconnectionCallChain.add(callback);}
|
||||
|
||||
template<typename T>
|
||||
void onDisconnection(T *tptr, void (T::*mptr)(const DisconnectionCallbackParams_t*)) {disconnectionCallChain.add(tptr, mptr);}
|
||||
|
||||
/**
|
||||
* @brief provide access to the callchain of disconnection event callbacks
|
||||
* It is possible to register callbacks using onDisconnection().add(callback);
|
||||
* It is possible to unregister callbacks using onDisconnection().detach(callback)
|
||||
* @return The disconnection event callbacks chain
|
||||
*/
|
||||
DisconnectionEventCallbackChain_t& onDisconnection() {
|
||||
return disconnectionCallChain;
|
||||
}
|
||||
|
@ -959,15 +980,10 @@ public:
|
|||
*/
|
||||
void onRadioNotification(void (*callback)(bool param)) {
|
||||
radioNotificationCallback.attach(callback);
|
||||
// why does it start radio notification ? It is not even indicated in the
|
||||
// doc that it start the listening process
|
||||
initRadioNotification();
|
||||
}
|
||||
template <typename T>
|
||||
void onRadioNotification(T *tptr, void (T::*mptr)(bool)) {
|
||||
radioNotificationCallback.attach(tptr, mptr);
|
||||
// why does it start radio notification ?
|
||||
initRadioNotification();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
|
@ -246,24 +246,40 @@ public:
|
|||
/* Event callback handlers. */
|
||||
public:
|
||||
/**
|
||||
* Set up a callback for read response events.
|
||||
* Set up a callback for read response events.
|
||||
* It is possible to remove registered callbacks using
|
||||
* onDataRead().detach(callbackToRemove)
|
||||
*/
|
||||
void onDataRead(ReadCallback_t callback) {
|
||||
onDataReadCallbackChain.add(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief provide access to the callchain of read callbacks
|
||||
* It is possible to register callbacks using onDataRead().add(callback);
|
||||
* It is possible to unregister callbacks using onDataRead().detach(callback)
|
||||
* @return The read callbacks chain
|
||||
*/
|
||||
ReadCallbackChain_t& onDataRead() {
|
||||
return onDataReadCallbackChain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up a callback for write response events.
|
||||
* It is possible to remove registered callbacks using
|
||||
* onDataWritten().detach(callbackToRemove).
|
||||
* @Note: Write commands (issued using writeWoResponse) don't generate a response.
|
||||
*/
|
||||
void onDataWritten(WriteCallback_t callback) {
|
||||
onDataWriteCallbackChain.add(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief provide access to the callchain of data written callbacks
|
||||
* It is possible to register callbacks using onDataWritten().add(callback);
|
||||
* It is possible to unregister callbacks using onDataWritten().detach(callback)
|
||||
* @return The data written callbacks chain
|
||||
*/
|
||||
WriteCallbackChain_t& onDataWritten() {
|
||||
return onDataWriteCallbackChain;
|
||||
}
|
||||
|
@ -292,11 +308,19 @@ public:
|
|||
* Set up a callback for when the GATT client receives an update event
|
||||
* corresponding to a change in the value of a characteristic on the remote
|
||||
* GATT server.
|
||||
* It is possible to remove registered callbacks using onHVX().detach(callbackToRemove).
|
||||
*/
|
||||
void onHVX(HVXCallback_t callback) {
|
||||
onHVXCallbackChain.add(callback);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief provide access to the callchain of HVX callbacks
|
||||
* It is possible to register callbacks using onHVX().add(callback);
|
||||
* It is possible to unregister callbacks using onHVX().detach(callback)
|
||||
* @return The HVX callbacks chain
|
||||
*/
|
||||
HVXCallbackChain_t& onHVX() {
|
||||
return onHVXCallbackChain;
|
||||
}
|
||||
|
|
|
@ -274,6 +274,8 @@ public:
|
|||
*
|
||||
* @Note: It is also possible to set up a callback into a member function of
|
||||
* some object.
|
||||
*
|
||||
* @Note It is possible to unregister a callback using onDataWritten().detach(callback)
|
||||
*/
|
||||
void onDataWritten(const DataWrittenCallback_t& callback) {dataWrittenCallChain.add(callback);}
|
||||
template <typename T>
|
||||
|
@ -281,6 +283,12 @@ public:
|
|||
dataWrittenCallChain.add(objPtr, memberPtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief provide access to the callchain of data written event callbacks
|
||||
* It is possible to register callbacks using onDataWritten().add(callback);
|
||||
* It is possible to unregister callbacks using onDataWritten().detach(callback)
|
||||
* @return The data written event callbacks chain
|
||||
*/
|
||||
DataWrittenCallbackChain_t& onDataWritten() {
|
||||
return dataWrittenCallChain;
|
||||
}
|
||||
|
@ -301,6 +309,8 @@ public:
|
|||
* @Note: It is also possible to set up a callback into a member function of
|
||||
* some object.
|
||||
*
|
||||
* @Note It is possible to unregister a callback using onDataRead().detach(callback)
|
||||
*
|
||||
* @return BLE_ERROR_NOT_IMPLEMENTED if this functionality isn't available;
|
||||
* else BLE_ERROR_NONE.
|
||||
*/
|
||||
|
@ -322,6 +332,12 @@ public:
|
|||
return BLE_ERROR_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief provide access to the callchain of data read event callbacks
|
||||
* It is possible to register callbacks using onDataRead().add(callback);
|
||||
* It is possible to unregister callbacks using onDataRead().detach(callback)
|
||||
* @return The data read event callbacks chain
|
||||
*/
|
||||
DataReadCallbackChain_t& onDataRead() {
|
||||
return dataReadCallChain;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2006-2013 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef BLE_API_SAFE_BOOL_H_
|
||||
#define BLE_API_SAFE_BOOL_H_
|
||||
|
||||
//safe bool idiom, see : http://www.artima.com/cppsource/safebool.html
|
||||
|
||||
namespace SafeBool_ {
|
||||
/**
|
||||
* @brief Base class for all intances of SafeBool,
|
||||
* This base class reduce instantiation of trueTag function
|
||||
*/
|
||||
class base {
|
||||
template<typename>
|
||||
friend class SafeBool;
|
||||
|
||||
protected:
|
||||
//the bool type is a pointer to method which can be used in boolean context
|
||||
typedef void (base::*BoolType_t)() const;
|
||||
|
||||
// non implemented call, use to disallow conversion between unrelated types
|
||||
void invalidTag() const;
|
||||
|
||||
// member function which indicate true value
|
||||
void trueTag() const {}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief template class SafeBool use CRTP to made boolean conversion easy and correct.
|
||||
* Derived class should implement the function bool toBool() const to make this work. Inheritance
|
||||
* should be public.
|
||||
*
|
||||
* @tparam T Type of the derived class
|
||||
*
|
||||
* \code
|
||||
*
|
||||
* class A : public SafeBool<A> {
|
||||
* public:
|
||||
*
|
||||
* // boolean conversion
|
||||
* bool toBool() {
|
||||
*
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* class B : public SafeBool<B> {
|
||||
* public:
|
||||
*
|
||||
* // boolean conversion
|
||||
* bool toBool() const {
|
||||
*
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* A a;
|
||||
* B b;
|
||||
*
|
||||
* // will compile
|
||||
* if(a) {
|
||||
*
|
||||
* }
|
||||
*
|
||||
* // compilation error
|
||||
* if(a == b) {
|
||||
*
|
||||
* }
|
||||
*
|
||||
*
|
||||
* \endcode
|
||||
*/
|
||||
template <typename T>
|
||||
class SafeBool : public SafeBool_::base {
|
||||
public:
|
||||
/**
|
||||
* bool operator implementation, derived class has to provide bool toBool() const function.
|
||||
*/
|
||||
operator BoolType_t() const {
|
||||
return (static_cast<const T*>(this))->toBool()
|
||||
? &SafeBool<T>::trueTag : 0;
|
||||
}
|
||||
};
|
||||
|
||||
//Avoid conversion to bool between different classes
|
||||
template <typename T, typename U>
|
||||
void operator==(const SafeBool<T>& lhs,const SafeBool<U>& rhs) {
|
||||
lhs.invalidTag();
|
||||
// return false;
|
||||
}
|
||||
|
||||
//Avoid conversion to bool between different classes
|
||||
template <typename T,typename U>
|
||||
void operator!=(const SafeBool<T>& lhs,const SafeBool<U>& rhs) {
|
||||
lhs.invalidTag();
|
||||
// return false;
|
||||
}
|
||||
|
||||
#endif /* BLE_API_SAFE_BOOL_H_ */
|
|
@ -33,7 +33,7 @@ DiscoveredCharacteristic::read(uint16_t offset) const
|
|||
|
||||
struct OneShotReadCallback {
|
||||
static void launch(GattClient* client, Gap::Handle_t connHandle,
|
||||
GattAttribute::Handle_t handle,const GattClient::ReadCallback_t& cb) {
|
||||
GattAttribute::Handle_t handle, const GattClient::ReadCallback_t& cb) {
|
||||
OneShotReadCallback* oneShot = new OneShotReadCallback(client, connHandle, handle, cb);
|
||||
oneShot->attach();
|
||||
// delete will be made when this callback is called
|
||||
|
@ -107,7 +107,7 @@ DiscoveredCharacteristic::writeWoResponse(uint16_t length, const uint8_t *value)
|
|||
|
||||
struct OneShotWriteCallback {
|
||||
static void launch(GattClient* client, Gap::Handle_t connHandle,
|
||||
GattAttribute::Handle_t handle,const GattClient::WriteCallback_t& cb) {
|
||||
GattAttribute::Handle_t handle, const GattClient::WriteCallback_t& cb) {
|
||||
OneShotWriteCallback* oneShot = new OneShotWriteCallback(client, connHandle, handle, cb);
|
||||
oneShot->attach();
|
||||
// delete will be made when this callback is called
|
||||
|
|
Loading…
Reference in New Issue