diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..9ddf6b28 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cmake.ignoreCMakeListsMissing": true +} \ No newline at end of file diff --git a/src/BLEAdvertisingData.cpp b/src/BLEAdvertisingData.cpp index 80105916..4f21139c 100644 --- a/src/BLEAdvertisingData.cpp +++ b/src/BLEAdvertisingData.cpp @@ -20,6 +20,7 @@ #include "BLEAdvertisingData.h" #define AD_FIELD_OVERHEAD (2) +#define AD_NAME_LENGTH (19) BLEAdvertisingData::BLEAdvertisingData() : _dataLength(0), @@ -29,6 +30,11 @@ BLEAdvertisingData::BLEAdvertisingData() : _flags(0), _hasFlags(false), _localName(NULL), + _minimumConnectionInterval(0), + _maximumConnectionInterval(0), + _hasConnectionInterval(false), + _TransmitPowerLevel(0), + _hasTransmitPowerLevel(false), _manufacturerData(NULL), _manufacturerDataLength(0), _manufacturerCompanyId(0), @@ -73,6 +79,11 @@ void BLEAdvertisingData::clear() _rawDataLength = 0; _hasFlags = false; _localName = NULL; + _minimumConnectionInterval = 0; + _maximumConnectionInterval = 0; + _hasConnectionInterval = false; + _TransmitPowerLevel = 0; + _hasTransmitPowerLevel = false; _manufacturerData = NULL; _manufacturerDataLength = 0; _hasManufacturerCompanyId = false; @@ -90,6 +101,11 @@ void BLEAdvertisingData::copy(const BLEAdvertisingData& adv) _flags = adv._flags; _hasFlags = adv._hasFlags; _localName = adv._localName; + _minimumConnectionInterval = adv._minimumConnectionInterval; + _maximumConnectionInterval = adv._maximumConnectionInterval; + _hasConnectionInterval = adv._hasConnectionInterval; + _TransmitPowerLevel = adv._TransmitPowerLevel; + _hasTransmitPowerLevel = adv._hasTransmitPowerLevel; _manufacturerData = adv._manufacturerData; _manufacturerDataLength = adv._manufacturerDataLength; _manufacturerCompanyId = adv._manufacturerCompanyId; @@ -183,6 +199,29 @@ bool BLEAdvertisingData::setLocalName(const char *localName) return success; } +bool BLEAdvertisingData::setAdvertisedConnectionInterval(uint16_t minimumConnectionInterval, uint16_t maximumConnectionInterval) +{ + int previousLength = (_hasConnectionInterval) ? ( sizeof(_minimumConnectionInterval) + sizeof(_maximumConnectionInterval) + AD_FIELD_OVERHEAD) : 0; + bool success = updateRemainingLength(previousLength, (sizeof(minimumConnectionInterval) + sizeof(maximumConnectionInterval) + AD_FIELD_OVERHEAD)); + if (success) { + _hasConnectionInterval = true; + _minimumConnectionInterval = minimumConnectionInterval; + _maximumConnectionInterval = maximumConnectionInterval; + } + return success; +} + +bool BLEAdvertisingData::setAdvertisedTransmitPowerLevel(uint8_t TransmitPowerLevel) +{ + int previousLength = (_hasTransmitPowerLevel) ? ( sizeof(_TransmitPowerLevel) + AD_FIELD_OVERHEAD) : 0; + bool success = updateRemainingLength(previousLength, (sizeof(TransmitPowerLevel) + AD_FIELD_OVERHEAD)); + if (success) { + _hasTransmitPowerLevel = true; + _TransmitPowerLevel = TransmitPowerLevel; + } + return success; +} + bool BLEAdvertisingData::setRawData(const uint8_t* data, int length) { if (length > MAX_AD_DATA_LENGTH) { @@ -248,6 +287,14 @@ bool BLEAdvertisingData::updateData() if (_localName) { success &= addLocalName(_localName); } + // Try to add Slave Connection Interval into the current advertising packet + if (_hasConnectionInterval) { + success &= addAdvertisedConnectionInterval(_minimumConnectionInterval, _maximumConnectionInterval); + } + // Try to add Transmit Power Level into the current advertising packet + if (_hasTransmitPowerLevel) { + success &= addAdvertisedTransmitPowerLevel(_TransmitPowerLevel); + } return success; } @@ -272,7 +319,11 @@ bool BLEAdvertisingData::addLocalName(const char *localName) if (strlen(localName) > (MAX_AD_DATA_LENGTH - AD_FIELD_OVERHEAD)) { success = addField(BLEFieldShortLocalName, (uint8_t*)localName, (MAX_AD_DATA_LENGTH - AD_FIELD_OVERHEAD)); } else { - success = addField(BLEFieldCompleteLocalName, localName); + uint8_t tempData[AD_NAME_LENGTH]; + uint8_t tempDataLength = strlen(localName); + memcpy(tempData, (uint8_t*)localName, tempDataLength + 1); + memset(&tempData[tempDataLength + 1], 0x20, AD_NAME_LENGTH - tempDataLength - 1); + success = addField(BLEFieldCompleteLocalName, tempData, AD_NAME_LENGTH); } return success; } @@ -330,6 +381,19 @@ bool BLEAdvertisingData::addFlags(uint8_t flags) return addField(BLEFieldFlags, &flags, sizeof(flags)); } +bool BLEAdvertisingData::addAdvertisedConnectionInterval(uint16_t minimumConnectionInterval, uint16_t maximumConnectionInterval) +{ + uint8_t tempData[sizeof(minimumConnectionInterval) + sizeof(maximumConnectionInterval)]; + memcpy(tempData, &minimumConnectionInterval, sizeof(minimumConnectionInterval)); + memcpy(&tempData[sizeof(minimumConnectionInterval)], &maximumConnectionInterval, sizeof(maximumConnectionInterval)); + return addField(BLEFieldConnectionInterval, tempData, sizeof(minimumConnectionInterval) + sizeof(maximumConnectionInterval)); +} + +bool BLEAdvertisingData::addAdvertisedTransmitPowerLevel(uint8_t TransmitPowerLevel) +{ + return addField(BLEFieldTransmitPowerLevel, &TransmitPowerLevel, sizeof(TransmitPowerLevel)); +} + bool BLEAdvertisingData::addField(BLEAdField field, const char* data) { int dataLength = strlen(data); diff --git a/src/BLEAdvertisingData.h b/src/BLEAdvertisingData.h index dc736053..9f11a85f 100644 --- a/src/BLEAdvertisingData.h +++ b/src/BLEAdvertisingData.h @@ -40,6 +40,8 @@ enum BLEAdField { BLEFieldCompleteAdvertisedService128 = 0x07, BLEFieldShortLocalName = 0x08, BLEFieldCompleteLocalName = 0x09, + BLEFieldTransmitPowerLevel = 0x0A, + BLEFieldConnectionInterval = 0x12, BLEFieldServiceData = 0x16, BLEFieldManufacturerData = 0xFF, @@ -66,6 +68,8 @@ class BLEAdvertisingData { bool setManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength); bool setManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength); bool setLocalName(const char *localName); + bool setAdvertisedConnectionInterval(uint16_t minimumConnectionInterval, uint16_t maximumConnectionInterval); + bool setAdvertisedTransmitPowerLevel(uint8_t TransmitPowerLevel); bool setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length); bool setRawData(const uint8_t* data, int length); bool setRawData(const BLEAdvertisingRawData& data); @@ -86,6 +90,8 @@ class BLEAdvertisingData { bool addManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength); bool addManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength); bool addLocalName(const char *localName); + bool addAdvertisedConnectionInterval(uint16_t minimumConnectionInterval, uint16_t maximumConnectionInterval); + bool addAdvertisedTransmitPowerLevel(uint8_t TransmitPowerLevel); bool addAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length); bool addRawData(const uint8_t* data, int length); bool addFlags(uint8_t flags); @@ -105,6 +111,12 @@ class BLEAdvertisingData { bool _hasFlags; const char* _localName; + uint16_t _minimumConnectionInterval; + uint16_t _maximumConnectionInterval; + bool _hasConnectionInterval; + uint8_t _TransmitPowerLevel; + bool _hasTransmitPowerLevel; + const uint8_t* _manufacturerData; int _manufacturerDataLength; uint16_t _manufacturerCompanyId; diff --git a/src/BLEProperty.h b/src/BLEProperty.h index b9238ba9..0735e6a9 100644 --- a/src/BLEProperty.h +++ b/src/BLEProperty.h @@ -75,5 +75,9 @@ enum BLE_GATT_PERM_ { WRITE_AUTHORIZATION = 1 << 10, }; +#define GAP_PPCP_MIN_CONN_INTERVAL (80) /* 100 ms */ +#define GAP_PPCP_MAX_CONN_INTERVAL (160) /* 200 ms */ +#define GAP_PPCP_SLAVE_LATENCY (0) /* 0 ms */ +#define GAP_PPCP_SUPERVISION_TMO (1000) /* 1000 ms */ #endif diff --git a/src/local/BLELocalCharacteristic.cpp b/src/local/BLELocalCharacteristic.cpp index dc8a819d..f7a7b732 100644 --- a/src/local/BLELocalCharacteristic.cpp +++ b/src/local/BLELocalCharacteristic.cpp @@ -221,7 +221,17 @@ void BLELocalCharacteristic::writeValue(BLEDevice device, const uint8_t value[], { _written = true; + if (_properties & BLEWriteWithoutResponse) { + _valueLength = min(length, _valueSize); + memcpy(_value, value, _valueLength); + + if (_fixedLength) { + _valueLength = _valueSize; + } + } + else { writeValue(value, length); + } if (_eventHandlers[BLEWritten]) { _eventHandlers[BLEWritten](device, BLECharacteristic(this)); diff --git a/src/local/BLELocalDevice.cpp b/src/local/BLELocalDevice.cpp index 89c7a580..abac9b5a 100644 --- a/src/local/BLELocalDevice.cpp +++ b/src/local/BLELocalDevice.cpp @@ -354,6 +354,11 @@ void BLELocalDevice::setAppearance(uint16_t appearance) GATT.setAppearance(appearance); } +void BLELocalDevice::setPreferredConnectionParameters(uint16_t minimumConnectionInterval, uint16_t maximumConnectionInterval, uint16_t slaveLatency, uint16_t connectionSupervisionTimeout) +{ + GATT.setPreferredConnectionParameters(minimumConnectionInterval, maximumConnectionInterval, slaveLatency, connectionSupervisionTimeout); +} + void BLELocalDevice::addService(BLEService& service) { GATT.addService(service); diff --git a/src/local/BLELocalDevice.h b/src/local/BLELocalDevice.h index 6c45c063..2d880e28 100644 --- a/src/local/BLELocalDevice.h +++ b/src/local/BLELocalDevice.h @@ -60,6 +60,7 @@ class BLELocalDevice { virtual void setDeviceName(const char* deviceName); virtual void setAppearance(uint16_t appearance); + virtual void setPreferredConnectionParameters(uint16_t minimumConnectionInterval, uint16_t maximumConnectionInterval, uint16_t slaveLatency, uint16_t connectionSupervisionTimeout); virtual void addService(BLEService& service); diff --git a/src/utility/GATT.cpp b/src/utility/GATT.cpp index 3550fd99..467b5b2e 100644 --- a/src/utility/GATT.cpp +++ b/src/utility/GATT.cpp @@ -31,8 +31,9 @@ GATTClass::GATTClass() : _genericAccessService(NULL), _deviceNameCharacteristic(NULL), _appearanceCharacteristic(NULL), - _genericAttributeService(NULL), - _servicesChangedCharacteristic(NULL) + _preferredConnectionParametersCharacteristic(NULL), + _genericAttributeService(NULL) +//_servicesChangedCharacteristic(NULL) { } @@ -46,21 +47,25 @@ void GATTClass::begin() _genericAccessService = new BLELocalService("1800"); _deviceNameCharacteristic = new BLELocalCharacteristic("2a00", BLERead, 20); _appearanceCharacteristic = new BLELocalCharacteristic("2a01", BLERead, 2); + _preferredConnectionParametersCharacteristic = new BLELocalCharacteristic("2a04", BLERead, 8); _genericAttributeService = new BLELocalService("1801"); - _servicesChangedCharacteristic = new BLELocalCharacteristic("2a05", BLEIndicate, 4); +//_servicesChangedCharacteristic = new BLELocalCharacteristic("2a05", BLEIndicate, 4); _genericAccessService->retain(); _deviceNameCharacteristic->retain(); _appearanceCharacteristic->retain(); + _preferredConnectionParametersCharacteristic->retain(); _genericAttributeService->retain(); - _servicesChangedCharacteristic->retain(); +//_servicesChangedCharacteristic->retain(); _genericAccessService->addCharacteristic(_deviceNameCharacteristic); _genericAccessService->addCharacteristic(_appearanceCharacteristic); - _genericAttributeService->addCharacteristic(_servicesChangedCharacteristic); + _genericAccessService->addCharacteristic(_preferredConnectionParametersCharacteristic); +//_genericAttributeService->addCharacteristic(_servicesChangedCharacteristic); setDeviceName("Arduino"); setAppearance(0x000); + setPreferredConnectionParameters(GAP_PPCP_MIN_CONN_INTERVAL, GAP_PPCP_MAX_CONN_INTERVAL, GAP_PPCP_SLAVE_LATENCY, GAP_PPCP_SUPERVISION_TMO); clearAttributes(); @@ -85,16 +90,21 @@ void GATTClass::end() _appearanceCharacteristic = NULL; } + if (_preferredConnectionParametersCharacteristic &&_preferredConnectionParametersCharacteristic->release() == 0) { + delete(_preferredConnectionParametersCharacteristic); + _preferredConnectionParametersCharacteristic = NULL; + } + if (_genericAttributeService && _genericAttributeService->release() == 0) { delete(_genericAttributeService); _genericAttributeService = NULL; } - +/* if (_servicesChangedCharacteristic && _servicesChangedCharacteristic->release() == 0) { - delete(_servicesChangedCharacteristic); - _servicesChangedCharacteristic = NULL; + delete(_servicesChangedCharacteristic); + _servicesChangedCharacteristic = NULL; } - +*/ clearAttributes(); } @@ -108,6 +118,12 @@ void GATTClass::setAppearance(uint16_t appearance) _appearanceCharacteristic->writeValue((uint8_t*)&appearance, sizeof(appearance)); } +void GATTClass::setPreferredConnectionParameters(uint16_t minimumConnectionInterval, uint16_t maximumConnectionInterval, uint16_t slaveLatency, uint16_t connectionSupervisionTimeout) +{ + uint16_t PPCPData[] = {minimumConnectionInterval, maximumConnectionInterval, slaveLatency, connectionSupervisionTimeout}; + _preferredConnectionParametersCharacteristic->writeValue((uint8_t*)&PPCPData, sizeof(PPCPData)); +} + void GATTClass::addService(BLEService& service) { BLELocalService* localService = service.local(); diff --git a/src/utility/GATT.h b/src/utility/GATT.h index 51d1537e..c8e2f86e 100644 --- a/src/utility/GATT.h +++ b/src/utility/GATT.h @@ -38,6 +38,7 @@ class GATTClass { virtual void setDeviceName(const char* deviceName); virtual void setAppearance(uint16_t appearance); + virtual void setPreferredConnectionParameters(uint16_t minimumConnectionInterval, uint16_t maximumConnectionInterval, uint16_t slaveLatency, uint16_t connectionSupervisionTimeout); virtual void addService(BLEService& service); @@ -64,8 +65,9 @@ class GATTClass { BLELocalService* _genericAccessService; BLELocalCharacteristic* _deviceNameCharacteristic; BLELocalCharacteristic* _appearanceCharacteristic; + BLELocalCharacteristic* _preferredConnectionParametersCharacteristic; BLELocalService* _genericAttributeService; - BLELocalCharacteristic* _servicesChangedCharacteristic; +//BLELocalCharacteristic* _servicesChangedCharacteristic; }; extern GATTClass& GATT;