Merge pull request #109 from pan-/removePersistantCallbacks

Remove persistant callbacks
This commit is contained in:
Rohit Grover 2015-11-26 09:44:12 +00:00
commit 7de3434278
9 changed files with 540 additions and 72 deletions

View File

@ -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,14 +159,54 @@ 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:
@ -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:

View File

@ -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);
}

View File

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

View File

@ -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;
TimeoutEventCallbackChain_t timeoutCallbackChain;
RadioNotificationEventCallback_t radioNotificationCallback;
AdvertisementReportCallback_t onAdvertisementReport;
CallChainOfFunctionPointersWithContext<const ConnectionCallbackParams_t*> connectionCallChain;
CallChainOfFunctionPointersWithContext<const DisconnectionCallbackParams_t*> disconnectionCallChain;
ConnectionEventCallbackChain_t connectionCallChain;
DisconnectionEventCallbackChain_t disconnectionCallChain;
private:
/* Disallow copy and assignment. */

View File

@ -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.
@ -242,17 +247,41 @@ public:
public:
/**
* 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. */

View File

@ -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,16 +363,12 @@ 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);
}
}
void handleDataReadEvent(const GattReadCallbackParams *params) {
if (dataReadCallChain.hasCallbacksAttached()) {
dataReadCallChain.call(params);
}
}
void handleEvent(GattServerEvents::gattEvent_e type, GattAttribute::Handle_t attributeHandle) {
switch (type) {
@ -357,19 +393,17 @@ protected:
}
void handleDataSentEvent(unsigned count) {
if (dataSentCallChain.hasCallbacksAttached()) {
dataSentCallChain.call(count);
}
}
protected:
uint8_t serviceCount;
uint8_t characteristicCount;
private:
CallChainOfFunctionPointersWithContext<unsigned> dataSentCallChain;
CallChainOfFunctionPointersWithContext<const GattWriteCallbackParams *> dataWrittenCallChain;
CallChainOfFunctionPointersWithContext<const GattReadCallbackParams *> dataReadCallChain;
DataSentCallbackChain_t dataSentCallChain;
DataWrittenCallbackChain_t dataWrittenCallChain;
DataReadCallbackChain_t dataReadCallChain;
EventCallback_t updatesEnabledCallback;
EventCallback_t updatesDisabledCallback;
EventCallback_t confirmationReceivedCallback;

114
ble/SafeBool.h Normal file
View 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_ */

View File

@ -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:
/**

View File

@ -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
{