From 6a9e6ae76317c8db50e857002fa7ae0920e718dc Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Mon, 21 Sep 2020 17:28:03 +0200 Subject: [PATCH 01/13] Implement AdvertisingData class to make advertising and scan response data more flexible --- src/BLEAdvertisingData.cpp | 175 +++++++++++++++++++++++++++++++++++++ src/BLEAdvertisingData.h | 79 +++++++++++++++++ src/utility/GAP.cpp | 101 +++++---------------- src/utility/GAP.h | 12 +-- 4 files changed, 280 insertions(+), 87 deletions(-) create mode 100644 src/BLEAdvertisingData.cpp create mode 100644 src/BLEAdvertisingData.h diff --git a/src/BLEAdvertisingData.cpp b/src/BLEAdvertisingData.cpp new file mode 100644 index 00000000..07f3ed2e --- /dev/null +++ b/src/BLEAdvertisingData.cpp @@ -0,0 +1,175 @@ +/* + This file is part of the ArduinoBLE library. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "BLEAdvertisingData.h" + +BLEAdvertisingData::BLEAdvertisingData() : + _dataLength(0), + _advertisedServiceUuid(NULL), + _manufacturerData(NULL), + _manufacturerDataLength(0), + _manufacturerCompanyId(0), + _hasManufacturerCompanyId(false), + _localName(NULL), + _serviceData(NULL), + _serviceDataLength(0) +{ +} + +BLEAdvertisingData::~BLEAdvertisingData() +{ +} + +void BLEAdvertisingData::setAdvertisedServiceUuid(const char* advertisedServiceUuid) +{ + _advertisedServiceUuid = advertisedServiceUuid; +} + +void BLEAdvertisingData::setManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength) +{ + _manufacturerData = manufacturerData; + _manufacturerDataLength = manufacturerDataLength; + _hasManufacturerCompanyId = false; +} + +void BLEAdvertisingData::setManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength) +{ + _manufacturerData = manufacturerData; + _manufacturerDataLength = manufacturerDataLength; + _manufacturerCompanyId = companyId; + _hasManufacturerCompanyId = true; +} + +void BLEAdvertisingData::setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length) +{ + _serviceDataUuid = uuid; + _serviceData = data; + _serviceDataLength = length; +} + +void BLEAdvertisingData::setLocalName(const char *localName) +{ + _localName = localName; +} + +bool BLEAdvertisingData::updateData() +{ + bool success = true; + // Reset data + _dataLength = 0; + // Try to add Advertised service uuid into the current advertising packet + if (_advertisedServiceUuid) { + success &= addAdvertisedServiceUuid(_advertisedServiceUuid); + } + // Try to add Manufacturer data into the current advertising packet + if (_manufacturerData && _manufacturerDataLength) { + if (_hasManufacturerCompanyId) { + success &= addManufacturerData(_manufacturerCompanyId, _manufacturerData, _manufacturerDataLength); + } else { + success &= addManufacturerData(_manufacturerData, _manufacturerDataLength); + } + } + // Try to add Service data into the current advertising packet + if (_serviceData && _serviceDataLength) { + success &= addAdvertisedServiceData(_serviceDataUuid, _serviceData, _serviceDataLength); + } + // Try to add Local name into the current advertising packet + if (_localName) { + success &= addLocalName(_localName); + } + return success; +} + +uint8_t* BLEAdvertisingData::getData() +{ + return _data; +} + +int BLEAdvertisingData::getDataLength() +{ + return _dataLength; +} + +bool BLEAdvertisingData::addLocalName(const char *localName) +{ + bool success = false; + if (strlen(localName) > (MAX_AD_DATA_LENGTH - 2)) { + success = addField(BLEFieldShortLocalName, (uint8_t*)localName, (MAX_AD_DATA_LENGTH - 2)); + } else { + success = addField(BLEFieldCompleteLocalName, localName); + } + return success; +} + +bool BLEAdvertisingData::addAdvertisedServiceUuid(const char* advertisedServiceUuid) +{ + BLEUuid uuid(advertisedServiceUuid); + int uuidLen = uuid.length(); + BLEAdField advField; + if (uuidLen > 2) { + advField = BLEFieldAdvertisedService128; + } else { + advField = BLEFieldAdvertisedService16; + } + return addField(advField, uuid.data(), uuidLen); +} + +bool BLEAdvertisingData::addManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength) +{ + return addField(BLEFieldManufacturerData, manufacturerData, manufacturerDataLength); +} + +bool BLEAdvertisingData::addManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength) +{ + uint8_t tempDataLength = manufacturerDataLength + sizeof(companyId); + uint8_t tempData[MAX_AD_DATA_LENGTH]; + memcpy(tempData, &companyId, sizeof(companyId)); + memcpy(&tempData[sizeof(companyId)], manufacturerData, manufacturerDataLength); + return addField(BLEFieldManufacturerData, tempData, tempDataLength); +} + +bool BLEAdvertisingData::addAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length) +{ + uint8_t tempDataLength = length + sizeof(uuid); + uint8_t tempData[MAX_AD_DATA_LENGTH]; + memcpy(tempData, &uuid, sizeof(uuid)); + memcpy(&tempData[sizeof(uuid)], data, length); + return addField(BLEFieldServiceData, tempData, tempDataLength); +} + +bool BLEAdvertisingData::addField(BLEAdField field, const char* data) +{ + uint8_t dataLength = strlen(data); + return addField(field, (uint8_t *)data, dataLength); +} + +bool BLEAdvertisingData::addField(BLEAdField field, const uint8_t* data, uint8_t length) +{ + uint8_t fieldLength = length + 2; // Considering data TYPE and LENGTH fields + if (fieldLength > (MAX_AD_DATA_LENGTH - _dataLength)) { + // Not enough space for storing this field + return false; + } + // Insert field into advertising data of the instance + _data[_dataLength++] = length + 1; + _data[_dataLength++] = field; + memcpy(&_data[_dataLength], data, length); + _dataLength += length; + return true; +} diff --git a/src/BLEAdvertisingData.h b/src/BLEAdvertisingData.h new file mode 100644 index 00000000..ff7cb1cf --- /dev/null +++ b/src/BLEAdvertisingData.h @@ -0,0 +1,79 @@ +/* + This file is part of the ArduinoBLE library. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _BLE_ADVERTISING_DATA_H_ +#define _BLE_ADVERTISING_DATA_H_ + +#include +#include "utility/BLEUuid.h" + +#define MAX_AD_DATA_LENGTH (31) + +enum BLEAdField { + BLEFieldShortLocalName = 0x08, + BLEFieldCompleteLocalName = 0x09, + BLEFieldAdvertisedService16 = 0x02, + BLEFieldAdvertisedService128 = 0x06, + BLEFieldServiceData = 0x16, + BLEFieldManufacturerData = 0xFF, + + BLEAdFieldLast +}; + +class BLEAdvertisingData { +public: + BLEAdvertisingData(); + virtual ~BLEAdvertisingData(); + + void setAdvertisedServiceUuid(const char* advertisedServiceUuid); + void setManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength); + void setManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength); + void setLocalName(const char *localName); + void setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length); + + bool updateData(); + + uint8_t* getData(); + int getDataLength(); + +private: + bool addAdvertisedServiceUuid(const char* advertisedServiceUuid); + 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 addAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length); + + bool addField(BLEAdField field, const char* data); + bool addField(BLEAdField field, const uint8_t* data, uint8_t length); + + uint8_t _data[MAX_AD_DATA_LENGTH]; + int _dataLength; + + const char* _advertisedServiceUuid; + const uint8_t* _manufacturerData; + int _manufacturerDataLength; + uint16_t _manufacturerCompanyId; + bool _hasManufacturerCompanyId; + const char* _localName; + uint16_t _serviceDataUuid; + const uint8_t* _serviceData; + int _serviceDataLength; +}; + +#endif diff --git a/src/utility/GAP.cpp b/src/utility/GAP.cpp index 83059899..ed3c859d 100644 --- a/src/utility/GAP.cpp +++ b/src/utility/GAP.cpp @@ -24,17 +24,15 @@ #define GAP_MAX_DISCOVERED_QUEUE_SIZE 5 +#define GAP_ADV_IND (0x00) +#define GAP_ADV_SCAN_IND (0x02) +#define GAP_ADV_NONCONN_IND (0x03) + GAPClass::GAPClass() : _advertising(false), _scanning(false), - _advertisedServiceUuid(NULL), - _manufacturerData(NULL), - _manufacturerDataLength(0), - _localName(NULL), _advertisingInterval(160), _connectable(true), - _serviceData(NULL), - _serviceDataLength(0), _discoverEventHandler(NULL) { } @@ -45,27 +43,27 @@ GAPClass::~GAPClass() void GAPClass::setAdvertisedServiceUuid(const char* advertisedServiceUuid) { - _advertisedServiceUuid = advertisedServiceUuid; + _advertisingData.setAdvertisedServiceUuid(advertisedServiceUuid); } void GAPClass::setManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength) { - _manufacturerData = manufacturerData; - _manufacturerDataLength = manufacturerDataLength; + _advertisingData.setManufacturerData(manufacturerData, manufacturerDataLength); } void GAPClass::setManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength) { - uint8_t* tmpManufacturerData = (uint8_t*)malloc(manufacturerDataLength + 2); - tmpManufacturerData[0] = companyId & 0xff; - tmpManufacturerData[1] = companyId >> 8; - memcpy(&tmpManufacturerData[2], manufacturerData, manufacturerDataLength); - this->setManufacturerData(tmpManufacturerData, manufacturerDataLength + 2); + _advertisingData.setManufacturerData(companyId, manufacturerData, manufacturerDataLength); } void GAPClass::setLocalName(const char *localName) { - _localName = localName; + _scanResponseData.setLocalName(localName); +} + +void GAPClass::setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length) +{ + _advertisingData.setAdvertisedServiceData(uuid, data, length); } bool GAPClass::advertising() @@ -77,7 +75,11 @@ int GAPClass::advertise() { uint8_t directBdaddr[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t type = (_connectable) ? 0x00 : (_localName ? 0x02 : 0x03); + _advertisingData.updateData(); + _scanResponseData.updateData(); + + uint8_t scanLength = _scanResponseData.getDataLength(); + uint8_t type = (_connectable) ? GAP_ADV_IND : (scanLength ? GAP_ADV_SCAN_IND : GAP_ADV_NONCONN_IND); stopAdvertise(); @@ -85,66 +87,14 @@ int GAPClass::advertise() return 0; } - uint8_t advertisingData[31]; - uint8_t advertisingDataLen = 0; - - advertisingData[0] = 0x02; - advertisingData[1] = 0x01; - advertisingData[2] = 0x06; - advertisingDataLen += 3; - - if (_advertisedServiceUuid) { - BLEUuid uuid(_advertisedServiceUuid); - int uuidLen = uuid.length(); - - advertisingData[advertisingDataLen++] = 1 + uuidLen; - advertisingData[advertisingDataLen++] = (uuidLen > 2) ? 0x06 : 0x02; - memcpy(&advertisingData[advertisingDataLen], uuid.data(), uuidLen); - - advertisingDataLen += uuidLen; - } else if (_manufacturerData && _manufacturerDataLength) { - advertisingData[advertisingDataLen++] = 1 + _manufacturerDataLength; - advertisingData[advertisingDataLen++] = 0xff; - memcpy(&advertisingData[advertisingDataLen], _manufacturerData, _manufacturerDataLength); - - advertisingDataLen += _manufacturerDataLength; - } - - if (_serviceData && _serviceDataLength > 0 && (sizeof(advertisingData) - advertisingDataLen) >= (_serviceDataLength + 4)) { - advertisingData[advertisingDataLen++] = _serviceDataLength + 3; - advertisingData[advertisingDataLen++] = 0x16; - - memcpy(&advertisingData[advertisingDataLen], &_serviceDataUuid, sizeof(_serviceDataUuid)); - advertisingDataLen += sizeof(_serviceDataUuid); - - memcpy(&advertisingData[advertisingDataLen],_serviceData, _serviceDataLength); - advertisingDataLen += _serviceDataLength; - } - + uint8_t* advertisingData = _advertisingData.getData(); + uint8_t advertisingDataLen = _advertisingData.getDataLength(); if (HCI.leSetAdvertisingData(advertisingDataLen, advertisingData) != 0) { return 0; } - uint8_t scanResponseData[31]; - uint8_t scanResponseDataLen = 0; - - if (_localName) { - int localNameLen = strlen(_localName); - - if (localNameLen > 29) { - localNameLen = 29; - scanResponseData[1] = 0x08; - } else { - scanResponseData[1] = 0x09; - } - - scanResponseData[0] = 1 + localNameLen; - - memcpy(&scanResponseData[2], _localName, localNameLen); - - scanResponseDataLen += (2 + localNameLen); - } - + uint8_t* scanResponseData = _scanResponseData.getData(); + uint8_t scanResponseDataLen = _scanResponseData.getDataLength(); if (HCI.leSetScanResponseData(scanResponseDataLen, scanResponseData) != 0) { return 0; } @@ -264,13 +214,6 @@ void GAPClass::setEventHandler(BLEDeviceEvent event, BLEDeviceEventHandler event } } -void GAPClass::setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length) -{ - _serviceDataUuid = uuid; - _serviceData = data; - _serviceDataLength = length; -} - void GAPClass::handleLeAdvertisingReport(uint8_t type, uint8_t addressType, uint8_t address[6], uint8_t eirLength, uint8_t eirData[], int8_t rssi) { diff --git a/src/utility/GAP.h b/src/utility/GAP.h index c2a99daa..f265e39b 100644 --- a/src/utility/GAP.h +++ b/src/utility/GAP.h @@ -22,6 +22,7 @@ #include "utility/BLELinkedList.h" +#include "BLEAdvertisingData.h" #include "BLEDevice.h" class GAPClass { @@ -68,23 +69,18 @@ class GAPClass { bool _advertising; bool _scanning; - const char* _advertisedServiceUuid; - const uint8_t* _manufacturerData; - int _manufacturerDataLength; - const char* _localName; uint16_t _advertisingInterval; bool _connectable; - uint16_t _serviceDataUuid; - const uint8_t* _serviceData; - int _serviceDataLength; - BLEDeviceEventHandler _discoverEventHandler; BLELinkedList _discoveredDevices; String _scanNameFilter; String _scanUuidFilter; String _scanAddressFilter; + + BLEAdvertisingData _advertisingData; + BLEAdvertisingData _scanResponseData; }; extern GAPClass GAP; From 88bf0ca1906b05f805ed415686bba9d41f79dfa4 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Fri, 25 Sep 2020 13:28:07 +0200 Subject: [PATCH 02/13] Change ownership of local advertising data from GAP to BLELocalDevice --- src/BLEAdvertisingData.cpp | 4 +-- src/BLEAdvertisingData.h | 5 ++-- src/local/BLELocalCharacteristic.cpp | 5 ++-- src/local/BLELocalDevice.cpp | 18 ++++++++---- src/local/BLELocalDevice.h | 4 +++ src/utility/GAP.cpp | 41 +++------------------------- src/utility/GAP.h | 16 +---------- 7 files changed, 29 insertions(+), 64 deletions(-) diff --git a/src/BLEAdvertisingData.cpp b/src/BLEAdvertisingData.cpp index 07f3ed2e..686cc66d 100644 --- a/src/BLEAdvertisingData.cpp +++ b/src/BLEAdvertisingData.cpp @@ -96,12 +96,12 @@ bool BLEAdvertisingData::updateData() return success; } -uint8_t* BLEAdvertisingData::getData() +uint8_t* BLEAdvertisingData::data() { return _data; } -int BLEAdvertisingData::getDataLength() +int BLEAdvertisingData::dataLength() const { return _dataLength; } diff --git a/src/BLEAdvertisingData.h b/src/BLEAdvertisingData.h index ff7cb1cf..ac2956cb 100644 --- a/src/BLEAdvertisingData.h +++ b/src/BLEAdvertisingData.h @@ -48,9 +48,8 @@ class BLEAdvertisingData { void setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length); bool updateData(); - - uint8_t* getData(); - int getDataLength(); + uint8_t* data(); + int dataLength() const; private: bool addAdvertisedServiceUuid(const char* advertisedServiceUuid); diff --git a/src/local/BLELocalCharacteristic.cpp b/src/local/BLELocalCharacteristic.cpp index 23b5f275..333d00b2 100644 --- a/src/local/BLELocalCharacteristic.cpp +++ b/src/local/BLELocalCharacteristic.cpp @@ -18,6 +18,7 @@ */ #include +#include "BLELocalDevice.h" #include "utility/ATT.h" #include "utility/GAP.h" @@ -121,10 +122,10 @@ int BLELocalCharacteristic::writeValue(const uint8_t value[], int length) if (_broadcast) { uint16_t serviceUuid = GATT.serviceUuidForCharacteristic(this); - GAP.setAdvertisedServiceData(serviceUuid, value, length); + BLE.setAdvertisedServiceData(serviceUuid, value, length); if (!ATT.connected() && GAP.advertising()) { - GAP.advertise(); + BLE.advertise(); } } diff --git a/src/local/BLELocalDevice.cpp b/src/local/BLELocalDevice.cpp index 57477e23..79fbb257 100644 --- a/src/local/BLELocalDevice.cpp +++ b/src/local/BLELocalDevice.cpp @@ -185,7 +185,7 @@ int BLELocalDevice::rssi() void BLELocalDevice::setAdvertisedServiceUuid(const char* advertisedServiceUuid) { - GAP.setAdvertisedServiceUuid(advertisedServiceUuid); + _advertisingData.setAdvertisedServiceUuid(advertisedServiceUuid); } void BLELocalDevice::setAdvertisedService(const BLEService& service) @@ -193,19 +193,24 @@ void BLELocalDevice::setAdvertisedService(const BLEService& service) setAdvertisedServiceUuid(service.uuid()); } +void BLELocalDevice::setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length) +{ + _advertisingData.setAdvertisedServiceData(uuid, data, length); +} + void BLELocalDevice::setManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength) { - GAP.setManufacturerData(manufacturerData, manufacturerDataLength); + _advertisingData.setManufacturerData(manufacturerData, manufacturerDataLength); } void BLELocalDevice::setManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength) { - GAP.setManufacturerData(companyId, manufacturerData, manufacturerDataLength); + _advertisingData.setManufacturerData(companyId, manufacturerData, manufacturerDataLength); } void BLELocalDevice::setLocalName(const char *localName) { - GAP.setLocalName(localName); + _scanResponseData.setLocalName(localName); } void BLELocalDevice::setDeviceName(const char* deviceName) @@ -225,7 +230,10 @@ void BLELocalDevice::addService(BLEService& service) int BLELocalDevice::advertise() { - return GAP.advertise(); + _advertisingData.updateData(); + _scanResponseData.updateData(); + return GAP.advertise( _advertisingData.data(), _advertisingData.dataLength(), + _scanResponseData.data(), _scanResponseData.dataLength()); } void BLELocalDevice::stopAdvertise() diff --git a/src/local/BLELocalDevice.h b/src/local/BLELocalDevice.h index 20837c14..b74a2b49 100644 --- a/src/local/BLELocalDevice.h +++ b/src/local/BLELocalDevice.h @@ -22,6 +22,7 @@ #include "BLEDevice.h" #include "BLEService.h" +#include "BLEAdvertisingData.h" class BLELocalDevice { public: @@ -43,6 +44,7 @@ class BLELocalDevice { void setAdvertisedServiceUuid(const char* advertisedServiceUuid); void setAdvertisedService(const BLEService& service); + void setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length); void setManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength); void setManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength); void setLocalName(const char *localName); @@ -76,6 +78,8 @@ class BLELocalDevice { void noDebug(); private: + BLEAdvertisingData _advertisingData; + BLEAdvertisingData _scanResponseData; }; extern BLELocalDevice BLE; diff --git a/src/utility/GAP.cpp b/src/utility/GAP.cpp index ed3c859d..a8ba6b02 100644 --- a/src/utility/GAP.cpp +++ b/src/utility/GAP.cpp @@ -41,45 +41,16 @@ GAPClass::~GAPClass() { } -void GAPClass::setAdvertisedServiceUuid(const char* advertisedServiceUuid) -{ - _advertisingData.setAdvertisedServiceUuid(advertisedServiceUuid); -} - -void GAPClass::setManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength) -{ - _advertisingData.setManufacturerData(manufacturerData, manufacturerDataLength); -} - -void GAPClass::setManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength) -{ - _advertisingData.setManufacturerData(companyId, manufacturerData, manufacturerDataLength); -} - -void GAPClass::setLocalName(const char *localName) -{ - _scanResponseData.setLocalName(localName); -} - -void GAPClass::setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length) -{ - _advertisingData.setAdvertisedServiceData(uuid, data, length); -} - bool GAPClass::advertising() { return _advertising; } -int GAPClass::advertise() +int GAPClass::advertise(uint8_t* advData, uint8_t advDataLen, uint8_t* scanData, uint8_t scanDataLen) { uint8_t directBdaddr[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - _advertisingData.updateData(); - _scanResponseData.updateData(); - - uint8_t scanLength = _scanResponseData.getDataLength(); - uint8_t type = (_connectable) ? GAP_ADV_IND : (scanLength ? GAP_ADV_SCAN_IND : GAP_ADV_NONCONN_IND); + uint8_t type = (_connectable) ? GAP_ADV_IND : (scanDataLen ? GAP_ADV_SCAN_IND : GAP_ADV_NONCONN_IND); stopAdvertise(); @@ -87,15 +58,11 @@ int GAPClass::advertise() return 0; } - uint8_t* advertisingData = _advertisingData.getData(); - uint8_t advertisingDataLen = _advertisingData.getDataLength(); - if (HCI.leSetAdvertisingData(advertisingDataLen, advertisingData) != 0) { + if (HCI.leSetAdvertisingData(advDataLen, advData) != 0) { return 0; } - uint8_t* scanResponseData = _scanResponseData.getData(); - uint8_t scanResponseDataLen = _scanResponseData.getDataLength(); - if (HCI.leSetScanResponseData(scanResponseDataLen, scanResponseData) != 0) { + if (HCI.leSetScanResponseData(scanDataLen, scanData) != 0) { return 0; } diff --git a/src/utility/GAP.h b/src/utility/GAP.h index f265e39b..5de62cb2 100644 --- a/src/utility/GAP.h +++ b/src/utility/GAP.h @@ -22,7 +22,6 @@ #include "utility/BLELinkedList.h" -#include "BLEAdvertisingData.h" #include "BLEDevice.h" class GAPClass { @@ -30,13 +29,8 @@ class GAPClass { GAPClass(); virtual ~GAPClass(); - void setAdvertisedServiceUuid(const char* advertisedServiceUuid); - void setManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength); - void setManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength); - void setLocalName(const char *localName); - bool advertising(); - int advertise(); + int advertise(uint8_t* advData, uint8_t advDataLength, uint8_t* scanData, uint8_t scanDataLength); void stopAdvertise(); int scan(bool withDuplicates); @@ -51,11 +45,6 @@ class GAPClass { void setEventHandler(BLEDeviceEvent event, BLEDeviceEventHandler eventHandler); -protected: - friend class BLELocalCharacteristic; - - void setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length); - protected: friend class HCIClass; @@ -78,9 +67,6 @@ class GAPClass { String _scanNameFilter; String _scanUuidFilter; String _scanAddressFilter; - - BLEAdvertisingData _advertisingData; - BLEAdvertisingData _scanResponseData; }; extern GAPClass GAP; From 79a9e2e15c5829d15ff08c56262e9ceb63a7367b Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Fri, 25 Sep 2020 18:35:55 +0200 Subject: [PATCH 03/13] Extend advertising data allowing insertion of flags and raw data --- src/BLEAdvertisingData.cpp | 47 +++++++++++++++++++++++++++++++++--- src/BLEAdvertisingData.h | 30 ++++++++++++++++++++--- src/local/BLELocalDevice.cpp | 1 + 3 files changed, 71 insertions(+), 7 deletions(-) diff --git a/src/BLEAdvertisingData.cpp b/src/BLEAdvertisingData.cpp index 686cc66d..237a3555 100644 --- a/src/BLEAdvertisingData.cpp +++ b/src/BLEAdvertisingData.cpp @@ -21,6 +21,7 @@ BLEAdvertisingData::BLEAdvertisingData() : _dataLength(0), + _rawDataLength(0), _advertisedServiceUuid(NULL), _manufacturerData(NULL), _manufacturerDataLength(0), @@ -28,7 +29,9 @@ BLEAdvertisingData::BLEAdvertisingData() : _hasManufacturerCompanyId(false), _localName(NULL), _serviceData(NULL), - _serviceDataLength(0) + _serviceDataLength(0), + _flags(0), + _hasFlags(false) { } @@ -68,11 +71,28 @@ void BLEAdvertisingData::setLocalName(const char *localName) _localName = localName; } +void BLEAdvertisingData::setRawData(const uint8_t* data, uint8_t length) +{ + _rawData = data; + _rawDataLength = length; +} + +void BLEAdvertisingData::setFlags(uint8_t flags) +{ + _hasFlags = true; + _flags = flags; +} + bool BLEAdvertisingData::updateData() { + // Success indicates whether all the fields have been inserted bool success = true; // Reset data _dataLength = 0; + // Try to add flags into the current advertising packet + if (_hasFlags) { + success &= addFlags(_flags); + } // Try to add Advertised service uuid into the current advertising packet if (_advertisedServiceUuid) { success &= addAdvertisedServiceUuid(_advertisedServiceUuid); @@ -93,6 +113,10 @@ bool BLEAdvertisingData::updateData() if (_localName) { success &= addLocalName(_localName); } + // Try to add Raw data + if (_rawDataLength) { + success &= addRawData(_rawData, _rawDataLength); + } return success; } @@ -123,9 +147,9 @@ bool BLEAdvertisingData::addAdvertisedServiceUuid(const char* advertisedServiceU int uuidLen = uuid.length(); BLEAdField advField; if (uuidLen > 2) { - advField = BLEFieldAdvertisedService128; + advField = BLEFieldIncompleteAdvertisedService128; } else { - advField = BLEFieldAdvertisedService16; + advField = BLEFieldIncompleteAdvertisedService16; } return addField(advField, uuid.data(), uuidLen); } @@ -153,6 +177,23 @@ bool BLEAdvertisingData::addAdvertisedServiceData(uint16_t uuid, const uint8_t d return addField(BLEFieldServiceData, tempData, tempDataLength); } +bool BLEAdvertisingData::addRawData(const uint8_t* data, uint8_t length) +{ + // Bypass addField to add the integral raw data + if (length > (MAX_AD_DATA_LENGTH - _dataLength)) { + // Not enough space + return false; + } + memcpy(&_data[_dataLength], data, length); + _dataLength += length; + return true; +} + +bool BLEAdvertisingData::addFlags(uint8_t flags) +{ + return addField(BLEFieldFlags, &flags, 1); +} + bool BLEAdvertisingData::addField(BLEAdField field, const char* data) { uint8_t dataLength = strlen(data); diff --git a/src/BLEAdvertisingData.h b/src/BLEAdvertisingData.h index ac2956cb..4299a2f5 100644 --- a/src/BLEAdvertisingData.h +++ b/src/BLEAdvertisingData.h @@ -25,11 +25,20 @@ #define MAX_AD_DATA_LENGTH (31) +enum BLEFlags { + BLEFlagsLimitedDiscoverable = 0x01, + BLEFlagsGeneralDiscoverable = 0x02, + BLEFlagsBREDRNotSupported = 0x04 +}; + enum BLEAdField { + BLEFieldFlags = 0x01, + BLEFieldIncompleteAdvertisedService16 = 0x02, + BLEFieldCompleteAdvertisedService16 = 0x03, + BLEFieldIncompleteAdvertisedService128 = 0x06, + BLEFieldCompleteAdvertisedService128 = 0x07, BLEFieldShortLocalName = 0x08, BLEFieldCompleteLocalName = 0x09, - BLEFieldAdvertisedService16 = 0x02, - BLEFieldAdvertisedService128 = 0x06, BLEFieldServiceData = 0x16, BLEFieldManufacturerData = 0xFF, @@ -46,7 +55,11 @@ class BLEAdvertisingData { void setManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength); void setLocalName(const char *localName); void setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length); + void setRawData(const uint8_t* data, uint8_t length); + void setFlags(uint8_t flags); +protected: + friend class BLELocalDevice; bool updateData(); uint8_t* data(); int dataLength() const; @@ -57,6 +70,8 @@ class BLEAdvertisingData { bool addManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength); bool addLocalName(const char *localName); bool addAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length); + bool addRawData(const uint8_t* data, uint8_t length); + bool addFlags(uint8_t flags); bool addField(BLEAdField field, const char* data); bool addField(BLEAdField field, const uint8_t* data, uint8_t length); @@ -64,12 +79,19 @@ class BLEAdvertisingData { uint8_t _data[MAX_AD_DATA_LENGTH]; int _dataLength; - const char* _advertisedServiceUuid; + const uint8_t* _rawData; + uint8_t _rawDataLength; + + uint8_t _flags; + bool _hasFlags; + const char* _localName; + const uint8_t* _manufacturerData; int _manufacturerDataLength; uint16_t _manufacturerCompanyId; bool _hasManufacturerCompanyId; - const char* _localName; + + const char* _advertisedServiceUuid; uint16_t _serviceDataUuid; const uint8_t* _serviceData; int _serviceDataLength; diff --git a/src/local/BLELocalDevice.cpp b/src/local/BLELocalDevice.cpp index 79fbb257..4e9e2b3d 100644 --- a/src/local/BLELocalDevice.cpp +++ b/src/local/BLELocalDevice.cpp @@ -33,6 +33,7 @@ BLELocalDevice::BLELocalDevice() { + _advertisingData.setFlags(BLEFlagsGeneralDiscoverable | BLEFlagsBREDRNotSupported); } BLELocalDevice::~BLELocalDevice() From f848913a6ba0ffcf083e8b227bb36da64e1ec318 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Mon, 28 Sep 2020 14:40:49 +0200 Subject: [PATCH 04/13] Perform remaining length checks on advertising parameters set methods Now all the set methods of advertising data parameters return a bool value. This bool indicates whether the parameter has been correctly set or not, depending on the size of the passed value. A remaining length parameter of advertising data has been introduced. It can be publicly read, it indicates how many bytes can be still written into the packet. --- src/BLEAdvertisingData.cpp | 124 +++++++++++++++++++++++++++---------- src/BLEAdvertisingData.h | 29 ++++++--- 2 files changed, 110 insertions(+), 43 deletions(-) diff --git a/src/BLEAdvertisingData.cpp b/src/BLEAdvertisingData.cpp index 237a3555..8dedc8e5 100644 --- a/src/BLEAdvertisingData.cpp +++ b/src/BLEAdvertisingData.cpp @@ -19,6 +19,8 @@ #include "BLEAdvertisingData.h" +#define AD_FIELD_OVERHEAD (2) + BLEAdvertisingData::BLEAdvertisingData() : _dataLength(0), _rawDataLength(0), @@ -31,7 +33,8 @@ BLEAdvertisingData::BLEAdvertisingData() : _serviceData(NULL), _serviceDataLength(0), _flags(0), - _hasFlags(false) + _hasFlags(false), + _remainingLength(MAX_AD_DATA_LENGTH) { } @@ -39,48 +42,103 @@ BLEAdvertisingData::~BLEAdvertisingData() { } -void BLEAdvertisingData::setAdvertisedServiceUuid(const char* advertisedServiceUuid) +inline bool BLEAdvertisingData::updateRemainingLength(int fieldLength) { - _advertisedServiceUuid = advertisedServiceUuid; + if (fieldLength <= _remainingLength) { + _remainingLength -= fieldLength; + return true; + } + return false; } -void BLEAdvertisingData::setManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength) +int BLEAdvertisingData::remainingLength() const { - _manufacturerData = manufacturerData; - _manufacturerDataLength = manufacturerDataLength; - _hasManufacturerCompanyId = false; + return _remainingLength; } -void BLEAdvertisingData::setManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength) +int BLEAdvertisingData::availableForWrite() { - _manufacturerData = manufacturerData; - _manufacturerDataLength = manufacturerDataLength; - _manufacturerCompanyId = companyId; - _hasManufacturerCompanyId = true; + int available = (_remainingLength - AD_FIELD_OVERHEAD); + if (available < 0) available = 0; + return available; } -void BLEAdvertisingData::setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length) +bool BLEAdvertisingData::setAdvertisedServiceUuid(const char* advertisedServiceUuid) { - _serviceDataUuid = uuid; - _serviceData = data; - _serviceDataLength = length; + BLEUuid uuid(advertisedServiceUuid); + bool success = updateRemainingLength(uuid.length() + AD_FIELD_OVERHEAD); + if (success) { + _advertisedServiceUuid = advertisedServiceUuid; + } + return success; } -void BLEAdvertisingData::setLocalName(const char *localName) +bool BLEAdvertisingData::setAdvertisedService(const BLEService& service) { - _localName = localName; + return setAdvertisedServiceUuid(service.uuid()); } -void BLEAdvertisingData::setRawData(const uint8_t* data, uint8_t length) +bool BLEAdvertisingData::setManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength) { - _rawData = data; - _rawDataLength = length; + bool success = updateRemainingLength(manufacturerDataLength + AD_FIELD_OVERHEAD); + if (success) { + _manufacturerData = manufacturerData; + _manufacturerDataLength = manufacturerDataLength; + _hasManufacturerCompanyId = false; + } + return success; } -void BLEAdvertisingData::setFlags(uint8_t flags) +bool BLEAdvertisingData::setManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength) { - _hasFlags = true; - _flags = flags; + bool success = updateRemainingLength(manufacturerDataLength + sizeof(companyId) + AD_FIELD_OVERHEAD); + if (success) { + _manufacturerData = manufacturerData; + _manufacturerDataLength = manufacturerDataLength; + _manufacturerCompanyId = companyId; + _hasManufacturerCompanyId = true; + } + return success; +} + +bool BLEAdvertisingData::setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length) +{ + bool success = updateRemainingLength(length + sizeof(uuid) + AD_FIELD_OVERHEAD); + if (success) { + _serviceDataUuid = uuid; + _serviceData = data; + _serviceDataLength = length; + } + return success; +} + +bool BLEAdvertisingData::setLocalName(const char *localName) +{ + bool success = updateRemainingLength(strlen(localName) + AD_FIELD_OVERHEAD); + if (success) { + _localName = localName; + } + return success; +} + +bool BLEAdvertisingData::setRawData(const uint8_t* data, int length) +{ + bool success = updateRemainingLength(length); + if (success) { + _rawData = data; + _rawDataLength = length; + } + return success; +} + +bool BLEAdvertisingData::setFlags(uint8_t flags) +{ + bool success = updateRemainingLength(sizeof(flags) + AD_FIELD_OVERHEAD); + if (success) { + _hasFlags = true; + _flags = flags; + } + return success; } bool BLEAdvertisingData::updateData() @@ -133,8 +191,8 @@ int BLEAdvertisingData::dataLength() const bool BLEAdvertisingData::addLocalName(const char *localName) { bool success = false; - if (strlen(localName) > (MAX_AD_DATA_LENGTH - 2)) { - success = addField(BLEFieldShortLocalName, (uint8_t*)localName, (MAX_AD_DATA_LENGTH - 2)); + 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); } @@ -161,7 +219,7 @@ bool BLEAdvertisingData::addManufacturerData(const uint8_t manufacturerData[], i bool BLEAdvertisingData::addManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength) { - uint8_t tempDataLength = manufacturerDataLength + sizeof(companyId); + int tempDataLength = manufacturerDataLength + sizeof(companyId); uint8_t tempData[MAX_AD_DATA_LENGTH]; memcpy(tempData, &companyId, sizeof(companyId)); memcpy(&tempData[sizeof(companyId)], manufacturerData, manufacturerDataLength); @@ -170,14 +228,14 @@ bool BLEAdvertisingData::addManufacturerData(const uint16_t companyId, const uin bool BLEAdvertisingData::addAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length) { - uint8_t tempDataLength = length + sizeof(uuid); + int tempDataLength = length + sizeof(uuid); uint8_t tempData[MAX_AD_DATA_LENGTH]; memcpy(tempData, &uuid, sizeof(uuid)); memcpy(&tempData[sizeof(uuid)], data, length); return addField(BLEFieldServiceData, tempData, tempDataLength); } -bool BLEAdvertisingData::addRawData(const uint8_t* data, uint8_t length) +bool BLEAdvertisingData::addRawData(const uint8_t* data, int length) { // Bypass addField to add the integral raw data if (length > (MAX_AD_DATA_LENGTH - _dataLength)) { @@ -191,18 +249,18 @@ bool BLEAdvertisingData::addRawData(const uint8_t* data, uint8_t length) bool BLEAdvertisingData::addFlags(uint8_t flags) { - return addField(BLEFieldFlags, &flags, 1); + return addField(BLEFieldFlags, &flags, sizeof(flags)); } bool BLEAdvertisingData::addField(BLEAdField field, const char* data) { - uint8_t dataLength = strlen(data); + int dataLength = strlen(data); return addField(field, (uint8_t *)data, dataLength); } -bool BLEAdvertisingData::addField(BLEAdField field, const uint8_t* data, uint8_t length) +bool BLEAdvertisingData::addField(BLEAdField field, const uint8_t* data, int length) { - uint8_t fieldLength = length + 2; // Considering data TYPE and LENGTH fields + int fieldLength = length + AD_FIELD_OVERHEAD; // Considering data TYPE and LENGTH fields if (fieldLength > (MAX_AD_DATA_LENGTH - _dataLength)) { // Not enough space for storing this field return false; diff --git a/src/BLEAdvertisingData.h b/src/BLEAdvertisingData.h index 4299a2f5..96b850c1 100644 --- a/src/BLEAdvertisingData.h +++ b/src/BLEAdvertisingData.h @@ -22,6 +22,7 @@ #include #include "utility/BLEUuid.h" +#include "BLEService.h" #define MAX_AD_DATA_LENGTH (31) @@ -50,37 +51,45 @@ class BLEAdvertisingData { BLEAdvertisingData(); virtual ~BLEAdvertisingData(); - void setAdvertisedServiceUuid(const char* advertisedServiceUuid); - void setManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength); - void setManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength); - void setLocalName(const char *localName); - void setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length); - void setRawData(const uint8_t* data, uint8_t length); - void setFlags(uint8_t flags); + int availableForWrite(); + + bool setAdvertisedService(const BLEService& service); + bool setAdvertisedServiceUuid(const char* advertisedServiceUuid); + 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 setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length); + bool setRawData(const uint8_t* data, int length); + bool setFlags(uint8_t flags); protected: friend class BLELocalDevice; bool updateData(); uint8_t* data(); int dataLength() const; + int remainingLength() const; private: + bool updateRemainingLength(int fieldLength); + bool addAdvertisedServiceUuid(const char* advertisedServiceUuid); 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 addAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length); - bool addRawData(const uint8_t* data, uint8_t length); + bool addRawData(const uint8_t* data, int length); bool addFlags(uint8_t flags); bool addField(BLEAdField field, const char* data); - bool addField(BLEAdField field, const uint8_t* data, uint8_t length); + bool addField(BLEAdField field, const uint8_t* data, int length); uint8_t _data[MAX_AD_DATA_LENGTH]; int _dataLength; + int _remainingLength; + const uint8_t* _rawData; - uint8_t _rawDataLength; + int _rawDataLength; uint8_t _flags; bool _hasFlags; From d27fff5fcc39077b22b3578420c421eedbd2207a Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Tue, 29 Sep 2020 15:45:25 +0200 Subject: [PATCH 05/13] Add API function to set advertising and scan response data --- src/BLEAdvertisingData.cpp | 39 ++++++++++++++++++++++++++++++++++++ src/BLEAdvertisingData.h | 3 +++ src/local/BLELocalDevice.cpp | 20 ++++++++++++++++++ src/local/BLELocalDevice.h | 7 +++++++ 4 files changed, 69 insertions(+) diff --git a/src/BLEAdvertisingData.cpp b/src/BLEAdvertisingData.cpp index 8dedc8e5..1c662c72 100644 --- a/src/BLEAdvertisingData.cpp +++ b/src/BLEAdvertisingData.cpp @@ -63,6 +63,45 @@ int BLEAdvertisingData::availableForWrite() return available; } +void BLEAdvertisingData::clear() +{ + _remainingLength = MAX_AD_DATA_LENGTH; + _rawData = NULL; + _rawDataLength = 0; + _hasFlags = false; + _localName = NULL; + _manufacturerData = NULL; + _manufacturerDataLength = 0; + _hasManufacturerCompanyId = false; + _advertisedServiceUuid = NULL; + _serviceData = NULL; + _serviceDataLength = 0; +} + +void BLEAdvertisingData::copy(const BLEAdvertisingData& adv) +{ + _remainingLength = adv._remainingLength; + _rawData = adv._rawData; + _rawDataLength = adv._rawDataLength; + _flags = adv._flags; + _hasFlags = adv._hasFlags; + _localName = adv._localName; + _manufacturerData = adv._manufacturerData; + _manufacturerDataLength = adv._manufacturerDataLength; + _manufacturerCompanyId = adv._manufacturerCompanyId; + _hasManufacturerCompanyId = adv._hasManufacturerCompanyId; + _advertisedServiceUuid = adv._advertisedServiceUuid; + _serviceDataUuid = adv._serviceDataUuid; + _serviceData = adv._serviceData; + _serviceDataLength = adv._serviceDataLength; +} + +BLEAdvertisingData& BLEAdvertisingData::operator=(const BLEAdvertisingData &other) +{ + copy(other); + return *this; +} + bool BLEAdvertisingData::setAdvertisedServiceUuid(const char* advertisedServiceUuid) { BLEUuid uuid(advertisedServiceUuid); diff --git a/src/BLEAdvertisingData.h b/src/BLEAdvertisingData.h index 96b850c1..42e8fa15 100644 --- a/src/BLEAdvertisingData.h +++ b/src/BLEAdvertisingData.h @@ -52,6 +52,9 @@ class BLEAdvertisingData { virtual ~BLEAdvertisingData(); int availableForWrite(); + void clear(); + void copy(const BLEAdvertisingData& adv); + BLEAdvertisingData& operator=(const BLEAdvertisingData &other); bool setAdvertisedService(const BLEService& service); bool setAdvertisedServiceUuid(const char* advertisedServiceUuid); diff --git a/src/local/BLELocalDevice.cpp b/src/local/BLELocalDevice.cpp index 4e9e2b3d..1f98a23e 100644 --- a/src/local/BLELocalDevice.cpp +++ b/src/local/BLELocalDevice.cpp @@ -214,6 +214,26 @@ void BLELocalDevice::setLocalName(const char *localName) _scanResponseData.setLocalName(localName); } +void BLELocalDevice::setAdvertisingData(BLEAdvertisingData& advertisingData) +{ + _advertisingData = advertisingData; +} + +void BLELocalDevice::setScanResponseData(BLEAdvertisingData& scanResponseData) +{ + _scanResponseData = scanResponseData; +} + +BLEAdvertisingData& BLELocalDevice::getAdvertisingData() +{ + return _advertisingData; +} + +BLEAdvertisingData& BLELocalDevice::getScanResponseData() +{ + return _scanResponseData; +} + void BLELocalDevice::setDeviceName(const char* deviceName) { GATT.setDeviceName(deviceName); diff --git a/src/local/BLELocalDevice.h b/src/local/BLELocalDevice.h index b74a2b49..3a664c44 100644 --- a/src/local/BLELocalDevice.h +++ b/src/local/BLELocalDevice.h @@ -49,6 +49,9 @@ class BLELocalDevice { void setManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength); void setLocalName(const char *localName); + void setAdvertisingData(BLEAdvertisingData& advertisingData); + void setScanResponseData(BLEAdvertisingData& scanResponseData); + void setDeviceName(const char* deviceName); void setAppearance(uint16_t appearance); @@ -76,6 +79,10 @@ class BLELocalDevice { void debug(Stream& stream); void noDebug(); + +protected: + BLEAdvertisingData& getAdvertisingData(); + BLEAdvertisingData& getScanResponseData(); private: BLEAdvertisingData _advertisingData; From f79e492d357199e7b8e6a32225fb2cd7fa0361b2 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Thu, 15 Oct 2020 00:53:48 +0200 Subject: [PATCH 06/13] Change default flags on advertising data packets In BLELocalDevice constructor, the flags field of the advertising data is set to a default value. If a new advertising data is passed to BLELocalDevice, then: if it has no flags -> default flags are set (if there is enough space) if it already has flags -> nothing happens, the already set flags are used --- src/BLEAdvertisingData.cpp | 5 +++++ src/BLEAdvertisingData.h | 1 + src/local/BLELocalDevice.cpp | 3 +++ 3 files changed, 9 insertions(+) diff --git a/src/BLEAdvertisingData.cpp b/src/BLEAdvertisingData.cpp index 1c662c72..7b377ff4 100644 --- a/src/BLEAdvertisingData.cpp +++ b/src/BLEAdvertisingData.cpp @@ -227,6 +227,11 @@ int BLEAdvertisingData::dataLength() const return _dataLength; } +bool BLEAdvertisingData::hasFlags() const +{ + return _hasFlags; +} + bool BLEAdvertisingData::addLocalName(const char *localName) { bool success = false; diff --git a/src/BLEAdvertisingData.h b/src/BLEAdvertisingData.h index 42e8fa15..f7195940 100644 --- a/src/BLEAdvertisingData.h +++ b/src/BLEAdvertisingData.h @@ -71,6 +71,7 @@ class BLEAdvertisingData { uint8_t* data(); int dataLength() const; int remainingLength() const; + bool hasFlags() const; private: bool updateRemainingLength(int fieldLength); diff --git a/src/local/BLELocalDevice.cpp b/src/local/BLELocalDevice.cpp index 1f98a23e..4f91c22f 100644 --- a/src/local/BLELocalDevice.cpp +++ b/src/local/BLELocalDevice.cpp @@ -217,6 +217,9 @@ void BLELocalDevice::setLocalName(const char *localName) void BLELocalDevice::setAdvertisingData(BLEAdvertisingData& advertisingData) { _advertisingData = advertisingData; + if (!_advertisingData.hasFlags()) { + _advertisingData.setFlags(BLEFlagsGeneralDiscoverable | BLEFlagsBREDRNotSupported); + } } void BLELocalDevice::setScanResponseData(BLEAdvertisingData& scanResponseData) From d03c74c20b2d29233a25c94d80f4f5829e5c70b6 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Tue, 29 Sep 2020 12:52:49 +0200 Subject: [PATCH 07/13] Refactor advertising raw data Add raw data class. When an AdvertisingData object has a rawData parameter set, the only advertised data will be the rawData parameter itself. --- src/BLEAdvertisingData.cpp | 29 ++++++++++++++++++++--------- src/BLEAdvertisingData.h | 6 ++++++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/BLEAdvertisingData.cpp b/src/BLEAdvertisingData.cpp index 7b377ff4..ee2f3549 100644 --- a/src/BLEAdvertisingData.cpp +++ b/src/BLEAdvertisingData.cpp @@ -23,6 +23,7 @@ BLEAdvertisingData::BLEAdvertisingData() : _dataLength(0), + _rawData(NULL), _rawDataLength(0), _advertisedServiceUuid(NULL), _manufacturerData(NULL), @@ -162,12 +163,22 @@ bool BLEAdvertisingData::setLocalName(const char *localName) bool BLEAdvertisingData::setRawData(const uint8_t* data, int length) { - bool success = updateRemainingLength(length); - if (success) { - _rawData = data; - _rawDataLength = length; + if (length > MAX_AD_DATA_LENGTH) { + length = MAX_AD_DATA_LENGTH; } - return success; + _rawData = data; + _rawDataLength = length; + return true; +} + +bool BLEAdvertisingData::setRawData(const BLEAdvertisingRawData& rawData) +{ + _rawData = rawData.data; + _rawDataLength = rawData.length; + if (_rawDataLength > MAX_AD_DATA_LENGTH) { + _rawDataLength = MAX_AD_DATA_LENGTH; + } + return true; } bool BLEAdvertisingData::setFlags(uint8_t flags) @@ -186,6 +197,10 @@ bool BLEAdvertisingData::updateData() bool success = true; // Reset data _dataLength = 0; + // If rawData is present, then only rawData is inserted in the advertising packet + if (_rawData && _rawDataLength) { + return addRawData(_rawData, _rawDataLength); + } // Try to add flags into the current advertising packet if (_hasFlags) { success &= addFlags(_flags); @@ -210,10 +225,6 @@ bool BLEAdvertisingData::updateData() if (_localName) { success &= addLocalName(_localName); } - // Try to add Raw data - if (_rawDataLength) { - success &= addRawData(_rawData, _rawDataLength); - } return success; } diff --git a/src/BLEAdvertisingData.h b/src/BLEAdvertisingData.h index f7195940..0bbef413 100644 --- a/src/BLEAdvertisingData.h +++ b/src/BLEAdvertisingData.h @@ -46,6 +46,11 @@ enum BLEAdField { BLEAdFieldLast }; +struct BLEAdvertisingRawData { + uint8_t data[MAX_AD_DATA_LENGTH]; + int length; +}; + class BLEAdvertisingData { public: BLEAdvertisingData(); @@ -63,6 +68,7 @@ class BLEAdvertisingData { bool setLocalName(const char *localName); bool setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length); bool setRawData(const uint8_t* data, int length); + bool setRawData(const BLEAdvertisingRawData& data); bool setFlags(uint8_t flags); protected: From 19e8d72e8c209e4f20eec5f8c50f63bcf429d00e Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Fri, 2 Oct 2020 18:32:00 +0200 Subject: [PATCH 08/13] Allow setting advertising parameters multiple time If the new value for the parameter is not valid, because too large, then the old value will remain the actual value of the parameter. --- src/BLEAdvertisingData.cpp | 41 +++++++++++++++++++++++++++++--------- src/BLEAdvertisingData.h | 3 ++- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/BLEAdvertisingData.cpp b/src/BLEAdvertisingData.cpp index ee2f3549..50063913 100644 --- a/src/BLEAdvertisingData.cpp +++ b/src/BLEAdvertisingData.cpp @@ -26,6 +26,7 @@ BLEAdvertisingData::BLEAdvertisingData() : _rawData(NULL), _rawDataLength(0), _advertisedServiceUuid(NULL), + _advertisedServiceUuidLength(0), _manufacturerData(NULL), _manufacturerDataLength(0), _manufacturerCompanyId(0), @@ -43,10 +44,11 @@ BLEAdvertisingData::~BLEAdvertisingData() { } -inline bool BLEAdvertisingData::updateRemainingLength(int fieldLength) +inline bool BLEAdvertisingData::updateRemainingLength(int oldFieldLength, int newFieldLength) { - if (fieldLength <= _remainingLength) { - _remainingLength -= fieldLength; + int updatedRemaining = _remainingLength + (oldFieldLength - newFieldLength); + if (updatedRemaining >= 0) { + _remainingLength = updatedRemaining; return true; } return false; @@ -75,6 +77,7 @@ void BLEAdvertisingData::clear() _manufacturerDataLength = 0; _hasManufacturerCompanyId = false; _advertisedServiceUuid = NULL; + _advertisedServiceUuidLength = 0; _serviceData = NULL; _serviceDataLength = 0; } @@ -92,6 +95,7 @@ void BLEAdvertisingData::copy(const BLEAdvertisingData& adv) _manufacturerCompanyId = adv._manufacturerCompanyId; _hasManufacturerCompanyId = adv._hasManufacturerCompanyId; _advertisedServiceUuid = adv._advertisedServiceUuid; + _advertisedServiceUuidLength = adv._advertisedServiceUuidLength; _serviceDataUuid = adv._serviceDataUuid; _serviceData = adv._serviceData; _serviceDataLength = adv._serviceDataLength; @@ -106,9 +110,11 @@ BLEAdvertisingData& BLEAdvertisingData::operator=(const BLEAdvertisingData &othe bool BLEAdvertisingData::setAdvertisedServiceUuid(const char* advertisedServiceUuid) { BLEUuid uuid(advertisedServiceUuid); - bool success = updateRemainingLength(uuid.length() + AD_FIELD_OVERHEAD); + int previousLength = (_advertisedServiceUuidLength > 0) ? (_advertisedServiceUuidLength + AD_FIELD_OVERHEAD) : 0; + bool success = updateRemainingLength(previousLength, (uuid.length() + AD_FIELD_OVERHEAD)); if (success) { _advertisedServiceUuid = advertisedServiceUuid; + _advertisedServiceUuidLength = uuid.length(); } return success; } @@ -120,7 +126,14 @@ bool BLEAdvertisingData::setAdvertisedService(const BLEService& service) bool BLEAdvertisingData::setManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength) { - bool success = updateRemainingLength(manufacturerDataLength + AD_FIELD_OVERHEAD); + int previousLength = 0; + if (_manufacturerDataLength) { + previousLength = _manufacturerDataLength + AD_FIELD_OVERHEAD; + if (_hasManufacturerCompanyId) { + previousLength += sizeof(_manufacturerCompanyId); + } + } + bool success = updateRemainingLength(previousLength, (manufacturerDataLength + AD_FIELD_OVERHEAD)); if (success) { _manufacturerData = manufacturerData; _manufacturerDataLength = manufacturerDataLength; @@ -131,7 +144,14 @@ bool BLEAdvertisingData::setManufacturerData(const uint8_t manufacturerData[], i bool BLEAdvertisingData::setManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength) { - bool success = updateRemainingLength(manufacturerDataLength + sizeof(companyId) + AD_FIELD_OVERHEAD); + int previousLength = 0; + if (_manufacturerDataLength) { + previousLength = _manufacturerDataLength + AD_FIELD_OVERHEAD; + if (_hasManufacturerCompanyId) { + previousLength += sizeof(_manufacturerCompanyId); + } + } + bool success = updateRemainingLength(previousLength, (manufacturerDataLength + sizeof(companyId) + AD_FIELD_OVERHEAD)); if (success) { _manufacturerData = manufacturerData; _manufacturerDataLength = manufacturerDataLength; @@ -143,7 +163,8 @@ bool BLEAdvertisingData::setManufacturerData(const uint16_t companyId, const uin bool BLEAdvertisingData::setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length) { - bool success = updateRemainingLength(length + sizeof(uuid) + AD_FIELD_OVERHEAD); + int previousLength = (_serviceDataLength > 0) ? (_serviceDataLength + sizeof(uuid) + AD_FIELD_OVERHEAD) : 0; + bool success = updateRemainingLength(previousLength, (length + sizeof(uuid) + AD_FIELD_OVERHEAD)); if (success) { _serviceDataUuid = uuid; _serviceData = data; @@ -154,7 +175,8 @@ bool BLEAdvertisingData::setAdvertisedServiceData(uint16_t uuid, const uint8_t d bool BLEAdvertisingData::setLocalName(const char *localName) { - bool success = updateRemainingLength(strlen(localName) + AD_FIELD_OVERHEAD); + int previousLength = (_localName && strlen(_localName) > 0) ? (strlen(_localName) + AD_FIELD_OVERHEAD) : 0; + bool success = updateRemainingLength(previousLength, (strlen(localName) + AD_FIELD_OVERHEAD)); if (success) { _localName = localName; } @@ -183,7 +205,8 @@ bool BLEAdvertisingData::setRawData(const BLEAdvertisingRawData& rawData) bool BLEAdvertisingData::setFlags(uint8_t flags) { - bool success = updateRemainingLength(sizeof(flags) + AD_FIELD_OVERHEAD); + int previousLength = (_hasFlags) ? (sizeof(_flags) + AD_FIELD_OVERHEAD) : 0; + bool success = updateRemainingLength(previousLength, (sizeof(flags) + AD_FIELD_OVERHEAD)); if (success) { _hasFlags = true; _flags = flags; diff --git a/src/BLEAdvertisingData.h b/src/BLEAdvertisingData.h index 0bbef413..dc736053 100644 --- a/src/BLEAdvertisingData.h +++ b/src/BLEAdvertisingData.h @@ -80,7 +80,7 @@ class BLEAdvertisingData { bool hasFlags() const; private: - bool updateRemainingLength(int fieldLength); + bool updateRemainingLength(int oldFieldLength, int newFieldLength); bool addAdvertisedServiceUuid(const char* advertisedServiceUuid); bool addManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength); @@ -111,6 +111,7 @@ class BLEAdvertisingData { bool _hasManufacturerCompanyId; const char* _advertisedServiceUuid; + int _advertisedServiceUuidLength; uint16_t _serviceDataUuid; const uint8_t* _serviceData; int _serviceDataLength; From b6424cff4861675d4ab0d9de35fdacdb3582cab1 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Wed, 7 Oct 2020 12:34:38 +0200 Subject: [PATCH 09/13] Change singleton definition. This change is needed for mocking BLE classes in the CI environment --- src/local/BLELocalDevice.cpp | 3 ++- src/local/BLELocalDevice.h | 2 +- src/utility/ATT.cpp | 3 ++- src/utility/ATT.h | 2 +- src/utility/GAP.cpp | 3 ++- src/utility/GAP.h | 2 +- src/utility/GATT.cpp | 3 ++- src/utility/GATT.h | 2 +- src/utility/HCI.cpp | 3 ++- src/utility/HCI.h | 2 +- src/utility/L2CAPSignaling.cpp | 3 ++- src/utility/L2CAPSignaling.h | 2 +- 12 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/local/BLELocalDevice.cpp b/src/local/BLELocalDevice.cpp index 4f91c22f..872a82ca 100644 --- a/src/local/BLELocalDevice.cpp +++ b/src/local/BLELocalDevice.cpp @@ -343,4 +343,5 @@ void BLELocalDevice::noDebug() HCI.noDebug(); } -BLELocalDevice BLE; +BLELocalDevice BLEObj; +BLELocalDevice& BLE = BLEObj; diff --git a/src/local/BLELocalDevice.h b/src/local/BLELocalDevice.h index 3a664c44..748e778c 100644 --- a/src/local/BLELocalDevice.h +++ b/src/local/BLELocalDevice.h @@ -89,6 +89,6 @@ class BLELocalDevice { BLEAdvertisingData _scanResponseData; }; -extern BLELocalDevice BLE; +extern BLELocalDevice& BLE; #endif diff --git a/src/utility/ATT.cpp b/src/utility/ATT.cpp index 296caeee..e6443b59 100644 --- a/src/utility/ATT.cpp +++ b/src/utility/ATT.cpp @@ -1687,4 +1687,5 @@ void ATTClass::writeCmd(uint16_t connectionHandle, uint16_t handle, const uint8_ sendReq(connectionHandle, &writeReq, 3 + dataLen, NULL); } -ATTClass ATT; +ATTClass ATTObj; +ATTClass& ATT = ATTObj; diff --git a/src/utility/ATT.h b/src/utility/ATT.h index 6a1611aa..b5df05d3 100644 --- a/src/utility/ATT.h +++ b/src/utility/ATT.h @@ -137,6 +137,6 @@ class ATTClass { BLEDeviceEventHandler _eventHandlers[2]; }; -extern ATTClass ATT; +extern ATTClass& ATT; #endif diff --git a/src/utility/GAP.cpp b/src/utility/GAP.cpp index a8ba6b02..654cef7b 100644 --- a/src/utility/GAP.cpp +++ b/src/utility/GAP.cpp @@ -258,4 +258,5 @@ bool GAPClass::matchesScanFilter(const BLEDevice& device) return true; } -GAPClass GAP; +GAPClass GAPObj; +GAPClass& GAP = GAPObj; diff --git a/src/utility/GAP.h b/src/utility/GAP.h index 5de62cb2..5da62528 100644 --- a/src/utility/GAP.h +++ b/src/utility/GAP.h @@ -69,6 +69,6 @@ class GAPClass { String _scanAddressFilter; }; -extern GAPClass GAP; +extern GAPClass& GAP; #endif diff --git a/src/utility/GATT.cpp b/src/utility/GATT.cpp index 0c7ab4dd..21df18fd 100644 --- a/src/utility/GATT.cpp +++ b/src/utility/GATT.cpp @@ -172,4 +172,5 @@ void GATTClass::clearAttributes() _attributes.clear(); } -GATTClass GATT; +GATTClass GATTObj; +GATTClass& GATT = GATTObj; diff --git a/src/utility/GATT.h b/src/utility/GATT.h index 249d5728..e2195a8f 100644 --- a/src/utility/GATT.h +++ b/src/utility/GATT.h @@ -67,6 +67,6 @@ class GATTClass { BLELocalCharacteristic* _servicesChangedCharacteristic; }; -extern GATTClass GATT; +extern GATTClass& GATT; #endif diff --git a/src/utility/HCI.cpp b/src/utility/HCI.cpp index 0234803f..6f602ea1 100644 --- a/src/utility/HCI.cpp +++ b/src/utility/HCI.cpp @@ -686,4 +686,5 @@ void HCIClass::dumpPkt(const char* prefix, uint8_t plen, uint8_t pdata[]) } } -HCIClass HCI; +HCIClass HCIObj; +HCIClass& HCI = HCIObj; diff --git a/src/utility/HCI.h b/src/utility/HCI.h index 86ec679c..37e4d803 100644 --- a/src/utility/HCI.h +++ b/src/utility/HCI.h @@ -96,6 +96,6 @@ class HCIClass { uint8_t _aclPktBuffer[255]; }; -extern HCIClass HCI; +extern HCIClass& HCI; #endif diff --git a/src/utility/L2CAPSignaling.cpp b/src/utility/L2CAPSignaling.cpp index f650cab2..4135099c 100644 --- a/src/utility/L2CAPSignaling.cpp +++ b/src/utility/L2CAPSignaling.cpp @@ -146,4 +146,5 @@ void L2CAPSignalingClass::connectionParameterUpdateResponse(uint16_t /*handle*/, { } -L2CAPSignalingClass L2CAPSignaling; +L2CAPSignalingClass L2CAPSignalingObj; +L2CAPSignalingClass& L2CAPSignaling = L2CAPSignalingObj; diff --git a/src/utility/L2CAPSignaling.h b/src/utility/L2CAPSignaling.h index 349ffb85..20c174e9 100644 --- a/src/utility/L2CAPSignaling.h +++ b/src/utility/L2CAPSignaling.h @@ -49,6 +49,6 @@ class L2CAPSignalingClass { uint16_t _maxInterval; }; -extern L2CAPSignalingClass L2CAPSignaling; +extern L2CAPSignalingClass& L2CAPSignaling; #endif From af9e096b3268a25d713b68c7dfbd1419e52b73ce Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Mon, 12 Oct 2020 11:44:06 +0200 Subject: [PATCH 10/13] Set singleton methods as virtual This change allows fake classes to override methods during unit testing. --- src/local/BLELocalDevice.h | 74 ++++++++++++------------- src/utility/ATT.h | 104 +++++++++++++++++------------------ src/utility/GAP.h | 28 +++++----- src/utility/GATT.h | 20 +++---- src/utility/HCI.h | 58 +++++++++---------- src/utility/L2CAPSignaling.h | 12 ++-- 6 files changed, 148 insertions(+), 148 deletions(-) diff --git a/src/local/BLELocalDevice.h b/src/local/BLELocalDevice.h index 748e778c..8fef70cc 100644 --- a/src/local/BLELocalDevice.h +++ b/src/local/BLELocalDevice.h @@ -29,60 +29,60 @@ class BLELocalDevice { BLELocalDevice(); virtual ~BLELocalDevice(); - int begin(); - void end(); + virtual int begin(); + virtual void end(); - void poll(); - void poll(unsigned long timeout); + virtual void poll(); + virtual void poll(unsigned long timeout); - bool connected() const; - bool disconnect(); + virtual bool connected() const; + virtual bool disconnect(); - String address() const; + virtual String address() const; - int rssi(); + virtual int rssi(); - void setAdvertisedServiceUuid(const char* advertisedServiceUuid); - void setAdvertisedService(const BLEService& service); - void setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length); - void setManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength); - void setManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength); - void setLocalName(const char *localName); + virtual void setAdvertisedServiceUuid(const char* advertisedServiceUuid); + virtual void setAdvertisedService(const BLEService& service); + virtual void setAdvertisedServiceData(uint16_t uuid, const uint8_t data[], int length); + virtual void setManufacturerData(const uint8_t manufacturerData[], int manufacturerDataLength); + virtual void setManufacturerData(const uint16_t companyId, const uint8_t manufacturerData[], int manufacturerDataLength); + virtual void setLocalName(const char *localName); - void setAdvertisingData(BLEAdvertisingData& advertisingData); - void setScanResponseData(BLEAdvertisingData& scanResponseData); + virtual void setAdvertisingData(BLEAdvertisingData& advertisingData); + virtual void setScanResponseData(BLEAdvertisingData& scanResponseData); - void setDeviceName(const char* deviceName); - void setAppearance(uint16_t appearance); + virtual void setDeviceName(const char* deviceName); + virtual void setAppearance(uint16_t appearance); - void addService(BLEService& service); + virtual void addService(BLEService& service); - int advertise(); - void stopAdvertise(); + virtual int advertise(); + virtual void stopAdvertise(); - int scan(bool withDuplicates = false); - int scanForName(String name, bool withDuplicates = false); - int scanForUuid(String uuid, bool withDuplicates = false); - int scanForAddress(String address, bool withDuplicates = false); - void stopScan(); + virtual int scan(bool withDuplicates = false); + virtual int scanForName(String name, bool withDuplicates = false); + virtual int scanForUuid(String uuid, bool withDuplicates = false); + virtual int scanForAddress(String address, bool withDuplicates = false); + virtual void stopScan(); - BLEDevice central(); - BLEDevice available(); + virtual BLEDevice central(); + virtual BLEDevice available(); - void setEventHandler(BLEDeviceEvent event, BLEDeviceEventHandler eventHandler); + virtual void setEventHandler(BLEDeviceEvent event, BLEDeviceEventHandler eventHandler); - void setAdvertisingInterval(uint16_t advertisingInterval); - void setConnectionInterval(uint16_t minimumConnectionInterval, uint16_t maximumConnectionInterval); - void setConnectable(bool connectable); + virtual void setAdvertisingInterval(uint16_t advertisingInterval); + virtual void setConnectionInterval(uint16_t minimumConnectionInterval, uint16_t maximumConnectionInterval); + virtual void setConnectable(bool connectable); - void setTimeout(unsigned long timeout); + virtual void setTimeout(unsigned long timeout); - void debug(Stream& stream); - void noDebug(); + virtual void debug(Stream& stream); + virtual void noDebug(); protected: - BLEAdvertisingData& getAdvertisingData(); - BLEAdvertisingData& getScanResponseData(); + virtual BLEAdvertisingData& getAdvertisingData(); + virtual BLEAdvertisingData& getScanResponseData(); private: BLEAdvertisingData _advertisingData; diff --git a/src/utility/ATT.h b/src/utility/ATT.h index b5df05d3..ea71d592 100644 --- a/src/utility/ATT.h +++ b/src/utility/ATT.h @@ -41,73 +41,73 @@ class ATTClass { ATTClass(); virtual ~ATTClass(); - void setMaxMtu(uint16_t maxMtu); - void setTimeout(unsigned long timeout); + virtual void setMaxMtu(uint16_t maxMtu); + virtual void setTimeout(unsigned long timeout); - bool connect(uint8_t peerBdaddrType, uint8_t peerBdaddr[6]); - bool disconnect(uint8_t peerBdaddrType, uint8_t peerBdaddr[6]); - bool discoverAttributes(uint8_t peerBdaddrType, uint8_t peerBdaddr[6], const char* serviceUuidFilter); + virtual bool connect(uint8_t peerBdaddrType, uint8_t peerBdaddr[6]); + virtual bool disconnect(uint8_t peerBdaddrType, uint8_t peerBdaddr[6]); + virtual bool discoverAttributes(uint8_t peerBdaddrType, uint8_t peerBdaddr[6], const char* serviceUuidFilter); - void addConnection(uint16_t handle, uint8_t role, uint8_t peerBdaddrType, + virtual void addConnection(uint16_t handle, uint8_t role, uint8_t peerBdaddrType, uint8_t peerBdaddr[6], uint16_t interval, uint16_t latency, uint16_t supervisionTimeout, uint8_t masterClockAccuracy); - void handleData(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); + virtual void handleData(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); - void removeConnection(uint16_t handle, uint8_t reason); + virtual void removeConnection(uint16_t handle, uint8_t reason); - uint16_t connectionHandle(uint8_t addressType, const uint8_t address[6]) const; - BLERemoteDevice* device(uint8_t addressType, const uint8_t address[6]) const; - bool connected() const; - bool connected(uint8_t addressType, const uint8_t address[6]) const; - bool connected(uint16_t handle) const; - uint16_t mtu(uint16_t handle) const; + virtual uint16_t connectionHandle(uint8_t addressType, const uint8_t address[6]) const; + virtual BLERemoteDevice* device(uint8_t addressType, const uint8_t address[6]) const; + virtual bool connected() const; + virtual bool connected(uint8_t addressType, const uint8_t address[6]) const; + virtual bool connected(uint16_t handle) const; + virtual uint16_t mtu(uint16_t handle) const; - bool disconnect(); + virtual bool disconnect(); - BLEDevice central(); + virtual BLEDevice central(); - bool handleNotify(uint16_t handle, const uint8_t* value, int length); - bool handleInd(uint16_t handle, const uint8_t* value, int length); + virtual bool handleNotify(uint16_t handle, const uint8_t* value, int length); + virtual bool handleInd(uint16_t handle, const uint8_t* value, int length); - void setEventHandler(BLEDeviceEvent event, BLEDeviceEventHandler eventHandler); + virtual void setEventHandler(BLEDeviceEvent event, BLEDeviceEventHandler eventHandler); - int readReq(uint16_t connectionHandle, uint16_t handle, uint8_t responseBuffer[]); - int writeReq(uint16_t connectionHandle, uint16_t handle, const uint8_t* data, uint8_t dataLen, uint8_t responseBuffer[]); - void writeCmd(uint16_t connectionHandle, uint16_t handle, const uint8_t* data, uint8_t dataLen); + virtual int readReq(uint16_t connectionHandle, uint16_t handle, uint8_t responseBuffer[]); + virtual int writeReq(uint16_t connectionHandle, uint16_t handle, const uint8_t* data, uint8_t dataLen, uint8_t responseBuffer[]); + virtual void writeCmd(uint16_t connectionHandle, uint16_t handle, const uint8_t* data, uint8_t dataLen); private: - void error(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); - void mtuReq(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); - int mtuReq(uint16_t connectionHandle, uint16_t mtu, uint8_t responseBuffer[]); - void mtuResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); - void findInfoReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[]); - int findInfoReq(uint16_t connectionHandle, uint16_t startHandle, uint16_t endHandle, uint8_t responseBuffer[]); - void findInfoResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); - void findByTypeReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[]); - void readByTypeReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[]); - int readByTypeReq(uint16_t connectionHandle, uint16_t startHandle, uint16_t endHandle, uint16_t type, uint8_t responseBuffer[]); - void readByTypeResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); - void readOrReadBlobReq(uint16_t connectionHandle, uint16_t mtu, uint8_t opcode, uint8_t dlen, uint8_t data[]); - void readResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); - void readByGroupReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[]); - int readByGroupReq(uint16_t connectionHandle, uint16_t startHandle, uint16_t endHandle, uint16_t uuid, uint8_t responseBuffer[]); - void readByGroupResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); - void writeReqOrCmd(uint16_t connectionHandle, uint16_t mtu, uint8_t op, uint8_t dlen, uint8_t data[]); - void writeResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); - void prepWriteReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[]); - void execWriteReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[]); - void handleNotifyOrInd(uint16_t connectionHandle, uint8_t opcode, uint8_t dlen, uint8_t data[]); - void handleCnf(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); - void sendError(uint16_t connectionHandle, uint8_t opcode, uint16_t handle, uint8_t code); - - bool exchangeMtu(uint16_t connectionHandle); - bool discoverServices(uint16_t connectionHandle, BLERemoteDevice* device, const char* serviceUuidFilter); - bool discoverCharacteristics(uint16_t connectionHandle, BLERemoteDevice* device); - bool discoverDescriptors(uint16_t connectionHandle, BLERemoteDevice* device); - - int sendReq(uint16_t connectionHandle, void* requestBuffer, int requestLength, uint8_t responseBuffer[]); + virtual void error(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); + virtual void mtuReq(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); + virtual int mtuReq(uint16_t connectionHandle, uint16_t mtu, uint8_t responseBuffer[]); + virtual void mtuResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); + virtual void findInfoReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[]); + virtual int findInfoReq(uint16_t connectionHandle, uint16_t startHandle, uint16_t endHandle, uint8_t responseBuffer[]); + virtual void findInfoResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); + virtual void findByTypeReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[]); + virtual void readByTypeReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[]); + virtual int readByTypeReq(uint16_t connectionHandle, uint16_t startHandle, uint16_t endHandle, uint16_t type, uint8_t responseBuffer[]); + virtual void readByTypeResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); + virtual void readOrReadBlobReq(uint16_t connectionHandle, uint16_t mtu, uint8_t opcode, uint8_t dlen, uint8_t data[]); + virtual void readResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); + virtual void readByGroupReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[]); + virtual int readByGroupReq(uint16_t connectionHandle, uint16_t startHandle, uint16_t endHandle, uint16_t uuid, uint8_t responseBuffer[]); + virtual void readByGroupResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); + virtual void writeReqOrCmd(uint16_t connectionHandle, uint16_t mtu, uint8_t op, uint8_t dlen, uint8_t data[]); + virtual void writeResp(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); + virtual void prepWriteReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[]); + virtual void execWriteReq(uint16_t connectionHandle, uint16_t mtu, uint8_t dlen, uint8_t data[]); + virtual void handleNotifyOrInd(uint16_t connectionHandle, uint8_t opcode, uint8_t dlen, uint8_t data[]); + virtual void handleCnf(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); + virtual void sendError(uint16_t connectionHandle, uint8_t opcode, uint16_t handle, uint8_t code); + + virtual bool exchangeMtu(uint16_t connectionHandle); + virtual bool discoverServices(uint16_t connectionHandle, BLERemoteDevice* device, const char* serviceUuidFilter); + virtual bool discoverCharacteristics(uint16_t connectionHandle, BLERemoteDevice* device); + virtual bool discoverDescriptors(uint16_t connectionHandle, BLERemoteDevice* device); + + virtual int sendReq(uint16_t connectionHandle, void* requestBuffer, int requestLength, uint8_t responseBuffer[]); private: uint16_t _maxMtu; diff --git a/src/utility/GAP.h b/src/utility/GAP.h index 5da62528..2ea22938 100644 --- a/src/utility/GAP.h +++ b/src/utility/GAP.h @@ -29,30 +29,30 @@ class GAPClass { GAPClass(); virtual ~GAPClass(); - bool advertising(); - int advertise(uint8_t* advData, uint8_t advDataLength, uint8_t* scanData, uint8_t scanDataLength); - void stopAdvertise(); + virtual bool advertising(); + virtual int advertise(uint8_t* advData, uint8_t advDataLength, uint8_t* scanData, uint8_t scanDataLength); + virtual void stopAdvertise(); - int scan(bool withDuplicates); - int scanForName(String name, bool withDuplicates); - int scanForUuid(String uuid, bool withDuplicates); - int scanForAddress(String address, bool withDuplicates); - void stopScan(); - BLEDevice available(); + virtual int scan(bool withDuplicates); + virtual int scanForName(String name, bool withDuplicates); + virtual int scanForUuid(String uuid, bool withDuplicates); + virtual int scanForAddress(String address, bool withDuplicates); + virtual void stopScan(); + virtual BLEDevice available(); - void setAdvertisingInterval(uint16_t advertisingInterval); - void setConnectable(bool connectable); + virtual void setAdvertisingInterval(uint16_t advertisingInterval); + virtual void setConnectable(bool connectable); - void setEventHandler(BLEDeviceEvent event, BLEDeviceEventHandler eventHandler); + virtual void setEventHandler(BLEDeviceEvent event, BLEDeviceEventHandler eventHandler); protected: friend class HCIClass; - void handleLeAdvertisingReport(uint8_t type, uint8_t addressType, uint8_t address[6], + virtual void handleLeAdvertisingReport(uint8_t type, uint8_t addressType, uint8_t address[6], uint8_t eirLength, uint8_t eirData[], int8_t rssi); private: - bool matchesScanFilter(const BLEDevice& device); + virtual bool matchesScanFilter(const BLEDevice& device); private: bool _advertising; diff --git a/src/utility/GATT.h b/src/utility/GATT.h index e2195a8f..fd916709 100644 --- a/src/utility/GATT.h +++ b/src/utility/GATT.h @@ -33,29 +33,29 @@ class GATTClass { GATTClass(); virtual ~GATTClass(); - void begin(); - void end(); + virtual void begin(); + virtual void end(); - void setDeviceName(const char* deviceName); - void setAppearance(uint16_t appearance); + virtual void setDeviceName(const char* deviceName); + virtual void setAppearance(uint16_t appearance); - void addService(BLEService& service); + virtual void addService(BLEService& service); protected: friend class ATTClass; - unsigned int attributeCount() const; - BLELocalAttribute* attribute(unsigned int index) const; + virtual unsigned int attributeCount() const; + virtual BLELocalAttribute* attribute(unsigned int index) const; protected: friend class BLELocalCharacteristic; - uint16_t serviceUuidForCharacteristic(BLELocalCharacteristic* characteristic) const; + virtual uint16_t serviceUuidForCharacteristic(BLELocalCharacteristic* characteristic) const; private: - void addService(BLELocalService* service); + virtual void addService(BLELocalService* service); - void clearAttributes(); + virtual void clearAttributes(); private: BLELinkedList _attributes; diff --git a/src/utility/HCI.h b/src/utility/HCI.h index 37e4d803..6d6b69ee 100644 --- a/src/utility/HCI.h +++ b/src/utility/HCI.h @@ -27,58 +27,58 @@ class HCIClass { HCIClass(); virtual ~HCIClass(); - int begin(); - void end(); + virtual int begin(); + virtual void end(); - void poll(); - void poll(unsigned long timeout); + virtual void poll(); + virtual void poll(unsigned long timeout); - int reset(); - int readLocalVersion(uint8_t& hciVer, uint16_t& hciRev, uint8_t& lmpVer, + virtual int reset(); + virtual int readLocalVersion(uint8_t& hciVer, uint16_t& hciRev, uint8_t& lmpVer, uint16_t& manufacturer, uint16_t& lmpSubVer); - int readBdAddr(uint8_t addr[6]); + virtual int readBdAddr(uint8_t addr[6]); - int readRssi(uint16_t handle); + virtual int readRssi(uint16_t handle); - int setEventMask(uint64_t eventMask); + virtual int setEventMask(uint64_t eventMask); - int readLeBufferSize(uint16_t& pktLen, uint8_t& maxPkt); - int leSetRandomAddress(uint8_t addr[6]); - int leSetAdvertisingParameters(uint16_t minInterval, uint16_t maxInterval, + virtual int readLeBufferSize(uint16_t& pktLen, uint8_t& maxPkt); + virtual int leSetRandomAddress(uint8_t addr[6]); + virtual int leSetAdvertisingParameters(uint16_t minInterval, uint16_t maxInterval, uint8_t advType, uint8_t ownBdaddrType, uint8_t directBdaddrType, uint8_t directBdaddr[6], uint8_t chanMap, uint8_t filter); - int leSetAdvertisingData(uint8_t length, uint8_t data[]); - int leSetScanResponseData(uint8_t length, uint8_t data[]); - int leSetAdvertiseEnable(uint8_t enable); - int leSetScanParameters(uint8_t type, uint16_t interval, uint16_t window, + virtual int leSetAdvertisingData(uint8_t length, uint8_t data[]); + virtual int leSetScanResponseData(uint8_t length, uint8_t data[]); + virtual int leSetAdvertiseEnable(uint8_t enable); + virtual int leSetScanParameters(uint8_t type, uint16_t interval, uint16_t window, uint8_t ownBdaddrType, uint8_t filter); - int leSetScanEnable(uint8_t enabled, uint8_t duplicates); - int leCreateConn(uint16_t interval, uint16_t window, uint8_t initiatorFilter, + virtual int leSetScanEnable(uint8_t enabled, uint8_t duplicates); + virtual int leCreateConn(uint16_t interval, uint16_t window, uint8_t initiatorFilter, uint8_t peerBdaddrType, uint8_t peerBdaddr[6], uint8_t ownBdaddrType, uint16_t minInterval, uint16_t maxInterval, uint16_t latency, uint16_t supervisionTimeout, uint16_t minCeLength, uint16_t maxCeLength); - int leConnUpdate(uint16_t handle, uint16_t minInterval, uint16_t maxInterval, + virtual int leConnUpdate(uint16_t handle, uint16_t minInterval, uint16_t maxInterval, uint16_t latency, uint16_t supervisionTimeout); - int leCancelConn(); + virtual int leCancelConn(); - int sendAclPkt(uint16_t handle, uint8_t cid, uint8_t plen, void* data); + virtual int sendAclPkt(uint16_t handle, uint8_t cid, uint8_t plen, void* data); - int disconnect(uint16_t handle); + virtual int disconnect(uint16_t handle); - void debug(Stream& stream); - void noDebug(); + virtual void debug(Stream& stream); + virtual void noDebug(); private: - int sendCommand(uint16_t opcode, uint8_t plen = 0, void* parameters = NULL); + virtual int sendCommand(uint16_t opcode, uint8_t plen = 0, void* parameters = NULL); - void handleAclDataPkt(uint8_t plen, uint8_t pdata[]); - void handleNumCompPkts(uint16_t handle, uint16_t numPkts); - void handleEventPkt(uint8_t plen, uint8_t pdata[]); + virtual void handleAclDataPkt(uint8_t plen, uint8_t pdata[]); + virtual void handleNumCompPkts(uint16_t handle, uint16_t numPkts); + virtual void handleEventPkt(uint8_t plen, uint8_t pdata[]); - void dumpPkt(const char* prefix, uint8_t plen, uint8_t pdata[]); + virtual void dumpPkt(const char* prefix, uint8_t plen, uint8_t pdata[]); Stream* _debug; diff --git a/src/utility/L2CAPSignaling.h b/src/utility/L2CAPSignaling.h index 20c174e9..0bd5fe33 100644 --- a/src/utility/L2CAPSignaling.h +++ b/src/utility/L2CAPSignaling.h @@ -29,20 +29,20 @@ class L2CAPSignalingClass { L2CAPSignalingClass(); virtual ~L2CAPSignalingClass(); - void addConnection(uint16_t handle, uint8_t role, uint8_t peerBdaddrType, + virtual void addConnection(uint16_t handle, uint8_t role, uint8_t peerBdaddrType, uint8_t peerBdaddr[6], uint16_t interval, uint16_t latency, uint16_t supervisionTimeout, uint8_t masterClockAccuracy); - void handleData(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); + virtual void handleData(uint16_t connectionHandle, uint8_t dlen, uint8_t data[]); - void removeConnection(uint8_t handle, uint16_t reason); + virtual void removeConnection(uint8_t handle, uint16_t reason); - void setConnectionInterval(uint16_t minInterval, uint16_t maxInterval); + virtual void setConnectionInterval(uint16_t minInterval, uint16_t maxInterval); private: - void connectionParameterUpdateRequest(uint16_t handle, uint8_t identifier, uint8_t dlen, uint8_t data[]); - void connectionParameterUpdateResponse(uint16_t handle, uint8_t identifier, uint8_t dlen, uint8_t data[]); + virtual void connectionParameterUpdateRequest(uint16_t handle, uint8_t identifier, uint8_t dlen, uint8_t data[]); + virtual void connectionParameterUpdateResponse(uint16_t handle, uint8_t identifier, uint8_t dlen, uint8_t data[]); private: uint16_t _minInterval; From 3cc745f5c4f0a12a4c35eea3d6a61c69c100f5f8 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Mon, 12 Oct 2020 11:51:24 +0200 Subject: [PATCH 11/13] Prevent singleton definition when fake objects are used This change allows to implement and use fake objects during unit testing Classes to be mocked will be extended by fake classes. Each fake class will define a fake singleton instance --- extras/test/CMakeLists.txt | 94 +++++++++++++++++++ .../test_discovered_device.cpp | 52 ++++++++++ src/local/BLELocalDevice.cpp | 2 + src/utility/ATT.cpp | 2 + src/utility/GAP.cpp | 2 + src/utility/GATT.cpp | 2 + src/utility/HCI.cpp | 2 + src/utility/L2CAPSignaling.cpp | 2 + 8 files changed, 158 insertions(+) create mode 100644 extras/test/CMakeLists.txt create mode 100644 extras/test/src/test_discovered_device/test_discovered_device.cpp diff --git a/extras/test/CMakeLists.txt b/extras/test/CMakeLists.txt new file mode 100644 index 00000000..88ac3aa0 --- /dev/null +++ b/extras/test/CMakeLists.txt @@ -0,0 +1,94 @@ +########################################################################## + +set(CMAKE_VERBOSE_MAKEFILE ON) +cmake_minimum_required(VERSION 2.8) + +########################################################################## + +project(testArduinoBLE) + +########################################################################## + +include_directories(include) +include_directories(include/util) +include_directories(../../src) +include_directories(../../src/local) +include_directories(../../src/remote) +include_directories(../../src/utility) +include_directories(external/catch/v2.12.1/include) +include_directories(external/fakeit/v2.0.5/include) + +########################################################################## + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + +########################################################################## + +set(TEST_TARGET_UUID_SRCS + src/Arduino.cpp + src/util/itoa.c + src/util/TestUtil.cpp + src/test_main.cpp + src/test_uuid/test_uuid.cpp + ../../src/utility/BLEUuid.cpp + src/util/String.cpp + src/util/Common.cpp +) + +set(TEST_TARGET_DISC_DEVICE_SRCS + src/Arduino.cpp + src/util/itoa.c + src/util/TestUtil.cpp + src/util/String.cpp + src/util/Common.cpp + src/test_main.cpp + src/test_discovered_device/test_discovered_device.cpp + ../../src/utility/BLEUuid.cpp + ../../src/BLEDevice.cpp + ../../src/BLECharacteristic.cpp + ../../src/BLEDescriptor.cpp + ../../src/BLEService.cpp + ../../src/BLEAdvertisingData.cpp + ../../src/utility/ATT.cpp + #../../src/utility/GAP.cpp + ../../src/utility/HCI.cpp + ../../src/utility/GATT.cpp + ../../src/utility/L2CAPSignaling.cpp + ../../src/local/BLELocalAttribute.cpp + ../../src/local/BLELocalCharacteristic.cpp + ../../src/local/BLELocalDescriptor.cpp + ../../src/local/BLELocalDevice.cpp + ../../src/local/BLELocalService.cpp + ../../src/remote/BLERemoteAttribute.cpp + ../../src/remote/BLERemoteAdvertisingData.cpp + ../../src/remote/BLERemoteCharacteristic.cpp + ../../src/remote/BLERemoteDescriptor.cpp + ../../src/remote/BLERemoteDevice.cpp + ../../src/remote/BLERemoteService.cpp + ../../src/BLEStringCharacteristic.cpp + ../../src/BLETypedCharacteristics.cpp + # Fake classes + src/util/HCIFakeTransport.cpp + src/test_discovered_device/FakeGAP.cpp +) + +########################################################################## + +set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} "--coverage") +set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "--coverage") + +########################################################################## + +add_executable(TEST_TARGET_UUID ${TEST_TARGET_UUID_SRCS}) +add_executable(TEST_TARGET_DISC_DEVICE ${TEST_TARGET_DISC_DEVICE_SRCS}) + +########################################################################## + +# Build unit tests as a post build step +add_custom_command(TARGET TEST_TARGET_UUID POST_BUILD + COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/TEST_TARGET_UUID +) +add_custom_command(TARGET TEST_TARGET_DISC_DEVICE POST_BUILD + COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/TEST_TARGET_DISC_DEVICE +) diff --git a/extras/test/src/test_discovered_device/test_discovered_device.cpp b/extras/test/src/test_discovered_device/test_discovered_device.cpp new file mode 100644 index 00000000..9227b920 --- /dev/null +++ b/extras/test/src/test_discovered_device/test_discovered_device.cpp @@ -0,0 +1,52 @@ +/* + This file is part of the ArduinoBLE library. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +#define private public +#define protected public +#include "BLEDevice.h" + +SCENARIO("BLE discovered device test", "[ArduinoBLE::BLEDevice]") +{ + + WHEN("Retrieve local name from advertisement packet") + { + // Mocking advertisement packet + uint8_t advType = 0x03; + uint8_t eirLength = 6; + uint8_t eirData[] = {0x05, 0x09, 't', 'e', 's', 't'}; + uint8_t rssi = 0; + + // Expected results + String goldenName = "test"; + + // Simulate device discovery + BLEDevice device = BLEDevice(); + device.setAdvertisingData(eirLength, eirData, rssi); + + bool hasName = device.hasLocalName(); + REQUIRE(hasName); + + String name = device.localName(); + REQUIRE(goldenName == name); + + } + +} diff --git a/src/local/BLELocalDevice.cpp b/src/local/BLELocalDevice.cpp index 872a82ca..27a23887 100644 --- a/src/local/BLELocalDevice.cpp +++ b/src/local/BLELocalDevice.cpp @@ -343,5 +343,7 @@ void BLELocalDevice::noDebug() HCI.noDebug(); } +#if !defined(FAKE_BLELOCALDEVICE) BLELocalDevice BLEObj; BLELocalDevice& BLE = BLEObj; +#endif diff --git a/src/utility/ATT.cpp b/src/utility/ATT.cpp index e6443b59..28c8d743 100644 --- a/src/utility/ATT.cpp +++ b/src/utility/ATT.cpp @@ -1687,5 +1687,7 @@ void ATTClass::writeCmd(uint16_t connectionHandle, uint16_t handle, const uint8_ sendReq(connectionHandle, &writeReq, 3 + dataLen, NULL); } +#if !defined(FAKE_ATT) ATTClass ATTObj; ATTClass& ATT = ATTObj; +#endif diff --git a/src/utility/GAP.cpp b/src/utility/GAP.cpp index 654cef7b..f3ee32fa 100644 --- a/src/utility/GAP.cpp +++ b/src/utility/GAP.cpp @@ -258,5 +258,7 @@ bool GAPClass::matchesScanFilter(const BLEDevice& device) return true; } +#if !defined(FAKE_GAP) GAPClass GAPObj; GAPClass& GAP = GAPObj; +#endif diff --git a/src/utility/GATT.cpp b/src/utility/GATT.cpp index 21df18fd..373213b9 100644 --- a/src/utility/GATT.cpp +++ b/src/utility/GATT.cpp @@ -172,5 +172,7 @@ void GATTClass::clearAttributes() _attributes.clear(); } +#if !defined(FAKE_GATT) GATTClass GATTObj; GATTClass& GATT = GATTObj; +#endif diff --git a/src/utility/HCI.cpp b/src/utility/HCI.cpp index 6f602ea1..233dd1a5 100644 --- a/src/utility/HCI.cpp +++ b/src/utility/HCI.cpp @@ -686,5 +686,7 @@ void HCIClass::dumpPkt(const char* prefix, uint8_t plen, uint8_t pdata[]) } } +#if !defined(FAKE_HCI) HCIClass HCIObj; HCIClass& HCI = HCIObj; +#endif diff --git a/src/utility/L2CAPSignaling.cpp b/src/utility/L2CAPSignaling.cpp index 4135099c..3e1d7b7c 100644 --- a/src/utility/L2CAPSignaling.cpp +++ b/src/utility/L2CAPSignaling.cpp @@ -146,5 +146,7 @@ void L2CAPSignalingClass::connectionParameterUpdateResponse(uint16_t /*handle*/, { } +#if !defined(FAKE_L2CAP) L2CAPSignalingClass L2CAPSignalingObj; L2CAPSignalingClass& L2CAPSignaling = L2CAPSignalingObj; +#endif From b586d0d69b21599330f4b0c840f4016bc4c4299a Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Fri, 31 Jul 2020 17:46:47 +0200 Subject: [PATCH 12/13] CI - Integrate CI unit testing Each class under test will have a dedicated test file. Each test file is placed in a dedicated folder in extras/test/src . Such dedicated folder will also contain the mock (Fake) objects needed by the test. Finally, an executable file will be generated for each test. --- extras/test/.gitignore | 1 + extras/test/CMakeLists.txt | 65 +- .../external/catch/v2.12.1/include/catch.hpp | 17698 ++++++++++++++++ extras/test/include/Arduino.h | 45 + .../include/test_discovered_device/FakeGAP.h | 33 + extras/test/include/util/Common.h | 167 + extras/test/include/util/HCIFakeTransport.h | 19 + extras/test/include/util/Stream.h | 40 + extras/test/include/util/String.h | 248 + extras/test/include/util/TestUtil.h | 3 + extras/test/include/util/itoa.h | 37 + extras/test/src/Arduino.cpp | 44 + .../src/test_discovered_device/FakeGAP.cpp | 31 + .../test_discovered_device.cpp | 7 +- extras/test/src/test_main.cpp | 21 + extras/test/src/test_uuid/test_uuid.cpp | 52 + extras/test/src/util/Common.cpp | 34 + extras/test/src/util/HCIFakeTransport.cpp | 23 + extras/test/src/util/String.cpp | 755 + extras/test/src/util/TestUtil.cpp | 3 + extras/test/src/util/itoa.c | 126 + 21 files changed, 19425 insertions(+), 27 deletions(-) create mode 100644 extras/test/.gitignore create mode 100644 extras/test/external/catch/v2.12.1/include/catch.hpp create mode 100644 extras/test/include/Arduino.h create mode 100644 extras/test/include/test_discovered_device/FakeGAP.h create mode 100644 extras/test/include/util/Common.h create mode 100644 extras/test/include/util/HCIFakeTransport.h create mode 100644 extras/test/include/util/Stream.h create mode 100644 extras/test/include/util/String.h create mode 100644 extras/test/include/util/TestUtil.h create mode 100644 extras/test/include/util/itoa.h create mode 100644 extras/test/src/Arduino.cpp create mode 100644 extras/test/src/test_discovered_device/FakeGAP.cpp create mode 100644 extras/test/src/test_main.cpp create mode 100644 extras/test/src/test_uuid/test_uuid.cpp create mode 100644 extras/test/src/util/Common.cpp create mode 100644 extras/test/src/util/HCIFakeTransport.cpp create mode 100644 extras/test/src/util/String.cpp create mode 100644 extras/test/src/util/TestUtil.cpp create mode 100644 extras/test/src/util/itoa.c diff --git a/extras/test/.gitignore b/extras/test/.gitignore new file mode 100644 index 00000000..c795b054 --- /dev/null +++ b/extras/test/.gitignore @@ -0,0 +1 @@ +build \ No newline at end of file diff --git a/extras/test/CMakeLists.txt b/extras/test/CMakeLists.txt index 88ac3aa0..436fcf22 100644 --- a/extras/test/CMakeLists.txt +++ b/extras/test/CMakeLists.txt @@ -9,41 +9,21 @@ project(testArduinoBLE) ########################################################################## -include_directories(include) -include_directories(include/util) -include_directories(../../src) -include_directories(../../src/local) -include_directories(../../src/remote) -include_directories(../../src/utility) -include_directories(external/catch/v2.12.1/include) -include_directories(external/fakeit/v2.0.5/include) - -########################################################################## - set(CMAKE_CXX_STANDARD 11) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) ########################################################################## -set(TEST_TARGET_UUID_SRCS +set(COMMON_TEST_SRCS + src/test_main.cpp src/Arduino.cpp src/util/itoa.c src/util/TestUtil.cpp - src/test_main.cpp - src/test_uuid/test_uuid.cpp - ../../src/utility/BLEUuid.cpp src/util/String.cpp src/util/Common.cpp ) -set(TEST_TARGET_DISC_DEVICE_SRCS - src/Arduino.cpp - src/util/itoa.c - src/util/TestUtil.cpp - src/util/String.cpp - src/util/Common.cpp - src/test_main.cpp - src/test_discovered_device/test_discovered_device.cpp +set(DUT_SRCS ../../src/utility/BLEUuid.cpp ../../src/BLEDevice.cpp ../../src/BLECharacteristic.cpp @@ -51,7 +31,7 @@ set(TEST_TARGET_DISC_DEVICE_SRCS ../../src/BLEService.cpp ../../src/BLEAdvertisingData.cpp ../../src/utility/ATT.cpp - #../../src/utility/GAP.cpp + ../../src/utility/GAP.cpp ../../src/utility/HCI.cpp ../../src/utility/GATT.cpp ../../src/utility/L2CAPSignaling.cpp @@ -61,14 +41,30 @@ set(TEST_TARGET_DISC_DEVICE_SRCS ../../src/local/BLELocalDevice.cpp ../../src/local/BLELocalService.cpp ../../src/remote/BLERemoteAttribute.cpp - ../../src/remote/BLERemoteAdvertisingData.cpp ../../src/remote/BLERemoteCharacteristic.cpp ../../src/remote/BLERemoteDescriptor.cpp ../../src/remote/BLERemoteDevice.cpp ../../src/remote/BLERemoteService.cpp ../../src/BLEStringCharacteristic.cpp ../../src/BLETypedCharacteristics.cpp - # Fake classes +) + +set(TEST_TARGET_UUID_SRCS + # Test files + ${COMMON_TEST_SRCS} + src/test_uuid/test_uuid.cpp + # DUT files + #${DUT_SRCS} + ../../src/utility/BLEUuid.cpp +) + +set(TEST_TARGET_DISC_DEVICE_SRCS + # Test files + ${COMMON_TEST_SRCS} + src/test_discovered_device/test_discovered_device.cpp + # DUT files + ${DUT_SRCS} + # Fake classes files src/util/HCIFakeTransport.cpp src/test_discovered_device/FakeGAP.cpp ) @@ -85,6 +81,23 @@ add_executable(TEST_TARGET_DISC_DEVICE ${TEST_TARGET_DISC_DEVICE_SRCS}) ########################################################################## +include_directories(include) +include_directories(include/util) +include_directories(../../src) +include_directories(../../src/local) +include_directories(../../src/remote) +include_directories(../../src/utility) +include_directories(external/catch/v2.12.1/include) +include_directories(external/fakeit/v2.0.5/include) + +target_include_directories(TEST_TARGET_DISC_DEVICE PUBLIC include/test_discovered_device) + +########################################################################## + +target_compile_definitions(TEST_TARGET_DISC_DEVICE PUBLIC FAKE_GAP) + +########################################################################## + # Build unit tests as a post build step add_custom_command(TARGET TEST_TARGET_UUID POST_BUILD COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/TEST_TARGET_UUID diff --git a/extras/test/external/catch/v2.12.1/include/catch.hpp b/extras/test/external/catch/v2.12.1/include/catch.hpp new file mode 100644 index 00000000..1d2c9bb6 --- /dev/null +++ b/extras/test/external/catch/v2.12.1/include/catch.hpp @@ -0,0 +1,17698 @@ +/* + * Catch v2.12.1 + * Generated: 2020-04-21 19:29:20.964532 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +// start catch.hpp + + +#define CATCH_VERSION_MAJOR 2 +#define CATCH_VERSION_MINOR 12 +#define CATCH_VERSION_PATCH 1 + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// start catch_suppress_warnings.h + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ + // Because REQUIREs trigger GCC's -Wparentheses, and because still + // supported version of g++ have only buggy support for _Pragmas, + // Wparentheses have to be suppressed globally. +# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details + +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic ignored "-Wpadded" +#endif +// end catch_suppress_warnings.h +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +# define CATCH_CONFIG_ALL_PARTS +#endif + +// In the impl file, we want to have access to all parts of the headers +// Can also be used to sanely support PCHs +#if defined(CATCH_CONFIG_ALL_PARTS) +# define CATCH_CONFIG_EXTERNAL_INTERFACES +# if defined(CATCH_CONFIG_DISABLE_MATCHERS) +# undef CATCH_CONFIG_DISABLE_MATCHERS +# endif +# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +# endif +#endif + +#if !defined(CATCH_CONFIG_IMPL_ONLY) +// start catch_platform.h + +#ifdef __APPLE__ +# include +# if TARGET_OS_OSX == 1 +# define CATCH_PLATFORM_MAC +# elif TARGET_OS_IPHONE == 1 +# define CATCH_PLATFORM_IPHONE +# endif + +#elif defined(linux) || defined(__linux) || defined(__linux__) +# define CATCH_PLATFORM_LINUX + +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) +# define CATCH_PLATFORM_WINDOWS +#endif + +// end catch_platform.h + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// start catch_user_interfaces.h + +namespace Catch { + unsigned int rngSeed(); +} + +// end catch_user_interfaces.h +// start catch_tag_alias_autoregistrar.h + +// start catch_common.h + +// start catch_compiler_capabilities.h + +// Detect a number of compiler features - by compiler +// The following features are defined: +// +// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? +// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? +// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? +// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +#ifdef __cplusplus + +# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) +# define CATCH_CPP14_OR_GREATER +# endif + +# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# define CATCH_CPP17_OR_GREATER +# endif + +#endif + +#if defined(__cpp_lib_uncaught_exceptions) +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +// We have to avoid both ICC and Clang, because they try to mask themselves +// as gcc, and we want only GCC in this block +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) + +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) + +#endif + +#if defined(__clang__) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) + +// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug +// which results in calls to destructors being emitted for each temporary, +// without a matching initialization. In practice, this can result in something +// like `std::string::~string` being called on an uninitialized value. +// +// For example, this code will likely segfault under IBM XL: +// ``` +// REQUIRE(std::string("12") + "34" == "1234") +// ``` +// +// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. +# if !defined(__ibmxl__) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg) */ +# endif + +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") + +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) + +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Assume that non-Windows platforms support posix signals by default +#if !defined(CATCH_PLATFORM_WINDOWS) + #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS +#endif + +//////////////////////////////////////////////////////////////////////////////// +// We know some environments not to support full POSIX signals +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) + #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +#endif + +#ifdef __OS400__ +# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +# define CATCH_CONFIG_COLOUR_NONE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Android somehow still does not support std::to_string +#if defined(__ANDROID__) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Not all Windows environments support SEH properly +#if defined(__MINGW32__) +# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH +#endif + +//////////////////////////////////////////////////////////////////////////////// +// PS4 +#if defined(__ORBIS__) +# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Cygwin +#ifdef __CYGWIN__ + +// Required for some versions of Cygwin to declare gettimeofday +// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin +# define _BSD_SOURCE +// some versions of cygwin (most) do not support std::to_string. Use the libstd check. +// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 +# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ + && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) + +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING + +# endif +#endif // __CYGWIN__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#if defined(_MSC_VER) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) + +# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +# endif + +// Universal Windows platform does not support SEH +// Or console colours (or console at all...) +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +# define CATCH_CONFIG_COLOUR_NONE +# else +# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH +# endif + +// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ +// _MSVC_TRADITIONAL == 0 means new conformant preprocessor +// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor +# if !defined(__clang__) // Handle Clang masquerading for msvc +# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) +# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +# endif // MSVC_TRADITIONAL +# endif // __clang__ + +#endif // _MSC_VER + +#if defined(_REENTRANT) || defined(_MSC_VER) +// Enable async processing, as -pthread is specified or no additional linking is required +# define CATCH_INTERNAL_CONFIG_USE_ASYNC +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// Check if we are compiled with -fno-exceptions or equivalent +#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) +# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED +#endif + +//////////////////////////////////////////////////////////////////////////////// +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ + +//////////////////////////////////////////////////////////////////////////////// +// Embarcadero C++Build +#if defined(__BORLANDC__) + #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN +#endif + +//////////////////////////////////////////////////////////////////////////////// + +// Use of __COUNTER__ is suppressed during code analysis in +// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly +// handled by it. +// Otherwise all supported compilers support COUNTER macro, +// but user still might want to turn it off +#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) + #define CATCH_INTERNAL_CONFIG_COUNTER +#endif + +//////////////////////////////////////////////////////////////////////////////// + +// RTX is a special version of Windows that is real time. +// This means that it is detected as Windows, but does not provide +// the same set of capabilities as real Windows does. +#if defined(UNDER_RTSS) || defined(RTX64_BUILD) + #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH + #define CATCH_INTERNAL_CONFIG_NO_ASYNC + #define CATCH_CONFIG_COLOUR_NONE +#endif + +#if !defined(_GLIBCXX_USE_C99_MATH_TR1) +#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Various stdlib support checks that require __has_include +#if defined(__has_include) + // Check if string_view is available and usable + #if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW + #endif + + // Check if optional is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if byte is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_BYTE + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if variant is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # if defined(__clang__) && (__clang_major__ < 8) + // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 + // fix should be in clang 8, workaround in libstdc++ 8.2 + # include + # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # define CATCH_CONFIG_NO_CPP17_VARIANT + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__clang__) && (__clang_major__ < 8) + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +#endif // defined(__has_include) + +#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) +# define CATCH_CONFIG_COUNTER +#endif +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) +# define CATCH_CONFIG_WINDOWS_SEH +#endif +// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. +#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +# define CATCH_CONFIG_POSIX_SIGNALS +#endif +// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. +#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) +# define CATCH_CONFIG_WCHAR +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) +# define CATCH_CONFIG_CPP11_TO_STRING +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) +# define CATCH_CONFIG_CPP17_OPTIONAL +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) +# define CATCH_CONFIG_CPP17_STRING_VIEW +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) +# define CATCH_CONFIG_CPP17_VARIANT +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) +# define CATCH_CONFIG_CPP17_BYTE +#endif + +#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) +# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) +# define CATCH_CONFIG_NEW_CAPTURE +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +# define CATCH_CONFIG_DISABLE_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) +# define CATCH_CONFIG_POLYFILL_ISNAN +#endif + +#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) +# define CATCH_CONFIG_USE_ASYNC +#endif + +#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) +# define CATCH_CONFIG_ANDROID_LOGWRITE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) +# define CATCH_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Even if we do not think the compiler has that warning, we still have +// to provide a macro that can be used by the code. +#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS +#endif + +// The goal of this macro is to avoid evaluation of the arguments, but +// still have the compiler warn on problems inside... +#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) +#endif + +#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#elif defined(__clang__) && (__clang_major__ < 5) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +#define CATCH_TRY if ((true)) +#define CATCH_CATCH_ALL if ((false)) +#define CATCH_CATCH_ANON(type) if ((false)) +#else +#define CATCH_TRY try +#define CATCH_CATCH_ALL catch (...) +#define CATCH_CATCH_ANON(type) catch (type) +#endif + +#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) +#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#endif + +// end catch_compiler_capabilities.h +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#ifdef CATCH_CONFIG_COUNTER +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) +#else +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) +#endif + +#include +#include +#include + +// We need a dummy global operator<< so we can bring it into Catch namespace later +struct Catch_global_namespace_dummy {}; +std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); + +namespace Catch { + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; + + protected: + NonCopyable(); + virtual ~NonCopyable(); + }; + + struct SourceLineInfo { + + SourceLineInfo() = delete; + SourceLineInfo( char const* _file, std::size_t _line ) noexcept + : file( _file ), + line( _line ) + {} + + SourceLineInfo( SourceLineInfo const& other ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo( SourceLineInfo&& ) noexcept = default; + SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; + + bool empty() const noexcept { return file[0] == '\0'; } + bool operator == ( SourceLineInfo const& other ) const noexcept; + bool operator < ( SourceLineInfo const& other ) const noexcept; + + char const* file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // Bring in operator<< from global namespace into Catch namespace + // This is necessary because the overload of operator<< above makes + // lookup stop at namespace Catch + using ::operator<<; + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() const; + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO \ + ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) + +// end catch_common.h +namespace Catch { + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +// end catch_tag_alias_autoregistrar.h +// start catch_test_registry.h + +// start catch_interfaces_testcase.h + +#include + +namespace Catch { + + class TestSpec; + + struct ITestInvoker { + virtual void invoke () const = 0; + virtual ~ITestInvoker(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool isThrowSafe( TestCase const& testCase, IConfig const& config ); + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + +} + +// end catch_interfaces_testcase.h +// start catch_stringref.h + +#include +#include +#include +#include + +namespace Catch { + + /// A non-owning string class (similar to the forthcoming std::string_view) + /// Note that, because a StringRef may be a substring of another string, + /// it may not be null terminated. + class StringRef { + public: + using size_type = std::size_t; + using const_iterator = const char*; + + private: + static constexpr char const* const s_empty = ""; + + char const* m_start = s_empty; + size_type m_size = 0; + + public: // construction + constexpr StringRef() noexcept = default; + + StringRef( char const* rawChars ) noexcept; + + constexpr StringRef( char const* rawChars, size_type size ) noexcept + : m_start( rawChars ), + m_size( size ) + {} + + StringRef( std::string const& stdString ) noexcept + : m_start( stdString.c_str() ), + m_size( stdString.size() ) + {} + + explicit operator std::string() const { + return std::string(m_start, m_size); + } + + public: // operators + auto operator == ( StringRef const& other ) const noexcept -> bool; + auto operator != (StringRef const& other) const noexcept -> bool { + return !(*this == other); + } + + auto operator[] ( size_type index ) const noexcept -> char { + assert(index < m_size); + return m_start[index]; + } + + public: // named queries + constexpr auto empty() const noexcept -> bool { + return m_size == 0; + } + constexpr auto size() const noexcept -> size_type { + return m_size; + } + + // Returns the current start pointer. If the StringRef is not + // null-terminated, throws std::domain_exception + auto c_str() const -> char const*; + + public: // substrings and searches + // Returns a substring of [start, start + length). + // If start + length > size(), then the substring is [start, size()). + // If start > size(), then the substring is empty. + auto substr( size_type start, size_type length ) const noexcept -> StringRef; + + // Returns the current start pointer. May not be null-terminated. + auto data() const noexcept -> char const*; + + constexpr auto isNullTerminated() const noexcept -> bool { + return m_start[m_size] == '\0'; + } + + public: // iterators + constexpr const_iterator begin() const { return m_start; } + constexpr const_iterator end() const { return m_start + m_size; } + }; + + auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; + auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; + + constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + return StringRef( rawChars, size ); + } +} // namespace Catch + +constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { + return Catch::StringRef( rawChars, size ); +} + +// end catch_stringref.h +// start catch_preprocessor.hpp + + +#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ +#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) + +#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ +// MSVC needs more evaluations +#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) +#else +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) +#endif + +#define CATCH_REC_END(...) +#define CATCH_REC_OUT + +#define CATCH_EMPTY() +#define CATCH_DEFER(id) id CATCH_EMPTY() + +#define CATCH_REC_GET_END2() 0, CATCH_REC_END +#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 +#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 +#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT +#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) +#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) + +#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) + +#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) + +// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, +// and passes userdata as the first parameter to each invocation, +// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) +#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) +#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ +#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ +#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) +#else +// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) +#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) +#endif + +#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ +#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) + +#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) +#else +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) +#endif + +#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ + CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) + +#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) +#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) +#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) +#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) +#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) +#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) +#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _4, _5, _6) +#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) +#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) +#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) +#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) + +#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N + +#define INTERNAL_CATCH_TYPE_GEN\ + template struct TypeList {};\ + template\ + constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ + template class...> struct TemplateTypeList{};\ + template class...Cs>\ + constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ + template\ + struct append;\ + template\ + struct rewrap;\ + template class, typename...>\ + struct create;\ + template class, typename>\ + struct convert;\ + \ + template \ + struct append { using type = T; };\ + template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ + struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ + template< template class L1, typename...E1, typename...Rest>\ + struct append, TypeList, Rest...> { using type = L1; };\ + \ + template< template class Container, template class List, typename...elems>\ + struct rewrap, List> { using type = TypeList>; };\ + template< template class Container, template class List, class...Elems, typename...Elements>\ + struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ + \ + template