Merge pull request #109 from pan-/removePersistantCallbacks
Remove persistant callbacks
This commit is contained in:
commit
7de3434278
9 changed files with 540 additions and 72 deletions
|
@ -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;
|
||||
|
||||
|
@ -97,6 +98,49 @@ public:
|
|||
return common_add(new FunctionPointerWithContext<ContextType>(tptr, mptr));
|
||||
}
|
||||
|
||||
/** Add a function at the front of the chain.
|
||||
*
|
||||
* @param func The FunctionPointerWithContext to add.
|
||||
*/
|
||||
pFunctionPointerWithContext_t add(const FunctionPointerWithContext<ContextType>& func) {
|
||||
return common_add(new FunctionPointerWithContext<ContextType>(func));
|
||||
}
|
||||
|
||||
/**
|
||||
* Detach a function pointer from a callchain
|
||||
*
|
||||
* @oaram toDetach FunctionPointerWithContext to detach from this callchain
|
||||
*
|
||||
* @return true if a function pointer has been detached and false otherwise
|
||||
*/
|
||||
bool detach(const FunctionPointerWithContext<ContextType>& toDetach) {
|
||||
pFunctionPointerWithContext_t current = chainHead;
|
||||
pFunctionPointerWithContext_t previous = NULL;
|
||||
|
||||
while (current) {
|
||||
if(*current == toDetach) {
|
||||
if(previous == NULL) {
|
||||
if(currentCalled == current) {
|
||||
currentCalled = NULL;
|
||||
}
|
||||
chainHead = current->getNext();
|
||||
} else {
|
||||
if(currentCalled == current) {
|
||||
currentCalled = previous;
|
||||
}
|
||||
previous->chainAsNext(current->getNext());
|
||||
}
|
||||
delete current;
|
||||
return true;
|
||||
}
|
||||
|
||||
previous = current;
|
||||
current = current->getNext();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Clear the call chain (remove all functions in the chain).
|
||||
*/
|
||||
void clear(void) {
|
||||
|
@ -115,16 +159,56 @@ 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) {
|
||||
if (chainHead) {
|
||||
chainHead->call(context);
|
||||
((const CallChainOfFunctionPointersWithContext*) this)->call(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief same as above but const
|
||||
*/
|
||||
void call(ContextType context) const {
|
||||
currentCalled = chainHead;
|
||||
|
||||
while(currentCalled) {
|
||||
currentCalled->call(context);
|
||||
// if this was the head and the call removed the head
|
||||
if(currentCalled == NULL) {
|
||||
currentCalled = chainHead;
|
||||
} else {
|
||||
currentCalled = currentCalled->getNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief bool conversion operation
|
||||
*/
|
||||
bool toBool() const {
|
||||
return chainHead != NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
pFunctionPointerWithContext_t common_add(pFunctionPointerWithContext_t pf) {
|
||||
if (chainHead == NULL) {
|
||||
|
@ -139,6 +223,11 @@ 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;
|
||||
|
||||
|
||||
/* Disallow copy constructor and assignment operators. */
|
||||
private:
|
||||
|
|
|
@ -83,6 +83,8 @@ public:
|
|||
*/
|
||||
ble_error_t read(uint16_t offset = 0) const;
|
||||
|
||||
ble_error_t read(uint16_t offset, const GattClient::ReadCallback_t& onRead) const;
|
||||
|
||||
/**
|
||||
* Perform a write without response procedure.
|
||||
*
|
||||
|
@ -135,6 +137,11 @@ public:
|
|||
*/
|
||||
ble_error_t write(uint16_t length, const uint8_t *value) const;
|
||||
|
||||
/**
|
||||
* Same as above but register the callback wich will be called once the data has been written
|
||||
*/
|
||||
ble_error_t write(uint16_t length, const uint8_t *value, const GattClient::WriteCallback_t& onRead) const;
|
||||
|
||||
void setupLongUUID(UUID::LongUUIDBytes_t longUUID) {
|
||||
uuid.setupLong(longUUID);
|
||||
}
|
||||
|
|
|
@ -18,14 +18,16 @@
|
|||
#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;
|
||||
typedef void (*pvoidfcontext_t)(ContextType context);
|
||||
|
||||
/** Create a FunctionPointerWithContext, attaching a static function.
|
||||
|
@ -33,7 +35,7 @@ public:
|
|||
* @param function The void static function to attach (default is none).
|
||||
*/
|
||||
FunctionPointerWithContext(void (*function)(ContextType context) = NULL) :
|
||||
_function(NULL), _caller(NULL), _next(NULL) {
|
||||
_memberFunctionAndPointer(), _caller(NULL), _next(NULL) {
|
||||
attach(function);
|
||||
}
|
||||
|
||||
|
@ -48,6 +50,17 @@ public:
|
|||
attach(object, member);
|
||||
}
|
||||
|
||||
FunctionPointerWithContext(const FunctionPointerWithContext& that) :
|
||||
_memberFunctionAndPointer(that._memberFunctionAndPointer), _caller(that._caller), _next(NULL) {
|
||||
}
|
||||
|
||||
FunctionPointerWithContext& operator=(const FunctionPointerWithContext& that) {
|
||||
_memberFunctionAndPointer = that._memberFunctionAndPointer;
|
||||
_caller = that._caller;
|
||||
_next = NULL;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Attach a static function.
|
||||
*
|
||||
* @param function The void static function to attach (default is none).
|
||||
|
@ -73,13 +86,29 @@ public:
|
|||
* FunctionPointers their callbacks are invoked as well.
|
||||
* @Note: All chained callbacks stack up, so hopefully there won't be too
|
||||
* many FunctionPointers in a chain. */
|
||||
void call(ContextType context) {
|
||||
void call(ContextType context) const {
|
||||
_caller(this, context);
|
||||
}
|
||||
|
||||
/* Propagate the call to next in the chain. */
|
||||
if (_next) {
|
||||
_next->call(context);
|
||||
}
|
||||
/**
|
||||
* @brief Same as above
|
||||
*/
|
||||
void operator()(ContextType context) const {
|
||||
call(context);
|
||||
}
|
||||
|
||||
/** Same as above, workaround for mbed os FunctionPointer implementation. */
|
||||
void call(ContextType context) {
|
||||
((const FunctionPointerWithContext*) this)->call(context);
|
||||
}
|
||||
|
||||
typedef void (FunctionPointerWithContext::*bool_type)() const;
|
||||
|
||||
/**
|
||||
* implementation of safe bool operator
|
||||
*/
|
||||
bool toBool() const {
|
||||
return (_function || _memberFunctionAndPointer._object);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -101,9 +130,18 @@ public:
|
|||
return (pvoidfcontext_t)_function;
|
||||
}
|
||||
|
||||
friend bool operator==(const FunctionPointerWithContext& lhs, const FunctionPointerWithContext& rhs) {
|
||||
return rhs._caller == lhs._caller &&
|
||||
memcmp(
|
||||
&rhs._memberFunctionAndPointer,
|
||||
&lhs._memberFunctionAndPointer,
|
||||
sizeof(rhs._memberFunctionAndPointer)
|
||||
) == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
static void membercaller(pFunctionPointerWithContext_t self, ContextType context) {
|
||||
static void membercaller(cpFunctionPointerWithContext_t self, ContextType context) {
|
||||
if (self->_memberFunctionAndPointer._object) {
|
||||
T *o = static_cast<T *>(self->_memberFunctionAndPointer._object);
|
||||
void (T::*m)(ContextType);
|
||||
|
@ -112,7 +150,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
static void functioncaller(pFunctionPointerWithContext_t self, ContextType context) {
|
||||
static void functioncaller(cpFunctionPointerWithContext_t self, ContextType context) {
|
||||
if (self->_function) {
|
||||
self->_function(context);
|
||||
}
|
||||
|
@ -141,10 +179,10 @@ private:
|
|||
* object this pointer and pointer to member -
|
||||
* _memberFunctionAndPointer._object will be NULL if none attached
|
||||
*/
|
||||
MemberFunctionAndPtr _memberFunctionAndPointer;
|
||||
mutable MemberFunctionAndPtr _memberFunctionAndPointer;
|
||||
};
|
||||
|
||||
void (*_caller)(FunctionPointerWithContext*, ContextType);
|
||||
void (*_caller)(const FunctionPointerWithContext*, ContextType);
|
||||
|
||||
pFunctionPointerWithContext_t _next; /**< Optional link to make a chain out of functionPointers. This
|
||||
* allows chaining function pointers without requiring
|
||||
|
@ -152,4 +190,23 @@ private:
|
|||
* 'CallChain' as an alternative. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a new FunctionPointerWithContext which bind an instance and a
|
||||
* a member function together.
|
||||
* @details This little helper is a just here to eliminate the need to write the
|
||||
* FunctionPointerWithContext type each time you want to create one by kicking
|
||||
* automatic type deduction of function templates. With this function, it is easy
|
||||
* to write only one entry point for functions which expect a FunctionPointer
|
||||
* in parameters.
|
||||
*
|
||||
* @param object to bound with member function
|
||||
* @param member The member function called
|
||||
* @return a new FunctionPointerWithContext
|
||||
*/
|
||||
template<typename T, typename ContextType>
|
||||
FunctionPointerWithContext<ContextType> makeFunctionPointer(T *object, void (T::*member)(ContextType context))
|
||||
{
|
||||
return FunctionPointerWithContext<ContextType>(object, member);
|
||||
}
|
||||
|
||||
#endif // ifndef MBED_FUNCTIONPOINTER_WITH_CONTEXT_H
|
||||
|
|
66
ble/Gap.h
66
ble/Gap.h
|
@ -140,10 +140,15 @@ public:
|
|||
return (durationInMillis * 1000) / UNIT_1_25_MS;
|
||||
}
|
||||
|
||||
typedef FunctionPointerWithContext<TimeoutSource_t> TimeoutEventCallback_t;
|
||||
typedef CallChainOfFunctionPointersWithContext<TimeoutSource_t> TimeoutEventCallbackChain_t;
|
||||
|
||||
typedef FunctionPointerWithContext<const ConnectionCallbackParams_t *> ConnectionEventCallback_t;
|
||||
typedef CallChainOfFunctionPointersWithContext<const ConnectionCallbackParams_t *> ConnectionEventCallbackChain_t;
|
||||
|
||||
typedef FunctionPointerWithContext<const DisconnectionCallbackParams_t*> DisconnectionEventCallback_t;
|
||||
typedef CallChainOfFunctionPointersWithContext<const DisconnectionCallbackParams_t*> DisconnectionEventCallbackChain_t;
|
||||
|
||||
typedef void (*TimeoutEventCallback_t)(TimeoutSource_t source);
|
||||
typedef void (*ConnectionEventCallback_t)(const ConnectionCallbackParams_t *params);
|
||||
typedef void (*DisconnectionEventCallback_t)(const DisconnectionCallbackParams_t *params);
|
||||
typedef FunctionPointerWithContext<bool> RadioNotificationEventCallback_t;
|
||||
|
||||
/*
|
||||
|
@ -892,25 +897,60 @@ 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) {timeoutCallback = 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the application callback for radio-notification events.
|
||||
*
|
||||
|
@ -940,12 +980,10 @@ public:
|
|||
*/
|
||||
void onRadioNotification(void (*callback)(bool param)) {
|
||||
radioNotificationCallback.attach(callback);
|
||||
initRadioNotification();
|
||||
}
|
||||
template <typename T>
|
||||
void onRadioNotification(T *tptr, void (T::*mptr)(bool)) {
|
||||
radioNotificationCallback.attach(tptr, mptr);
|
||||
initRadioNotification();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -956,7 +994,7 @@ protected:
|
|||
_scanResponse(),
|
||||
state(),
|
||||
scanningActive(false),
|
||||
timeoutCallback(NULL),
|
||||
timeoutCallbackChain(),
|
||||
radioNotificationCallback(),
|
||||
onAdvertisementReport(),
|
||||
connectionCallChain(),
|
||||
|
@ -1002,8 +1040,8 @@ public:
|
|||
}
|
||||
|
||||
void processTimeoutEvent(TimeoutSource_t source) {
|
||||
if (timeoutCallback) {
|
||||
timeoutCallback(source);
|
||||
if (timeoutCallbackChain) {
|
||||
timeoutCallbackChain(source);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1017,11 +1055,11 @@ protected:
|
|||
bool scanningActive;
|
||||
|
||||
protected:
|
||||
TimeoutEventCallback_t timeoutCallback;
|
||||
RadioNotificationEventCallback_t radioNotificationCallback;
|
||||
AdvertisementReportCallback_t onAdvertisementReport;
|
||||
CallChainOfFunctionPointersWithContext<const ConnectionCallbackParams_t*> connectionCallChain;
|
||||
CallChainOfFunctionPointersWithContext<const DisconnectionCallbackParams_t*> disconnectionCallChain;
|
||||
TimeoutEventCallbackChain_t timeoutCallbackChain;
|
||||
RadioNotificationEventCallback_t radioNotificationCallback;
|
||||
AdvertisementReportCallback_t onAdvertisementReport;
|
||||
ConnectionEventCallbackChain_t connectionCallChain;
|
||||
DisconnectionEventCallbackChain_t disconnectionCallChain;
|
||||
|
||||
private:
|
||||
/* Disallow copy and assignment. */
|
||||
|
|
|
@ -23,18 +23,23 @@
|
|||
|
||||
#include "GattCallbackParamTypes.h"
|
||||
|
||||
#include "CallChainOfFunctionPointersWithContext.h"
|
||||
|
||||
class GattClient {
|
||||
public:
|
||||
typedef void (*ReadCallback_t)(const GattReadCallbackParams *params);
|
||||
typedef FunctionPointerWithContext<const GattReadCallbackParams*> ReadCallback_t;
|
||||
typedef CallChainOfFunctionPointersWithContext<const GattReadCallbackParams*> ReadCallbackChain_t;
|
||||
|
||||
enum WriteOp_t {
|
||||
GATT_OP_WRITE_REQ = 0x01, /**< Write request. */
|
||||
GATT_OP_WRITE_CMD = 0x02, /**< Write command. */
|
||||
};
|
||||
|
||||
typedef void (*WriteCallback_t)(const GattWriteCallbackParams *params);
|
||||
typedef FunctionPointerWithContext<const GattWriteCallbackParams*> WriteCallback_t;
|
||||
typedef CallChainOfFunctionPointersWithContext<const GattWriteCallbackParams*> WriteCallbackChain_t;
|
||||
|
||||
typedef void (*HVXCallback_t)(const GattHVXCallbackParams *params);
|
||||
typedef FunctionPointerWithContext<const GattHVXCallbackParams*> HVXCallback_t;
|
||||
typedef CallChainOfFunctionPointersWithContext<const GattHVXCallbackParams*> HVXCallbackChain_t;
|
||||
|
||||
/*
|
||||
* The following functions are meant to be overridden in the platform-specific sub-class.
|
||||
|
@ -241,18 +246,42 @@ 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) {
|
||||
onDataReadCallback = 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) {
|
||||
onDataWriteCallback = 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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -279,9 +308,21 @@ 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) {
|
||||
onHVXCallback = 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;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -292,27 +333,23 @@ protected:
|
|||
/* Entry points for the underlying stack to report events back to the user. */
|
||||
public:
|
||||
void processReadResponse(const GattReadCallbackParams *params) {
|
||||
if (onDataReadCallback) {
|
||||
onDataReadCallback(params);
|
||||
}
|
||||
onDataReadCallbackChain(params);
|
||||
}
|
||||
|
||||
void processWriteResponse(const GattWriteCallbackParams *params) {
|
||||
if (onDataWriteCallback) {
|
||||
onDataWriteCallback(params);
|
||||
}
|
||||
onDataWriteCallbackChain(params);
|
||||
}
|
||||
|
||||
void processHVXEvent(const GattHVXCallbackParams *params) {
|
||||
if (onHVXCallback) {
|
||||
onHVXCallback(params);
|
||||
if (onHVXCallbackChain) {
|
||||
onHVXCallbackChain(params);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
ReadCallback_t onDataReadCallback;
|
||||
WriteCallback_t onDataWriteCallback;
|
||||
HVXCallback_t onHVXCallback;
|
||||
ReadCallbackChain_t onDataReadCallbackChain;
|
||||
WriteCallbackChain_t onDataWriteCallbackChain;
|
||||
HVXCallbackChain_t onHVXCallbackChain;
|
||||
|
||||
private:
|
||||
/* Disallow copy and assignment. */
|
||||
|
|
|
@ -26,9 +26,18 @@
|
|||
|
||||
class GattServer {
|
||||
public:
|
||||
|
||||
/* Event callback handlers. */
|
||||
typedef void (*EventCallback_t)(GattAttribute::Handle_t attributeHandle);
|
||||
typedef void (*ServerEventCallback_t)(void); /**< Independent of any particular attribute. */
|
||||
typedef FunctionPointerWithContext<unsigned> DataSentCallback_t;
|
||||
typedef CallChainOfFunctionPointersWithContext<unsigned> DataSentCallbackChain_t;
|
||||
|
||||
typedef FunctionPointerWithContext<const GattWriteCallbackParams*> DataWrittenCallback_t;
|
||||
typedef CallChainOfFunctionPointersWithContext<const GattWriteCallbackParams*> DataWrittenCallbackChain_t;
|
||||
|
||||
typedef FunctionPointerWithContext<const GattReadCallbackParams*> DataReadCallback_t;
|
||||
typedef CallChainOfFunctionPointersWithContext<const GattReadCallbackParams *> DataReadCallbackChain_t;
|
||||
|
||||
typedef FunctionPointerWithContext<GattAttribute::Handle_t> EventCallback_t;
|
||||
|
||||
protected:
|
||||
GattServer() :
|
||||
|
@ -238,12 +247,19 @@ public:
|
|||
* @Note: It is also possible to set up a callback into a member function of
|
||||
* some object.
|
||||
*/
|
||||
void onDataSent(void (*callback)(unsigned count)) {dataSentCallChain.add(callback);}
|
||||
void onDataSent(const DataSentCallback_t& callback) {dataSentCallChain.add(callback);}
|
||||
template <typename T>
|
||||
void onDataSent(T *objPtr, void (T::*memberPtr)(unsigned count)) {
|
||||
dataSentCallChain.add(objPtr, memberPtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the callback chain called when the event DATA_EVENT is triggered.
|
||||
*/
|
||||
DataSentCallbackChain_t& onDataSent() {
|
||||
return dataSentCallChain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up a callback for when an attribute has its value updated by or at the
|
||||
* connected peer. For a peripheral, this callback is triggered when the local
|
||||
|
@ -258,13 +274,25 @@ 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(void (*callback)(const GattWriteCallbackParams *eventDataP)) {dataWrittenCallChain.add(callback);}
|
||||
void onDataWritten(const DataWrittenCallback_t& callback) {dataWrittenCallChain.add(callback);}
|
||||
template <typename T>
|
||||
void onDataWritten(T *objPtr, void (T::*memberPtr)(const GattWriteCallbackParams *context)) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup a callback to be invoked on the peripheral when an attribute is
|
||||
* being read by a remote client.
|
||||
|
@ -281,10 +309,12 @@ 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.
|
||||
*/
|
||||
ble_error_t onDataRead(void (*callback)(const GattReadCallbackParams *eventDataP)) {
|
||||
ble_error_t onDataRead(const DataReadCallback_t& callback) {
|
||||
if (!isOnDataReadAvailable()) {
|
||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -302,6 +332,16 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up a callback for when notifications or indications are enabled for a
|
||||
* characteristic on the local GATT server.
|
||||
|
@ -323,15 +363,11 @@ public:
|
|||
/* Entry points for the underlying stack to report events back to the user. */
|
||||
protected:
|
||||
void handleDataWrittenEvent(const GattWriteCallbackParams *params) {
|
||||
if (dataWrittenCallChain.hasCallbacksAttached()) {
|
||||
dataWrittenCallChain.call(params);
|
||||
}
|
||||
dataWrittenCallChain.call(params);
|
||||
}
|
||||
|
||||
void handleDataReadEvent(const GattReadCallbackParams *params) {
|
||||
if (dataReadCallChain.hasCallbacksAttached()) {
|
||||
dataReadCallChain.call(params);
|
||||
}
|
||||
dataReadCallChain.call(params);
|
||||
}
|
||||
|
||||
void handleEvent(GattServerEvents::gattEvent_e type, GattAttribute::Handle_t attributeHandle) {
|
||||
|
@ -357,9 +393,7 @@ protected:
|
|||
}
|
||||
|
||||
void handleDataSentEvent(unsigned count) {
|
||||
if (dataSentCallChain.hasCallbacksAttached()) {
|
||||
dataSentCallChain.call(count);
|
||||
}
|
||||
dataSentCallChain.call(count);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -367,12 +401,12 @@ protected:
|
|||
uint8_t characteristicCount;
|
||||
|
||||
private:
|
||||
CallChainOfFunctionPointersWithContext<unsigned> dataSentCallChain;
|
||||
CallChainOfFunctionPointersWithContext<const GattWriteCallbackParams *> dataWrittenCallChain;
|
||||
CallChainOfFunctionPointersWithContext<const GattReadCallbackParams *> dataReadCallChain;
|
||||
EventCallback_t updatesEnabledCallback;
|
||||
EventCallback_t updatesDisabledCallback;
|
||||
EventCallback_t confirmationReceivedCallback;
|
||||
DataSentCallbackChain_t dataSentCallChain;
|
||||
DataWrittenCallbackChain_t dataWrittenCallChain;
|
||||
DataReadCallbackChain_t dataReadCallChain;
|
||||
EventCallback_t updatesEnabledCallback;
|
||||
EventCallback_t updatesDisabledCallback;
|
||||
EventCallback_t confirmationReceivedCallback;
|
||||
|
||||
private:
|
||||
/* Disallow copy and assignment. */
|
||||
|
|
114
ble/SafeBool.h
Normal file
114
ble/SafeBool.h
Normal file
|
@ -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_ */
|
|
@ -38,7 +38,7 @@ public:
|
|||
* framework. The application can safely make a persistent shallow-copy of
|
||||
* this object to work with the service beyond the callback.
|
||||
*/
|
||||
typedef void (*ServiceCallback_t)(const DiscoveredService *);
|
||||
typedef FunctionPointerWithContext<const DiscoveredService *> ServiceCallback_t;
|
||||
|
||||
/**
|
||||
* Callback type for when a matching characteristic is found during service-
|
||||
|
@ -48,12 +48,12 @@ public:
|
|||
* framework. The application can safely make a persistent shallow-copy of
|
||||
* this object to work with the characteristic beyond the callback.
|
||||
*/
|
||||
typedef void (*CharacteristicCallback_t)(const DiscoveredCharacteristic *);
|
||||
typedef FunctionPointerWithContext<const DiscoveredCharacteristic *> CharacteristicCallback_t;
|
||||
|
||||
/**
|
||||
* Callback type for when serviceDiscovery terminates.
|
||||
*/
|
||||
typedef void (*TerminationCallback_t)(Gap::Handle_t connectionHandle);
|
||||
typedef FunctionPointerWithContext<Gap::Handle_t> TerminationCallback_t;
|
||||
|
||||
public:
|
||||
/**
|
||||
|
|
|
@ -31,6 +31,52 @@ DiscoveredCharacteristic::read(uint16_t offset) const
|
|||
return gattc->read(connHandle, valueHandle, offset);
|
||||
}
|
||||
|
||||
struct OneShotReadCallback {
|
||||
static void launch(GattClient* client, Gap::Handle_t connHandle,
|
||||
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
|
||||
}
|
||||
|
||||
private:
|
||||
OneShotReadCallback(GattClient* client, Gap::Handle_t connHandle,
|
||||
GattAttribute::Handle_t handle, const GattClient::ReadCallback_t& cb) :
|
||||
_client(client),
|
||||
_connHandle(connHandle),
|
||||
_handle(handle),
|
||||
_callback(cb) { }
|
||||
|
||||
void attach() {
|
||||
_client->onDataRead(makeFunctionPointer(this, &OneShotReadCallback::call));
|
||||
}
|
||||
|
||||
void call(const GattReadCallbackParams* params) {
|
||||
// verifiy that it is the right characteristic on the right connection
|
||||
if (params->connHandle == _connHandle && params->handle == _handle) {
|
||||
_callback(params);
|
||||
_client->onDataRead().detach(makeFunctionPointer(this, &OneShotReadCallback::call));
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
GattClient* _client;
|
||||
Gap::Handle_t _connHandle;
|
||||
GattAttribute::Handle_t _handle;
|
||||
GattClient::ReadCallback_t _callback;
|
||||
};
|
||||
|
||||
ble_error_t DiscoveredCharacteristic::read(uint16_t offset, const GattClient::ReadCallback_t& onRead) const {
|
||||
ble_error_t error = read(offset);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
OneShotReadCallback::launch(gattc, connHandle, valueHandle, onRead);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
ble_error_t
|
||||
DiscoveredCharacteristic::write(uint16_t length, const uint8_t *value) const
|
||||
{
|
||||
|
@ -59,6 +105,52 @@ DiscoveredCharacteristic::writeWoResponse(uint16_t length, const uint8_t *value)
|
|||
return gattc->write(GattClient::GATT_OP_WRITE_CMD, connHandle, valueHandle, length, value);
|
||||
}
|
||||
|
||||
struct OneShotWriteCallback {
|
||||
static void launch(GattClient* client, Gap::Handle_t connHandle,
|
||||
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
|
||||
}
|
||||
|
||||
private:
|
||||
OneShotWriteCallback(GattClient* client, Gap::Handle_t connHandle,
|
||||
GattAttribute::Handle_t handle, const GattClient::WriteCallback_t& cb) :
|
||||
_client(client),
|
||||
_connHandle(connHandle),
|
||||
_handle(handle),
|
||||
_callback(cb) { }
|
||||
|
||||
void attach() {
|
||||
_client->onDataWritten(makeFunctionPointer(this, &OneShotWriteCallback::call));
|
||||
}
|
||||
|
||||
void call(const GattWriteCallbackParams* params) {
|
||||
// verifiy that it is the right characteristic on the right connection
|
||||
if (params->connHandle == _connHandle && params->handle == _handle) {
|
||||
_callback(params);
|
||||
_client->onDataWritten().detach(makeFunctionPointer(this, &OneShotWriteCallback::call));
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
GattClient* _client;
|
||||
Gap::Handle_t _connHandle;
|
||||
GattAttribute::Handle_t _handle;
|
||||
GattClient::WriteCallback_t _callback;
|
||||
};
|
||||
|
||||
ble_error_t DiscoveredCharacteristic::write(uint16_t length, const uint8_t *value, const GattClient::WriteCallback_t& onRead) const {
|
||||
ble_error_t error = write(length, value);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
OneShotWriteCallback::launch(gattc, connHandle, valueHandle, onRead);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
ble_error_t
|
||||
DiscoveredCharacteristic::discoverDescriptors(DescriptorCallback_t callback, const UUID &matchingUUID) const
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue