diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..4b9f4ce --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,7 @@ +# Hello! +We are an open source project of [ARM mbed](www.mbed.com). Contributions via [pull request](https://github.com/armmbed/yotta/pulls), and [bug reports](https://github.com/armmbed/yotta/issues) are welcome! + +Please submit your pull request to the 'develop' branch of this module. Commits to develop will merge into master at the time of the next release. + +# Contributor agreement +For your pull request to be accepted, we will need you to agree to our [contributor agreement](http://developer.mbed.org/contributor_agreement/) to give us the necessary rights to use and distribute your contributions. (To click through the agreement create an account on mbed.com and log in.) diff --git a/ble/BLE.h b/ble/BLE.h index d95471c..00bce18 100644 --- a/ble/BLE.h +++ b/ble/BLE.h @@ -21,9 +21,15 @@ #include "Gap.h" #include "GattServer.h" #include "GattClient.h" -#include "BLEInstanceBase.h" +#ifdef YOTTA_CFG_MBED_OS +#include "mbed-drivers/mbed_error.h" +#else #include "mbed_error.h" +#endif + +/* forward declaration for the implementation class */ +class BLEInstanceBase; /** * The base class used to abstract away BLE capable radio transceivers or SOCs, @@ -32,6 +38,20 @@ class BLE { public: + typedef unsigned InstanceID_t; /** The type returned by BLE::getInstanceID(). */ + + /** + * The function signature for callbacks for initialization completion. + * @param ble + * A reference to the BLE instance being initialized. + * @param error + * This captures the result of initialization. It is set to + * BLE_ERROR_NONE if initialization completed successfully. Else + * the error value is implementation specific. + * + */ + typedef void (*InitializationCompleteCallback_t)(BLE &ble, ble_error_t error); + /** * Initialize the BLE controller. This should be called before using * anything else in the BLE_API. @@ -42,21 +62,44 @@ public: * system startup. It may not be safe to call init() from global static * context where ordering is compiler specific and can't be guaranteed--it * is safe to call BLE::init() from within main(). + * + * @param callback + * A callback for when initialization completes for a BLE + * instance. This is an optional parameter, if no callback is + * setup the application can still determine the status of + * initialization using BLE::hasInitialized() (see below). + * + * @return BLE_ERROR_NONE if the initialization procedure was started + * successfully. + * + * @note The underlying stack must invoke the initialization completion + * callback in response to init(). In some cases, initialization is + * instantaneous (or blocking); if so, it is acceptable for the stack- + * specific implementation of init() to invoke the completion callback + * directly--i.e. within its own context. + * + * @note Nearly all BLE APIs would return + * BLE_ERROR_INITIALIZATION_INCOMPLETE if used on an instance before the + * corresponding transport is initialized. */ - ble_error_t init(); + ble_error_t init(InitializationCompleteCallback_t callback = NULL); + + /** + * @return true if initialization has completed for the underlying BLE + * transport. + * + * The application can setup a callback to signal completion of + * initialization when using init(). Otherwise, this method can be used to + * poll the state of initialization. + */ + bool hasInitialized(void) const; /** * Purge the BLE stack of GATT and GAP state. init() must be called * afterwards to re-instate services and GAP state. This API offers a way to * repopulate the GATT database with new services and characteristics. */ - ble_error_t shutdown(void) { - clearAdvertisingPayload(); - if (!transport) { - error("bad handle to underlying transport"); - } - return transport->shutdown(); - } + ble_error_t shutdown(void); /** * This call allows the application to get the BLE stack version information. @@ -64,81 +107,36 @@ public: * @return A pointer to a const string representing the version. * Note: The string is owned by the BLE_API. */ - const char *getVersion(void) { - if (!transport) { - error("bad handle to underlying transport"); - } - return transport->getVersion(); - } + const char *getVersion(void); /* * Accessors to GAP. Please refer to Gap.h. All GAP related functionality requires * going through this accessor. */ - const Gap &gap() const { - if (!transport) { - error("bad handle to underlying transport"); - } - return transport->getGap(); - } - Gap &gap() { - if (!transport) { - error("bad handle to underlying transport"); - } - return transport->getGap(); - } + const Gap &gap() const; + Gap &gap(); /* * Accessors to GATT Server. Please refer to GattServer.h. All GATTServer related * functionality requires going through this accessor. */ - const GattServer& gattServer() const { - if (!transport) { - error("bad handle to underlying transport"); - } - return transport->getGattServer(); - } - GattServer& gattServer() { - if (!transport) { - error("bad handle to underlying transport"); - } - return transport->getGattServer(); - } + const GattServer& gattServer() const; + GattServer& gattServer(); /* * Accessors to GATT Client. Please refer to GattClient.h. All GATTClient related * functionality requires going through this accessor. */ - const GattClient& gattClient() const { - if (!transport) { - error("bad handle to underlying transport"); - } - return transport->getGattClient(); - } - GattClient& gattClient() { - if (!transport) { - error("bad handle to underlying transport"); - } - return transport->getGattClient(); - } + const GattClient& gattClient() const; + GattClient& gattClient(); /* * Accessors to Security Manager. Please refer to SecurityManager.h. All * SecurityManager related functionality requires going through this * accessor. */ - const SecurityManager& securityManager() const { - if (!transport) { - error("bad handle to underlying transport"); - } - return transport->getSecurityManager(); - } - SecurityManager& securityManager() { - if (!transport) { - error("bad handle to underlying transport"); - } - return transport->getSecurityManager(); - } + const SecurityManager& securityManager() const; + SecurityManager& securityManager(); /** * Yield control to the BLE stack or to other tasks waiting for events. This @@ -147,15 +145,9 @@ public: * returning (to service the stack). This is not always interchangeable with * WFE(). */ - void waitForEvent(void) { - if (!transport) { - error("bad handle to underlying transport"); - } - transport->waitForEvent(); - } + void waitForEvent(void); public: - typedef unsigned InstanceID_t; static const InstanceID_t DEFAULT_INSTANCE = 0; #ifndef YOTTA_CFG_BLE_INSTANCES_COUNT static const InstanceID_t NUM_INSTANCES = 1; @@ -190,6 +182,12 @@ public: */ BLE(InstanceID_t instanceID = DEFAULT_INSTANCE); + /** + * Fetch the ID of a BLE instance. Typically there would only be the DEFAULT_INSTANCE. + */ + InstanceID_t getInstanceID(void) const { + return instanceID; + } /* * Deprecation alert! @@ -1394,6 +1392,7 @@ private: BLE &operator=(const BLE &); private: + InstanceID_t instanceID; BLEInstanceBase *transport; /* the device specific backend */ }; diff --git a/ble/BLEInstanceBase.h b/ble/BLEInstanceBase.h index db050f5..e8cfc0d 100644 --- a/ble/BLEInstanceBase.h +++ b/ble/BLEInstanceBase.h @@ -18,6 +18,8 @@ #define __BLE_DEVICE_INSTANCE_BASE__ #include "Gap.h" +#include "ble/SecurityManager.h" +#include "ble/BLE.h" /* forward declarations */ class GattServer; @@ -30,17 +32,18 @@ class GattClient; class BLEInstanceBase { public: - virtual ble_error_t init(void) = 0; - virtual ble_error_t shutdown(void) = 0; - virtual const char *getVersion(void) = 0; - virtual Gap& getGap() = 0; - virtual const Gap& getGap() const = 0; - virtual GattServer& getGattServer() = 0; - virtual const GattServer& getGattServer() const = 0; - virtual GattClient& getGattClient() = 0; - virtual SecurityManager& getSecurityManager() = 0; + virtual ble_error_t init(BLE::InstanceID_t instanceID, BLE::InitializationCompleteCallback_t) = 0; + virtual bool hasInitialized(void) const = 0; + virtual ble_error_t shutdown(void) = 0; + virtual const char * getVersion(void) = 0; + virtual Gap& getGap() = 0; + virtual const Gap& getGap() const = 0; + virtual GattServer& getGattServer() = 0; + virtual const GattServer& getGattServer() const = 0; + virtual GattClient& getGattClient() = 0; + virtual SecurityManager& getSecurityManager() = 0; virtual const SecurityManager& getSecurityManager() const = 0; - virtual void waitForEvent(void) = 0; + virtual void waitForEvent(void) = 0; }; /** diff --git a/ble/FunctionPointerWithContext.h b/ble/FunctionPointerWithContext.h index c886bb3..41f8687 100644 --- a/ble/FunctionPointerWithContext.h +++ b/ble/FunctionPointerWithContext.h @@ -20,6 +20,7 @@ #include + /** A class for storing and calling a pointer to a static or member void function * which takes a context. */ @@ -34,7 +35,7 @@ public: * @param function The void static function to attach (default is none) */ FunctionPointerWithContext(void (*function)(ContextType context) = NULL) : - _function(NULL), _object(NULL), _member(), _membercaller(NULL), _next(NULL) { + _function(NULL), _caller(NULL), _next(NULL) { attach(function); } @@ -45,7 +46,7 @@ public: */ template FunctionPointerWithContext(T *object, void (T::*member)(ContextType context)) : - _function(NULL), _object(NULL), _member(), _membercaller(NULL), _next(NULL) { + _memberFunctionAndPointer(), _caller(NULL), _next(NULL) { attach(object, member); } @@ -55,6 +56,7 @@ public: */ void attach(void (*function)(ContextType context) = NULL) { _function = function; + _caller = functioncaller; } /** Attach a member function @@ -64,9 +66,9 @@ public: */ template void attach(T *object, void (T::*member)(ContextType context)) { - _object = static_cast(object); - memcpy(_member, (char *)&member, sizeof(member)); - _membercaller = &FunctionPointerWithContext::membercaller; + _memberFunctionAndPointer._object = static_cast(object); + memcpy(_memberFunctionAndPointer._memberFunction, (char*) &member, sizeof(member)); + _caller = &FunctionPointerWithContext::membercaller; } /** Call the attached static or member function; and if there are chained @@ -74,11 +76,7 @@ public: * @Note: all chained callbacks stack up; so hopefully there won't be too * many FunctionPointers in a chain. */ void call(ContextType context) { - if (_function) { - _function(context); - } else if (_object && _membercaller) { - _membercaller(_object, _member, context); - } + _caller(this, context); /* Propagate the call to next in the chain. */ if (_next) { @@ -107,19 +105,49 @@ public: private: template - static void membercaller(void *object, char *member, ContextType context) { - T *o = static_cast(object); - void (T::*m)(ContextType); - memcpy((char *)&m, member, sizeof(m)); - (o->*m)(context); + static void membercaller(pFunctionPointerWithContext_t self, ContextType context) { + if (self->_memberFunctionAndPointer._object) { + T *o = static_cast(self->_memberFunctionAndPointer._object); + void (T::*m)(ContextType); + memcpy((char*) &m, self->_memberFunctionAndPointer._memberFunction, sizeof(m)); + (o->*m)(context); + } } - void (*_function)(ContextType context); /**< static function pointer - NULL if none attached */ - void *_object; /**< object this pointer - NULL if none attached */ - char _member[16]; /**< raw member function pointer storage - converted back by - * registered _membercaller */ - void (*_membercaller)(void *, char *, ContextType); /**< registered membercaller function to convert back and call - * _member on _object passing the context. */ + static void functioncaller(pFunctionPointerWithContext_t self, ContextType context) { + if (self->_function) { + self->_function(context); + } + } + + struct MemberFunctionAndPtr { + /* + * forward declaration of a class and a member function to this class. + * Because the compiler doesn't know anything about the forwarded member + * function, it will always use the biggest size and the biggest alignment + * that a member function can take for objects of type UndefinedMemberFunction. + */ + class UndefinedClass; + typedef void (UndefinedClass::*UndefinedMemberFunction)(ContextType); + + void* _object; + union { + char _memberFunction[sizeof(UndefinedMemberFunction)]; + UndefinedMemberFunction _alignment; + }; + }; + + union { + pvoidfcontext_t _function; /**< static function pointer - NULL if none attached */ + /** + * object this pointer and pointer to member - + * _memberFunctionAndPointer._object will be NULL if none attached + */ + MemberFunctionAndPtr _memberFunctionAndPointer; + }; + + void (*_caller)(FunctionPointerWithContext*, ContextType); + pFunctionPointerWithContext_t _next; /**< Optional link to make a chain out of functionPointers; this * allows chaining function pointers without requiring * external memory to manage the chain. Also refer to diff --git a/ble/Gap.h b/ble/Gap.h index 06793e9..66165b1 100644 --- a/ble/Gap.h +++ b/ble/Gap.h @@ -867,8 +867,8 @@ private: } private: - virtual ble_error_t setAdvertisingData(const GapAdvertisingData &, const GapAdvertisingData &) = 0; - virtual ble_error_t startAdvertising(const GapAdvertisingParams &) = 0; + virtual ble_error_t setAdvertisingData(const GapAdvertisingData &advData, const GapAdvertisingData &scanResponse) = 0; + virtual ble_error_t startAdvertising(const GapAdvertisingParams &) = 0; public: /** diff --git a/ble/GattCharacteristic.h b/ble/GattCharacteristic.h index 2e27c19..37d745f 100644 --- a/ble/GattCharacteristic.h +++ b/ble/GattCharacteristic.h @@ -57,6 +57,7 @@ public: UUID_HEART_RATE_MEASUREMENT_CHAR = 0x2A37, UUID_HID_CONTROL_POINT_CHAR = 0x2A4C, UUID_HID_INFORMATION_CHAR = 0x2A4A, + UUID_HUMIDITY_CHAR = 0x2A6F, UUID_IEEE_REGULATORY_CERTIFICATION_DATA_LIST_CHAR = 0x2A2A, UUID_INTERMEDIATE_CUFF_PRESSURE_CHAR = 0x2A36, UUID_INTERMEDIATE_TEMPERATURE_CHAR = 0x2A1E, @@ -67,6 +68,7 @@ public: UUID_UNREAD_ALERT_CHAR = 0x2A45, UUID_NEW_ALERT_CHAR = 0x2A46, UUID_PNP_ID_CHAR = 0x2A50, + UUID_PRESSURE_CHAR = 0x2A6D, UUID_PROTOCOL_MODE_CHAR = 0x2A4E, UUID_RECORD_ACCESS_CONTROL_POINT_CHAR = 0x2A52, UUID_REFERENCE_TIME_INFORMATION_CHAR = 0x2A14, @@ -81,6 +83,7 @@ public: UUID_SUPPORTED_NEW_ALERT_CATEGORY_CHAR = 0x2A47, UUID_SUPPORTED_UNREAD_ALERT_CATEGORY_CHAR = 0x2A48, UUID_SYSTEM_ID_CHAR = 0x2A23, + UUID_TEMPERATURE_CHAR = 0x2A6E, UUID_TEMPERATURE_MEASUREMENT_CHAR = 0x2A1C, UUID_TEMPERATURE_TYPE_CHAR = 0x2A1D, UUID_TIME_ACCURACY_CHAR = 0x2A12, @@ -93,7 +96,7 @@ public: UUID_CSC_FEATURE_CHAR = 0x2A5C, UUID_CSC_MEASUREMENT_CHAR = 0x2A5B, UUID_RSC_FEATURE_CHAR = 0x2A54, - UUID_RSC_MEASUREMENT_CHAR = 0x2A53, + UUID_RSC_MEASUREMENT_CHAR = 0x2A53 }; /**************************************************************************/ diff --git a/ble/GattService.h b/ble/GattService.h index f3d3b85..d2ff649 100644 --- a/ble/GattService.h +++ b/ble/GattService.h @@ -29,6 +29,7 @@ public: UUID_CURRENT_TIME_SERVICE = 0x1805, UUID_CYCLING_SPEED_AND_CADENCE = 0x1816, UUID_DEVICE_INFORMATION_SERVICE = 0x180A, + UUID_ENVIRONMENTAL_SERVICE = 0x181A, UUID_GLUCOSE_SERVICE = 0x1808, UUID_HEALTH_THERMOMETER_SERVICE = 0x1809, UUID_HEART_RATE_SERVICE = 0x180D, diff --git a/ble/UUID.h b/ble/UUID.h index fc32098..0e0e087 100644 --- a/ble/UUID.h +++ b/ble/UUID.h @@ -74,7 +74,7 @@ public: * * @note we don't yet support 32-bit shortened UUIDs. */ - UUID(ShortUUIDBytes_t shortUUID) : type(UUID_TYPE_SHORT), baseUUID(), shortUUID(shortUUID) { + UUID(ShortUUIDBytes_t _shortUUID) : type(UUID_TYPE_SHORT), baseUUID(), shortUUID(_shortUUID) { /* empty */ } diff --git a/ble/blecommon.h b/ble/blecommon.h index 07e5b63..c2c49db 100644 --- a/ble/blecommon.h +++ b/ble/blecommon.h @@ -114,16 +114,18 @@ enum { */ /**************************************************************************/ enum ble_error_t { - BLE_ERROR_NONE = 0, /**< No error */ - BLE_ERROR_BUFFER_OVERFLOW = 1, /**< The requested action would cause a buffer overflow and has been aborted */ - BLE_ERROR_NOT_IMPLEMENTED = 2, /**< Requested a feature that isn't yet implement or isn't supported by the target HW */ - BLE_ERROR_PARAM_OUT_OF_RANGE = 3, /**< One of the supplied parameters is outside the valid range */ - BLE_ERROR_INVALID_PARAM = 4, /**< One of the supplied parameters is invalid */ - BLE_STACK_BUSY = 5, /**< The stack is busy */ - BLE_ERROR_INVALID_STATE = 6, /**< Invalid state. */ - BLE_ERROR_NO_MEM = 7, /**< Out of Memory */ - BLE_ERROR_OPERATION_NOT_PERMITTED = 8, - BLE_ERROR_UNSPECIFIED = 9, /**< Unknown error. */ + BLE_ERROR_NONE = 0, /**< No error */ + BLE_ERROR_BUFFER_OVERFLOW = 1, /**< The requested action would cause a buffer overflow and has been aborted */ + BLE_ERROR_NOT_IMPLEMENTED = 2, /**< Requested a feature that isn't yet implement or isn't supported by the target HW */ + BLE_ERROR_PARAM_OUT_OF_RANGE = 3, /**< One of the supplied parameters is outside the valid range */ + BLE_ERROR_INVALID_PARAM = 4, /**< One of the supplied parameters is invalid */ + BLE_STACK_BUSY = 5, /**< The stack is busy */ + BLE_ERROR_INVALID_STATE = 6, /**< Invalid state. */ + BLE_ERROR_NO_MEM = 7, /**< Out of Memory */ + BLE_ERROR_OPERATION_NOT_PERMITTED = 8, + BLE_ERROR_INITIALIZATION_INCOMPLETE = 9, + BLE_ERROR_ALREADY_INITIALIZED = 10, + BLE_ERROR_UNSPECIFIED = 11, /**< Unknown error. */ }; /** @brief Default MTU size. */ diff --git a/ble/services/EddystoneConfigService.h b/ble/services/EddystoneConfigService.h index 5a06b8b..1d39824 100644 --- a/ble/services/EddystoneConfigService.h +++ b/ble/services/EddystoneConfigService.h @@ -285,7 +285,7 @@ public: ble.setTxPower(radioPowerLevels[params.txPowerMode]); ble.setDeviceName(reinterpret_cast(&DEVICE_NAME)); ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); - ble.setAdvertisingInterval(GapAdvertisingParams::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(ADVERTISING_INTERVAL_MSEC)); + ble.setAdvertisingInterval(ADVERTISING_INTERVAL_MSEC); } /* @@ -306,7 +306,7 @@ public: eddyServ.setTLMFrameData(params.tlmVersion, params.tlmBeaconPeriod); } if (params.uriEnabled) { - eddyServ.setURLFrameData(params.advPowerLevels[params.txPowerMode], (const char *) params.uriData, params.uriBeaconPeriod); + eddyServ.setURLFrameEncodedData(params.advPowerLevels[params.txPowerMode], (const char *) params.uriData, params.uriDataLength, params.uriBeaconPeriod); } if (params.uidEnabled) { eddyServ.setUIDFrameData(params.advPowerLevels[params.txPowerMode], @@ -340,7 +340,7 @@ private: } else if (handle == uriDataChar.getValueHandle()) { params.uriDataLength = writeParams->len; memset(params.uriData, 0x00, URI_DATA_MAX); // clear URI string - memcpy(params.uriData, writeParams->data, params.uriDataLength); // set URI string + memcpy(params.uriData, writeParams->data, writeParams->len); // set URI string params.uriEnabled = true; INFO("URI = %s, URILen = %d", writeParams->data, writeParams->len); } else if (handle == flagsChar.getValueHandle()) { diff --git a/ble/services/EddystoneService.h b/ble/services/EddystoneService.h index dcf0eaf..a3c1bd0 100644 --- a/ble/services/EddystoneService.h +++ b/ble/services/EddystoneService.h @@ -175,16 +175,40 @@ public: urlIsSet = false; return false; } - defaultUrlPower = power; encodeURL(urlIn, defaultUriData, defaultUriDataLength); // encode URL to URL Formatting if (defaultUriDataLength > URI_DATA_MAX) { return true; // error, URL is too big } + defaultUrlPower = power; urlAdvPeriod = urlAdvPeriodIn; urlIsSet = true; return false; } + /** + * Set Eddystone URL Frame information. + * @param[in] power TX Power in dB measured at 0 meters from the device. + * @param[in] encodedUrlIn Encoded URL + * @param[in] encodedUrlInLength Length of the encoded URL + * @param[in] urlAdvPeriodIn How long to advertise the URL frame (measured in # of adv periods) + * @return false on success, true on failure. + */ + bool setURLFrameEncodedData(int8_t power, const char *encodedUrlIn, uint8_t encodedUrlInLength, uint32_t urlAdvPeriodIn) { + if (0 == urlAdvPeriodIn) { + urlIsSet = false; + return false; + } + memcpy(defaultUriData, encodedUrlIn, encodedUrlInLength); + if (defaultUriDataLength > URI_DATA_MAX) { + return true; // error, URL is too big + } + defaultUrlPower = power; + defaultUriDataLength = encodedUrlInLength; + urlAdvPeriod = urlAdvPeriodIn; + urlIsSet = true; + return false; + } + /* * Construct URL frame from private variables * @param[in/out] Data pointer to array to store constructed frame in @@ -236,6 +260,10 @@ public: * @return number of bytes used. negative number indicates error message. */ int constructTLMFrame(uint8_t *Data, uint8_t maxSize) { + uint32_t now = timeSinceBootTimer.read_ms(); + TlmTimeSinceBoot += (now - lastBootTimerRead) / 100; + lastBootTimerRead = now; + int index = 0; Data[index++] = FRAME_TYPE_TLM; // Eddystone frame type = Telemetry Data[index++] = TlmVersion; // TLM Version Number @@ -291,14 +319,6 @@ public: TlmTimeSinceBoot = timeSinceBoot; } - /* - * callback function, called every 0.1s, incriments the TimeSinceBoot field in the TLM frame - * @return nothing - */ - void tsbCallback(void) { - TlmTimeSinceBoot++; - } - /* * Update advertising data * @return true on success, false on failure @@ -500,7 +520,8 @@ public: // Make double sure the PDUCount and TimeSinceBoot fields are set to zero at reset updateTlmPduCount(0); updateTlmTimeSinceBoot(0); - timeSinceBootTick.attach(this, &EddystoneService::tsbCallback, 0.1); // incriment the TimeSinceBoot ticker every 0.1s + lastBootTimerRead = 0; + timeSinceBootTimer.start(); tlmTicker.attach(this, &EddystoneService::tlmCallback, TlmAdvPeriod); DBG("attached tlmCallback every %d seconds", TlmAdvPeriod); } @@ -519,7 +540,8 @@ private: BLEDevice &ble; uint16_t advPeriodus; uint8_t txPower; - Ticker timeSinceBootTick; // counter that counts time since boot + Timer timeSinceBootTimer; + volatile uint32_t lastBootTimerRead; volatile bool advLock; volatile FrameTypes frameIndex; Timeout stopAdv; diff --git a/ble/services/EnvironmentalService.h b/ble/services/EnvironmentalService.h new file mode 100644 index 0000000..d9ef455 --- /dev/null +++ b/ble/services/EnvironmentalService.h @@ -0,0 +1,106 @@ +/* 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_ENVIRONMENTAL_SERVICE_H__ +#define __BLE_ENVIRONMENTAL_SERVICE_H__ + +#include "ble/BLE.h" + +/** +* @class EnvironmentalService +* @brief BLE Environmental Service. This service provides the location of the thermometer and the temperature.
+* Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.environmental_sensing.xml
+* Temperature: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature.xml
+* Humidity: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.humidity.xml
+* Pressure: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.pressure.xml +*/ +class EnvironmentalService { +public: + typedef int16_t TemperatureType_t; + typedef uint16_t HumidityType_t; + typedef uint32_t PressureType_t; + + /** + * @brief EnvironmentalService constructor. + * @param ble Reference to BLE device. + * @param temperature_en Enable this characteristic. + * @param humidity_en Enable this characteristic. + * @param pressure_en Enable this characteristic. + */ + EnvironmentalService(BLE& _ble) : + ble(_ble), + temperatureCharacteristic(GattCharacteristic::UUID_TEMPERATURE_CHAR, &temperature), + humidityCharacteristic(GattCharacteristic::UUID_HUMIDITY_CHAR, &humidity), + pressureCharacteristic(GattCharacteristic::UUID_PRESSURE_CHAR, &pressure) + { + static bool serviceAdded = false; /* We should only ever need to add the information service once. */ + if (serviceAdded) { + return; + } + + GattCharacteristic *charTable[] = { &humidityCharacteristic, + &pressureCharacteristic, + &temperatureCharacteristic }; + + GattService environmentalService(GattService::UUID_ENVIRONMENTAL_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); + + ble.gattServer().addService(environmentalService); + serviceAdded = true; + } + + /** + * @brief Update humidity characteristic. + * @param newHumidityVal New humidity measurement. + */ + void updateHumidity(HumidityType_t newHumidityVal) + { + humidity = (HumidityType_t) (newHumidityVal * 100); + ble.gattServer().write(humidityCharacteristic.getValueHandle(), (uint8_t *) &humidity, sizeof(HumidityType_t)); + } + + /** + * @brief Update pressure characteristic. + * @param newPressureVal New pressure measurement. + */ + void updatePressure(PressureType_t newPressureVal) + { + pressure = (PressureType_t) (newPressureVal * 10); + ble.gattServer().write(pressureCharacteristic.getValueHandle(), (uint8_t *) &pressure, sizeof(PressureType_t)); + } + + /** + * @brief Update temperature characteristic. + * @param newTemperatureVal New temperature measurement. + */ + void updateTemperature(float newTemperatureVal) + { + temperature = (TemperatureType_t) (newTemperatureVal * 100); + ble.gattServer().write(temperatureCharacteristic.getValueHandle(), (uint8_t *) &temperature, sizeof(TemperatureType_t)); + } + +private: + BLE& ble; + + TemperatureType_t temperature; + HumidityType_t humidity; + PressureType_t pressure; + + ReadOnlyGattCharacteristic temperatureCharacteristic; + ReadOnlyGattCharacteristic humidityCharacteristic; + ReadOnlyGattCharacteristic pressureCharacteristic; +}; + +#endif /* #ifndef __BLE_ENVIRONMENTAL_SERVICE_H__*/ diff --git a/ble/services/HealthThermometerService.h b/ble/services/HealthThermometerService.h index 063d5fc..e119fff 100644 --- a/ble/services/HealthThermometerService.h +++ b/ble/services/HealthThermometerService.h @@ -17,7 +17,7 @@ #ifndef __BLE_HEALTH_THERMOMETER_SERVICE_H__ #define __BLE_HEALTH_THERMOMETER_SERVICE_H__ -#include "BLE.h" +#include "ble/BLE.h" /** * @class HealthThermometerService diff --git a/ble/services/LinkLossService.h b/ble/services/LinkLossService.h index 66a1ac2..520189c 100644 --- a/ble/services/LinkLossService.h +++ b/ble/services/LinkLossService.h @@ -17,7 +17,7 @@ #ifndef __BLE_LINK_LOSS_SERVICE_H__ #define __BLE_LINK_LOSS_SERVICE_H__ -#include "Gap.h" +#include "ble/Gap.h" /** * @class LinkLossService @@ -52,11 +52,11 @@ public: GattCharacteristic *charTable[] = {&alertLevelChar}; GattService linkLossService(GattService::UUID_LINK_LOSS_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); - ble.addService(linkLossService); + ble.gattServer().addService(linkLossService); serviceAdded = true; - ble.addToDisconnectionCallChain(this, &LinkLossService::onDisconnectionFilter); - ble.onDataWritten(this, &LinkLossService::onDataWritten); + ble.gap().onDisconnection(this, &LinkLossService::onDisconnectionFilter); + ble.gattServer().onDataWritten(this, &LinkLossService::onDataWritten); } /** @@ -86,7 +86,7 @@ protected: } } - void onDisconnectionFilter(void) { + void onDisconnectionFilter(const Gap::DisconnectionCallbackParams_t *params) { if (alertLevel != NO_ALERT) { callback(alertLevel); } diff --git a/ble/services/UARTService.h b/ble/services/UARTService.h index ef9914e..b3840bc 100644 --- a/ble/services/UARTService.h +++ b/ble/services/UARTService.h @@ -17,8 +17,13 @@ #ifndef __BLE_UART_SERVICE_H__ #define __BLE_UART_SERVICE_H__ +#ifdef YOTTA_CFG_MBED_OS +#include "mbed-drivers/mbed.h" +#include "mbed-drivers/Stream.h" +#else #include "mbed.h" #include "Stream.h" +#endif #include "ble/UUID.h" #include "ble/BLE.h" diff --git a/ble/services/URIBeaconConfigService.h b/ble/services/URIBeaconConfigService.h index 8e4e878..e2b54f1 100644 --- a/ble/services/URIBeaconConfigService.h +++ b/ble/services/URIBeaconConfigService.h @@ -18,7 +18,12 @@ #define SERVICES_URIBEACONCONFIGSERVICE_H_ #include "ble/BLE.h" + +#ifdef YOTTA_CFG_MBED_OS +#include "mbed-drivers/mbed.h" +#else #include "mbed.h" +#endif extern const uint8_t UUID_URI_BEACON_SERVICE[UUID::LENGTH_OF_LONG_UUID]; extern const uint8_t UUID_LOCK_STATE_CHAR[UUID::LENGTH_OF_LONG_UUID]; diff --git a/module.json b/module.json index 82bdf38..5f13f41 100644 --- a/module.json +++ b/module.json @@ -1,6 +1,6 @@ { "name": "ble", - "version": "1.0.0", + "version": "2.0.0", "description": "The BLE module offers a high level abstraction for using Bluetooth Low Energy on multiple platforms.", "keywords": [ "Bluetooth", @@ -26,7 +26,10 @@ "x-nucleo-idb0xa1": "ARMmbed/ble-x-nucleo-idb0xa1" }, "nrf51822": { - "ble-nrf51822": "^1.0.0" + "ble-nrf51822": "^2.0.0" + }, + "cordio": { + "ble-wicentric": "~0.0.4" }, "mbed-classic": { "mbed-classic": "~0.0.1" diff --git a/source/BLE.cpp b/source/BLE.cpp index 28bfd0b..0328ef9 100644 --- a/source/BLE.cpp +++ b/source/BLE.cpp @@ -15,15 +15,16 @@ */ #include "ble/BLE.h" +#include "ble/BLEInstanceBase.h" #if defined(TARGET_OTA_ENABLED) #include "ble/services/DFUService.h" #endif ble_error_t -BLE::init() +BLE::init(BLE::InitializationCompleteCallback_t callback) { - ble_error_t err = transport->init(); + ble_error_t err = transport->init(instanceID, callback); if (err != BLE_ERROR_NONE) { return err; } @@ -105,7 +106,7 @@ BLE::Instance(InstanceID_t id) return badSingleton; } -BLE::BLE(InstanceID_t instanceID) : transport() +BLE::BLE(InstanceID_t instanceIDIn) : instanceID(instanceIDIn), transport() { static BLEInstanceBase *transportInstances[NUM_INSTANCES]; @@ -118,3 +119,112 @@ BLE::BLE(InstanceID_t instanceID) : transport() transport = NULL; } } + +bool BLE::hasInitialized(void) const +{ + if (!transport) { + error("bad handle to underlying transport"); + } + + return transport->hasInitialized(); +} + +ble_error_t BLE::shutdown(void) +{ + clearAdvertisingPayload(); + if (!transport) { + error("bad handle to underlying transport"); + } + + return transport->shutdown(); +} + +const char *BLE::getVersion(void) +{ + if (!transport) { + error("bad handle to underlying transport"); + } + + return transport->getVersion(); +} + +const Gap &BLE::gap() const +{ + if (!transport) { + error("bad handle to underlying transport"); + } + + return transport->getGap(); +} + +Gap &BLE::gap() +{ + if (!transport) { + error("bad handle to underlying transport"); + } + + return transport->getGap(); +} + +const GattServer& BLE::gattServer() const +{ + if (!transport) { + error("bad handle to underlying transport"); + } + + return transport->getGattServer(); +} + +GattServer& BLE::gattServer() +{ + if (!transport) { + error("bad handle to underlying transport"); + } + + return transport->getGattServer(); +} + +const GattClient& BLE::gattClient() const +{ + if (!transport) { + error("bad handle to underlying transport"); + } + + return transport->getGattClient(); +} + +GattClient& BLE::gattClient() +{ + if (!transport) { + error("bad handle to underlying transport"); + } + + return transport->getGattClient(); +} + +const SecurityManager& BLE::securityManager() const +{ + if (!transport) { + error("bad handle to underlying transport"); + } + + return transport->getSecurityManager(); +} + +SecurityManager& BLE::securityManager() +{ + if (!transport) { + error("bad handle to underlying transport"); + } + + return transport->getSecurityManager(); +} + +void BLE::waitForEvent(void) +{ + if (!transport) { + error("bad handle to underlying transport"); + } + + transport->waitForEvent(); +}