update BLE library for ESP32 env compatibility
with the last version of ESP32 arduino env it is not possible to compile on ESP32, we get "missing gatt_api.h" ERROR. So as to avoid that we need to use the last version of the nkolban library for BLE 0.4.16
This commit is contained in:
1 parent
1dd68ab078
commit
42be3fe0f2
48 files changed
+2970
-426
No files matched your search
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* BLE2904.cpp
|
||||
*
|
||||
* Created on: Dec 23, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
/*
|
||||
* See also:
|
||||
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "BLE2904.h"
|
||||
|
||||
|
||||
BLE2904::BLE2904() : BLEDescriptor(BLEUUID((uint16_t) 0x2904)) {
|
||||
m_data.m_format = 0;
|
||||
m_data.m_exponent = 0;
|
||||
m_data.m_namespace = 1; // 1 = Bluetooth SIG Assigned Numbers
|
||||
m_data.m_unit = 0;
|
||||
m_data.m_description = 0;
|
||||
setValue((uint8_t*)&m_data, sizeof(m_data));
|
||||
} // BLE2902
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the description.
|
||||
*/
|
||||
void BLE2904::setDescription(uint16_t description) {
|
||||
m_data.m_description = description;
|
||||
setValue((uint8_t*)&m_data, sizeof(m_data));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the exponent.
|
||||
*/
|
||||
void BLE2904::setExponent(int8_t exponent) {
|
||||
m_data.m_exponent = exponent;
|
||||
setValue((uint8_t*)&m_data, sizeof(m_data));
|
||||
} // setExponent
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the format.
|
||||
*/
|
||||
void BLE2904::setFormat(uint8_t format) {
|
||||
m_data.m_format = format;
|
||||
setValue((uint8_t*)&m_data, sizeof(m_data));
|
||||
} // setFormat
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the namespace.
|
||||
*/
|
||||
void BLE2904::setNamespace(uint8_t namespace_value) {
|
||||
m_data.m_namespace = namespace_value;
|
||||
setValue((uint8_t*)&m_data, sizeof(m_data));
|
||||
} // setNamespace
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the units for this value. It should be one of the encoded values defined here:
|
||||
* https://www.bluetooth.com/specifications/assigned-numbers/units
|
||||
* @param [in] uint The type of units of this characteristic as defined by assigned numbers.
|
||||
*/
|
||||
void BLE2904::setUnit(uint16_t unit) {
|
||||
m_data.m_unit = unit;
|
||||
setValue((uint8_t*)&m_data, sizeof(m_data));
|
||||
} // setUnit
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* BLE2904.h
|
||||
*
|
||||
* Created on: Dec 23, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLE2904_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLE2904_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "BLEDescriptor.h"
|
||||
|
||||
struct BLE2904_Data {
|
||||
uint8_t m_format;
|
||||
int8_t m_exponent;
|
||||
uint16_t m_unit; // See https://www.bluetooth.com/specifications/assigned-numbers/units
|
||||
uint8_t m_namespace;
|
||||
uint16_t m_description;
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* @brief Descriptor for Characteristic Presentation Format.
|
||||
*
|
||||
* This is a convenience descriptor for the Characteristic Presentation Format which has a UUID of 0x2904.
|
||||
*
|
||||
* See also:
|
||||
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
|
||||
*/
|
||||
class BLE2904: public BLEDescriptor {
|
||||
public:
|
||||
BLE2904();
|
||||
static const uint8_t FORMAT_BOOLEAN = 1;
|
||||
static const uint8_t FORMAT_UINT2 = 2;
|
||||
static const uint8_t FORMAT_UINT4 = 3;
|
||||
static const uint8_t FORMAT_UINT8 = 4;
|
||||
static const uint8_t FORMAT_UINT12 = 5;
|
||||
static const uint8_t FORMAT_UINT16 = 6;
|
||||
static const uint8_t FORMAT_UINT24 = 7;
|
||||
static const uint8_t FORMAT_UINT32 = 8;
|
||||
static const uint8_t FORMAT_UINT48 = 9;
|
||||
static const uint8_t FORMAT_UINT64 = 10;
|
||||
static const uint8_t FORMAT_UINT128 = 11;
|
||||
static const uint8_t FORMAT_SINT8 = 12;
|
||||
static const uint8_t FORMAT_SINT12 = 13;
|
||||
static const uint8_t FORMAT_SINT16 = 14;
|
||||
static const uint8_t FORMAT_SINT24 = 15;
|
||||
static const uint8_t FORMAT_SINT32 = 16;
|
||||
static const uint8_t FORMAT_SINT48 = 17;
|
||||
static const uint8_t FORMAT_SINT64 = 18;
|
||||
static const uint8_t FORMAT_SINT128 = 19;
|
||||
static const uint8_t FORMAT_FLOAT32 = 20;
|
||||
static const uint8_t FORMAT_FLOAT64 = 21;
|
||||
static const uint8_t FORMAT_SFLOAT16 = 22;
|
||||
static const uint8_t FORMAT_SFLOAT32 = 23;
|
||||
static const uint8_t FORMAT_IEEE20601 = 24;
|
||||
static const uint8_t FORMAT_UTF8 = 25;
|
||||
static const uint8_t FORMAT_UTF16 = 26;
|
||||
static const uint8_t FORMAT_OPAQUE = 27;
|
||||
|
||||
void setDescription(uint16_t);
|
||||
void setExponent(int8_t exponent);
|
||||
void setFormat(uint8_t format);
|
||||
void setNamespace(uint8_t namespace_value);
|
||||
void setUnit(uint16_t unit);
|
||||
|
||||
private:
|
||||
BLE2904_Data m_data;
|
||||
}; // BLE2904
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLE2904_H_ */
|
||||
@@ -234,6 +234,7 @@ void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload) {
|
||||
uint8_t ad_type;
|
||||
uint8_t sizeConsumed = 0;
|
||||
bool finished = false;
|
||||
setPayload(payload);
|
||||
|
||||
while(!finished) {
|
||||
length = *payload; // Retrieve the length of the record.
|
||||
@@ -506,7 +507,13 @@ std::string BLEAdvertisedDevice::toString() {
|
||||
return ss.str();
|
||||
} // toString
|
||||
|
||||
uint8_t* BLEAdvertisedDevice::getPayload() {
|
||||
return m_payload;
|
||||
}
|
||||
|
||||
void BLEAdvertisedDevice::setPayload(uint8_t* payload) {
|
||||
m_payload = payload;
|
||||
}
|
||||
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
|
||||
@@ -39,9 +39,10 @@ public:
|
||||
BLEUUID getServiceDataUUID();
|
||||
BLEUUID getServiceUUID();
|
||||
int8_t getTXPower();
|
||||
uint8_t* getPayload();
|
||||
|
||||
|
||||
bool isAdvertisingService(BLEUUID uuid);
|
||||
bool isAdvertisingService(BLEUUID uuid);
|
||||
bool haveAppearance();
|
||||
bool haveManufacturerData();
|
||||
bool haveName();
|
||||
@@ -69,6 +70,7 @@ private:
|
||||
void setServiceUUID(const char* serviceUUID);
|
||||
void setServiceUUID(BLEUUID serviceUUID);
|
||||
void setTXPower(int8_t txPower);
|
||||
void setPayload(uint8_t* payload);
|
||||
|
||||
|
||||
bool m_haveAppearance;
|
||||
@@ -92,6 +94,7 @@ private:
|
||||
int8_t m_txPower;
|
||||
std::string m_serviceData;
|
||||
BLEUUID m_serviceDataUUID;
|
||||
uint8_t* m_payload;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,17 @@
|
||||
* This class encapsulates advertising a BLE Server.
|
||||
* Created on: Jun 21, 2017
|
||||
* Author: kolban
|
||||
*
|
||||
* The ESP-IDF provides a framework for BLE advertising. It has determined that there are a common set
|
||||
* of properties that are advertised and has built a data structure that can be populated by the programmer.
|
||||
* This means that the programmer doesn't have to "mess with" the low level construction of a low level
|
||||
* BLE advertising frame. Many of the fields are determined for us while others we can set before starting
|
||||
* to advertise.
|
||||
*
|
||||
* Should we wish to construct our own payload, we can use the BLEAdvertisementData class and call the setters
|
||||
* upon it. Once it is populated, we can then associate it with the advertising and what ever the programmer
|
||||
* set in the data will be advertised.
|
||||
*
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
@@ -12,6 +23,7 @@
|
||||
#include <esp_err.h>
|
||||
#include "BLEUtils.h"
|
||||
#include "GeneralUtils.h"
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "esp32-hal-log.h"
|
||||
#endif
|
||||
@@ -44,6 +56,9 @@ BLEAdvertising::BLEAdvertising() {
|
||||
m_advParams.own_addr_type = BLE_ADDR_TYPE_PUBLIC;
|
||||
m_advParams.channel_map = ADV_CHNL_ALL;
|
||||
m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY;
|
||||
|
||||
m_customAdvData = false; // No custom advertising data
|
||||
m_customScanResponseData = false; // No custom scan response data
|
||||
} // BLEAdvertising
|
||||
|
||||
|
||||
@@ -76,6 +91,79 @@ void BLEAdvertising::setAppearance(uint16_t appearance) {
|
||||
m_advData.appearance = appearance;
|
||||
} // setAppearance
|
||||
|
||||
void BLEAdvertising::setMinInterval(uint16_t mininterval) {
|
||||
m_advData.min_interval = mininterval;
|
||||
m_advParams.adv_int_min = mininterval;
|
||||
} // setMinInterval
|
||||
|
||||
void BLEAdvertising::setMaxInterval(uint16_t maxinterval) {
|
||||
m_advData.max_interval = maxinterval;
|
||||
m_advParams.adv_int_max = maxinterval;
|
||||
} // setMaxInterval
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the filtering for the scan filter.
|
||||
* @param [in] scanRequestWhitelistOnly If true, only allow scan requests from those on the white list.
|
||||
* @param [in] connectWhitelistOnly If true, only allow connections from those on the white list.
|
||||
*/
|
||||
void BLEAdvertising::setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly) {
|
||||
ESP_LOGD(LOG_TAG, ">> setScanFilter: scanRequestWhitelistOnly: %d, connectWhitelistOnly: %d", scanRequestWhitelistOnly, connectWhitelistOnly);
|
||||
if (!scanRequestWhitelistOnly && !connectWhitelistOnly) {
|
||||
m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY;
|
||||
ESP_LOGD(LOG_TAG, "<< setScanFilter");
|
||||
return;
|
||||
}
|
||||
if (scanRequestWhitelistOnly && !connectWhitelistOnly) {
|
||||
m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY;
|
||||
ESP_LOGD(LOG_TAG, "<< setScanFilter");
|
||||
return;
|
||||
}
|
||||
if (!scanRequestWhitelistOnly && connectWhitelistOnly) {
|
||||
m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_WLST;
|
||||
ESP_LOGD(LOG_TAG, "<< setScanFilter");
|
||||
return;
|
||||
}
|
||||
if (scanRequestWhitelistOnly && connectWhitelistOnly) {
|
||||
m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_WLST_CON_WLST;
|
||||
ESP_LOGD(LOG_TAG, "<< setScanFilter");
|
||||
return;
|
||||
}
|
||||
} // setScanFilter
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the advertisement data that is to be published in a regular advertisement.
|
||||
* @param [in] advertisementData The data to be advertised.
|
||||
*/
|
||||
void BLEAdvertising::setAdvertisementData(BLEAdvertisementData& advertisementData) {
|
||||
ESP_LOGD(LOG_TAG, ">> setAdvertisementData");
|
||||
esp_err_t errRc = ::esp_ble_gap_config_adv_data_raw(
|
||||
(uint8_t*)advertisementData.getPayload().data(),
|
||||
advertisementData.getPayload().length());
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_config_adv_data_raw: %d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
m_customAdvData = true; // Set the flag that indicates we are using custom advertising data.
|
||||
ESP_LOGD(LOG_TAG, "<< setAdvertisementData");
|
||||
} // setAdvertisementData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the advertisement data that is to be published in a scan response.
|
||||
* @param [in] advertisementData The data to be advertised.
|
||||
*/
|
||||
void BLEAdvertising::setScanResponseData(BLEAdvertisementData& advertisementData) {
|
||||
ESP_LOGD(LOG_TAG, ">> setScanResponseData");
|
||||
esp_err_t errRc = ::esp_ble_gap_config_scan_rsp_data_raw(
|
||||
(uint8_t*)advertisementData.getPayload().data(),
|
||||
advertisementData.getPayload().length());
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_config_scan_rsp_data_raw: %d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
m_customScanResponseData = true; // Set the flag that indicates we are using custom scan response data.
|
||||
ESP_LOGD(LOG_TAG, "<< setScanResponseData");
|
||||
} // setScanResponseData
|
||||
|
||||
/**
|
||||
* @brief Start advertising.
|
||||
@@ -83,7 +171,8 @@ void BLEAdvertising::setAppearance(uint16_t appearance) {
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLEAdvertising::start() {
|
||||
ESP_LOGD(LOG_TAG, ">> start");
|
||||
ESP_LOGD(LOG_TAG, ">> start: customAdvData: %d, customScanResponseData: %d", m_customAdvData, m_customScanResponseData);
|
||||
|
||||
|
||||
// We have a vector of service UUIDs that we wish to advertise. In order to use the
|
||||
// ESP-IDF framework, these must be supplied in a contiguous array of their 128bit (16 byte)
|
||||
@@ -92,7 +181,7 @@ void BLEAdvertising::start() {
|
||||
int numServices = m_serviceUUIDs.size();
|
||||
if (numServices > 0) {
|
||||
m_advData.service_uuid_len = 16*numServices;
|
||||
m_advData.p_service_uuid = new uint8_t[m_advData.service_uuid_len];
|
||||
m_advData.p_service_uuid = new uint8_t[m_advData.service_uuid_len];
|
||||
uint8_t* p = m_advData.p_service_uuid;
|
||||
for (int i=0; i<numServices; i++) {
|
||||
ESP_LOGD(LOG_TAG, "- advertising service: %s", m_serviceUUIDs[i].toString().c_str());
|
||||
@@ -105,20 +194,25 @@ void BLEAdvertising::start() {
|
||||
ESP_LOGD(LOG_TAG, "- no services advertised");
|
||||
}
|
||||
|
||||
esp_err_t errRc;
|
||||
|
||||
if (m_customAdvData == false) {
|
||||
// Set the configuration for advertising.
|
||||
m_advData.set_scan_rsp = false;
|
||||
esp_err_t errRc = ::esp_ble_gap_config_adv_data(&m_advData);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< esp_ble_gap_config_adv_data: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
m_advData.set_scan_rsp = false;
|
||||
errRc = ::esp_ble_gap_config_adv_data(&m_advData);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< esp_ble_gap_config_adv_data: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_advData.set_scan_rsp = true;
|
||||
errRc = ::esp_ble_gap_config_adv_data(&m_advData);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< esp_ble_gap_config_adv_data (Scan response): rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
if (m_customScanResponseData == false) {
|
||||
m_advData.set_scan_rsp = true;
|
||||
errRc = ::esp_ble_gap_config_adv_data(&m_advData);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< esp_ble_gap_config_adv_data (Scan response): rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If we had services to advertise then we previously allocated some storage for them.
|
||||
@@ -153,5 +247,216 @@ void BLEAdvertising::stop() {
|
||||
ESP_LOGD(LOG_TAG, "<< stop");
|
||||
} // stop
|
||||
|
||||
/**
|
||||
* @brief Add data to the payload to be advertised.
|
||||
* @param [in] data The data to be added to the payload.
|
||||
*/
|
||||
void BLEAdvertisementData::addData(std::string data) {
|
||||
if ((m_payload.length() + data.length()) > ESP_BLE_ADV_DATA_LEN_MAX) {
|
||||
return;
|
||||
}
|
||||
m_payload.append(data);
|
||||
} // addData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the appearance.
|
||||
* @param [in] appearance The appearance code value.
|
||||
*
|
||||
* See also:
|
||||
* https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml
|
||||
*/
|
||||
void BLEAdvertisementData::setAppearance(uint16_t appearance) {
|
||||
char cdata[2];
|
||||
cdata[0] = 3;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_APPEARANCE; // 0x19
|
||||
addData(std::string(cdata, 2) + std::string((char *)&appearance,2));
|
||||
} // setAppearance
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the complete services.
|
||||
* @param [in] uuid The single service to advertise.
|
||||
*/
|
||||
void BLEAdvertisementData::setCompleteServices(BLEUUID uuid) {
|
||||
char cdata[2];
|
||||
switch(uuid.bitSize()) {
|
||||
case 16: {
|
||||
// [Len] [0x02] [LL] [HH]
|
||||
cdata[0] = 3;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_16SRV_CMPL; // 0x03
|
||||
addData(std::string(cdata, 2) + std::string((char *)&uuid.getNative()->uuid.uuid16,2));
|
||||
break;
|
||||
}
|
||||
|
||||
case 32: {
|
||||
// [Len] [0x04] [LL] [LL] [HH] [HH]
|
||||
cdata[0] = 5;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_32SRV_CMPL; // 0x05
|
||||
addData(std::string(cdata, 2) + std::string((char *)&uuid.getNative()->uuid.uuid32,4));
|
||||
break;
|
||||
}
|
||||
|
||||
case 128: {
|
||||
// [Len] [0x04] [0] [1] ... [15]
|
||||
cdata[0] = 17;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_128SRV_CMPL; // 0x07
|
||||
addData(std::string(cdata, 2) + std::string((char *)uuid.getNative()->uuid.uuid128,16));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
} // setCompleteServices
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the advertisement flags.
|
||||
* @param [in] The flags to be set in the advertisement.
|
||||
*
|
||||
* * ESP_BLE_ADV_FLAG_LIMIT_DISC
|
||||
* * ESP_BLE_ADV_FLAG_GEN_DISC
|
||||
* * ESP_BLE_ADV_FLAG_BREDR_NOT_SPT
|
||||
* * ESP_BLE_ADV_FLAG_DMT_CONTROLLER_SPT
|
||||
* * ESP_BLE_ADV_FLAG_DMT_HOST_SPT
|
||||
* * ESP_BLE_ADV_FLAG_NON_LIMIT_DISC
|
||||
*/
|
||||
void BLEAdvertisementData::setFlags(uint8_t flag) {
|
||||
char cdata[3];
|
||||
cdata[0] = 2;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_FLAG; // 0x01
|
||||
cdata[2] = flag;
|
||||
addData(std::string(cdata, 3));
|
||||
} // setFlag
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set manufacturer specific data.
|
||||
* @param [in] data Manufacturer data.
|
||||
*/
|
||||
void BLEAdvertisementData::setManufacturerData(std::string data) {
|
||||
ESP_LOGD("BLEAdvertisementData", ">> setManufacturerData");
|
||||
char cdata[2];
|
||||
cdata[0] = data.length() + 1;
|
||||
cdata[1] = ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE; // 0xff
|
||||
addData(std::string(cdata, 2) + data);
|
||||
ESP_LOGD("BLEAdvertisementData", "<< setManufacturerData");
|
||||
} // setManufacturerData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the name.
|
||||
* @param [in] The complete name of the device.
|
||||
*/
|
||||
void BLEAdvertisementData::setName(std::string name) {
|
||||
ESP_LOGD("BLEAdvertisementData", ">> setName: %s", name.c_str());
|
||||
char cdata[2];
|
||||
cdata[0] = name.length() + 1;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_NAME_CMPL; // 0x09
|
||||
addData(std::string(cdata, 2) + name);
|
||||
ESP_LOGD("BLEAdvertisementData", "<< setName");
|
||||
} // setName
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the partial services.
|
||||
* @param [in] uuid The single service to advertise.
|
||||
*/
|
||||
void BLEAdvertisementData::setPartialServices(BLEUUID uuid) {
|
||||
char cdata[2];
|
||||
switch(uuid.bitSize()) {
|
||||
case 16: {
|
||||
// [Len] [0x02] [LL] [HH]
|
||||
cdata[0] = 3;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_16SRV_PART; // 0x02
|
||||
addData(std::string(cdata, 2) + std::string((char *)&uuid.getNative()->uuid.uuid16,2));
|
||||
break;
|
||||
}
|
||||
|
||||
case 32: {
|
||||
// [Len] [0x04] [LL] [LL] [HH] [HH]
|
||||
cdata[0] = 5;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_32SRV_PART; // 0x04
|
||||
addData(std::string(cdata, 2) + std::string((char *)&uuid.getNative()->uuid.uuid32,4));
|
||||
break;
|
||||
}
|
||||
|
||||
case 128: {
|
||||
// [Len] [0x04] [0] [1] ... [15]
|
||||
cdata[0] = 17;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_128SRV_PART; // 0x06
|
||||
addData(std::string(cdata, 2) + std::string((char *)uuid.getNative()->uuid.uuid128,16));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
} // setPartialServices
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the service data (UUID + data)
|
||||
* @param [in] uuid The UUID to set with the service data. Size of UUID will be used.
|
||||
* @param [in] data The data to be associated with the service data advert.
|
||||
*/
|
||||
void BLEAdvertisementData::setServiceData(BLEUUID uuid, std::string data) {
|
||||
char cdata[2];
|
||||
switch(uuid.bitSize()) {
|
||||
case 16: {
|
||||
// [Len] [0x16] [UUID16] data
|
||||
cdata[0] = data.length() + 3;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_SERVICE_DATA; // 0x16
|
||||
addData(std::string(cdata, 2) + std::string((char *)&uuid.getNative()->uuid.uuid16,2) + data);
|
||||
break;
|
||||
}
|
||||
|
||||
case 32: {
|
||||
// [Len] [0x20] [UUID32] data
|
||||
cdata[0] = data.length() + 5;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_32SERVICE_DATA; // 0x20
|
||||
addData(std::string(cdata, 2) + std::string((char *)&uuid.getNative()->uuid.uuid32,4) + data);
|
||||
break;
|
||||
}
|
||||
|
||||
case 128: {
|
||||
// [Len] [0x21] [UUID128] data
|
||||
cdata[0] = data.length() + 17;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_128SERVICE_DATA; // 0x21
|
||||
addData(std::string(cdata, 2) + std::string((char *)uuid.getNative()->uuid.uuid128,16) + data);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
} // setServiceData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the short name.
|
||||
* @param [in] The short name of the device.
|
||||
*/
|
||||
void BLEAdvertisementData::setShortName(std::string name) {
|
||||
ESP_LOGD("BLEAdvertisementData", ">> setShortName: %s", name.c_str());
|
||||
char cdata[2];
|
||||
cdata[0] = name.length() + 1;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_NAME_SHORT; // 0x08
|
||||
addData(std::string(cdata, 2) + name);
|
||||
ESP_LOGD("BLEAdvertisementData", "<< setShortName");
|
||||
} // setShortName
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the payload that is to be advertised.
|
||||
* @return The payload that is to be advertised.
|
||||
*/
|
||||
std::string BLEAdvertisementData::getPayload() {
|
||||
return m_payload;
|
||||
} // getPayload
|
||||
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
@@ -13,6 +13,31 @@
|
||||
#include "BLEUUID.h"
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @brief Advertisement data set by the programmer to be published by the %BLE server.
|
||||
*/
|
||||
class BLEAdvertisementData {
|
||||
// Only a subset of the possible BLE architected advertisement fields are currently exposed. Others will
|
||||
// be exposed on demand/request or as time permits.
|
||||
//
|
||||
public:
|
||||
void setAppearance(uint16_t appearance);
|
||||
void setCompleteServices(BLEUUID uuid);
|
||||
void setFlags(uint8_t);
|
||||
void setManufacturerData(std::string data);
|
||||
void setName(std::string name);
|
||||
void setPartialServices(BLEUUID uuid);
|
||||
void setServiceData(BLEUUID uuid, std::string data);
|
||||
void setShortName(std::string name);
|
||||
void addData(std::string data); // Add data to the payload.
|
||||
std::string getPayload(); // Retrieve the current advert payload.
|
||||
|
||||
private:
|
||||
friend class BLEAdvertising;
|
||||
std::string m_payload; // The payload of the advertisement.
|
||||
}; // BLEAdvertisementData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Perform and manage %BLE advertising.
|
||||
*
|
||||
@@ -26,10 +51,18 @@ public:
|
||||
void start();
|
||||
void stop();
|
||||
void setAppearance(uint16_t appearance);
|
||||
void setMaxInterval(uint16_t maxinterval);
|
||||
void setMinInterval(uint16_t mininterval);
|
||||
void setAdvertisementData(BLEAdvertisementData& advertisementData);
|
||||
void setScanFilter(bool scanRequertWhitelistOnly, bool connectWhitelistOnly);
|
||||
void setScanResponseData(BLEAdvertisementData& advertisementData);
|
||||
|
||||
private:
|
||||
esp_ble_adv_data_t m_advData;
|
||||
esp_ble_adv_params_t m_advParams;
|
||||
std::vector<BLEUUID> m_serviceUUIDs;
|
||||
bool m_customAdvData; // Are we using custom advertising data?
|
||||
bool m_customScanResponseData; // Are we using custom scan response data?
|
||||
};
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ */
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* BLEBeacon.cpp
|
||||
*
|
||||
* Created on: Jan 4, 2018
|
||||
* Author: kolban
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <string.h>
|
||||
#include <esp_log.h>
|
||||
#include "BLEBeacon.h"
|
||||
|
||||
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8))
|
||||
|
||||
static const char LOG_TAG[] = "BLEBeacon";
|
||||
|
||||
BLEBeacon::BLEBeacon() {
|
||||
m_beaconData.manufacturerId = 0x4c00;
|
||||
m_beaconData.subType = 0x02;
|
||||
m_beaconData.subTypeLength = 0x15;
|
||||
m_beaconData.major = 0;
|
||||
m_beaconData.minor = 0;
|
||||
m_beaconData.signalPower = 0;
|
||||
memset(m_beaconData.proximityUUID, 0, sizeof(m_beaconData.proximityUUID));
|
||||
} // BLEBeacon
|
||||
|
||||
std::string BLEBeacon::getData() {
|
||||
return std::string((char*)&m_beaconData, sizeof(m_beaconData));
|
||||
} // getData
|
||||
|
||||
uint16_t BLEBeacon::getMajor() {
|
||||
return m_beaconData.major;
|
||||
}
|
||||
|
||||
uint16_t BLEBeacon::getManufacturerId() {
|
||||
return m_beaconData.manufacturerId;
|
||||
}
|
||||
|
||||
uint16_t BLEBeacon::getMinor() {
|
||||
return m_beaconData.minor;
|
||||
}
|
||||
|
||||
BLEUUID BLEBeacon::getProximityUUID() {
|
||||
return BLEUUID(m_beaconData.proximityUUID, 16, false);
|
||||
}
|
||||
|
||||
int8_t BLEBeacon::getSignalPower() {
|
||||
return m_beaconData.signalPower;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the raw data for the beacon record.
|
||||
*/
|
||||
void BLEBeacon::setData(std::string data) {
|
||||
if (data.length() != sizeof(m_beaconData)) {
|
||||
ESP_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and expected %d", data.length(), sizeof(m_beaconData));
|
||||
return;
|
||||
}
|
||||
memcpy(&m_beaconData, data.data(), sizeof(m_beaconData));
|
||||
} // setData
|
||||
|
||||
void BLEBeacon::setMajor(uint16_t major) {
|
||||
m_beaconData.major = ENDIAN_CHANGE_U16(major);
|
||||
} // setMajor
|
||||
|
||||
void BLEBeacon::setManufacturerId(uint16_t manufacturerId) {
|
||||
m_beaconData.manufacturerId = ENDIAN_CHANGE_U16(manufacturerId);
|
||||
} // setManufacturerId
|
||||
|
||||
void BLEBeacon::setMinor(uint16_t minor) {
|
||||
m_beaconData.minor = ENDIAN_CHANGE_U16(minor);
|
||||
} // setMinior
|
||||
|
||||
void BLEBeacon::setProximityUUID(BLEUUID uuid) {
|
||||
uuid = uuid.to128();
|
||||
memcpy(m_beaconData.proximityUUID, uuid.getNative()->uuid.uuid128, 16);
|
||||
} // setProximityUUID
|
||||
|
||||
void BLEBeacon::setSignalPower(int8_t signalPower) {
|
||||
m_beaconData.signalPower = signalPower;
|
||||
} // setSignalPower
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* BLEBeacon2.h
|
||||
*
|
||||
* Created on: Jan 4, 2018
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLEBEACON_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLEBEACON_H_
|
||||
#include "BLEUUID.h"
|
||||
/**
|
||||
* @brief Representation of a beacon.
|
||||
* See:
|
||||
* * https://en.wikipedia.org/wiki/IBeacon
|
||||
*/
|
||||
class BLEBeacon {
|
||||
private:
|
||||
struct {
|
||||
uint16_t manufacturerId;
|
||||
uint8_t subType;
|
||||
uint8_t subTypeLength;
|
||||
uint8_t proximityUUID[16];
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
int8_t signalPower;
|
||||
} __attribute__((packed))m_beaconData;
|
||||
public:
|
||||
BLEBeacon();
|
||||
std::string getData();
|
||||
uint16_t getMajor();
|
||||
uint16_t getMinor();
|
||||
uint16_t getManufacturerId();
|
||||
BLEUUID getProximityUUID();
|
||||
int8_t getSignalPower();
|
||||
void setData(std::string data);
|
||||
void setMajor(uint16_t major);
|
||||
void setMinor(uint16_t minor);
|
||||
void setManufacturerId(uint16_t manufacturerId);
|
||||
void setProximityUUID(BLEUUID uuid);
|
||||
void setSignalPower(int8_t signalPower);
|
||||
}; // BLEBeacon
|
||||
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLEBEACON_H_ */
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <esp_err.h>
|
||||
#include "BLECharacteristic.h"
|
||||
#include "BLEService.h"
|
||||
#include "BLEDevice.h"
|
||||
#include "BLEUtils.h"
|
||||
#include "BLE2902.h"
|
||||
#include "GeneralUtils.h"
|
||||
@@ -107,7 +108,7 @@ void BLECharacteristic::executeCreate(BLEService* pService) {
|
||||
esp_err_t errRc = ::esp_ble_gatts_add_char(
|
||||
m_pService->getHandle(),
|
||||
getUUID().getNative(),
|
||||
static_cast<esp_gatt_perm_t>(ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE),
|
||||
static_cast<esp_gatt_perm_t>(m_permissions),
|
||||
getProperties(),
|
||||
//&value,
|
||||
nullptr,
|
||||
@@ -163,6 +164,9 @@ uint16_t BLECharacteristic::getHandle() {
|
||||
return m_handle;
|
||||
} // getHandle
|
||||
|
||||
void BLECharacteristic::setAccessPermissions(esp_gatt_perm_t perm) {
|
||||
m_permissions = perm;
|
||||
}
|
||||
|
||||
esp_gatt_char_prop_t BLECharacteristic::getProperties() {
|
||||
return m_properties;
|
||||
@@ -195,17 +199,27 @@ std::string BLECharacteristic::getValue() {
|
||||
} // getValue
|
||||
|
||||
|
||||
/**
|
||||
* Handle a GATT server event.
|
||||
*/
|
||||
void BLECharacteristic::handleGATTServerEvent(
|
||||
esp_gatts_cb_event_t event,
|
||||
esp_gatt_if_t gatts_if,
|
||||
esp_ble_gatts_cb_param_t* param) {
|
||||
ESP_LOGD(LOG_TAG, ">> handleGATTServerEvent: %s", BLEUtils::gattServerEventTypeToString(event).c_str());
|
||||
|
||||
switch(event) {
|
||||
// Events handled:
|
||||
// ESP_GATTS_ADD_CHAR_EVT
|
||||
// ESP_GATTS_WRITE_EVT
|
||||
// ESP_GATTS_READ_EVT
|
||||
//
|
||||
// ESP_GATTS_ADD_CHAR_EVT
|
||||
// ESP_GATTS_CONF_EVT
|
||||
// ESP_GATTS_CONNECT_EVT
|
||||
// ESP_GATTS_DISCONNECT_EVT
|
||||
// ESP_GATTS_EXEC_WRITE_EVT
|
||||
// ESP_GATTS_READ_EVT
|
||||
// ESP_GATTS_WRITE_EVT
|
||||
|
||||
//
|
||||
// ESP_GATTS_EXEC_WRITE_EVT
|
||||
// When we receive this event it is an indication that a previous write long needs to be committed.
|
||||
//
|
||||
@@ -213,7 +227,7 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
// - uint16_t conn_id
|
||||
// - uint32_t trans_id
|
||||
// - esp_bd_addr_t bda
|
||||
// - uint8_t exec_write_flag
|
||||
// - uint8_t exec_write_flag - Either ESP_GATT_PREP_WRITE_EXEC or ESP_GATT_PREP_WRITE_CANCEL
|
||||
//
|
||||
case ESP_GATTS_EXEC_WRITE_EVT: {
|
||||
if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) {
|
||||
@@ -321,20 +335,18 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
// - bool need_rsp
|
||||
//
|
||||
case ESP_GATTS_READ_EVT: {
|
||||
ESP_LOGD(LOG_TAG, "- Testing: 0x%.2x == 0x%.2x", param->read.handle, m_handle);
|
||||
if (param->read.handle == m_handle) {
|
||||
|
||||
if (m_pCallbacks != nullptr) {
|
||||
m_pCallbacks->onRead(this); // Invoke the read callback.
|
||||
}
|
||||
|
||||
|
||||
// Here's an interesting thing. The read request has the option of saying whether we need a response
|
||||
// or not. What would it "mean" to receive a read request and NOT send a response back? That feels like
|
||||
// a very strange read.
|
||||
//
|
||||
// We have to handle the case where the data we wish to send back to the client is greater than the maximum
|
||||
// packet size of 22 bytes. In this case, we become responsible for chunking the data into uints of 22 bytes.
|
||||
// The apparent algorithm is as follows.
|
||||
// packet size of 22 bytes. In this case, we become responsible for chunking the data into units of 22 bytes.
|
||||
// The apparent algorithm is as follows:
|
||||
//
|
||||
// If the is_long flag is set then this is a follow on from an original read and we will already have sent at least 22 bytes.
|
||||
// If the is_long flag is not set then we need to check how much data we are going to send. If we are sending LESS than
|
||||
// 22 bytes, then we "just" send it and thats the end of the story.
|
||||
@@ -348,12 +360,19 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
// The following code has deliberately not been factored to make it fewer statements because this would cloud the
|
||||
// the logic flow comprehension.
|
||||
//
|
||||
// TODO requires some more research to confirm that 512 is max PDU like in bluetooth specs
|
||||
uint16_t maxOffset = BLEDevice::getMTU() - 1;
|
||||
if (BLEDevice::getMTU() > 512) {
|
||||
maxOffset = 512;
|
||||
}
|
||||
if (param->read.need_rsp) {
|
||||
ESP_LOGD(LOG_TAG, "Sending a response (esp_ble_gatts_send_response)");
|
||||
esp_gatt_rsp_t rsp;
|
||||
std::string value = m_value.getValue();
|
||||
|
||||
if (param->read.is_long) {
|
||||
if (value.length() - m_value.getReadOffset() < 22) {
|
||||
std::string value = m_value.getValue();
|
||||
|
||||
if (value.length() - m_value.getReadOffset() < maxOffset) {
|
||||
// This is the last in the chain
|
||||
rsp.attr_value.len = value.length() - m_value.getReadOffset();
|
||||
rsp.attr_value.offset = m_value.getReadOffset();
|
||||
@@ -361,16 +380,23 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
m_value.setReadOffset(0);
|
||||
} else {
|
||||
// There will be more to come.
|
||||
rsp.attr_value.len = 22;
|
||||
rsp.attr_value.len = maxOffset;
|
||||
rsp.attr_value.offset = m_value.getReadOffset();
|
||||
memcpy(rsp.attr_value.value, value.data() + rsp.attr_value.offset, rsp.attr_value.len);
|
||||
m_value.setReadOffset(rsp.attr_value.offset + 22);
|
||||
m_value.setReadOffset(rsp.attr_value.offset + maxOffset);
|
||||
}
|
||||
} else {
|
||||
if (value.length() > 21) {
|
||||
} else { // read.is_long == false
|
||||
|
||||
if (m_pCallbacks != nullptr) { // If is.long is false then this is the first (or only) request to read data, so invoke the callback
|
||||
m_pCallbacks->onRead(this); // Invoke the read callback.
|
||||
}
|
||||
|
||||
std::string value = m_value.getValue();
|
||||
|
||||
if (value.length()+1 > maxOffset) {
|
||||
// Too big for a single shot entry.
|
||||
m_value.setReadOffset(22);
|
||||
rsp.attr_value.len = 22;
|
||||
m_value.setReadOffset(maxOffset);
|
||||
rsp.attr_value.len = maxOffset;
|
||||
rsp.attr_value.offset = 0;
|
||||
memcpy(rsp.attr_value.value, value.data(), rsp.attr_value.len);
|
||||
} else {
|
||||
@@ -400,6 +426,7 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
break;
|
||||
} // ESP_GATTS_READ_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_CONF_EVT
|
||||
//
|
||||
// conf:
|
||||
@@ -411,6 +438,16 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
break;
|
||||
}
|
||||
|
||||
case ESP_GATTS_CONNECT_EVT: {
|
||||
m_semaphoreConfEvt.give();
|
||||
break;
|
||||
}
|
||||
|
||||
case ESP_GATTS_DISCONNECT_EVT: {
|
||||
m_semaphoreConfEvt.give();
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
} // default
|
||||
@@ -421,7 +458,7 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
// event.
|
||||
|
||||
m_descriptorMap.handleGATTServerEvent(event, gatts_if, param);
|
||||
|
||||
ESP_LOGD(LOG_TAG, "<< handleGATTServerEvent");
|
||||
} // handleGATTServerEvent
|
||||
|
||||
|
||||
@@ -454,14 +491,11 @@ void BLECharacteristic::indicate() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_value.getValue().length() > 20) {
|
||||
ESP_LOGD(LOG_TAG, "- Truncating to 20 bytes (maximum notify size)");
|
||||
if (m_value.getValue().length() > (BLEDevice::getMTU() - 3)) {
|
||||
ESP_LOGI(LOG_TAG, "- Truncating to %d bytes (maximum indicate size)", BLEDevice::getMTU() - 3);
|
||||
}
|
||||
|
||||
size_t length = m_value.getValue().length();
|
||||
if (length > 20) {
|
||||
length = 20;
|
||||
}
|
||||
|
||||
m_semaphoreConfEvt.take("indicate");
|
||||
|
||||
@@ -510,14 +544,13 @@ void BLECharacteristic::notify() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_value.getValue().length() > 20) {
|
||||
ESP_LOGD(LOG_TAG, "- Truncating to 20 bytes (maximum notify size)");
|
||||
if (m_value.getValue().length() > (BLEDevice::getMTU() - 3)) {
|
||||
ESP_LOGI(LOG_TAG, "- Truncating to %d bytes (maximum notify size)", BLEDevice::getMTU() - 3);
|
||||
}
|
||||
|
||||
size_t length = m_value.getValue().length();
|
||||
if (length > 20) {
|
||||
length = 20;
|
||||
}
|
||||
|
||||
m_semaphoreConfEvt.take("notify");
|
||||
|
||||
esp_err_t errRc = ::esp_ble_gatts_send_indicate(
|
||||
getService()->getServer()->getGattsIf(),
|
||||
@@ -528,6 +561,8 @@ void BLECharacteristic::notify() {
|
||||
return;
|
||||
}
|
||||
|
||||
m_semaphoreConfEvt.wait("notify");
|
||||
|
||||
ESP_LOGD(LOG_TAG, "<< notify");
|
||||
} // Notify
|
||||
|
||||
@@ -648,6 +683,43 @@ void BLECharacteristic::setValue(std::string value) {
|
||||
setValue((uint8_t*)(value.data()), value.length());
|
||||
} // setValue
|
||||
|
||||
void BLECharacteristic::setValue(uint16_t& data16) {
|
||||
uint8_t temp[2];
|
||||
temp[0]=data16;
|
||||
temp[1]=data16>>8;
|
||||
setValue(temp, 2);
|
||||
} // setValue
|
||||
|
||||
void BLECharacteristic::setValue(uint32_t& data32) {
|
||||
uint8_t temp[4];
|
||||
temp[0]=data32;
|
||||
temp[1]=data32>>8;
|
||||
temp[2]=data32>>16;
|
||||
temp[3]=data32>>24;
|
||||
setValue(temp, 4);
|
||||
} // setValue
|
||||
|
||||
void BLECharacteristic::setValue(int& data32) {
|
||||
uint8_t temp[4];
|
||||
temp[0]=data32;
|
||||
temp[1]=data32>>8;
|
||||
temp[2]=data32>>16;
|
||||
temp[3]=data32>>24;
|
||||
setValue(temp, 4);
|
||||
} // setValue
|
||||
|
||||
void BLECharacteristic::setValue(float& data32) {
|
||||
uint8_t temp[4];
|
||||
*((float *)temp) = data32;
|
||||
setValue(temp, 4);
|
||||
} // setValue
|
||||
|
||||
void BLECharacteristic::setValue(double& data64) {
|
||||
uint8_t temp[8];
|
||||
*((double *)temp) = data64;
|
||||
setValue(temp, 8);
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the Write No Response property value.
|
||||
@@ -695,8 +767,10 @@ std::string BLECharacteristic::toString() {
|
||||
return stringstream.str();
|
||||
} // toString
|
||||
|
||||
|
||||
BLECharacteristicCallbacks::~BLECharacteristicCallbacks() {}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a read request.
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <map>
|
||||
#include "BLEUUID.h"
|
||||
#include <esp_gatts_api.h>
|
||||
#include <esp_gap_ble_api.h>
|
||||
#include "BLEDescriptor.h"
|
||||
#include "BLEValue.h"
|
||||
#include "FreeRTOS.h"
|
||||
@@ -74,11 +75,16 @@ public:
|
||||
void setReadProperty(bool value);
|
||||
void setValue(uint8_t* data, size_t size);
|
||||
void setValue(std::string value);
|
||||
void setValue(uint16_t& data16);
|
||||
void setValue(uint32_t& data32);
|
||||
void setValue(int& data32);
|
||||
void setValue(float& data32);
|
||||
void setValue(double& data64);
|
||||
void setWriteProperty(bool value);
|
||||
void setWriteNoResponseProperty(bool value);
|
||||
std::string toString();
|
||||
uint16_t getHandle();
|
||||
|
||||
void setAccessPermissions(esp_gatt_perm_t perm);
|
||||
|
||||
static const uint32_t PROPERTY_READ = 1<<0;
|
||||
static const uint32_t PROPERTY_WRITE = 1<<1;
|
||||
@@ -88,6 +94,7 @@ public:
|
||||
static const uint32_t PROPERTY_WRITE_NR = 1<<5;
|
||||
|
||||
private:
|
||||
|
||||
friend class BLEServer;
|
||||
friend class BLEService;
|
||||
friend class BLEDescriptor;
|
||||
@@ -100,6 +107,7 @@ private:
|
||||
BLECharacteristicCallbacks* m_pCallbacks;
|
||||
BLEService* m_pService;
|
||||
BLEValue m_value;
|
||||
esp_gatt_perm_t m_permissions = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE;
|
||||
|
||||
void handleGATTServerEvent(
|
||||
esp_gatts_cb_event_t event,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <esp_log.h>
|
||||
#include <bt.h>
|
||||
#include <esp_bt.h>
|
||||
#include <esp_bt_main.h>
|
||||
#include <esp_gap_ble_api.h>
|
||||
#include <esp_gattc_api.h>
|
||||
@@ -66,6 +66,22 @@ BLEClient::~BLEClient() {
|
||||
} // ~BLEClient
|
||||
|
||||
|
||||
/**
|
||||
* @brief Clear any existing services.
|
||||
*
|
||||
*/
|
||||
void BLEClient::clearServices() {
|
||||
ESP_LOGD(LOG_TAG, ">> clearServices");
|
||||
// Delete all the services.
|
||||
for (auto &myPair : m_servicesMap) {
|
||||
delete myPair.second;
|
||||
}
|
||||
m_servicesMap.clear();
|
||||
m_haveServices = false;
|
||||
ESP_LOGD(LOG_TAG, "<< clearServices");
|
||||
} // clearServices
|
||||
|
||||
|
||||
/**
|
||||
* @brief Connect to the partner (BLE Server).
|
||||
* @param [in] address The address of the partner.
|
||||
@@ -78,6 +94,8 @@ bool BLEClient::connect(BLEAddress address) {
|
||||
// and then block on its completion. When the event has arrived, we will have the handle.
|
||||
m_semaphoreRegEvt.take("connect");
|
||||
|
||||
clearServices(); // Delete any services that may exist.
|
||||
|
||||
esp_err_t errRc = ::esp_ble_gattc_app_register(0);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_app_register: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
@@ -93,6 +111,7 @@ bool BLEClient::connect(BLEAddress address) {
|
||||
errRc = ::esp_ble_gattc_open(
|
||||
getGattcIf(),
|
||||
*getPeerAddress().getNative(), // address
|
||||
BLE_ADDR_TYPE_PUBLIC, // Note: This was added on 2018-04-03 when the latest ESP-IDF was detected to have changed the signature.
|
||||
1 // direct connection
|
||||
);
|
||||
if (errRc != ESP_OK) {
|
||||
@@ -100,7 +119,7 @@ bool BLEClient::connect(BLEAddress address) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t rc = m_semaphoreOpenEvt.wait("connect");
|
||||
uint32_t rc = m_semaphoreOpenEvt.wait("connect"); // Wait for the connection to complete.
|
||||
ESP_LOGD(LOG_TAG, "<< connect(), rc=%d", rc==ESP_GATT_OK);
|
||||
return rc == ESP_GATT_OK;
|
||||
} // connect
|
||||
@@ -144,11 +163,15 @@ void BLEClient::gattClientEventHandler(
|
||||
case ESP_GATTC_DISCONNECT_EVT: {
|
||||
// If we receive a disconnect event, set the class flag that indicates that we are
|
||||
// no longer connected.
|
||||
if (m_pClientCallbacks != nullptr) {
|
||||
m_pClientCallbacks->onDisconnect(this);
|
||||
}
|
||||
m_isConnected = false;
|
||||
m_semaphoreRssiCmplEvt.give();
|
||||
m_semaphoreSearchCmplEvt.give(1);
|
||||
break;
|
||||
} // ESP_GATTC_DISCONNECT_EVT
|
||||
|
||||
|
||||
//
|
||||
// ESP_GATTC_OPEN_EVT
|
||||
//
|
||||
@@ -193,7 +216,7 @@ void BLEClient::gattClientEventHandler(
|
||||
// - uint16_t conn_id
|
||||
//
|
||||
case ESP_GATTC_SEARCH_CMPL_EVT: {
|
||||
m_semaphoreSearchCmplEvt.give();
|
||||
m_semaphoreSearchCmplEvt.give(0);
|
||||
break;
|
||||
} // ESP_GATTC_SEARCH_CMPL_EVT
|
||||
|
||||
@@ -293,6 +316,7 @@ BLERemoteService* BLEClient::getService(const char* uuid) {
|
||||
* @brief Get the service object corresponding to the uuid.
|
||||
* @param [in] uuid The UUID of the service being sought.
|
||||
* @return A reference to the Service or nullptr if don't know about it.
|
||||
* @throws BLEUuidNotFound
|
||||
*/
|
||||
BLERemoteService* BLEClient::getService(BLEUUID uuid) {
|
||||
ESP_LOGD(LOG_TAG, ">> getService: uuid: %s", uuid.toString().c_str());
|
||||
@@ -313,7 +337,7 @@ BLERemoteService* BLEClient::getService(BLEUUID uuid) {
|
||||
}
|
||||
} // End of each of the services.
|
||||
ESP_LOGD(LOG_TAG, "<< getService: not found");
|
||||
return nullptr;
|
||||
throw new BLEUuidNotFoundException;
|
||||
} // getService
|
||||
|
||||
|
||||
@@ -332,7 +356,9 @@ std::map<std::string, BLERemoteService*>* BLEClient::getServices() {
|
||||
* and will culminate with an ESP_GATTC_SEARCH_CMPL_EVT when all have been received.
|
||||
*/
|
||||
ESP_LOGD(LOG_TAG, ">> getServices");
|
||||
m_servicesMap.clear();
|
||||
|
||||
clearServices(); // Clear any services that may exist.
|
||||
|
||||
esp_err_t errRc = esp_ble_gattc_search_service(
|
||||
getGattcIf(),
|
||||
getConnId(),
|
||||
@@ -343,12 +369,27 @@ std::map<std::string, BLERemoteService*>* BLEClient::getServices() {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_search_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return &m_servicesMap;
|
||||
}
|
||||
m_semaphoreSearchCmplEvt.wait("getServices");
|
||||
m_haveServices = true; // Remember that we now have services.
|
||||
// If sucessfull, remember that we now have services.
|
||||
m_haveServices = (m_semaphoreSearchCmplEvt.wait("getServices") == 0);
|
||||
ESP_LOGD(LOG_TAG, "<< getServices");
|
||||
return &m_servicesMap;
|
||||
} // getServices
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the value of a specific characteristic associated with a specific service.
|
||||
* @param [in] serviceUUID The service that owns the characteristic.
|
||||
* @param [in] characteristicUUID The characteristic whose value we wish to read.
|
||||
* @throws BLEUuidNotFound
|
||||
*/
|
||||
std::string BLEClient::getValue(BLEUUID serviceUUID, BLEUUID characteristicUUID) {
|
||||
ESP_LOGD(LOG_TAG, ">> getValue: serviceUUID: %s, characteristicUUID: %s", serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||
std::string ret = getService(serviceUUID)->getCharacteristic(characteristicUUID)->readValue();
|
||||
ESP_LOGD(LOG_TAG, "<<getValue");
|
||||
return ret;
|
||||
} // getValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle a received GAP event.
|
||||
*
|
||||
@@ -388,6 +429,8 @@ bool BLEClient::isConnected() {
|
||||
} // isConnected
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the callbacks that will be invoked.
|
||||
*/
|
||||
@@ -396,6 +439,19 @@ void BLEClient::setClientCallbacks(BLEClientCallbacks* pClientCallbacks) {
|
||||
} // setClientCallbacks
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of a specific characteristic associated with a specific service.
|
||||
* @param [in] serviceUUID The service that owns the characteristic.
|
||||
* @param [in] characteristicUUID The characteristic whose value we wish to write.
|
||||
* @throws BLEUuidNotFound
|
||||
*/
|
||||
void BLEClient::setValue(BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value) {
|
||||
ESP_LOGD(LOG_TAG, ">> setValue: serviceUUID: %s, characteristicUUID: %s", serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||
getService(serviceUUID)->getCharacteristic(characteristicUUID)->writeValue(value);
|
||||
ESP_LOGD(LOG_TAG, "<< setValue");
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of this client.
|
||||
* @return A string representation of this client.
|
||||
@@ -411,4 +467,5 @@ std::string BLEClient::toString() {
|
||||
return ss.str();
|
||||
} // toString
|
||||
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <string.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "BLEExceptions.h"
|
||||
#include "BLERemoteService.h"
|
||||
#include "BLEService.h"
|
||||
#include "BLEAddress.h"
|
||||
@@ -29,19 +30,28 @@ class BLEClient {
|
||||
public:
|
||||
BLEClient();
|
||||
~BLEClient();
|
||||
bool connect(BLEAddress address);
|
||||
void disconnect();
|
||||
BLEAddress getPeerAddress();
|
||||
int getRssi();
|
||||
std::map<std::string, BLERemoteService*>* getServices();
|
||||
BLERemoteService* getService(const char* uuid);
|
||||
BLERemoteService* getService(BLEUUID uuid);
|
||||
|
||||
bool connect(BLEAddress address); // Connect to the remote BLE Server
|
||||
void disconnect(); // Disconnect from the remote BLE Server
|
||||
BLEAddress getPeerAddress(); // Get the address of the remote BLE Server
|
||||
int getRssi(); // Get the RSSI of the remote BLE Server
|
||||
std::map<std::string, BLERemoteService*>* getServices(); // Get a map of the services offered by the remote BLE Server
|
||||
BLERemoteService* getService(const char* uuid); // Get a reference to a specified service offered by the remote BLE server.
|
||||
BLERemoteService* getService(BLEUUID uuid); // Get a reference to a specified service offered by the remote BLE server.
|
||||
std::string getValue(BLEUUID serviceUUID, BLEUUID characteristicUUID); // Get the value of a given characteristic at a given service.
|
||||
|
||||
|
||||
void handleGAPEvent(
|
||||
esp_gap_ble_cb_event_t event,
|
||||
esp_ble_gap_cb_param_t* param);
|
||||
bool isConnected();
|
||||
|
||||
bool isConnected(); // Return true if we are connected.
|
||||
|
||||
void setClientCallbacks(BLEClientCallbacks *pClientCallbacks);
|
||||
std::string toString();
|
||||
void setValue(BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value); // Set the value of a given characteristic at a given service.
|
||||
|
||||
std::string toString(); // Return a string representation of this client.
|
||||
|
||||
|
||||
private:
|
||||
friend class BLEDevice;
|
||||
@@ -56,11 +66,12 @@ private:
|
||||
|
||||
uint16_t getConnId();
|
||||
esp_gatt_if_t getGattcIf();
|
||||
BLEAddress m_peerAddress = BLEAddress((uint8_t*)"\0\0\0\0\0\0");
|
||||
BLEAddress m_peerAddress = BLEAddress((uint8_t*)"\0\0\0\0\0\0"); // The BD address of the remote server.
|
||||
uint16_t m_conn_id;
|
||||
// int m_deviceType;
|
||||
esp_gatt_if_t m_gattc_if;
|
||||
bool m_isConnected;
|
||||
bool m_haveServices; // Have we previously obtain the set of services from the remote server.
|
||||
bool m_isConnected; // Are we currently connected.
|
||||
|
||||
BLEClientCallbacks* m_pClientCallbacks;
|
||||
FreeRTOS::Semaphore m_semaphoreRegEvt = FreeRTOS::Semaphore("RegEvt");
|
||||
@@ -68,7 +79,8 @@ private:
|
||||
FreeRTOS::Semaphore m_semaphoreSearchCmplEvt = FreeRTOS::Semaphore("SearchCmplEvt");
|
||||
FreeRTOS::Semaphore m_semaphoreRssiCmplEvt = FreeRTOS::Semaphore("RssiCmplEvt");
|
||||
std::map<std::string, BLERemoteService*> m_servicesMap;
|
||||
bool m_haveServices; // Have we previously obtain the set of services.
|
||||
void clearServices(); // Clear any existing services.
|
||||
|
||||
}; // class BLEDevice
|
||||
|
||||
|
||||
@@ -79,6 +91,7 @@ class BLEClientCallbacks {
|
||||
public:
|
||||
virtual ~BLEClientCallbacks() {};
|
||||
virtual void onConnect(BLEClient *pClient) = 0;
|
||||
virtual void onDisconnect(BLEClient *pClient) = 0;
|
||||
};
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
|
||||
@@ -37,12 +37,12 @@ BLEDescriptor::BLEDescriptor(const char* uuid) : BLEDescriptor(BLEUUID(uuid)) {
|
||||
*/
|
||||
BLEDescriptor::BLEDescriptor(BLEUUID uuid) {
|
||||
m_bleUUID = uuid;
|
||||
m_value.attr_value = (uint8_t *)malloc(ESP_GATT_MAX_ATTR_LEN); // Allocate storage for the value.
|
||||
m_value.attr_len = 0;
|
||||
m_value.attr_max_len = ESP_GATT_MAX_ATTR_LEN;
|
||||
m_handle = NULL_HANDLE;
|
||||
m_pCharacteristic = nullptr; // No initial characteristic.
|
||||
m_pCallback = nullptr; // No initial callback.
|
||||
m_value.attr_value = (uint8_t *)malloc(ESP_GATT_MAX_ATTR_LEN); // Allocate storage for the value.
|
||||
m_value.attr_len = 0; // Initial length is 0.
|
||||
m_value.attr_max_len = ESP_GATT_MAX_ATTR_LEN; // Maximum length of the data.
|
||||
m_handle = NULL_HANDLE; // Handle is initially unknown.
|
||||
m_pCharacteristic = nullptr; // No initial characteristic.
|
||||
m_pCallback = nullptr; // No initial callback.
|
||||
|
||||
} // BLEDescriptor
|
||||
|
||||
@@ -51,7 +51,7 @@ BLEDescriptor::BLEDescriptor(BLEUUID uuid) {
|
||||
* @brief BLEDescriptor destructor.
|
||||
*/
|
||||
BLEDescriptor::~BLEDescriptor() {
|
||||
free(m_value.attr_value);
|
||||
free(m_value.attr_value); // Release the storage we created in the constructor.
|
||||
} // ~BLEDescriptor
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ void BLEDescriptor::handleGATTServerEvent(
|
||||
(uint32_t)m_pCharacteristic->getService()->getLastCreatedCharacteristic());
|
||||
*/
|
||||
if (m_pCharacteristic != nullptr &&
|
||||
m_bleUUID.equals(BLEUUID(param->add_char_descr.char_uuid)) &&
|
||||
m_bleUUID.equals(BLEUUID(param->add_char_descr.descr_uuid)) &&
|
||||
m_pCharacteristic->getService()->getHandle() == param->add_char_descr.service_handle &&
|
||||
m_pCharacteristic == m_pCharacteristic->getService()->getLastCreatedCharacteristic()) {
|
||||
setHandle(param->add_char_descr.attr_handle);
|
||||
@@ -301,6 +301,9 @@ void BLEDescriptor::setValue(std::string value) {
|
||||
setValue((uint8_t *)value.data(), value.length());
|
||||
} // setValue
|
||||
|
||||
void BLEDescriptor::setAccessPermissions(esp_gatt_perm_t perm) {
|
||||
m_permissions = perm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of the descriptor.
|
||||
|
||||
@@ -28,31 +28,37 @@ public:
|
||||
BLEDescriptor(BLEUUID uuid);
|
||||
virtual ~BLEDescriptor();
|
||||
|
||||
uint16_t getHandle();
|
||||
size_t getLength();
|
||||
BLEUUID getUUID();
|
||||
uint8_t* getValue();
|
||||
uint16_t getHandle(); // Get the handle of the descriptor.
|
||||
size_t getLength(); // Get the length of the value of the descriptor.
|
||||
BLEUUID getUUID(); // Get the UUID of the descriptor.
|
||||
uint8_t* getValue(); // Get a pointer to the value of the descriptor.
|
||||
void handleGATTServerEvent(
|
||||
esp_gatts_cb_event_t event,
|
||||
esp_gatt_if_t gatts_if,
|
||||
esp_ble_gatts_cb_param_t* param);
|
||||
void setCallbacks(BLEDescriptorCallbacks* pCallbacks);
|
||||
void setValue(uint8_t* data, size_t size);
|
||||
void setValue(std::string value);
|
||||
std::string toString();
|
||||
|
||||
void setAccessPermissions(esp_gatt_perm_t perm); // Set the permissions of the descriptor.
|
||||
void setCallbacks(BLEDescriptorCallbacks* pCallbacks); // Set callbacks to be invoked for the descriptor.
|
||||
void setValue(uint8_t* data, size_t size); // Set the value of the descriptor as a pointer to data.
|
||||
void setValue(std::string value); // Set the value of the descriptor as a data buffer.
|
||||
|
||||
std::string toString(); // Convert the descriptor to a string representation.
|
||||
|
||||
private:
|
||||
friend class BLEDescriptorMap;
|
||||
friend class BLECharacteristic;
|
||||
BLEUUID m_bleUUID;
|
||||
esp_attr_value_t m_value;
|
||||
uint16_t m_handle;
|
||||
BLECharacteristic* m_pCharacteristic;
|
||||
BLEUUID m_bleUUID;
|
||||
uint16_t m_handle;
|
||||
BLEDescriptorCallbacks* m_pCallback;
|
||||
BLECharacteristic* m_pCharacteristic;
|
||||
esp_gatt_perm_t m_permissions = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE;
|
||||
FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt");
|
||||
esp_attr_value_t m_value;
|
||||
|
||||
void executeCreate(BLECharacteristic* pCharacteristic);
|
||||
void setHandle(uint16_t handle);
|
||||
FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt");
|
||||
};
|
||||
}; // BLEDescriptor
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callbacks that can be associated with a %BLE descriptors to inform of events.
|
||||
|
||||
@@ -11,11 +11,13 @@
|
||||
#include <freertos/task.h>
|
||||
#include <esp_err.h>
|
||||
#include <nvs_flash.h>
|
||||
#include <bt.h> // ESP32 BLE
|
||||
#include <esp_bt.h> // ESP32 BLE
|
||||
#include <esp_bt_device.h> // ESP32 BLE
|
||||
#include <esp_bt_main.h> // ESP32 BLE
|
||||
#include <esp_gap_ble_api.h> // ESP32 BLE
|
||||
#include <esp_gatts_api.h> // ESP32 BLE
|
||||
#include <esp_gattc_api.h> // ESP32 BLE
|
||||
#include <esp_gatt_common_api.h>// ESP32 BLE
|
||||
#include <esp_err.h> // ESP32 ESP-IDF
|
||||
#include <esp_log.h> // ESP32 ESP-IDF
|
||||
#include <map> // Part of C++ Standard library
|
||||
@@ -28,24 +30,34 @@
|
||||
#include "GeneralUtils.h"
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "esp32-hal-log.h"
|
||||
#include "esp32-hal-bt.h"
|
||||
#endif
|
||||
|
||||
static const char* LOG_TAG = "BLEDevice";
|
||||
|
||||
|
||||
/**
|
||||
* Singletons for the BLEDevice.
|
||||
*/
|
||||
BLEServer* BLEDevice::m_pServer = nullptr;
|
||||
BLEScan* BLEDevice::m_pScan = nullptr;
|
||||
BLEClient* BLEDevice::m_pClient = nullptr;
|
||||
bool initialized = false;
|
||||
bool initialized = false; // Have we been initialized?
|
||||
esp_ble_sec_act_t BLEDevice::m_securityLevel = (esp_ble_sec_act_t)0;
|
||||
BLESecurityCallbacks* BLEDevice::m_securityCallbacks = nullptr;
|
||||
uint16_t BLEDevice::m_localMTU = 23;
|
||||
|
||||
/**
|
||||
* @brief Create a new instance of a client.
|
||||
* @return A new instance of the client.
|
||||
*/
|
||||
BLEClient* BLEDevice::createClient() {
|
||||
/* STATIC */ BLEClient* BLEDevice::createClient() {
|
||||
ESP_LOGD(LOG_TAG, ">> createClient");
|
||||
#ifndef CONFIG_GATTC_ENABLE // Check that BLE GATTC is enabled in make menuconfig
|
||||
ESP_LOGE(LOG_TAG, "BLE GATTC is not enabled - CONFIG_GATTC_ENABLE not defined");
|
||||
abort();
|
||||
#endif // CONFIG_GATTC_ENABLE
|
||||
m_pClient = new BLEClient();
|
||||
ESP_LOGD(LOG_TAG, "<< createClient");
|
||||
return m_pClient;
|
||||
} // createClient
|
||||
|
||||
@@ -54,8 +66,12 @@ BLEClient* BLEDevice::createClient() {
|
||||
* @brief Create a new instance of a server.
|
||||
* @return A new instance of the server.
|
||||
*/
|
||||
BLEServer* BLEDevice::createServer() {
|
||||
/* STATIC */ BLEServer* BLEDevice::createServer() {
|
||||
ESP_LOGD(LOG_TAG, ">> createServer");
|
||||
#ifndef CONFIG_GATTS_ENABLE // Check that BLE GATTS is enabled in make menuconfig
|
||||
ESP_LOGE(LOG_TAG, "BLE GATTS is not enabled - CONFIG_GATTS_ENABLE not defined");
|
||||
abort();
|
||||
#endif // CONFIG_GATTS_ENABLE
|
||||
m_pServer = new BLEServer();
|
||||
m_pServer->createApp(0);
|
||||
ESP_LOGD(LOG_TAG, "<< createServer");
|
||||
@@ -70,7 +86,7 @@ BLEServer* BLEDevice::createServer() {
|
||||
* @param [in] gatts_if The connection to the GATT interface.
|
||||
* @param [in] param Parameters for the event.
|
||||
*/
|
||||
void BLEDevice::gattServerEventHandler(
|
||||
/* STATIC */ void BLEDevice::gattServerEventHandler(
|
||||
esp_gatts_cb_event_t event,
|
||||
esp_gatt_if_t gatts_if,
|
||||
esp_ble_gatts_cb_param_t* param
|
||||
@@ -81,6 +97,28 @@ void BLEDevice::gattServerEventHandler(
|
||||
|
||||
BLEUtils::dumpGattServerEvent(event, gatts_if, param);
|
||||
|
||||
switch(event) {
|
||||
case ESP_GATTS_CONNECT_EVT: {
|
||||
BLEDevice::m_localMTU = 23;
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
if(BLEDevice::m_securityLevel){
|
||||
esp_ble_set_encryption(param->connect.remote_bda, BLEDevice::m_securityLevel);
|
||||
}
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
break;
|
||||
} // ESP_GATTS_CONNECT_EVT
|
||||
|
||||
case ESP_GATTS_MTU_EVT: {
|
||||
BLEDevice::m_localMTU = param->mtu.mtu;
|
||||
ESP_LOGI(LOG_TAG, "ESP_GATTS_MTU_EVT, MTU %d", BLEDevice::m_localMTU);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
} // switch
|
||||
|
||||
|
||||
if (BLEDevice::m_pServer != nullptr) {
|
||||
BLEDevice::m_pServer->handleGATTServerEvent(event, gatts_if, param);
|
||||
}
|
||||
@@ -96,7 +134,7 @@ void BLEDevice::gattServerEventHandler(
|
||||
* @param [in] gattc_if
|
||||
* @param [in] param
|
||||
*/
|
||||
void BLEDevice::gattClientEventHandler(
|
||||
/* STATIC */ void BLEDevice::gattClientEventHandler(
|
||||
esp_gattc_cb_event_t event,
|
||||
esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t* param) {
|
||||
@@ -104,13 +142,28 @@ void BLEDevice::gattClientEventHandler(
|
||||
ESP_LOGD(LOG_TAG, "gattClientEventHandler [esp_gatt_if: %d] ... %s",
|
||||
gattc_if, BLEUtils::gattClientEventTypeToString(event).c_str());
|
||||
BLEUtils::dumpGattClientEvent(event, gattc_if, param);
|
||||
/*
|
||||
|
||||
switch(event) {
|
||||
case ESP_GATTC_CONNECT_EVT: {
|
||||
if(BLEDevice::getMTU() != 23){
|
||||
esp_err_t errRc = esp_ble_gattc_send_mtu_req(gattc_if, param->connect.conn_id);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_send_mtu_req: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
if(BLEDevice::m_securityLevel){
|
||||
esp_ble_set_encryption(param->connect.remote_bda, BLEDevice::m_securityLevel);
|
||||
}
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
break;
|
||||
} // ESP_GATTC_CONNECT_EVT
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
} // switch
|
||||
*/
|
||||
|
||||
|
||||
// If we have a client registered, call it.
|
||||
if (BLEDevice::m_pClient != nullptr) {
|
||||
@@ -123,21 +176,84 @@ void BLEDevice::gattClientEventHandler(
|
||||
/**
|
||||
* @brief Handle GAP events.
|
||||
*/
|
||||
void BLEDevice::gapEventHandler(
|
||||
/* STATIC */ void BLEDevice::gapEventHandler(
|
||||
esp_gap_ble_cb_event_t event,
|
||||
esp_ble_gap_cb_param_t *param) {
|
||||
|
||||
BLEUtils::dumpGapEvent(event, param);
|
||||
|
||||
switch(event) {
|
||||
case ESP_GAP_BLE_SEC_REQ_EVT: {
|
||||
esp_err_t errRc = ::esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_security_rsp: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ESP_GAP_BLE_OOB_REQ_EVT: /* OOB request event */
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_OOB_REQ_EVT");
|
||||
break;
|
||||
case ESP_GAP_BLE_LOCAL_IR_EVT: /* BLE local IR event */
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_LOCAL_IR_EVT");
|
||||
break;
|
||||
case ESP_GAP_BLE_LOCAL_ER_EVT: /* BLE local ER event */
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_LOCAL_ER_EVT");
|
||||
break;
|
||||
case ESP_GAP_BLE_NC_REQ_EVT:
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_NC_REQ_EVT");
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
if(BLEDevice::m_securityCallbacks!=nullptr){
|
||||
esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, BLEDevice::m_securityCallbacks->onConfirmPIN(param->ble_security.key_notif.passkey));
|
||||
}
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
break;
|
||||
case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PASSKEY_REQ_EVT: ");
|
||||
// esp_log_buffer_hex(LOG_TAG, m_remote_bda, sizeof(m_remote_bda));
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
if(BLEDevice::m_securityCallbacks!=nullptr){
|
||||
esp_ble_passkey_reply(param->ble_security.ble_req.bd_addr, true, BLEDevice::m_securityCallbacks->onPassKeyRequest());
|
||||
}
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
break;
|
||||
/*
|
||||
* TODO should we add white/black list comparison?
|
||||
*/
|
||||
case ESP_GAP_BLE_SEC_REQ_EVT:
|
||||
/* send the positive(true) security response to the peer device to accept the security request.
|
||||
If not accept the security request, should sent the security response with negative(false) accept value*/
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_SEC_REQ_EVT");
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
if(BLEDevice::m_securityCallbacks!=nullptr){
|
||||
esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, BLEDevice::m_securityCallbacks->onSecurityRequest());
|
||||
}
|
||||
else{
|
||||
esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);
|
||||
}
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
break;
|
||||
/*
|
||||
*
|
||||
*/
|
||||
case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: ///the app will receive this evt when the IO has Output capability and the peer device IO has Input capability.
|
||||
///show the passkey number to the user to input it in the peer deivce.
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PASSKEY_NOTIF_EVT");
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
if(BLEDevice::m_securityCallbacks!=nullptr){
|
||||
ESP_LOGI(LOG_TAG, "passKey = %d", param->ble_security.key_notif.passkey);
|
||||
BLEDevice::m_securityCallbacks->onPassKeyNotify(param->ble_security.key_notif.passkey);
|
||||
}
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
break;
|
||||
case ESP_GAP_BLE_KEY_EVT:
|
||||
//shows the ble key type info share with peer device to the user.
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_KEY_EVT");
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
ESP_LOGI(LOG_TAG, "key type = %s", BLESecurity::esp_key_type_to_str(param->ble_security.ble_key.key_type));
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
break;
|
||||
case ESP_GAP_BLE_AUTH_CMPL_EVT:
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_AUTH_CMPL_EVT");
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
if(BLEDevice::m_securityCallbacks!=nullptr){
|
||||
BLEDevice::m_securityCallbacks->onAuthenticationComplete(param->ble_security.auth_cmpl);
|
||||
}
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
break;
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
@@ -154,15 +270,33 @@ void BLEDevice::gapEventHandler(
|
||||
if (BLEDevice::m_pScan != nullptr) {
|
||||
BLEDevice::getScan()->handleGAPEvent(event, param);
|
||||
}
|
||||
|
||||
/*
|
||||
* Security events:
|
||||
*/
|
||||
|
||||
|
||||
} // gapEventHandler
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the BLE device address.
|
||||
* @return The BLE device address.
|
||||
*/
|
||||
/* STATIC*/ BLEAddress BLEDevice::getAddress() {
|
||||
const uint8_t* bdAddr = esp_bt_dev_get_address();
|
||||
esp_bd_addr_t addr;
|
||||
memcpy(addr, bdAddr, sizeof(addr));
|
||||
return BLEAddress(addr);
|
||||
} // getAddress
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the Scan object that we use for scanning.
|
||||
* @return The scanning object reference. This is a singleton object. The caller should not
|
||||
* try and release/delete it.
|
||||
*/
|
||||
BLEScan* BLEDevice::getScan() {
|
||||
/* STATIC */ BLEScan* BLEDevice::getScan() {
|
||||
//ESP_LOGD(LOG_TAG, ">> getScan");
|
||||
if (m_pScan == nullptr) {
|
||||
m_pScan = new BLEScan();
|
||||
@@ -173,25 +307,51 @@ BLEScan* BLEDevice::getScan() {
|
||||
} // getScan
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the value of a characteristic of a service on a remote device.
|
||||
* @param [in] bdAddress
|
||||
* @param [in] serviceUUID
|
||||
* @param [in] characteristicUUID
|
||||
*/
|
||||
/* STATIC */ std::string BLEDevice::getValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID) {
|
||||
ESP_LOGD(LOG_TAG, ">> getValue: bdAddress: %s, serviceUUID: %s, characteristicUUID: %s", bdAddress.toString().c_str(), serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||
BLEClient *pClient = createClient();
|
||||
pClient->connect(bdAddress);
|
||||
std::string ret = pClient->getValue(serviceUUID, characteristicUUID);
|
||||
pClient->disconnect();
|
||||
ESP_LOGD(LOG_TAG, "<< getValue");
|
||||
return ret;
|
||||
} // getValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initialize the %BLE environment.
|
||||
* @param deviceName The device name of the device.
|
||||
*/
|
||||
void BLEDevice::init(std::string deviceName) {
|
||||
/* STATIC */ void BLEDevice::init(std::string deviceName) {
|
||||
if(!initialized){
|
||||
initialized = true;
|
||||
esp_err_t errRc = ::nvs_flash_init();
|
||||
initialized = true; // Set the initialization flag to ensure we are only initialized once.
|
||||
|
||||
esp_err_t errRc = ESP_OK;
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
if (!btStart()) {
|
||||
errRc = ESP_FAIL;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
errRc = ::nvs_flash_init();
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "nvs_flash_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
errRc = esp_bt_controller_init(&bt_cfg);
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
errRc = esp_bt_controller_init(&bt_cfg);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_bt_controller_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef CLASSIC_BT_ENABLED
|
||||
// esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); //FIXME waiting for response from esp-idf issue
|
||||
errRc = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
||||
@@ -207,16 +367,23 @@ void BLEDevice::init(std::string deviceName) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
errRc = esp_bluedroid_init();
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_bluedroid_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
#endif
|
||||
|
||||
esp_bluedroid_status_t bt_state = esp_bluedroid_get_status();
|
||||
if (bt_state == ESP_BLUEDROID_STATUS_UNINITIALIZED){
|
||||
errRc = esp_bluedroid_init();
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_bluedroid_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
errRc = esp_bluedroid_enable();
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_bluedroid_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
if (bt_state != ESP_BLUEDROID_STATUS_ENABLED){
|
||||
errRc = esp_bluedroid_enable();
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_bluedroid_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
errRc = esp_ble_gap_register_callback(BLEDevice::gapEventHandler);
|
||||
@@ -225,17 +392,21 @@ void BLEDevice::init(std::string deviceName) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GATTC_ENABLE // Check that BLE client is configured in make menuconfig
|
||||
errRc = esp_ble_gattc_register_callback(BLEDevice::gattClientEventHandler);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
#endif // CONFIG_GATTC_ENABLE
|
||||
|
||||
#ifdef CONFIG_GATTS_ENABLE // Check that BLE server is configured in make menuconfig
|
||||
errRc = esp_ble_gatts_register_callback(BLEDevice::gattServerEventHandler);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gatts_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
#endif // CONFIG_GATTS_ENABLE
|
||||
|
||||
errRc = ::esp_ble_gap_set_device_name(deviceName.c_str());
|
||||
if (errRc != ESP_OK) {
|
||||
@@ -243,12 +414,14 @@ void BLEDevice::init(std::string deviceName) {
|
||||
return;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE;
|
||||
errRc = ::esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_set_security_param: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
};
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
}
|
||||
vTaskDelay(200/portTICK_PERIOD_MS); // Delay for 200 msecs as a workaround to an apparent Arduino environment issue.
|
||||
} // init
|
||||
@@ -276,4 +449,100 @@ void BLEDevice::init(std::string deviceName) {
|
||||
ESP_LOGD(LOG_TAG, "<< setPower");
|
||||
} // setPower
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of a characteristic of a service on a remote device.
|
||||
* @param [in] bdAddress
|
||||
* @param [in] serviceUUID
|
||||
* @param [in] characteristicUUID
|
||||
*/
|
||||
/* STATIC */ void BLEDevice::setValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value) {
|
||||
ESP_LOGD(LOG_TAG, ">> setValue: bdAddress: %s, serviceUUID: %s, characteristicUUID: %s", bdAddress.toString().c_str(), serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||
BLEClient *pClient = createClient();
|
||||
pClient->connect(bdAddress);
|
||||
pClient->setValue(serviceUUID, characteristicUUID, value);
|
||||
pClient->disconnect();
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of the nature of this device.
|
||||
* @return A string representation of the nature of this device.
|
||||
*/
|
||||
/* STATIC */ std::string BLEDevice::toString() {
|
||||
std::ostringstream oss;
|
||||
oss << "BD Address: " << getAddress().toString();
|
||||
return oss.str();
|
||||
} // toString
|
||||
|
||||
|
||||
/**
|
||||
* @brief Add an entry to the BLE white list.
|
||||
* @param [in] address The address to add to the white list.
|
||||
*/
|
||||
void BLEDevice::whiteListAdd(BLEAddress address) {
|
||||
ESP_LOGD(LOG_TAG, ">> whiteListAdd: %s", address.toString().c_str());
|
||||
esp_err_t errRc = esp_ble_gap_update_whitelist(true, *address.getNative()); // True to add an entry.
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_update_whitelist: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "<< whiteListAdd");
|
||||
} // whiteListAdd
|
||||
|
||||
|
||||
/**
|
||||
* @brief Remove an entry from the BLE white list.
|
||||
* @param [in] address The address to remove from the white list.
|
||||
*/
|
||||
void BLEDevice::whiteListRemove(BLEAddress address) {
|
||||
ESP_LOGD(LOG_TAG, ">> whiteListRemove: %s", address.toString().c_str());
|
||||
esp_err_t errRc = esp_ble_gap_update_whitelist(false, *address.getNative()); // False to remove an entry.
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_update_whitelist: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "<< whiteListRemove");
|
||||
} // whiteListRemove
|
||||
|
||||
/*
|
||||
* @brief Set encryption level that will be negotiated with peer device durng connection
|
||||
* @param [in] level Requested encryption level
|
||||
*/
|
||||
void BLEDevice::setEncryptionLevel(esp_ble_sec_act_t level) {
|
||||
BLEDevice::m_securityLevel = level;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Set callbacks that will be used to handle encryption negotiation events and authentication events
|
||||
* @param [in] cllbacks Pointer to BLESecurityCallbacks class callback
|
||||
*/
|
||||
void BLEDevice::setSecurityCallbacks(BLESecurityCallbacks* callbacks) {
|
||||
BLEDevice::m_securityCallbacks = callbacks;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Setup local mtu that will be used to negotiate mtu during request from client peer
|
||||
* @param [in] mtu Value to set local mtu, should be larger than 23 and lower or equal to 517
|
||||
*/
|
||||
esp_err_t BLEDevice::setMTU(uint16_t mtu) {
|
||||
ESP_LOGD(LOG_TAG, ">> setLocalMTU: %d", mtu);
|
||||
esp_err_t err = esp_ble_gatt_set_local_mtu(mtu);
|
||||
if(err == ESP_OK){
|
||||
m_localMTU = mtu;
|
||||
} else {
|
||||
ESP_LOGE(LOG_TAG, "can't set local mtu value: %d", mtu);
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "<< setLocalMTU");
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Get local MTU value set during mtu request or default value
|
||||
*/
|
||||
uint16_t BLEDevice::getMTU() {
|
||||
return m_localMTU;
|
||||
}
|
||||
|
||||
bool BLEDevice::getInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
@@ -13,29 +13,44 @@
|
||||
#include <esp_gattc_api.h> // ESP32 BLE
|
||||
#include <map> // Part of C++ STL
|
||||
#include <string>
|
||||
#include <bt.h>
|
||||
#include <esp_bt.h>
|
||||
|
||||
#include "BLEServer.h"
|
||||
#include "BLEClient.h"
|
||||
#include "BLEUtils.h"
|
||||
#include "BLEScan.h"
|
||||
#include "BLEAddress.h"
|
||||
|
||||
/**
|
||||
* @brief %BLE functions.
|
||||
*/
|
||||
class BLEDevice {
|
||||
public:
|
||||
|
||||
static BLEClient* createClient();
|
||||
static BLEServer* createServer();
|
||||
static void dumpDevices();
|
||||
static BLEScan* getScan();
|
||||
static void init(std::string deviceName);
|
||||
static BLEClient* createClient(); // Create a new BLE client.
|
||||
static BLEServer* createServer(); // Cretae a new BLE server.
|
||||
static BLEAddress getAddress(); // Retrieve our own local BD address.
|
||||
static BLEScan* getScan(); // Get the scan object
|
||||
static std::string getValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID); // Get the value of a characteristic of a service on a server.
|
||||
static void init(std::string deviceName); // Initialize the local BLE environment.
|
||||
static void setPower(esp_power_level_t powerLevel); // Set our power level.
|
||||
static void setValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value); // Set the value of a characteristic on a service on a server.
|
||||
static std::string toString(); // Return a string representation of our device.
|
||||
static void whiteListAdd(BLEAddress address); // Add an entry to the BLE white list.
|
||||
static void whiteListRemove(BLEAddress address); // Remove an entry from the BLE white list.
|
||||
static void setEncryptionLevel(esp_ble_sec_act_t level);
|
||||
static void setSecurityCallbacks(BLESecurityCallbacks* pCallbacks);
|
||||
static esp_err_t setMTU(uint16_t mtu);
|
||||
static uint16_t getMTU();
|
||||
static bool getInitialized(); // Returns the state of the device, is it initialized or not?
|
||||
|
||||
private:
|
||||
static BLEServer *m_pServer;
|
||||
static BLEScan *m_pScan;
|
||||
static BLEClient *m_pClient;
|
||||
static esp_ble_sec_act_t m_securityLevel;
|
||||
static BLESecurityCallbacks* m_securityCallbacks;
|
||||
static uint16_t m_localMTU;
|
||||
|
||||
static esp_gatt_if_t getGattcIF();
|
||||
|
||||
@@ -53,9 +68,6 @@ private:
|
||||
esp_gap_ble_cb_event_t event,
|
||||
esp_ble_gap_cb_param_t* param);
|
||||
|
||||
public:
|
||||
static void setPower(esp_power_level_t powerLevel);
|
||||
|
||||
}; // class BLE
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* BLExceptions.cpp
|
||||
*
|
||||
* Created on: Nov 27, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#include "BLEExceptions.h"
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* BLExceptions.h
|
||||
*
|
||||
* Created on: Nov 27, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLEEXCEPTIONS_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLEEXCEPTIONS_H_
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_CXX_EXCEPTIONS != 1
|
||||
#error "C++ exception handling must be enabled within make menuconfig. See Compiler Options > Enable C++ Exceptions."
|
||||
#endif
|
||||
|
||||
#include <exception>
|
||||
|
||||
|
||||
class BLEDisconnectedException : public std::exception {
|
||||
const char *what() const throw () {
|
||||
return "BLE Disconnected";
|
||||
}
|
||||
};
|
||||
|
||||
class BLEUuidNotFoundException : public std::exception {
|
||||
const char *what() const throw () {
|
||||
return "No such UUID";
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLEEXCEPTIONS_H_ */
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* BLEHIDDevice.cpp
|
||||
*
|
||||
* Created on: Jan 03, 2018
|
||||
* Author: chegewara
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "BLEHIDDevice.h"
|
||||
#include "BLE2904.h"
|
||||
|
||||
|
||||
BLEHIDDevice::BLEHIDDevice(BLEServer* server) {
|
||||
/*
|
||||
* Here we create mandatory services described in bluetooth specification
|
||||
*/
|
||||
m_deviceInfoService = server->createService(BLEUUID((uint16_t) 0x180a));
|
||||
m_hidService = server->createService(BLEUUID((uint16_t) 0x1812), 40);
|
||||
m_batteryService = server->createService(BLEUUID((uint16_t) 0x180f));
|
||||
|
||||
/*
|
||||
* Mandatory characteristic for device info service
|
||||
*/
|
||||
m_pnpCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t)0x2a50, BLECharacteristic::PROPERTY_READ);
|
||||
|
||||
/*
|
||||
* Mandatory characteristics for HID service
|
||||
*/
|
||||
m_hidInfoCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4a, BLECharacteristic::PROPERTY_READ);
|
||||
m_reportMapCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4b, BLECharacteristic::PROPERTY_READ);
|
||||
m_hidControlCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4c, BLECharacteristic::PROPERTY_WRITE_NR);
|
||||
m_protocolModeCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4e, BLECharacteristic::PROPERTY_WRITE_NR | BLECharacteristic::PROPERTY_READ);
|
||||
|
||||
/*
|
||||
* Mandatory battery level characteristic with notification and presence descriptor
|
||||
*/
|
||||
BLE2904* batteryLevelDescriptor = new BLE2904();
|
||||
batteryLevelDescriptor->setFormat(BLE2904::FORMAT_UINT8);
|
||||
batteryLevelDescriptor->setNamespace(1);
|
||||
batteryLevelDescriptor->setUnit(0x27ad);
|
||||
|
||||
m_batteryLevelCharacteristic = m_batteryService->createCharacteristic((uint16_t)0x2a19, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
|
||||
m_batteryLevelCharacteristic->addDescriptor(batteryLevelDescriptor);
|
||||
m_batteryLevelCharacteristic->addDescriptor(new BLE2902());
|
||||
|
||||
/*
|
||||
* This value is setup here because its default value in most usage cases, its very rare to use boot mode
|
||||
* and we want to simplify library using as much as possible
|
||||
*/
|
||||
const uint8_t pMode[] = {0x01};
|
||||
protocolMode()->setValue((uint8_t*)pMode, 1);
|
||||
}
|
||||
|
||||
BLEHIDDevice::~BLEHIDDevice() {
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void BLEHIDDevice::reportMap(uint8_t* map, uint16_t size) {
|
||||
m_reportMapCharacteristic->setValue(map, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief This function suppose to be called at the end, when we have created all characteristics we need to build HID service
|
||||
*/
|
||||
void BLEHIDDevice::startServices() {
|
||||
m_deviceInfoService->start();
|
||||
m_hidService->start();
|
||||
m_batteryService->start();
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Create manufacturer characteristic (this characteristic is optional)
|
||||
*/
|
||||
BLECharacteristic* BLEHIDDevice::manufacturer() {
|
||||
m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t)0x2a29, BLECharacteristic::PROPERTY_READ);
|
||||
return m_manufacturerCharacteristic;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Set manufacturer name
|
||||
* @param [in] name manufacturer name
|
||||
*/
|
||||
void BLEHIDDevice::manufacturer(std::string name) {
|
||||
m_manufacturerCharacteristic->setValue(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void BLEHIDDevice::pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version) {
|
||||
uint8_t pnp[] = {sig, (uint8_t)(vid>>8), (uint8_t)vid, (uint8_t)(pid>>8), (uint8_t)pid, (uint8_t)(version>>8), (uint8_t)version};
|
||||
m_pnpCharacteristic->setValue(pnp, sizeof(pnp));
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
void BLEHIDDevice::hidInfo(uint8_t country, uint8_t flags) {
|
||||
uint8_t info[] = {0x11,0x1, country, flags};
|
||||
m_hidInfoCharacteristic->setValue(info, sizeof(info));;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Create input report characteristic that need to be saved as new characteristic object so can be further used
|
||||
* @param [in] reportID input report ID, the same as in report map for input object related to created characteristic
|
||||
* @return pointer to new input report characteristic
|
||||
*/
|
||||
BLECharacteristic* BLEHIDDevice::inputReport(uint8_t reportID) {
|
||||
BLECharacteristic* inputReportCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4d, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
|
||||
BLEDescriptor* inputReportDescriptor = new BLEDescriptor(BLEUUID((uint16_t)0x2908));
|
||||
|
||||
uint8_t desc1_val[] = {reportID, 0x01};
|
||||
inputReportDescriptor->setValue((uint8_t*)desc1_val, 2);
|
||||
inputReportCharacteristic->addDescriptor(new BLE2902());
|
||||
inputReportCharacteristic->addDescriptor(inputReportDescriptor);
|
||||
|
||||
return inputReportCharacteristic;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Create output report characteristic that need to be saved as new characteristic object so can be further used
|
||||
* @param [in] reportID Output report ID, the same as in report map for output object related to created characteristic
|
||||
* @return Pointer to new output report characteristic
|
||||
*/
|
||||
BLECharacteristic* BLEHIDDevice::outputReport(uint8_t reportID) {
|
||||
BLECharacteristic* outputReportCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4d, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR);
|
||||
BLEDescriptor* outputReportDescriptor = new BLEDescriptor(BLEUUID((uint16_t)0x2908));
|
||||
|
||||
uint8_t desc1_val[] = {reportID, 0x02};
|
||||
outputReportDescriptor->setValue((uint8_t*)desc1_val, 2);
|
||||
outputReportCharacteristic->addDescriptor(outputReportDescriptor);
|
||||
|
||||
return outputReportCharacteristic;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Create feature report characteristic that need to be saved as new characteristic object so can be further used
|
||||
* @param [in] reportID Feature report ID, the same as in report map for feature object related to created characteristic
|
||||
* @return Pointer to new feature report characteristic
|
||||
*/
|
||||
BLECharacteristic* BLEHIDDevice::featureReport(uint8_t reportID) {
|
||||
BLECharacteristic* featureReportCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4d, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE);
|
||||
BLEDescriptor* featureReportDescriptor = new BLEDescriptor(BLEUUID((uint16_t)0x2908));
|
||||
|
||||
uint8_t desc1_val[] = {reportID, 0x03};
|
||||
featureReportDescriptor->setValue((uint8_t*)desc1_val, 2);
|
||||
featureReportCharacteristic->addDescriptor(featureReportDescriptor);
|
||||
|
||||
return featureReportCharacteristic;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
BLECharacteristic* BLEHIDDevice::bootInput() {
|
||||
BLECharacteristic* bootInputCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a22, BLECharacteristic::PROPERTY_NOTIFY);
|
||||
bootInputCharacteristic->addDescriptor(new BLE2902());
|
||||
|
||||
return bootInputCharacteristic;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
BLECharacteristic* BLEHIDDevice::bootOutput() {
|
||||
return m_hidService->createCharacteristic((uint16_t)0x2a32, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
BLECharacteristic* BLEHIDDevice::hidControl() {
|
||||
return m_hidControlCharacteristic;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
BLECharacteristic* BLEHIDDevice::protocolMode() {
|
||||
return m_protocolModeCharacteristic;
|
||||
}
|
||||
|
||||
void BLEHIDDevice::setBatteryLevel(uint8_t level) {
|
||||
m_batteryLevelCharacteristic->setValue(&level, 1);
|
||||
}
|
||||
/*
|
||||
* @brief Returns battery level characteristic
|
||||
* @ return battery level characteristic
|
||||
*//*
|
||||
BLECharacteristic* BLEHIDDevice::batteryLevel() {
|
||||
return m_batteryLevelCharacteristic;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BLECharacteristic* BLEHIDDevice::reportMap() {
|
||||
return m_reportMapCharacteristic;
|
||||
}
|
||||
|
||||
BLECharacteristic* BLEHIDDevice::pnp() {
|
||||
return m_pnpCharacteristic;
|
||||
}
|
||||
|
||||
|
||||
BLECharacteristic* BLEHIDDevice::hidInfo() {
|
||||
return m_hidInfoCharacteristic;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
BLEService* BLEHIDDevice::deviceInfo() {
|
||||
return m_deviceInfoService;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
BLEService* BLEHIDDevice::hidService() {
|
||||
return m_hidService;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief
|
||||
*/
|
||||
BLEService* BLEHIDDevice::batteryService() {
|
||||
return m_batteryService;
|
||||
}
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* BLEHIDDevice.h
|
||||
*
|
||||
* Created on: Jan 03, 2018
|
||||
* Author: chegewara
|
||||
*/
|
||||
|
||||
#ifndef _BLEHIDDEVICE_H_
|
||||
#define _BLEHIDDEVICE_H_
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include "BLECharacteristic.h"
|
||||
#include "BLEService.h"
|
||||
#include "BLEDescriptor.h"
|
||||
#include "BLE2902.h"
|
||||
#include "HIDTypes.h"
|
||||
|
||||
#define GENERIC_HID 960
|
||||
#define HID_KEYBOARD 961
|
||||
#define HID_MOUSE 962
|
||||
#define HID_JOYSTICK 963
|
||||
#define HID_GAMEPAD 964
|
||||
#define HID_TABLET 965
|
||||
#define HID_CARD_READER 966
|
||||
#define HID_DIGITAL_PEN 967
|
||||
#define HID_BARCODE 968
|
||||
|
||||
class BLEHIDDevice {
|
||||
public:
|
||||
BLEHIDDevice(BLEServer*);
|
||||
virtual ~BLEHIDDevice();
|
||||
|
||||
void reportMap(uint8_t* map, uint16_t);
|
||||
void startServices();
|
||||
|
||||
BLEService* deviceInfo();
|
||||
BLEService* hidService();
|
||||
BLEService* batteryService();
|
||||
|
||||
BLECharacteristic* manufacturer();
|
||||
void manufacturer(std::string name);
|
||||
//BLECharacteristic* pnp();
|
||||
void pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version);
|
||||
//BLECharacteristic* hidInfo();
|
||||
void hidInfo(uint8_t country, uint8_t flags);
|
||||
//BLECharacteristic* batteryLevel();
|
||||
void setBatteryLevel(uint8_t level);
|
||||
|
||||
|
||||
//BLECharacteristic* reportMap();
|
||||
BLECharacteristic* hidControl();
|
||||
BLECharacteristic* inputReport(uint8_t reportID);
|
||||
BLECharacteristic* outputReport(uint8_t reportID);
|
||||
BLECharacteristic* featureReport(uint8_t reportID);
|
||||
BLECharacteristic* protocolMode();
|
||||
BLECharacteristic* bootInput();
|
||||
BLECharacteristic* bootOutput();
|
||||
|
||||
private:
|
||||
BLEService* m_deviceInfoService; //0x180a
|
||||
BLEService* m_hidService; //0x1812
|
||||
BLEService* m_batteryService = 0; //0x180f
|
||||
|
||||
BLECharacteristic* m_manufacturerCharacteristic; //0x2a29
|
||||
BLECharacteristic* m_pnpCharacteristic; //0x2a50
|
||||
BLECharacteristic* m_hidInfoCharacteristic; //0x2a4a
|
||||
BLECharacteristic* m_reportMapCharacteristic; //0x2a4b
|
||||
BLECharacteristic* m_hidControlCharacteristic; //0x2a4c
|
||||
BLECharacteristic* m_protocolModeCharacteristic; //0x2a4e
|
||||
BLECharacteristic* m_batteryLevelCharacteristic; //0x2a19
|
||||
};
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif /* _BLEHIDDEVICE_H_ */
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <esp_err.h>
|
||||
|
||||
#include <sstream>
|
||||
#include "BLEExceptions.h"
|
||||
#include "BLEUtils.h"
|
||||
#include "GeneralUtils.h"
|
||||
#include "BLERemoteDescriptor.h"
|
||||
@@ -432,6 +433,12 @@ uint8_t BLERemoteCharacteristic::readUInt8(void) {
|
||||
std::string BLERemoteCharacteristic::readValue() {
|
||||
ESP_LOGD(LOG_TAG, ">> readValue(): uuid: %s, handle: %d 0x%.2x", getUUID().toString().c_str(), getHandle(), getHandle());
|
||||
|
||||
// Check to see that we are connected.
|
||||
if (!getRemoteService()->getClient()->isConnected()) {
|
||||
ESP_LOGE(LOG_TAG, "Disconnected");
|
||||
throw BLEDisconnectedException();
|
||||
}
|
||||
|
||||
m_semaphoreReadCharEvt.take("readValue");
|
||||
|
||||
// Ask the BLE subsystem to retrieve the value for the remote hosted characteristic.
|
||||
@@ -543,6 +550,12 @@ std::string BLERemoteCharacteristic::toString() {
|
||||
void BLERemoteCharacteristic::writeValue(std::string newValue, bool response) {
|
||||
ESP_LOGD(LOG_TAG, ">> writeValue(), length: %d", newValue.length());
|
||||
|
||||
// Check to see that we are connected.
|
||||
if (!getRemoteService()->getClient()->isConnected()) {
|
||||
ESP_LOGE(LOG_TAG, "Disconnected");
|
||||
throw BLEDisconnectedException();
|
||||
}
|
||||
|
||||
m_semaphoreWriteCharEvt.take("writeValue");
|
||||
|
||||
// Invoke the ESP-IDF API to perform the write.
|
||||
|
||||
@@ -27,6 +27,7 @@ BLERemoteDescriptor::BLERemoteDescriptor(
|
||||
m_pRemoteCharacteristic = pRemoteCharacteristic;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the handle associated with this remote descriptor.
|
||||
* @return The handle associated with this remote descriptor.
|
||||
@@ -36,6 +37,15 @@ uint16_t BLERemoteDescriptor::getHandle() {
|
||||
} // getHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the characteristic that owns this descriptor.
|
||||
* @return The characteristic that owns this descriptor.
|
||||
*/
|
||||
BLERemoteCharacteristic* BLERemoteDescriptor::getRemoteCharacteristic() {
|
||||
return m_pRemoteCharacteristic;
|
||||
} // getRemoteCharacteristic
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve the UUID associated this remote descriptor.
|
||||
* @return The UUID associated this remote descriptor.
|
||||
@@ -46,6 +56,14 @@ BLEUUID BLERemoteDescriptor::getUUID() {
|
||||
|
||||
|
||||
std::string BLERemoteDescriptor::readValue(void) {
|
||||
ESP_LOGD(LOG_TAG, ">> readValue: %s", toString().c_str());
|
||||
|
||||
// Check to see that we are connected.
|
||||
if (!getRemoteCharacteristic()->getRemoteService()->getClient()->isConnected()) {
|
||||
ESP_LOGE(LOG_TAG, "Disconnected");
|
||||
throw BLEDisconnectedException();
|
||||
}
|
||||
|
||||
m_semaphoreReadDescrEvt.take("readValue");
|
||||
|
||||
// Ask the BLE subsystem to retrieve the value for the remote hosted characteristic.
|
||||
@@ -66,7 +84,6 @@ std::string BLERemoteDescriptor::readValue(void) {
|
||||
|
||||
ESP_LOGD(LOG_TAG, "<< readValue(): length: %d", m_value.length());
|
||||
return m_value;
|
||||
return "";
|
||||
} // readValue
|
||||
|
||||
|
||||
@@ -119,6 +136,12 @@ void BLERemoteDescriptor::writeValue(
|
||||
size_t length,
|
||||
bool response) {
|
||||
ESP_LOGD(LOG_TAG, ">> writeValue: %s", toString().c_str());
|
||||
// Check to see that we are connected.
|
||||
if (!getRemoteCharacteristic()->getRemoteService()->getClient()->isConnected()) {
|
||||
ESP_LOGE(LOG_TAG, "Disconnected");
|
||||
throw BLEDisconnectedException();
|
||||
}
|
||||
|
||||
esp_err_t errRc = ::esp_ble_gattc_write_char_descr(
|
||||
m_pRemoteCharacteristic->getRemoteService()->getClient()->getGattcIf(),
|
||||
m_pRemoteCharacteristic->getRemoteService()->getClient()->getConnId(),
|
||||
|
||||
@@ -24,13 +24,13 @@ class BLERemoteCharacteristic;
|
||||
class BLERemoteDescriptor {
|
||||
public:
|
||||
uint16_t getHandle();
|
||||
BLERemoteCharacteristic* getRemoteCharacteristic();
|
||||
BLEUUID getUUID();
|
||||
std::string readValue(void);
|
||||
uint8_t readUInt8(void);
|
||||
uint16_t readUInt16(void);
|
||||
uint32_t readUInt32(void);
|
||||
std::string toString(void);
|
||||
//void registerForNotify(void (*notifyCallback)(BLERemoteCharacteristic *pBLERemoteCharacteristic, uint8_t *pData, size_t length, bool isNotify));
|
||||
void writeValue(uint8_t* data, size_t length, bool response = false);
|
||||
void writeValue(std::string newValue, bool response = false);
|
||||
void writeValue(uint8_t newValue, bool response = false);
|
||||
|
||||
@@ -115,7 +115,7 @@ void BLERemoteService::gattClientEventHandler(
|
||||
|
||||
// Send the event to each of the characteristics owned by this service.
|
||||
for (auto &myPair : m_characteristicMap) {
|
||||
myPair.first->gattClientEventHandler(event, gattc_if, evtParam);
|
||||
myPair.second->gattClientEventHandler(event, gattc_if, evtParam);
|
||||
}
|
||||
} // gattClientEventHandler
|
||||
|
||||
@@ -124,6 +124,7 @@ void BLERemoteService::gattClientEventHandler(
|
||||
* @brief Get the remote characteristic object for the characteristic UUID.
|
||||
* @param [in] uuid Remote characteristic uuid.
|
||||
* @return Reference to the remote characteristic object.
|
||||
* @throws BLEUuidNotFoundException
|
||||
*/
|
||||
BLERemoteCharacteristic* BLERemoteService::getCharacteristic(const char* uuid) {
|
||||
return getCharacteristic(BLEUUID(uuid));
|
||||
@@ -134,6 +135,7 @@ BLERemoteCharacteristic* BLERemoteService::getCharacteristic(const char* uuid) {
|
||||
* @brief Get the characteristic object for the UUID.
|
||||
* @param [in] uuid Characteristic uuid.
|
||||
* @return Reference to the characteristic object.
|
||||
* @throws BLEUuidNotFoundException
|
||||
*/
|
||||
BLERemoteCharacteristic* BLERemoteService::getCharacteristic(BLEUUID uuid) {
|
||||
// Design
|
||||
@@ -147,11 +149,11 @@ BLERemoteCharacteristic* BLERemoteService::getCharacteristic(BLEUUID uuid) {
|
||||
}
|
||||
std::string v = uuid.toString();
|
||||
for (auto &myPair : m_characteristicMap) {
|
||||
if (myPair.second == v) {
|
||||
return myPair.first;
|
||||
if (myPair.first == v) {
|
||||
return myPair.second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
throw new BLEUuidNotFoundException();
|
||||
} // getCharacteristic
|
||||
|
||||
|
||||
@@ -165,60 +167,6 @@ void BLERemoteService::retrieveCharacteristics() {
|
||||
ESP_LOGD(LOG_TAG, ">> getCharacteristics() for service: %s", getUUID().toString().c_str());
|
||||
|
||||
removeCharacteristics(); // Forget any previous characteristics.
|
||||
/*
|
||||
m_semaphoreGetCharEvt.take("getCharacteristics");
|
||||
|
||||
esp_err_t errRc = ::esp_ble_gattc_get_characteristic(
|
||||
m_pClient->getGattcIf(),
|
||||
m_pClient->getConnId(),
|
||||
&m_srvcId,
|
||||
nullptr);
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_get_characteristic: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
|
||||
m_semaphoreGetCharEvt.wait("getCharacteristics"); // Wait for the characteristics to become available.
|
||||
|
||||
m_haveCharacteristics = true; // Remember that we have received the characteristics.
|
||||
*/
|
||||
//ESP_LOGE(LOG_TAG, "!!! NOT IMPLEMENTED !!!");
|
||||
//ESP_LOGD(LOG_TAG, "--- test code ---");
|
||||
/*
|
||||
uint16_t count;
|
||||
esp_gatt_status_t status = ::esp_ble_gattc_get_attr_count(
|
||||
getClient()->getGattcIf(),
|
||||
getClient()->getConnId(),
|
||||
ESP_GATT_DB_CHARACTERISTIC,
|
||||
m_startHandle,
|
||||
m_endHandle,
|
||||
0, // Characteristic handle ... only used for ESP_GATT_DB_DESCRIPTOR
|
||||
&count
|
||||
);
|
||||
if (status != ESP_GATT_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_get_attr_count: %s", BLEUtils::gattStatusToString(status).c_str());
|
||||
} else {
|
||||
ESP_LOGD(LOG_TAG, "Number of characteristics associated with service is %d", count);
|
||||
}
|
||||
|
||||
count = 1;
|
||||
esp_gattc_service_elem_t srvcElem;
|
||||
status = ::esp_ble_gattc_get_service(
|
||||
getClient()->getGattcIf(),
|
||||
getClient()->getConnId(),
|
||||
&m_srvcId.uuid, // UUID of service
|
||||
&srvcElem, // Records
|
||||
&count, // records retrieved
|
||||
0 // offset
|
||||
);
|
||||
if (status != ESP_GATT_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_get_service: %s", BLEUtils::gattStatusToString(status).c_str());
|
||||
}
|
||||
else {
|
||||
ESP_LOGD(LOG_TAG, "%s", BLEUtils::gattcServiceElementToString(&srvcElem).c_str());
|
||||
}
|
||||
*/
|
||||
|
||||
uint16_t offset = 0;
|
||||
esp_gattc_char_elem_t result;
|
||||
@@ -257,7 +205,7 @@ void BLERemoteService::retrieveCharacteristics() {
|
||||
this
|
||||
);
|
||||
|
||||
m_characteristicMap.insert(std::pair<BLERemoteCharacteristic*, std::string>(pNewRemoteCharacteristic, pNewRemoteCharacteristic->getUUID().toString()));
|
||||
m_characteristicMap.insert(std::pair<std::string, BLERemoteCharacteristic*>(pNewRemoteCharacteristic->getUUID().toString(), pNewRemoteCharacteristic));
|
||||
|
||||
offset++; // Increment our count of number of descriptors found.
|
||||
} // Loop forever (until we break inside the loop).
|
||||
@@ -271,7 +219,7 @@ void BLERemoteService::retrieveCharacteristics() {
|
||||
* @brief Retrieve a map of all the characteristics of this service.
|
||||
* @return A map of all the characteristics of this service.
|
||||
*/
|
||||
std::map<BLERemoteCharacteristic*, std::string>* BLERemoteService::getCharacteristics() {
|
||||
std::map<std::string, BLERemoteCharacteristic *> * BLERemoteService::getCharacteristics() {
|
||||
ESP_LOGD(LOG_TAG, ">> getCharacteristics() for service: %s", getUUID().toString().c_str());
|
||||
// If is possible that we have not read the characteristics associated with the service so do that
|
||||
// now. The request to retrieve the characteristics by calling "retrieveCharacteristics" is a blocking
|
||||
@@ -284,37 +232,52 @@ std::map<BLERemoteCharacteristic*, std::string>* BLERemoteService::getCharacteri
|
||||
} // getCharacteristics
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the client associated with this service.
|
||||
* @return A reference to the client associated with this service.
|
||||
*/
|
||||
BLEClient* BLERemoteService::getClient() {
|
||||
return m_pClient;
|
||||
}
|
||||
} // getClient
|
||||
|
||||
|
||||
uint16_t BLERemoteService::getEndHandle() {
|
||||
return m_endHandle;
|
||||
}
|
||||
} // getEndHandle
|
||||
|
||||
|
||||
esp_gatt_id_t* BLERemoteService::getSrvcId() {
|
||||
return &m_srvcId;
|
||||
}
|
||||
} // getSrvcId
|
||||
|
||||
|
||||
uint16_t BLERemoteService::getStartHandle() {
|
||||
return m_startHandle;
|
||||
}
|
||||
} // getStartHandle
|
||||
|
||||
|
||||
uint16_t BLERemoteService::getHandle() {
|
||||
ESP_LOGD(LOG_TAG, ">> getHandle: service: %s", getUUID().toString().c_str());
|
||||
//ESP_LOGE(LOG_TAG, "!!! getHandle: NOT IMPLEMENTED !!!");
|
||||
ESP_LOGD(LOG_TAG, "<< getHandle: %d 0x%.2x", getStartHandle(), getStartHandle());
|
||||
return getStartHandle();
|
||||
}
|
||||
} // getHandle
|
||||
|
||||
|
||||
BLEUUID BLERemoteService::getUUID() {
|
||||
return m_uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read the value of a characteristic associated with this service.
|
||||
*/
|
||||
std::string BLERemoteService::getValue(BLEUUID characteristicUuid) {
|
||||
ESP_LOGD(LOG_TAG, ">> readValue: uuid: %s", characteristicUuid.toString().c_str());
|
||||
std::string ret = getCharacteristic(characteristicUuid)->readValue();
|
||||
ESP_LOGD(LOG_TAG, "<< readValue");
|
||||
return ret;
|
||||
} // readValue
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Delete the characteristics in the characteristics map.
|
||||
@@ -325,13 +288,25 @@ BLEUUID BLERemoteService::getUUID() {
|
||||
*/
|
||||
void BLERemoteService::removeCharacteristics() {
|
||||
for (auto &myPair : m_characteristicMap) {
|
||||
delete myPair.first;
|
||||
m_characteristicMap.erase(myPair.first);
|
||||
delete myPair.second;
|
||||
//m_characteristicMap.erase(myPair.first); // Should be no need to delete as it will be deleted by the clear
|
||||
}
|
||||
m_characteristicMap.clear(); // Clear the map
|
||||
} // removeCharacteristics
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the value of a characteristic.
|
||||
* @param [in] characteristicUuid The characteristic to set.
|
||||
* @param [in] value The value to set.
|
||||
* @throws BLEUuidNotFound
|
||||
*/
|
||||
void BLERemoteService::setValue(BLEUUID characteristicUuid, std::string value) {
|
||||
ESP_LOGD(LOG_TAG, ">> setValue: uuid: %s", characteristicUuid.toString().c_str());
|
||||
getCharacteristic(characteristicUuid)->writeValue(value);
|
||||
ESP_LOGD(LOG_TAG, "<< setValue");
|
||||
} // setValue
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a string representation of this remote service.
|
||||
@@ -343,14 +318,11 @@ std::string BLERemoteService::toString() {
|
||||
ss << ", start_handle: " << std::dec << m_startHandle << " 0x" << std::hex << m_startHandle <<
|
||||
", end_handle: " << std::dec << m_endHandle << " 0x" << std::hex << m_endHandle;
|
||||
for (auto &myPair : m_characteristicMap) {
|
||||
ss << "\n" << myPair.first->toString();
|
||||
ss << "\n" << myPair.second->toString();
|
||||
// myPair.second is the value
|
||||
}
|
||||
return ss.str();
|
||||
} // toString
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
@@ -30,15 +30,17 @@ public:
|
||||
virtual ~BLERemoteService();
|
||||
|
||||
// Public methods
|
||||
BLERemoteCharacteristic* getCharacteristic(const char* uuid);
|
||||
BLERemoteCharacteristic* getCharacteristic(BLEUUID uuid);
|
||||
BLERemoteCharacteristic* getCharacteristic(uint16_t uuid);
|
||||
std::map<BLERemoteCharacteristic*, std::string>* getCharacteristics();
|
||||
void getCharacteristics(std::map<uint16_t, BLERemoteCharacteristic*>* ptr);
|
||||
BLERemoteCharacteristic* getCharacteristic(const char* uuid); // Get the specified characteristic reference.
|
||||
BLERemoteCharacteristic* getCharacteristic(BLEUUID uuid); // Get the specified characteristic reference.
|
||||
BLERemoteCharacteristic* getCharacteristic(uint16_t uuid); // Get the specified characteristic reference.
|
||||
std::map<std::string, BLERemoteCharacteristic*>* getCharacteristics();
|
||||
void getCharacteristics(std::map<uint16_t, BLERemoteCharacteristic*>* pCharacteristicMap); // Get the characteristics map.
|
||||
|
||||
BLEClient* getClient(void);
|
||||
uint16_t getHandle();
|
||||
BLEUUID getUUID(void);
|
||||
BLEClient* getClient(void); // Get a reference to the client associated with this service.
|
||||
uint16_t getHandle(); // Get the handle of this service.
|
||||
BLEUUID getUUID(void); // Get the UUID of this service.
|
||||
std::string getValue(BLEUUID characteristicUuid); // Get the value of a characteristic.
|
||||
void setValue(BLEUUID characteristicUuid, std::string value); // Set the value of a characteristic.
|
||||
std::string toString(void);
|
||||
|
||||
private:
|
||||
@@ -50,20 +52,23 @@ private:
|
||||
friend class BLERemoteCharacteristic;
|
||||
|
||||
// Private methods
|
||||
void retrieveCharacteristics(void);
|
||||
void retrieveCharacteristics(void); // Retrieve the characteristics from the BLE Server.
|
||||
esp_gatt_id_t* getSrvcId(void);
|
||||
uint16_t getStartHandle();
|
||||
uint16_t getEndHandle();
|
||||
uint16_t getStartHandle(); // Get the start handle for this service.
|
||||
uint16_t getEndHandle(); // Get the end handle for this service.
|
||||
|
||||
void gattClientEventHandler(
|
||||
esp_gattc_cb_event_t event,
|
||||
esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t* evtParam);
|
||||
|
||||
void removeCharacteristics();
|
||||
|
||||
// Properties
|
||||
|
||||
// We maintain a map of characteristics owned by this service keyed by a string representation of the UUID.
|
||||
std::map<BLERemoteCharacteristic *, std::string> m_characteristicMap;
|
||||
std::map<std::string, BLERemoteCharacteristic *> m_characteristicMap;
|
||||
|
||||
// We maintain a map of characteristics owned by this service keyed by a handle.
|
||||
std::map<uint16_t, BLERemoteCharacteristic *> m_characteristicMapByHandle;
|
||||
|
||||
@@ -71,9 +76,9 @@ private:
|
||||
BLEClient* m_pClient;
|
||||
FreeRTOS::Semaphore m_semaphoreGetCharEvt = FreeRTOS::Semaphore("GetCharEvt");
|
||||
esp_gatt_id_t m_srvcId;
|
||||
BLEUUID m_uuid;
|
||||
uint16_t m_startHandle;
|
||||
uint16_t m_endHandle;
|
||||
BLEUUID m_uuid; // The UUID of this service.
|
||||
uint16_t m_startHandle; // The starting handle of this service.
|
||||
uint16_t m_endHandle; // The ending handle of this service.
|
||||
}; // BLERemoteService
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
|
||||
@@ -33,6 +33,7 @@ BLEScan::BLEScan() {
|
||||
m_scan_params.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL;
|
||||
m_pAdvertisedDeviceCallbacks = nullptr;
|
||||
m_stopped = true;
|
||||
m_wantDuplicates = false;
|
||||
setInterval(100);
|
||||
setWindow(100);
|
||||
} // BLEScan
|
||||
@@ -73,6 +74,9 @@ void BLEScan::handleGAPEvent(
|
||||
// asked to stop.
|
||||
case ESP_GAP_SEARCH_INQ_CMPL_EVT: {
|
||||
m_stopped = true;
|
||||
if (m_scanCompleteCB != nullptr) {
|
||||
m_scanCompleteCB(m_scanResults);
|
||||
}
|
||||
m_semaphoreScanEnd.give();
|
||||
break;
|
||||
} // ESP_GAP_SEARCH_INQ_CMPL_EVT
|
||||
@@ -97,7 +101,7 @@ void BLEScan::handleGAPEvent(
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
if (found && !m_wantDuplicates) { // If we found a previous entry AND we don't want duplicates, then we are done.
|
||||
ESP_LOGD(LOG_TAG, "Ignoring %s, already seen it.", advertisedAddress.toString().c_str());
|
||||
break;
|
||||
}
|
||||
@@ -115,7 +119,9 @@ void BLEScan::handleGAPEvent(
|
||||
m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
|
||||
}
|
||||
|
||||
m_scanResults.m_vectorAdvertisedDevices.push_back(advertisedDevice);
|
||||
if (!found) { // If we have previously seen this device, don't record it again.
|
||||
m_scanResults.m_vectorAdvertisedDevices.push_back(advertisedDevice);
|
||||
}
|
||||
|
||||
break;
|
||||
} // ESP_GAP_SEARCH_INQ_RES_EVT
|
||||
@@ -154,8 +160,10 @@ void BLEScan::setActiveScan(bool active) {
|
||||
/**
|
||||
* @brief Set the call backs to be invoked.
|
||||
* @param [in] pAdvertisedDeviceCallbacks Call backs to be invoked.
|
||||
* @param [in] wantDuplicates True if we wish to be called back with duplicates. Default is false.
|
||||
*/
|
||||
void BLEScan::setAdvertisedDeviceCallbacks(BLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks) {
|
||||
void BLEScan::setAdvertisedDeviceCallbacks(BLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks, bool wantDuplicates) {
|
||||
m_wantDuplicates = wantDuplicates;
|
||||
m_pAdvertisedDeviceCallbacks = pAdvertisedDeviceCallbacks;
|
||||
} // setAdvertisedDeviceCallbacks
|
||||
|
||||
@@ -181,12 +189,14 @@ void BLEScan::setWindow(uint16_t windowMSecs) {
|
||||
/**
|
||||
* @brief Start scanning.
|
||||
* @param [in] duration The duration in seconds for which to scan.
|
||||
* @return N/A.
|
||||
* @param [in] scanCompleteCB A function to be called when scanning has completed.
|
||||
* @return True if scan started or false if there was an error.
|
||||
*/
|
||||
BLEScanResults BLEScan::start(uint32_t duration) {
|
||||
bool BLEScan::start(uint32_t duration, void (*scanCompleteCB)(BLEScanResults)) {
|
||||
ESP_LOGD(LOG_TAG, ">> start(duration=%d)", duration);
|
||||
|
||||
m_semaphoreScanEnd.take(std::string("start"));
|
||||
m_scanCompleteCB = scanCompleteCB; // Save the callback to be invoked when the scan completes.
|
||||
|
||||
m_scanResults.m_vectorAdvertisedDevices.clear();
|
||||
|
||||
@@ -195,7 +205,7 @@ BLEScanResults BLEScan::start(uint32_t duration) {
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_set_scan_params: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
m_semaphoreScanEnd.give();
|
||||
return m_scanResults;
|
||||
return false;
|
||||
}
|
||||
|
||||
errRc = ::esp_ble_gap_start_scanning(duration);
|
||||
@@ -203,14 +213,25 @@ BLEScanResults BLEScan::start(uint32_t duration) {
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_start_scanning: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
m_semaphoreScanEnd.give();
|
||||
return m_scanResults;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_stopped = false;
|
||||
|
||||
m_semaphoreScanEnd.wait("start"); // Wait for the semaphore to release.
|
||||
|
||||
ESP_LOGD(LOG_TAG, "<< start()");
|
||||
return true;
|
||||
} // start
|
||||
|
||||
|
||||
/**
|
||||
* @brief Start scanning and block until scanning has been completed.
|
||||
* @param [in] duration The duration in seconds for which to scan.
|
||||
* @return The BLEScanResults.
|
||||
*/
|
||||
BLEScanResults BLEScan::start(uint32_t duration) {
|
||||
if(start(duration, nullptr)) {
|
||||
m_semaphoreScanEnd.wait("start"); // Wait for the semaphore to release.
|
||||
}
|
||||
return m_scanResults;
|
||||
} // start
|
||||
|
||||
|
||||
@@ -48,9 +48,12 @@ private:
|
||||
class BLEScan {
|
||||
public:
|
||||
void setActiveScan(bool active);
|
||||
void setAdvertisedDeviceCallbacks(BLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks);
|
||||
void setAdvertisedDeviceCallbacks(
|
||||
BLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks,
|
||||
bool wantDuplicates = false);
|
||||
void setInterval(uint16_t intervalMSecs);
|
||||
void setWindow(uint16_t windowMSecs);
|
||||
bool start(uint32_t duration, void (*scanCompleteCB)(BLEScanResults));
|
||||
BLEScanResults start(uint32_t duration);
|
||||
void stop();
|
||||
|
||||
@@ -68,6 +71,8 @@ private:
|
||||
bool m_stopped;
|
||||
FreeRTOS::Semaphore m_semaphoreScanEnd = FreeRTOS::Semaphore("ScanEnd");
|
||||
BLEScanResults m_scanResults;
|
||||
bool m_wantDuplicates;
|
||||
void (*m_scanCompleteCB)(BLEScanResults scanResults);
|
||||
}; // BLEScan
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* BLESecurity.cpp
|
||||
*
|
||||
* Created on: Dec 17, 2017
|
||||
* Author: chegewara
|
||||
*/
|
||||
|
||||
#include <BLESecurity.h>
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
BLESecurity::BLESecurity() {
|
||||
}
|
||||
|
||||
BLESecurity::~BLESecurity() {
|
||||
}
|
||||
/*
|
||||
* @brief Set requested authentication mode
|
||||
*/
|
||||
void BLESecurity::setAuthenticationMode(esp_ble_auth_req_t auth_req) {
|
||||
m_authReq = auth_req;
|
||||
esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &m_authReq, sizeof(uint8_t)); // <--- setup requested authentication mode
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set our device IO capability to let end user perform authorization
|
||||
* either by displaying or entering generated 6-digits pin code
|
||||
*/
|
||||
void BLESecurity::setCapability(esp_ble_io_cap_t iocap) {
|
||||
m_iocap = iocap;
|
||||
esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
|
||||
} // setCapability
|
||||
|
||||
|
||||
/**
|
||||
* @brief Init encryption key by server
|
||||
* @param key_size is value between 7 and 16
|
||||
*/
|
||||
void BLESecurity::setInitEncryptionKey(uint8_t init_key) {
|
||||
m_initKey = init_key;
|
||||
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &m_initKey, sizeof(uint8_t));
|
||||
} // setInitEncryptionKey
|
||||
|
||||
|
||||
/**
|
||||
* @brief Init encryption key by client
|
||||
* @param key_size is value between 7 and 16
|
||||
*/
|
||||
void BLESecurity::setRespEncryptionKey(uint8_t resp_key) {
|
||||
m_respKey = resp_key;
|
||||
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &m_respKey, sizeof(uint8_t));
|
||||
} // setRespEncryptionKey
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
void BLESecurity::setKeySize(uint8_t key_size) {
|
||||
m_keySize = key_size;
|
||||
esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &m_keySize, sizeof(uint8_t));
|
||||
} //setKeySize
|
||||
|
||||
|
||||
/**
|
||||
* @brief Debug function to display what keys are exchanged by peers
|
||||
*/
|
||||
char* BLESecurity::esp_key_type_to_str(esp_ble_key_type_t key_type)
|
||||
{
|
||||
char* key_str = nullptr;
|
||||
switch(key_type) {
|
||||
case ESP_LE_KEY_NONE:
|
||||
key_str = (char*)"ESP_LE_KEY_NONE";
|
||||
break;
|
||||
case ESP_LE_KEY_PENC:
|
||||
key_str = (char*)"ESP_LE_KEY_PENC";
|
||||
break;
|
||||
case ESP_LE_KEY_PID:
|
||||
key_str = (char*)"ESP_LE_KEY_PID";
|
||||
break;
|
||||
case ESP_LE_KEY_PCSRK:
|
||||
key_str = (char*)"ESP_LE_KEY_PCSRK";
|
||||
break;
|
||||
case ESP_LE_KEY_PLK:
|
||||
key_str = (char*)"ESP_LE_KEY_PLK";
|
||||
break;
|
||||
case ESP_LE_KEY_LLK:
|
||||
key_str = (char*)"ESP_LE_KEY_LLK";
|
||||
break;
|
||||
case ESP_LE_KEY_LENC:
|
||||
key_str = (char*)"ESP_LE_KEY_LENC";
|
||||
break;
|
||||
case ESP_LE_KEY_LID:
|
||||
key_str = (char*)"ESP_LE_KEY_LID";
|
||||
break;
|
||||
case ESP_LE_KEY_LCSRK:
|
||||
key_str = (char*)"ESP_LE_KEY_LCSRK";
|
||||
break;
|
||||
default:
|
||||
key_str = (char*)"INVALID BLE KEY TYPE";
|
||||
break;
|
||||
}
|
||||
return key_str;
|
||||
} // esp_key_type_to_str
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* BLESecurity.h
|
||||
*
|
||||
* Created on: Dec 17, 2017
|
||||
* Author: chegewara
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_CPP_UTILS_BLESECURITY_H_
|
||||
#define COMPONENTS_CPP_UTILS_BLESECURITY_H_
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
|
||||
#include <esp_gap_ble_api.h>
|
||||
|
||||
class BLESecurity {
|
||||
public:
|
||||
BLESecurity();
|
||||
virtual ~BLESecurity();
|
||||
void setAuthenticationMode(esp_ble_auth_req_t auth_req);
|
||||
void setCapability(esp_ble_io_cap_t iocap);
|
||||
void setInitEncryptionKey(uint8_t init_key);
|
||||
void setRespEncryptionKey(uint8_t resp_key);
|
||||
void setKeySize(uint8_t key_size = 16);
|
||||
static char* esp_key_type_to_str(esp_ble_key_type_t key_type);
|
||||
|
||||
private:
|
||||
esp_ble_auth_req_t m_authReq;
|
||||
esp_ble_io_cap_t m_iocap;
|
||||
uint8_t m_initKey;
|
||||
uint8_t m_respKey;
|
||||
uint8_t m_keySize;
|
||||
}; // BLESecurity
|
||||
|
||||
|
||||
/*
|
||||
* @brief Callbacks to handle GAP events related to authorization
|
||||
*/
|
||||
class BLESecurityCallbacks {
|
||||
public:
|
||||
virtual ~BLESecurityCallbacks() {};
|
||||
|
||||
/**
|
||||
* @brief Its request from peer device to input authentication pin code displayed on peer device.
|
||||
* It requires that our device is capable to input 6-digits code by end user
|
||||
* @return Return 6-digits integer value from input device
|
||||
*/
|
||||
virtual uint32_t onPassKeyRequest() = 0;
|
||||
|
||||
/**
|
||||
* @brief Provide us 6-digits code to perform authentication.
|
||||
* It requires that our device is capable to display this code to end user
|
||||
* @param
|
||||
*/
|
||||
virtual void onPassKeyNotify(uint32_t pass_key);
|
||||
|
||||
/**
|
||||
* @brief Here we can make decision if we want to let negotiate authorization with peer device or not
|
||||
* return Return true if we accept this peer device request
|
||||
*/
|
||||
|
||||
virtual bool onSecurityRequest();
|
||||
/**
|
||||
* Provide us information when authentication process is completed
|
||||
*/
|
||||
virtual void onAuthenticationComplete(esp_ble_auth_cmpl_t);
|
||||
|
||||
virtual bool onConfirmPIN(uint32_t pin);
|
||||
}; // BLESecurityCallbacks
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
#endif // COMPONENTS_CPP_UTILS_BLESECURITY_H_
|
||||
@@ -8,17 +8,16 @@
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <esp_log.h>
|
||||
#include <bt.h>
|
||||
#include <esp_bt.h>
|
||||
#include <esp_bt_main.h>
|
||||
#include <esp_gap_ble_api.h>
|
||||
#include <esp_gatts_api.h>
|
||||
//#include <esp_gatts_api.h>
|
||||
#include "BLEDevice.h"
|
||||
#include "BLEServer.h"
|
||||
#include "BLEService.h"
|
||||
#include "BLEUtils.h"
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <gatt_api.h>
|
||||
#include <unordered_set>
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "esp32-hal-log.h"
|
||||
@@ -70,21 +69,23 @@ BLEService* BLEServer::createService(const char* uuid) {
|
||||
* of a new service. Every service must have a unique UUID.
|
||||
* @param [in] uuid The UUID of the new service.
|
||||
* @param [in] numHandles The maximum number of handles associated with this service.
|
||||
* @param [in] inst_id With multiple services with the same UUID we need to provide inst_id value different for each service.
|
||||
* @return A reference to the new service object.
|
||||
*/
|
||||
BLEService* BLEServer::createService(BLEUUID uuid, uint32_t numHandles) {
|
||||
BLEService* BLEServer::createService(BLEUUID uuid, uint32_t numHandles, uint8_t inst_id) {
|
||||
ESP_LOGD(LOG_TAG, ">> createService - %s", uuid.toString().c_str());
|
||||
m_semaphoreCreateEvt.take("createService");
|
||||
|
||||
// Check that a service with the supplied UUID does not already exist.
|
||||
if (m_serviceMap.getByUUID(uuid) != nullptr) {
|
||||
ESP_LOGE(LOG_TAG, "<< Attempt to create a new service with uuid %s but a service with that UUID already exists.",
|
||||
ESP_LOGW(LOG_TAG, "<< Attempt to create a new service with uuid %s but a service with that UUID already exists.",
|
||||
uuid.toString().c_str());
|
||||
m_semaphoreCreateEvt.give();
|
||||
return nullptr;
|
||||
//m_semaphoreCreateEvt.give();
|
||||
//return nullptr;
|
||||
}
|
||||
|
||||
BLEService* pService = new BLEService(uuid, numHandles);
|
||||
pService->m_id = inst_id;
|
||||
m_serviceMap.setByUUID(uuid, pService); // Save a reference to this service being on this server.
|
||||
pService->executeCreate(this); // Perform the API calls to actually create the service.
|
||||
|
||||
@@ -151,6 +152,7 @@ void BLEServer::handleGAPEvent(
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -178,27 +180,90 @@ void BLEServer::handleGATTServerEvent(
|
||||
m_serviceMap.handleGATTServerEvent(event, gatts_if, param);
|
||||
|
||||
switch(event) {
|
||||
// ESP_GATTS_ADD_CHAR_EVT - Indicate that a characteristic was added to the service.
|
||||
// add_char:
|
||||
// - esp_gatt_status_t status
|
||||
// - uint16_t attr_handle
|
||||
// - uint16_t service_handle
|
||||
// - esp_bt_uuid_t char_uuid
|
||||
//
|
||||
case ESP_GATTS_ADD_CHAR_EVT: {
|
||||
break;
|
||||
} // ESP_GATTS_ADD_CHAR_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_CONNECT_EVT
|
||||
// connect:
|
||||
// - uint16_t conn_id
|
||||
// - uint16_t conn_id
|
||||
// - esp_bd_addr_t remote_bda
|
||||
// - bool is_connected
|
||||
// - bool is_connected
|
||||
//
|
||||
case ESP_GATTS_CONNECT_EVT: {
|
||||
m_connId = param->connect.conn_id; // Save the connection id.
|
||||
if (m_pServerCallbacks != nullptr) {
|
||||
m_pServerCallbacks->onConnect(this);
|
||||
}
|
||||
m_connectedCount++;
|
||||
m_connectedCount++; // Increment the number of connected devices count.
|
||||
break;
|
||||
} // ESP_GATTS_CONNECT_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_CREATE_EVT
|
||||
// Called when a new service is registered as having been created.
|
||||
//
|
||||
// create:
|
||||
// * esp_gatt_status_t status
|
||||
// * uint16_t service_handle
|
||||
// * esp_gatt_srvc_id_t service_id
|
||||
//
|
||||
case ESP_GATTS_CREATE_EVT: {
|
||||
BLEService* pService = m_serviceMap.getByUUID(param->create.service_id.id.uuid);
|
||||
m_serviceMap.setByHandle(param->create.service_handle, pService);
|
||||
m_semaphoreCreateEvt.give();
|
||||
break;
|
||||
} // ESP_GATTS_CREATE_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_DISCONNECT_EVT
|
||||
//
|
||||
// disconnect
|
||||
// - uint16_t conn_id
|
||||
// - esp_bd_addr_t remote_bda
|
||||
// - bool is_connected
|
||||
//
|
||||
// If we receive a disconnect event then invoke the callback for disconnects (if one is present).
|
||||
// we also want to start advertising again.
|
||||
case ESP_GATTS_DISCONNECT_EVT: {
|
||||
m_connectedCount--; // Decrement the number of connected devices count.
|
||||
if (m_pServerCallbacks != nullptr) { // If we have callbacks, call now.
|
||||
m_pServerCallbacks->onDisconnect(this);
|
||||
}
|
||||
startAdvertising(); //- do this with some delay from the loop()
|
||||
break;
|
||||
} // ESP_GATTS_DISCONNECT_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_READ_EVT - A request to read the value of a characteristic has arrived.
|
||||
//
|
||||
// read:
|
||||
// - uint16_t conn_id
|
||||
// - uint32_t trans_id
|
||||
// - esp_bd_addr_t bda
|
||||
// - uint16_t handle
|
||||
// - uint16_t offset
|
||||
// - bool is_long
|
||||
// - bool need_rsp
|
||||
//
|
||||
case ESP_GATTS_READ_EVT: {
|
||||
break;
|
||||
} // ESP_GATTS_READ_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_REG_EVT
|
||||
// reg:
|
||||
// - esp_gatt_status_t status
|
||||
// - uint16_t app_id
|
||||
//
|
||||
case ESP_GATTS_REG_EVT: {
|
||||
m_gatts_if = gatts_if;
|
||||
m_semaphoreRegisterAppEvt.give(); // Unlock the mutex waiting for the registration of the app.
|
||||
@@ -206,80 +271,23 @@ void BLEServer::handleGATTServerEvent(
|
||||
} // ESP_GATTS_REG_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_CREATE_EVT
|
||||
// Called when a new service is registered as having been created.
|
||||
//
|
||||
// create:
|
||||
// * esp_gatt_status_t status
|
||||
// * uint16_t service_handle
|
||||
// * esp_gatt_srvc_id_t service_id
|
||||
//
|
||||
case ESP_GATTS_CREATE_EVT: {
|
||||
BLEService* pService = m_serviceMap.getByUUID(param->create.service_id.id.uuid);
|
||||
m_serviceMap.setByHandle(param->create.service_handle, pService);
|
||||
//pService->setHandle(param->create.service_handle);
|
||||
m_semaphoreCreateEvt.give();
|
||||
break;
|
||||
} // ESP_GATTS_CREATE_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_READ_EVT - A request to read the value of a characteristic has arrived.
|
||||
//
|
||||
// read:
|
||||
// - uint16_t conn_id
|
||||
// - uint32_t trans_id
|
||||
// - esp_bd_addr_t bda
|
||||
// - uint16_t handle
|
||||
// - uint16_t offset
|
||||
// - bool is_long
|
||||
// - bool need_rsp
|
||||
//
|
||||
case ESP_GATTS_READ_EVT: {
|
||||
break;
|
||||
} // ESP_GATTS_READ_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_WRITE_EVT - A request to write the value of a characteristic has arrived.
|
||||
//
|
||||
// write:
|
||||
// - uint16_t conn_id
|
||||
// - uint16_t trans_id
|
||||
// - uint16_t conn_id
|
||||
// - uint16_t trans_id
|
||||
// - esp_bd_addr_t bda
|
||||
// - uint16_t handle
|
||||
// - uint16_t offset
|
||||
// - bool need_rsp
|
||||
// - bool is_prep
|
||||
// - uint16_t len
|
||||
// - uint8_t *value
|
||||
|
||||
// - uint16_t handle
|
||||
// - uint16_t offset
|
||||
// - bool need_rsp
|
||||
// - bool is_prep
|
||||
// - uint16_t len
|
||||
// - uint8_t* value
|
||||
//
|
||||
case ESP_GATTS_WRITE_EVT: {
|
||||
break;
|
||||
}
|
||||
|
||||
// ESP_GATTS_DISCONNECT_EVT
|
||||
// If we receive a disconnect event then invoke the callback for disconnects (if one is present).
|
||||
// we also want to start advertising again.
|
||||
case ESP_GATTS_DISCONNECT_EVT: {
|
||||
m_connectedCount--;
|
||||
if (m_pServerCallbacks != nullptr) {
|
||||
m_pServerCallbacks->onDisconnect(this);
|
||||
}
|
||||
startAdvertising();
|
||||
break;
|
||||
} // ESP_GATTS_DISCONNECT_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_ADD_CHAR_EVT - Indicate that a characteristic was added to the service.
|
||||
// add_char:
|
||||
// - esp_gatt_status_t status
|
||||
// - uint16_t attr_handle
|
||||
// - uint16_t service_handle
|
||||
// - esp_bt_uuid_t char_uuid
|
||||
case ESP_GATTS_ADD_CHAR_EVT: {
|
||||
break;
|
||||
} // ESP_GATTS_ADD_CHAR_EVT
|
||||
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
@@ -303,7 +311,7 @@ void BLEServer::registerApp() {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the callbacks.
|
||||
* @brief Set the server callbacks.
|
||||
*
|
||||
* As a %BLE server operates, it will generate server level events such as a new client connecting or a previous client
|
||||
* disconnecting. This function can be called to register a callback handler that will be invoked when these
|
||||
@@ -315,6 +323,14 @@ void BLEServer::setCallbacks(BLEServerCallbacks* pCallbacks) {
|
||||
m_pServerCallbacks = pCallbacks;
|
||||
} // setCallbacks
|
||||
|
||||
/*
|
||||
* Remove service
|
||||
*/
|
||||
void BLEServer::removeService(BLEService *service) {
|
||||
service->stop();
|
||||
service->executeDelete();
|
||||
m_serviceMap.removeService(service);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start advertising.
|
||||
@@ -329,36 +345,16 @@ void BLEServer::startAdvertising() {
|
||||
} // startAdvertising
|
||||
|
||||
|
||||
/*
|
||||
void BLEServer::addCharacteristic(BLECharacteristic *characteristic, BLEService *pService) {
|
||||
ESP_LOGD(tag, "Adding characteristic (esp_ble_gatts_add_char): uuid=%s, serviceHandle=0x%.2x",
|
||||
characteristic->m_bleUUID.toString().c_str(),
|
||||
pService->getHandle());
|
||||
|
||||
m_characteristicMap.setByUUID(characteristic->m_bleUUID, characteristic);
|
||||
|
||||
esp_err_t errRc = ::esp_ble_gatts_add_char(
|
||||
pService->getHandle(),
|
||||
characteristic->getUUID().getNative(),
|
||||
(esp_gatt_perm_t)(ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE),
|
||||
characteristic->getProperties(),
|
||||
&characteristic->m_value,
|
||||
NULL);
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(tag, "esp_ble_gatts_add_char: rc=%d %s", errRc, espToString(errRc));
|
||||
return;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void BLEServerCallbacks::onConnect(BLEServer* pServer) {
|
||||
ESP_LOGD("BLEServerCallbacks", ">> onConnect(): Default");
|
||||
ESP_LOGD("BLEServerCallbacks", "Device: %s", BLEDevice::toString().c_str());
|
||||
ESP_LOGD("BLEServerCallbacks", "<< onConnect()");
|
||||
} // onConnect
|
||||
|
||||
|
||||
void BLEServerCallbacks::onDisconnect(BLEServer* pServer) {
|
||||
ESP_LOGD("BLEServerCallbacks", ">> onDisconnect(): Default");
|
||||
ESP_LOGD("BLEServerCallbacks", "Device: %s", BLEDevice::toString().c_str());
|
||||
ESP_LOGD("BLEServerCallbacks", "<< onDisconnect()");
|
||||
} // onDisconnect
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "BLEAdvertising.h"
|
||||
#include "BLECharacteristic.h"
|
||||
#include "BLEService.h"
|
||||
#include "BLESecurity.h"
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
class BLEServerCallbacks;
|
||||
@@ -39,10 +40,14 @@ public:
|
||||
void setByUUID(const char* uuid, BLEService* service);
|
||||
void setByUUID(BLEUUID uuid, BLEService* service);
|
||||
std::string toString();
|
||||
BLEService* getFirst();
|
||||
BLEService* getNext();
|
||||
void removeService(BLEService *service);
|
||||
|
||||
private:
|
||||
std::map<std::string, BLEService*> m_uuidMap;
|
||||
std::map<uint16_t, BLEService*> m_handleMap;
|
||||
std::map<BLEService*, std::string> m_uuidMap;
|
||||
std::map<BLEService*, std::string>::iterator m_iterator;
|
||||
};
|
||||
|
||||
|
||||
@@ -53,10 +58,11 @@ class BLEServer {
|
||||
public:
|
||||
uint32_t getConnectedCount();
|
||||
BLEService* createService(const char* uuid);
|
||||
BLEService* createService(BLEUUID uuid, uint32_t numHandles=15);
|
||||
BLEService* createService(BLEUUID uuid, uint32_t numHandles=15, uint8_t inst_id=0);
|
||||
BLEAdvertising* getAdvertising();
|
||||
void setCallbacks(BLEServerCallbacks *pCallbacks);
|
||||
void setCallbacks(BLEServerCallbacks* pCallbacks);
|
||||
void startAdvertising();
|
||||
void removeService(BLEService *service);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
@@ -72,7 +72,8 @@ void BLEService::executeCreate(BLEServer *pServer) {
|
||||
m_semaphoreCreateEvt.take("executeCreate"); // Take the mutex and release at event ESP_GATTS_CREATE_EVT
|
||||
|
||||
esp_gatt_srvc_id_t srvc_id;
|
||||
srvc_id.id.inst_id = 0;
|
||||
srvc_id.is_primary = true;
|
||||
srvc_id.id.inst_id = m_id;
|
||||
srvc_id.id.uuid = *m_uuid.getNative();
|
||||
esp_err_t errRc = ::esp_ble_gatts_create_service(
|
||||
getServer()->getGattsIf(),
|
||||
@@ -90,6 +91,28 @@ void BLEService::executeCreate(BLEServer *pServer) {
|
||||
} // executeCreate
|
||||
|
||||
|
||||
/**
|
||||
* @brief Delete the service.
|
||||
* Delete the service.
|
||||
* @return N/A.
|
||||
*/
|
||||
|
||||
void BLEService::executeDelete() {
|
||||
ESP_LOGD(LOG_TAG, ">> executeDelete()");
|
||||
m_semaphoreDeleteEvt.take("executeDelete"); // Take the mutex and release at event ESP_GATTS_DELETE_EVT
|
||||
|
||||
esp_err_t errRc = ::esp_ble_gatts_delete_service( getHandle() );
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gatts_delete_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
|
||||
m_semaphoreDeleteEvt.wait("executeDelete");
|
||||
ESP_LOGD(LOG_TAG, "<< executeDelete");
|
||||
} // executeDelete
|
||||
|
||||
|
||||
/**
|
||||
* @brief Dump details of this BLE GATT service.
|
||||
* @return N/A.
|
||||
@@ -152,6 +175,34 @@ void BLEService::start() {
|
||||
} // start
|
||||
|
||||
|
||||
/**
|
||||
* @brief Stop the service.
|
||||
* @return Stop the service.
|
||||
*/
|
||||
void BLEService::stop() {
|
||||
// We ask the BLE runtime to start the service and then create each of the characteristics.
|
||||
// We start the service through its local handle which was returned in the ESP_GATTS_CREATE_EVT event
|
||||
// obtained as a result of calling esp_ble_gatts_create_service().
|
||||
//
|
||||
ESP_LOGD(LOG_TAG, ">> stop(): Stopping service (esp_ble_gatts_stop_service): %s", toString().c_str());
|
||||
if (m_handle == NULL_HANDLE) {
|
||||
ESP_LOGE(LOG_TAG, "<< !!! We attempted to stop a service but don't know its handle!");
|
||||
return;
|
||||
}
|
||||
|
||||
m_semaphoreStopEvt.take("stop");
|
||||
esp_err_t errRc = ::esp_ble_gatts_stop_service(m_handle);
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_stop_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
m_semaphoreStopEvt.wait("stop");
|
||||
|
||||
ESP_LOGD(LOG_TAG, "<< stop()");
|
||||
} // start
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the handle associated with this service.
|
||||
* @param [in] handle The handle associated with the service.
|
||||
@@ -192,7 +243,7 @@ void BLEService::addCharacteristic(BLECharacteristic* pCharacteristic) {
|
||||
|
||||
// Check that we don't add the same characteristic twice.
|
||||
if (m_characteristicMap.getByUUID(pCharacteristic->getUUID()) != nullptr) {
|
||||
ESP_LOGE(LOG_TAG, "<< Attempt to add a characteristic but we already have one with this UUID");
|
||||
ESP_LOGW(LOG_TAG, "<< Adding a new characteristic with the same UUID as a previous one");
|
||||
//return;
|
||||
}
|
||||
|
||||
@@ -277,6 +328,19 @@ void BLEService::handleGATTServerEvent(
|
||||
break;
|
||||
} // ESP_GATTS_START_EVT
|
||||
|
||||
// ESP_GATTS_STOP_EVT
|
||||
//
|
||||
// stop:
|
||||
// esp_gatt_status_t status
|
||||
// uint16_t service_handle
|
||||
//
|
||||
case ESP_GATTS_STOP_EVT: {
|
||||
if (param->stop.service_handle == getHandle()) {
|
||||
m_semaphoreStopEvt.give();
|
||||
}
|
||||
break;
|
||||
} // ESP_GATTS_STOP_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_CREATE_EVT
|
||||
// Called when a new service is registered as having been created.
|
||||
@@ -291,13 +355,28 @@ void BLEService::handleGATTServerEvent(
|
||||
// * - bool is_primary
|
||||
//
|
||||
case ESP_GATTS_CREATE_EVT: {
|
||||
if (getUUID().equals(BLEUUID(param->create.service_id.id.uuid))) {
|
||||
if (getUUID().equals(BLEUUID(param->create.service_id.id.uuid)) && m_id == param->create.service_id.id.inst_id) {
|
||||
setHandle(param->create.service_handle);
|
||||
m_semaphoreCreateEvt.give();
|
||||
}
|
||||
break;
|
||||
} // ESP_GATTS_CREATE_EVT
|
||||
|
||||
|
||||
// ESP_GATTS_DELETE_EVT
|
||||
// Called when a service is deleted.
|
||||
//
|
||||
// delete:
|
||||
// * esp_gatt_status_t status
|
||||
// * uint16_t service_handle
|
||||
//
|
||||
case ESP_GATTS_DELETE_EVT: {
|
||||
if (param->del.service_handle == getHandle()) {
|
||||
m_semaphoreDeleteEvt.give();
|
||||
}
|
||||
break;
|
||||
} // ESP_GATTS_DELETE_EVT
|
||||
|
||||
default: {
|
||||
break;
|
||||
} // Default
|
||||
|
||||
@@ -52,23 +52,25 @@ private:
|
||||
*/
|
||||
class BLEService {
|
||||
public:
|
||||
BLEService(const char* uuid, uint32_t numHandles=10);
|
||||
BLEService(BLEUUID uuid, uint32_t numHandles=10);
|
||||
|
||||
void addCharacteristic(BLECharacteristic* pCharacteristic);
|
||||
BLECharacteristic* createCharacteristic(const char* uuid, uint32_t properties);
|
||||
BLECharacteristic* createCharacteristic(BLEUUID uuid, uint32_t properties);
|
||||
void dump();
|
||||
void executeCreate(BLEServer* pServer);
|
||||
void executeDelete();
|
||||
BLECharacteristic* getCharacteristic(const char* uuid);
|
||||
BLECharacteristic* getCharacteristic(BLEUUID uuid);
|
||||
BLEUUID getUUID();
|
||||
BLEServer* getServer();
|
||||
void start();
|
||||
void stop();
|
||||
std::string toString();
|
||||
uint16_t getHandle();
|
||||
uint8_t m_id = 0;
|
||||
|
||||
private:
|
||||
BLEService(const char* uuid, uint32_t numHandles);
|
||||
BLEService(BLEUUID uuid, uint32_t numHandles);
|
||||
friend class BLEServer;
|
||||
friend class BLEServiceMap;
|
||||
friend class BLEDescriptor;
|
||||
@@ -80,10 +82,11 @@ private:
|
||||
BLECharacteristic* m_lastCreatedCharacteristic;
|
||||
BLEServer* m_pServer;
|
||||
BLEUUID m_uuid;
|
||||
char deleteMe[10];
|
||||
//FreeRTOS::Semaphore m_serializeMutex;
|
||||
|
||||
FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt");
|
||||
FreeRTOS::Semaphore m_semaphoreDeleteEvt = FreeRTOS::Semaphore("DeleteEvt");
|
||||
FreeRTOS::Semaphore m_semaphoreStartEvt = FreeRTOS::Semaphore("StartEvt");
|
||||
FreeRTOS::Semaphore m_semaphoreStopEvt = FreeRTOS::Semaphore("StopEvt");
|
||||
|
||||
uint32_t m_numHandles;
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ BLEService* BLEServiceMap::getByUUID(const char* uuid) {
|
||||
*/
|
||||
BLEService* BLEServiceMap::getByUUID(BLEUUID uuid) {
|
||||
for (auto &myPair : m_uuidMap) {
|
||||
if (myPair.second->getUUID().equals(uuid)) {
|
||||
return myPair.second;
|
||||
if (myPair.first->getUUID().equals(uuid)) {
|
||||
return myPair.first;
|
||||
}
|
||||
}
|
||||
//return m_uuidMap.at(uuid.toString());
|
||||
@@ -54,7 +54,7 @@ BLEService* BLEServiceMap::getByHandle(uint16_t handle) {
|
||||
*/
|
||||
void BLEServiceMap::setByUUID(BLEUUID uuid,
|
||||
BLEService *service) {
|
||||
m_uuidMap.insert(std::pair<std::string, BLEService *>(uuid.toString(), service));
|
||||
m_uuidMap.insert(std::pair<BLEService *, std::string>(service, uuid.toString()));
|
||||
} // setByUUID
|
||||
|
||||
|
||||
@@ -89,7 +89,44 @@ void BLEServiceMap::handleGATTServerEvent(
|
||||
esp_ble_gatts_cb_param_t *param) {
|
||||
// Invoke the handler for every Service we have.
|
||||
for (auto &myPair : m_uuidMap) {
|
||||
myPair.second->handleGATTServerEvent(event, gatts_if, param);
|
||||
myPair.first->handleGATTServerEvent(event, gatts_if, param);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the first service in the map.
|
||||
* @return The first service in the map.
|
||||
*/
|
||||
BLEService* BLEServiceMap::getFirst() {
|
||||
m_iterator = m_uuidMap.begin();
|
||||
if (m_iterator == m_uuidMap.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
BLEService* pRet = m_iterator->first;
|
||||
m_iterator++;
|
||||
return pRet;
|
||||
} // getFirst
|
||||
|
||||
/**
|
||||
* @brief Get the next service in the map.
|
||||
* @return The next service in the map.
|
||||
*/
|
||||
BLEService* BLEServiceMap::getNext() {
|
||||
if (m_iterator == m_uuidMap.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
BLEService* pRet = m_iterator->first;
|
||||
m_iterator++;
|
||||
return pRet;
|
||||
} // getNext
|
||||
|
||||
/**
|
||||
* @brief Removes service from maps.
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLEServiceMap::removeService(BLEService *service){
|
||||
m_handleMap.erase(service->getHandle());
|
||||
m_uuidMap.erase(service);
|
||||
} // removeService
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
@@ -11,6 +11,8 @@
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include "BLEUUID.h"
|
||||
static const char* LOG_TAG = "BLEUUID";
|
||||
|
||||
@@ -188,6 +190,32 @@ BLEUUID::BLEUUID() {
|
||||
} // BLEUUID
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the number of bits in this uuid.
|
||||
* @return The number of bits in the UUID. One of 16, 32 or 128.
|
||||
*/
|
||||
int BLEUUID::bitSize() {
|
||||
if (m_valueSet == false) {
|
||||
return 0;
|
||||
}
|
||||
switch(m_uuid.len) {
|
||||
case ESP_UUID_LEN_16: {
|
||||
return 16;
|
||||
}
|
||||
case ESP_UUID_LEN_32: {
|
||||
return 32;
|
||||
}
|
||||
case ESP_UUID_LEN_128: {
|
||||
return 128;
|
||||
}
|
||||
default: {
|
||||
ESP_LOGE(LOG_TAG, "Unknown UUID length: %d", m_uuid.len);
|
||||
return 0;
|
||||
}
|
||||
} // End of switch
|
||||
} // bitSize
|
||||
|
||||
|
||||
/**
|
||||
* @brief Compare a UUID against this UUID.
|
||||
*
|
||||
@@ -216,6 +244,35 @@ bool BLEUUID::equals(BLEUUID uuid) {
|
||||
} // equals
|
||||
|
||||
|
||||
/**
|
||||
* Create a BLEUUID from a string of the form:
|
||||
* 0xNNNN
|
||||
* 0xNNNNNNNN
|
||||
* 0x<UUID>
|
||||
* NNNN
|
||||
* NNNNNNNN
|
||||
* <UUID>
|
||||
*/
|
||||
BLEUUID BLEUUID::fromString(std::string _uuid){
|
||||
uint8_t start = 0;
|
||||
if (strstr(_uuid.c_str(), "0x") != nullptr) { // If the string starts with 0x, skip those characters.
|
||||
start = 2;
|
||||
}
|
||||
uint8_t len = _uuid.length() - start; // Calculate the length of the string we are going to use.
|
||||
|
||||
if( len == 4) {
|
||||
uint16_t x = strtoul(_uuid.substr(start, len).c_str(), NULL, 16);
|
||||
return BLEUUID(x);
|
||||
} else if (len == 8) {
|
||||
uint32_t x = strtoul(_uuid.substr(start, len).c_str(), NULL, 16);
|
||||
return BLEUUID(x);
|
||||
} else if (len == 36) {
|
||||
return BLEUUID(_uuid);
|
||||
}
|
||||
return BLEUUID();
|
||||
} // fromString
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the native UUID value.
|
||||
*
|
||||
@@ -350,21 +407,4 @@ std::string BLEUUID::toString() {
|
||||
return ss.str();
|
||||
} // toString
|
||||
|
||||
BLEUUID BLEUUID::fromString(std::string _uuid){
|
||||
uint8_t start = 0;
|
||||
if(strstr(_uuid.c_str(), "0x") != nullptr){
|
||||
start = 2;
|
||||
}
|
||||
uint8_t len = _uuid.length() - start;
|
||||
if(len == 4 ){
|
||||
uint16_t x = strtoul(_uuid.substr(start, len).c_str(), NULL, 16);
|
||||
return BLEUUID(x);
|
||||
}else if(len == 8){
|
||||
uint32_t x = strtoul(_uuid.substr(start, len).c_str(), NULL, 16);
|
||||
return BLEUUID(x);
|
||||
}else if (len == 36){
|
||||
return BLEUUID(_uuid);
|
||||
}
|
||||
return BLEUUID();
|
||||
}
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
@@ -24,11 +24,12 @@ public:
|
||||
BLEUUID(uint8_t* pData, size_t size, bool msbFirst);
|
||||
BLEUUID(esp_gatt_id_t gattId);
|
||||
BLEUUID();
|
||||
int bitSize(); // Get the number of bits in this uuid.
|
||||
bool equals(BLEUUID uuid);
|
||||
esp_bt_uuid_t* getNative();
|
||||
BLEUUID to128();
|
||||
std::string toString();
|
||||
static BLEUUID fromString(std::string uuid);
|
||||
static BLEUUID fromString(std::string uuid); // Create a BLEUUID from a string
|
||||
|
||||
private:
|
||||
esp_bt_uuid_t m_uuid; // The underlying UUID structure that this class wraps.
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/event_groups.h>
|
||||
#include <bt.h> // ESP32 BLE
|
||||
#include <esp_bt.h> // ESP32 BLE
|
||||
#include <esp_bt_main.h> // ESP32 BLE
|
||||
#include <esp_gap_ble_api.h> // ESP32 BLE
|
||||
#include <esp_gattc_api.h> // ESP32 BLE
|
||||
@@ -838,28 +838,52 @@ std::string BLEUtils::buildPrintData(uint8_t* source, size_t length) {
|
||||
} // buildPrintData
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convert a close/disconnect reason to a string.
|
||||
* @param [in] reason The close reason.
|
||||
* @return A string representation of the reason.
|
||||
*/
|
||||
std::string BLEUtils::gattCloseReasonToString(esp_gatt_conn_reason_t reason) {
|
||||
switch(reason) {
|
||||
case ESP_GATT_CONN_UNKNOWN:
|
||||
case ESP_GATT_CONN_UNKNOWN: {
|
||||
return "ESP_GATT_CONN_UNKNOWN";
|
||||
case ESP_GATT_CONN_L2C_FAILURE:
|
||||
}
|
||||
|
||||
case ESP_GATT_CONN_L2C_FAILURE: {
|
||||
return "ESP_GATT_CONN_L2C_FAILURE";
|
||||
case ESP_GATT_CONN_TIMEOUT:
|
||||
}
|
||||
|
||||
case ESP_GATT_CONN_TIMEOUT: {
|
||||
return "ESP_GATT_CONN_TIMEOUT";
|
||||
case ESP_GATT_CONN_TERMINATE_PEER_USER:
|
||||
}
|
||||
|
||||
case ESP_GATT_CONN_TERMINATE_PEER_USER: {
|
||||
return "ESP_GATT_CONN_TERMINATE_PEER_USER";
|
||||
case ESP_GATT_CONN_TERMINATE_LOCAL_HOST:
|
||||
}
|
||||
|
||||
case ESP_GATT_CONN_TERMINATE_LOCAL_HOST: {
|
||||
return "ESP_GATT_CONN_TERMINATE_LOCAL_HOST";
|
||||
case ESP_GATT_CONN_FAIL_ESTABLISH:
|
||||
}
|
||||
|
||||
case ESP_GATT_CONN_FAIL_ESTABLISH: {
|
||||
return "ESP_GATT_CONN_FAIL_ESTABLISH";
|
||||
case ESP_GATT_CONN_LMP_TIMEOUT:
|
||||
}
|
||||
|
||||
case ESP_GATT_CONN_LMP_TIMEOUT: {
|
||||
return "ESP_GATT_CONN_LMP_TIMEOUT";
|
||||
case ESP_GATT_CONN_CONN_CANCEL:
|
||||
}
|
||||
|
||||
case ESP_GATT_CONN_CONN_CANCEL: {
|
||||
return "ESP_GATT_CONN_CONN_CANCEL";
|
||||
case ESP_GATT_CONN_NONE:
|
||||
}
|
||||
|
||||
case ESP_GATT_CONN_NONE: {
|
||||
return "ESP_GATT_CONN_NONE";
|
||||
default:
|
||||
}
|
||||
|
||||
default: {
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
} // gattCloseReasonToString
|
||||
|
||||
@@ -1263,6 +1287,15 @@ void BLEUtils::dumpGapEvent(
|
||||
} // ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT
|
||||
|
||||
|
||||
//
|
||||
// ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT
|
||||
//
|
||||
case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: {
|
||||
ESP_LOGD(LOG_TAG, "[status: %d]", param->scan_rsp_data_raw_cmpl.status);
|
||||
break;
|
||||
} // ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT
|
||||
|
||||
|
||||
//
|
||||
// ESP_GAP_BLE_SCAN_START_COMPLETE_EVT
|
||||
//
|
||||
@@ -1379,11 +1412,12 @@ void BLEUtils::dumpGattClientEvent(
|
||||
// ESP_GATTC_DISCONNECT_EVT
|
||||
//
|
||||
// disconnect:
|
||||
// - esp_gatt_status_t status
|
||||
// - uint16_t conn_id
|
||||
// - esp_bd_addr_t remote_bda
|
||||
// - esp_gatt_conn_reason_t reason
|
||||
// - uint16_t conn_id
|
||||
// - esp_bd_addr_t remote_bda
|
||||
case ESP_GATTC_DISCONNECT_EVT: {
|
||||
ESP_LOGD(LOG_TAG, "[conn_id: %d, remote_bda: %s]",
|
||||
ESP_LOGD(LOG_TAG, "[reason: %s, conn_id: %d, remote_bda: %s]",
|
||||
BLEUtils::gattCloseReasonToString(evtParam->disconnect.reason).c_str(),
|
||||
evtParam->disconnect.conn_id,
|
||||
BLEAddress(evtParam->disconnect.remote_bda).toString().c_str()
|
||||
);
|
||||
@@ -1577,13 +1611,15 @@ void BLEUtils::dumpGattClientEvent(
|
||||
// - esp_gatt_status_t status
|
||||
// - uint16_t conn_id
|
||||
// - uint16_t handle
|
||||
// - uint16_t offset
|
||||
//
|
||||
case ESP_GATTC_WRITE_CHAR_EVT: {
|
||||
ESP_LOGD(LOG_TAG, "[status: %s, conn_id: %d, handle: %d 0x%.2x]",
|
||||
ESP_LOGD(LOG_TAG, "[status: %s, conn_id: %d, handle: %d 0x%.2x, offset: %d]",
|
||||
BLEUtils::gattStatusToString(evtParam->write.status).c_str(),
|
||||
evtParam->write.conn_id,
|
||||
evtParam->write.handle,
|
||||
evtParam->write.handle
|
||||
evtParam->write.handle,
|
||||
evtParam->write.offset
|
||||
);
|
||||
break;
|
||||
} // ESP_GATTC_WRITE_CHAR_EVT
|
||||
@@ -1618,7 +1654,7 @@ void BLEUtils::dumpGattServerEvent(
|
||||
evtParam->add_char_descr.attr_handle,
|
||||
evtParam->add_char_descr.service_handle,
|
||||
evtParam->add_char_descr.service_handle,
|
||||
BLEUUID(evtParam->add_char_descr.char_uuid).toString().c_str());
|
||||
BLEUUID(evtParam->add_char_descr.descr_uuid).toString().c_str());
|
||||
break;
|
||||
} // ESP_GATTS_ADD_CHAR_DESCR_EVT
|
||||
|
||||
|
||||
@@ -133,9 +133,9 @@ void FreeRTOS::Semaphore::give() {
|
||||
} else {
|
||||
xSemaphoreGive(m_semaphore);
|
||||
}
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
FreeRTOS::sleep(10);
|
||||
#endif
|
||||
// #ifdef ARDUINO_ARCH_ESP32
|
||||
// FreeRTOS::sleep(10);
|
||||
// #endif
|
||||
|
||||
m_owner = std::string("<N/A>");
|
||||
} // Semaphore::give
|
||||
@@ -168,17 +168,25 @@ void FreeRTOS::Semaphore::giveFromISR() {
|
||||
/**
|
||||
* @brief Take a semaphore.
|
||||
* Take a semaphore and wait indefinitely.
|
||||
* @param [in] owner The new owner (for debugging)
|
||||
* @return True if we took the semaphore.
|
||||
*/
|
||||
void FreeRTOS::Semaphore::take(std::string owner)
|
||||
bool FreeRTOS::Semaphore::take(std::string owner)
|
||||
{
|
||||
ESP_LOGD(LOG_TAG, "Semaphore taking: %s for %s", toString().c_str(), owner.c_str());
|
||||
bool rc = false;
|
||||
if (m_usePthreads) {
|
||||
pthread_mutex_lock(&m_pthread_mutex);
|
||||
} else {
|
||||
xSemaphoreTake(m_semaphore, portMAX_DELAY);
|
||||
rc = ::xSemaphoreTake(m_semaphore, portMAX_DELAY);
|
||||
}
|
||||
m_owner = owner;
|
||||
ESP_LOGD(LOG_TAG, "Semaphore taken: %s", toString().c_str());
|
||||
if (rc) {
|
||||
ESP_LOGD(LOG_TAG, "Semaphore taken: %s", toString().c_str());
|
||||
} else {
|
||||
ESP_LOGE(LOG_TAG, "Semaphore NOT taken: %s", toString().c_str());
|
||||
}
|
||||
return rc;
|
||||
} // Semaphore::take
|
||||
|
||||
|
||||
@@ -186,21 +194,33 @@ void FreeRTOS::Semaphore::take(std::string owner)
|
||||
* @brief Take a semaphore.
|
||||
* Take a semaphore but return if we haven't obtained it in the given period of milliseconds.
|
||||
* @param [in] timeoutMs Timeout in milliseconds.
|
||||
* @param [in] owner The new owner (for debugging)
|
||||
* @return True if we took the semaphore.
|
||||
*/
|
||||
void FreeRTOS::Semaphore::take(uint32_t timeoutMs, std::string owner) {
|
||||
bool FreeRTOS::Semaphore::take(uint32_t timeoutMs, std::string owner) {
|
||||
|
||||
ESP_LOGV(LOG_TAG, "Semaphore taking: %s for %s", toString().c_str(), owner.c_str());
|
||||
|
||||
bool rc = false;
|
||||
if (m_usePthreads) {
|
||||
assert(false);
|
||||
assert(false); // We apparently don't have a timed wait for pthreads.
|
||||
} else {
|
||||
xSemaphoreTake(m_semaphore, timeoutMs/portTICK_PERIOD_MS);
|
||||
rc = ::xSemaphoreTake(m_semaphore, timeoutMs/portTICK_PERIOD_MS);
|
||||
}
|
||||
m_owner = owner;
|
||||
ESP_LOGV(LOG_TAG, "Semaphore taken: %s", toString().c_str());
|
||||
if (rc) {
|
||||
ESP_LOGV(LOG_TAG, "Semaphore taken: %s", toString().c_str());
|
||||
} else {
|
||||
ESP_LOGE(LOG_TAG, "Semaphore NOT taken: %s", toString().c_str());
|
||||
}
|
||||
return rc;
|
||||
} // Semaphore::take
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a string representation of the semaphore.
|
||||
* @return A string representation of the semaphore.
|
||||
*/
|
||||
std::string FreeRTOS::Semaphore::toString() {
|
||||
std::stringstream stringStream;
|
||||
stringStream << "name: "<< m_name << " (0x" << std::hex << std::setfill('0') << (uint32_t)m_semaphore << "), owner: " << m_owner;
|
||||
@@ -208,6 +228,10 @@ std::string FreeRTOS::Semaphore::toString() {
|
||||
} // toString
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the name of the semaphore.
|
||||
* @param [in] name The name of the semaphore.
|
||||
*/
|
||||
void FreeRTOS::Semaphore::setName(std::string name) {
|
||||
m_name = name;
|
||||
} // setName
|
||||
|
||||
@@ -36,8 +36,8 @@ public:
|
||||
void give(uint32_t value);
|
||||
void giveFromISR();
|
||||
void setName(std::string name);
|
||||
void take(std::string owner="<Unknown>");
|
||||
void take(uint32_t timeoutMs, std::string owner="<Unknown>");
|
||||
bool take(std::string owner="<Unknown>");
|
||||
bool take(uint32_t timeoutMs, std::string owner="<Unknown>");
|
||||
std::string toString();
|
||||
uint32_t wait(std::string owner="<Unknown>");
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <esp_err.h>
|
||||
#include <nvs.h>
|
||||
#include <esp_wifi.h>
|
||||
#include <esp_heap_caps.h>
|
||||
#include <esp_system.h>
|
||||
|
||||
static const char* LOG_TAG = "GeneralUtils";
|
||||
|
||||
@@ -98,6 +100,23 @@ bool GeneralUtils::base64Encode(const std::string &in, std::string *out) {
|
||||
} // base64Encode
|
||||
|
||||
|
||||
/**
|
||||
* @brief Dump general info to the log.
|
||||
* Data includes:
|
||||
* * Amount of free RAM
|
||||
*/
|
||||
void GeneralUtils::dumpInfo() {
|
||||
size_t freeHeap = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
esp_chip_info_t chipInfo;
|
||||
esp_chip_info(&chipInfo);
|
||||
ESP_LOGD(LOG_TAG, "--- dumpInfo ---");
|
||||
ESP_LOGD(LOG_TAG, "Free heap: %d", freeHeap);
|
||||
ESP_LOGD(LOG_TAG, "Chip Info: Model: %d, cores: %d, revision: %d", chipInfo.model, chipInfo.cores, chipInfo.revision);
|
||||
ESP_LOGD(LOG_TAG, "ESP-IDF version: %s", esp_get_idf_version());
|
||||
ESP_LOGD(LOG_TAG, "---");
|
||||
} // dumpInfo
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does the string end with a specific character?
|
||||
* @param [in] str The string to examine.
|
||||
@@ -320,6 +339,24 @@ std::string GeneralUtils::ipToString(uint8_t *ip) {
|
||||
} // ipToString
|
||||
|
||||
|
||||
/**
|
||||
* @brief Split a string into parts based on a delimiter.
|
||||
* @param [in] source The source string to split.
|
||||
* @param [in] delimiter The delimiter characters.
|
||||
* @return A vector of strings that are the split of the input.
|
||||
*/
|
||||
std::vector<std::string> GeneralUtils::split(std::string source, char delimiter) {
|
||||
// See also: https://stackoverflow.com/questions/5167625/splitting-a-c-stdstring-using-tokens-e-g
|
||||
std::vector<std::string> strings;
|
||||
std::istringstream iss(source);
|
||||
std::string s;
|
||||
while(std::getline(iss, s, delimiter)) {
|
||||
strings.push_back(trim(s));
|
||||
}
|
||||
return strings;
|
||||
} // split
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convert an ESP error code to a string.
|
||||
* @param [in] errCode The errCode to be converted.
|
||||
@@ -399,8 +436,30 @@ const char* GeneralUtils::errorToString(esp_err_t errCode) {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Restart the ESP32.
|
||||
* @brief Convert a string to lower case.
|
||||
* @param [in] value The string to convert to lower case.
|
||||
* @return A lower case representation of the string.
|
||||
*/
|
||||
void GeneralUtils::restart() {
|
||||
esp_restart();
|
||||
} // restart
|
||||
std::string GeneralUtils::toLower(std::string& value) {
|
||||
// Question: Could this be improved with a signature of:
|
||||
// std::string& GeneralUtils::toLower(std::string& value)
|
||||
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
|
||||
return value;
|
||||
} // toLower
|
||||
|
||||
|
||||
/**
|
||||
* @brief Remove white space from a string.
|
||||
*/
|
||||
std::string GeneralUtils::trim(const std::string& str)
|
||||
{
|
||||
size_t first = str.find_first_not_of(' ');
|
||||
if (std::string::npos == first)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
size_t last = str.find_last_not_of(' ');
|
||||
return str.substr(first, (last - first + 1));
|
||||
} // trim
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <esp_err.h>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @brief General utilities.
|
||||
@@ -18,11 +20,15 @@ class GeneralUtils {
|
||||
public:
|
||||
static bool base64Decode(const std::string& in, std::string* out);
|
||||
static bool base64Encode(const std::string& in, std::string* out);
|
||||
static void dumpInfo();
|
||||
static bool endsWith(std::string str, char c);
|
||||
static const char* errorToString(esp_err_t errCode);
|
||||
static void hexDump(const uint8_t* pData, uint32_t length);
|
||||
static std::string ipToString(uint8_t* ip);
|
||||
static void restart();
|
||||
static std::vector<std::string> split(std::string source, char delimiter);
|
||||
static std::string toLower(std::string& value);
|
||||
static std::string trim(const std::string& str);
|
||||
|
||||
};
|
||||
|
||||
#endif /* COMPONENTS_CPP_UTILS_GENERALUTILS_H_ */
|
||||
@@ -0,0 +1,402 @@
|
||||
/* Copyright (c) 2015 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Note: this file was pulled from different parts of the USBHID library, in mbed SDK
|
||||
*/
|
||||
|
||||
#ifndef KEYBOARD_DEFS_H
|
||||
#define KEYBOARD_DEFS_H
|
||||
|
||||
#define REPORT_ID_KEYBOARD 1
|
||||
#define REPORT_ID_VOLUME 3
|
||||
|
||||
/* Modifiers */
|
||||
enum MODIFIER_KEY {
|
||||
KEY_CTRL = 1,
|
||||
KEY_SHIFT = 2,
|
||||
KEY_ALT = 4,
|
||||
};
|
||||
|
||||
|
||||
enum MEDIA_KEY {
|
||||
KEY_NEXT_TRACK, /*!< next Track Button */
|
||||
KEY_PREVIOUS_TRACK, /*!< Previous track Button */
|
||||
KEY_STOP, /*!< Stop Button */
|
||||
KEY_PLAY_PAUSE, /*!< Play/Pause Button */
|
||||
KEY_MUTE, /*!< Mute Button */
|
||||
KEY_VOLUME_UP, /*!< Volume Up Button */
|
||||
KEY_VOLUME_DOWN, /*!< Volume Down Button */
|
||||
};
|
||||
|
||||
enum FUNCTION_KEY {
|
||||
KEY_F1 = 128, /* F1 key */
|
||||
KEY_F2, /* F2 key */
|
||||
KEY_F3, /* F3 key */
|
||||
KEY_F4, /* F4 key */
|
||||
KEY_F5, /* F5 key */
|
||||
KEY_F6, /* F6 key */
|
||||
KEY_F7, /* F7 key */
|
||||
KEY_F8, /* F8 key */
|
||||
KEY_F9, /* F9 key */
|
||||
KEY_F10, /* F10 key */
|
||||
KEY_F11, /* F11 key */
|
||||
KEY_F12, /* F12 key */
|
||||
|
||||
KEY_PRINT_SCREEN, /* Print Screen key */
|
||||
KEY_SCROLL_LOCK, /* Scroll lock */
|
||||
KEY_CAPS_LOCK, /* caps lock */
|
||||
KEY_NUM_LOCK, /* num lock */
|
||||
KEY_INSERT, /* Insert key */
|
||||
KEY_HOME, /* Home key */
|
||||
KEY_PAGE_UP, /* Page Up key */
|
||||
KEY_PAGE_DOWN, /* Page Down key */
|
||||
|
||||
RIGHT_ARROW, /* Right arrow */
|
||||
LEFT_ARROW, /* Left arrow */
|
||||
DOWN_ARROW, /* Down arrow */
|
||||
UP_ARROW, /* Up arrow */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
unsigned char usage;
|
||||
unsigned char modifier;
|
||||
} KEYMAP;
|
||||
|
||||
#ifdef US_KEYBOARD
|
||||
/* US keyboard (as HID standard) */
|
||||
#define KEYMAP_SIZE (152)
|
||||
const KEYMAP keymap[KEYMAP_SIZE] = {
|
||||
{0, 0}, /* NUL */
|
||||
{0, 0}, /* SOH */
|
||||
{0, 0}, /* STX */
|
||||
{0, 0}, /* ETX */
|
||||
{0, 0}, /* EOT */
|
||||
{0, 0}, /* ENQ */
|
||||
{0, 0}, /* ACK */
|
||||
{0, 0}, /* BEL */
|
||||
{0x2a, 0}, /* BS */ /* Keyboard Delete (Backspace) */
|
||||
{0x2b, 0}, /* TAB */ /* Keyboard Tab */
|
||||
{0x28, 0}, /* LF */ /* Keyboard Return (Enter) */
|
||||
{0, 0}, /* VT */
|
||||
{0, 0}, /* FF */
|
||||
{0, 0}, /* CR */
|
||||
{0, 0}, /* SO */
|
||||
{0, 0}, /* SI */
|
||||
{0, 0}, /* DEL */
|
||||
{0, 0}, /* DC1 */
|
||||
{0, 0}, /* DC2 */
|
||||
{0, 0}, /* DC3 */
|
||||
{0, 0}, /* DC4 */
|
||||
{0, 0}, /* NAK */
|
||||
{0, 0}, /* SYN */
|
||||
{0, 0}, /* ETB */
|
||||
{0, 0}, /* CAN */
|
||||
{0, 0}, /* EM */
|
||||
{0, 0}, /* SUB */
|
||||
{0, 0}, /* ESC */
|
||||
{0, 0}, /* FS */
|
||||
{0, 0}, /* GS */
|
||||
{0, 0}, /* RS */
|
||||
{0, 0}, /* US */
|
||||
{0x2c, 0}, /* */
|
||||
{0x1e, KEY_SHIFT}, /* ! */
|
||||
{0x34, KEY_SHIFT}, /* " */
|
||||
{0x20, KEY_SHIFT}, /* # */
|
||||
{0x21, KEY_SHIFT}, /* $ */
|
||||
{0x22, KEY_SHIFT}, /* % */
|
||||
{0x24, KEY_SHIFT}, /* & */
|
||||
{0x34, 0}, /* ' */
|
||||
{0x26, KEY_SHIFT}, /* ( */
|
||||
{0x27, KEY_SHIFT}, /* ) */
|
||||
{0x25, KEY_SHIFT}, /* * */
|
||||
{0x2e, KEY_SHIFT}, /* + */
|
||||
{0x36, 0}, /* , */
|
||||
{0x2d, 0}, /* - */
|
||||
{0x37, 0}, /* . */
|
||||
{0x38, 0}, /* / */
|
||||
{0x27, 0}, /* 0 */
|
||||
{0x1e, 0}, /* 1 */
|
||||
{0x1f, 0}, /* 2 */
|
||||
{0x20, 0}, /* 3 */
|
||||
{0x21, 0}, /* 4 */
|
||||
{0x22, 0}, /* 5 */
|
||||
{0x23, 0}, /* 6 */
|
||||
{0x24, 0}, /* 7 */
|
||||
{0x25, 0}, /* 8 */
|
||||
{0x26, 0}, /* 9 */
|
||||
{0x33, KEY_SHIFT}, /* : */
|
||||
{0x33, 0}, /* ; */
|
||||
{0x36, KEY_SHIFT}, /* < */
|
||||
{0x2e, 0}, /* = */
|
||||
{0x37, KEY_SHIFT}, /* > */
|
||||
{0x38, KEY_SHIFT}, /* ? */
|
||||
{0x1f, KEY_SHIFT}, /* @ */
|
||||
{0x04, KEY_SHIFT}, /* A */
|
||||
{0x05, KEY_SHIFT}, /* B */
|
||||
{0x06, KEY_SHIFT}, /* C */
|
||||
{0x07, KEY_SHIFT}, /* D */
|
||||
{0x08, KEY_SHIFT}, /* E */
|
||||
{0x09, KEY_SHIFT}, /* F */
|
||||
{0x0a, KEY_SHIFT}, /* G */
|
||||
{0x0b, KEY_SHIFT}, /* H */
|
||||
{0x0c, KEY_SHIFT}, /* I */
|
||||
{0x0d, KEY_SHIFT}, /* J */
|
||||
{0x0e, KEY_SHIFT}, /* K */
|
||||
{0x0f, KEY_SHIFT}, /* L */
|
||||
{0x10, KEY_SHIFT}, /* M */
|
||||
{0x11, KEY_SHIFT}, /* N */
|
||||
{0x12, KEY_SHIFT}, /* O */
|
||||
{0x13, KEY_SHIFT}, /* P */
|
||||
{0x14, KEY_SHIFT}, /* Q */
|
||||
{0x15, KEY_SHIFT}, /* R */
|
||||
{0x16, KEY_SHIFT}, /* S */
|
||||
{0x17, KEY_SHIFT}, /* T */
|
||||
{0x18, KEY_SHIFT}, /* U */
|
||||
{0x19, KEY_SHIFT}, /* V */
|
||||
{0x1a, KEY_SHIFT}, /* W */
|
||||
{0x1b, KEY_SHIFT}, /* X */
|
||||
{0x1c, KEY_SHIFT}, /* Y */
|
||||
{0x1d, KEY_SHIFT}, /* Z */
|
||||
{0x2f, 0}, /* [ */
|
||||
{0x31, 0}, /* \ */
|
||||
{0x30, 0}, /* ] */
|
||||
{0x23, KEY_SHIFT}, /* ^ */
|
||||
{0x2d, KEY_SHIFT}, /* _ */
|
||||
{0x35, 0}, /* ` */
|
||||
{0x04, 0}, /* a */
|
||||
{0x05, 0}, /* b */
|
||||
{0x06, 0}, /* c */
|
||||
{0x07, 0}, /* d */
|
||||
{0x08, 0}, /* e */
|
||||
{0x09, 0}, /* f */
|
||||
{0x0a, 0}, /* g */
|
||||
{0x0b, 0}, /* h */
|
||||
{0x0c, 0}, /* i */
|
||||
{0x0d, 0}, /* j */
|
||||
{0x0e, 0}, /* k */
|
||||
{0x0f, 0}, /* l */
|
||||
{0x10, 0}, /* m */
|
||||
{0x11, 0}, /* n */
|
||||
{0x12, 0}, /* o */
|
||||
{0x13, 0}, /* p */
|
||||
{0x14, 0}, /* q */
|
||||
{0x15, 0}, /* r */
|
||||
{0x16, 0}, /* s */
|
||||
{0x17, 0}, /* t */
|
||||
{0x18, 0}, /* u */
|
||||
{0x19, 0}, /* v */
|
||||
{0x1a, 0}, /* w */
|
||||
{0x1b, 0}, /* x */
|
||||
{0x1c, 0}, /* y */
|
||||
{0x1d, 0}, /* z */
|
||||
{0x2f, KEY_SHIFT}, /* { */
|
||||
{0x31, KEY_SHIFT}, /* | */
|
||||
{0x30, KEY_SHIFT}, /* } */
|
||||
{0x35, KEY_SHIFT}, /* ~ */
|
||||
{0,0}, /* DEL */
|
||||
|
||||
{0x3a, 0}, /* F1 */
|
||||
{0x3b, 0}, /* F2 */
|
||||
{0x3c, 0}, /* F3 */
|
||||
{0x3d, 0}, /* F4 */
|
||||
{0x3e, 0}, /* F5 */
|
||||
{0x3f, 0}, /* F6 */
|
||||
{0x40, 0}, /* F7 */
|
||||
{0x41, 0}, /* F8 */
|
||||
{0x42, 0}, /* F9 */
|
||||
{0x43, 0}, /* F10 */
|
||||
{0x44, 0}, /* F11 */
|
||||
{0x45, 0}, /* F12 */
|
||||
|
||||
{0x46, 0}, /* PRINT_SCREEN */
|
||||
{0x47, 0}, /* SCROLL_LOCK */
|
||||
{0x39, 0}, /* CAPS_LOCK */
|
||||
{0x53, 0}, /* NUM_LOCK */
|
||||
{0x49, 0}, /* INSERT */
|
||||
{0x4a, 0}, /* HOME */
|
||||
{0x4b, 0}, /* PAGE_UP */
|
||||
{0x4e, 0}, /* PAGE_DOWN */
|
||||
|
||||
{0x4f, 0}, /* RIGHT_ARROW */
|
||||
{0x50, 0}, /* LEFT_ARROW */
|
||||
{0x51, 0}, /* DOWN_ARROW */
|
||||
{0x52, 0}, /* UP_ARROW */
|
||||
};
|
||||
|
||||
#else
|
||||
/* UK keyboard */
|
||||
#define KEYMAP_SIZE (152)
|
||||
const KEYMAP keymap[KEYMAP_SIZE] = {
|
||||
{0, 0}, /* NUL */
|
||||
{0, 0}, /* SOH */
|
||||
{0, 0}, /* STX */
|
||||
{0, 0}, /* ETX */
|
||||
{0, 0}, /* EOT */
|
||||
{0, 0}, /* ENQ */
|
||||
{0, 0}, /* ACK */
|
||||
{0, 0}, /* BEL */
|
||||
{0x2a, 0}, /* BS */ /* Keyboard Delete (Backspace) */
|
||||
{0x2b, 0}, /* TAB */ /* Keyboard Tab */
|
||||
{0x28, 0}, /* LF */ /* Keyboard Return (Enter) */
|
||||
{0, 0}, /* VT */
|
||||
{0, 0}, /* FF */
|
||||
{0, 0}, /* CR */
|
||||
{0, 0}, /* SO */
|
||||
{0, 0}, /* SI */
|
||||
{0, 0}, /* DEL */
|
||||
{0, 0}, /* DC1 */
|
||||
{0, 0}, /* DC2 */
|
||||
{0, 0}, /* DC3 */
|
||||
{0, 0}, /* DC4 */
|
||||
{0, 0}, /* NAK */
|
||||
{0, 0}, /* SYN */
|
||||
{0, 0}, /* ETB */
|
||||
{0, 0}, /* CAN */
|
||||
{0, 0}, /* EM */
|
||||
{0, 0}, /* SUB */
|
||||
{0, 0}, /* ESC */
|
||||
{0, 0}, /* FS */
|
||||
{0, 0}, /* GS */
|
||||
{0, 0}, /* RS */
|
||||
{0, 0}, /* US */
|
||||
{0x2c, 0}, /* */
|
||||
{0x1e, KEY_SHIFT}, /* ! */
|
||||
{0x1f, KEY_SHIFT}, /* " */
|
||||
{0x32, 0}, /* # */
|
||||
{0x21, KEY_SHIFT}, /* $ */
|
||||
{0x22, KEY_SHIFT}, /* % */
|
||||
{0x24, KEY_SHIFT}, /* & */
|
||||
{0x34, 0}, /* ' */
|
||||
{0x26, KEY_SHIFT}, /* ( */
|
||||
{0x27, KEY_SHIFT}, /* ) */
|
||||
{0x25, KEY_SHIFT}, /* * */
|
||||
{0x2e, KEY_SHIFT}, /* + */
|
||||
{0x36, 0}, /* , */
|
||||
{0x2d, 0}, /* - */
|
||||
{0x37, 0}, /* . */
|
||||
{0x38, 0}, /* / */
|
||||
{0x27, 0}, /* 0 */
|
||||
{0x1e, 0}, /* 1 */
|
||||
{0x1f, 0}, /* 2 */
|
||||
{0x20, 0}, /* 3 */
|
||||
{0x21, 0}, /* 4 */
|
||||
{0x22, 0}, /* 5 */
|
||||
{0x23, 0}, /* 6 */
|
||||
{0x24, 0}, /* 7 */
|
||||
{0x25, 0}, /* 8 */
|
||||
{0x26, 0}, /* 9 */
|
||||
{0x33, KEY_SHIFT}, /* : */
|
||||
{0x33, 0}, /* ; */
|
||||
{0x36, KEY_SHIFT}, /* < */
|
||||
{0x2e, 0}, /* = */
|
||||
{0x37, KEY_SHIFT}, /* > */
|
||||
{0x38, KEY_SHIFT}, /* ? */
|
||||
{0x34, KEY_SHIFT}, /* @ */
|
||||
{0x04, KEY_SHIFT}, /* A */
|
||||
{0x05, KEY_SHIFT}, /* B */
|
||||
{0x06, KEY_SHIFT}, /* C */
|
||||
{0x07, KEY_SHIFT}, /* D */
|
||||
{0x08, KEY_SHIFT}, /* E */
|
||||
{0x09, KEY_SHIFT}, /* F */
|
||||
{0x0a, KEY_SHIFT}, /* G */
|
||||
{0x0b, KEY_SHIFT}, /* H */
|
||||
{0x0c, KEY_SHIFT}, /* I */
|
||||
{0x0d, KEY_SHIFT}, /* J */
|
||||
{0x0e, KEY_SHIFT}, /* K */
|
||||
{0x0f, KEY_SHIFT}, /* L */
|
||||
{0x10, KEY_SHIFT}, /* M */
|
||||
{0x11, KEY_SHIFT}, /* N */
|
||||
{0x12, KEY_SHIFT}, /* O */
|
||||
{0x13, KEY_SHIFT}, /* P */
|
||||
{0x14, KEY_SHIFT}, /* Q */
|
||||
{0x15, KEY_SHIFT}, /* R */
|
||||
{0x16, KEY_SHIFT}, /* S */
|
||||
{0x17, KEY_SHIFT}, /* T */
|
||||
{0x18, KEY_SHIFT}, /* U */
|
||||
{0x19, KEY_SHIFT}, /* V */
|
||||
{0x1a, KEY_SHIFT}, /* W */
|
||||
{0x1b, KEY_SHIFT}, /* X */
|
||||
{0x1c, KEY_SHIFT}, /* Y */
|
||||
{0x1d, KEY_SHIFT}, /* Z */
|
||||
{0x2f, 0}, /* [ */
|
||||
{0x64, 0}, /* \ */
|
||||
{0x30, 0}, /* ] */
|
||||
{0x23, KEY_SHIFT}, /* ^ */
|
||||
{0x2d, KEY_SHIFT}, /* _ */
|
||||
{0x35, 0}, /* ` */
|
||||
{0x04, 0}, /* a */
|
||||
{0x05, 0}, /* b */
|
||||
{0x06, 0}, /* c */
|
||||
{0x07, 0}, /* d */
|
||||
{0x08, 0}, /* e */
|
||||
{0x09, 0}, /* f */
|
||||
{0x0a, 0}, /* g */
|
||||
{0x0b, 0}, /* h */
|
||||
{0x0c, 0}, /* i */
|
||||
{0x0d, 0}, /* j */
|
||||
{0x0e, 0}, /* k */
|
||||
{0x0f, 0}, /* l */
|
||||
{0x10, 0}, /* m */
|
||||
{0x11, 0}, /* n */
|
||||
{0x12, 0}, /* o */
|
||||
{0x13, 0}, /* p */
|
||||
{0x14, 0}, /* q */
|
||||
{0x15, 0}, /* r */
|
||||
{0x16, 0}, /* s */
|
||||
{0x17, 0}, /* t */
|
||||
{0x18, 0}, /* u */
|
||||
{0x19, 0}, /* v */
|
||||
{0x1a, 0}, /* w */
|
||||
{0x1b, 0}, /* x */
|
||||
{0x1c, 0}, /* y */
|
||||
{0x1d, 0}, /* z */
|
||||
{0x2f, KEY_SHIFT}, /* { */
|
||||
{0x64, KEY_SHIFT}, /* | */
|
||||
{0x30, KEY_SHIFT}, /* } */
|
||||
{0x32, KEY_SHIFT}, /* ~ */
|
||||
{0,0}, /* DEL */
|
||||
|
||||
{0x3a, 0}, /* F1 */
|
||||
{0x3b, 0}, /* F2 */
|
||||
{0x3c, 0}, /* F3 */
|
||||
{0x3d, 0}, /* F4 */
|
||||
{0x3e, 0}, /* F5 */
|
||||
{0x3f, 0}, /* F6 */
|
||||
{0x40, 0}, /* F7 */
|
||||
{0x41, 0}, /* F8 */
|
||||
{0x42, 0}, /* F9 */
|
||||
{0x43, 0}, /* F10 */
|
||||
{0x44, 0}, /* F11 */
|
||||
{0x45, 0}, /* F12 */
|
||||
|
||||
{0x46, 0}, /* PRINT_SCREEN */
|
||||
{0x47, 0}, /* SCROLL_LOCK */
|
||||
{0x39, 0}, /* CAPS_LOCK */
|
||||
{0x53, 0}, /* NUM_LOCK */
|
||||
{0x49, 0}, /* INSERT */
|
||||
{0x4a, 0}, /* HOME */
|
||||
{0x4b, 0}, /* PAGE_UP */
|
||||
{0x4e, 0}, /* PAGE_DOWN */
|
||||
|
||||
{0x4f, 0}, /* RIGHT_ARROW */
|
||||
{0x50, 0}, /* LEFT_ARROW */
|
||||
{0x51, 0}, /* DOWN_ARROW */
|
||||
{0x52, 0}, /* UP_ARROW */
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,96 @@
|
||||
/* Copyright (c) 2010-2011 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
* and associated documentation files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or
|
||||
* substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef USBCLASS_HID_TYPES
|
||||
#define USBCLASS_HID_TYPES
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* */
|
||||
#define HID_VERSION_1_11 (0x0111)
|
||||
|
||||
/* HID Class */
|
||||
#define HID_CLASS (3)
|
||||
#define HID_SUBCLASS_NONE (0)
|
||||
#define HID_PROTOCOL_NONE (0)
|
||||
|
||||
/* Descriptors */
|
||||
#define HID_DESCRIPTOR (33)
|
||||
#define HID_DESCRIPTOR_LENGTH (0x09)
|
||||
#define REPORT_DESCRIPTOR (34)
|
||||
|
||||
/* Class requests */
|
||||
#define GET_REPORT (0x1)
|
||||
#define GET_IDLE (0x2)
|
||||
#define SET_REPORT (0x9)
|
||||
#define SET_IDLE (0xa)
|
||||
|
||||
/* HID Class Report Descriptor */
|
||||
/* Short items: size is 0, 1, 2 or 3 specifying 0, 1, 2 or 4 (four) bytes */
|
||||
/* of data as per HID Class standard */
|
||||
|
||||
/* Main items */
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#define HIDINPUT(size) (0x80 | size)
|
||||
#define HIDOUTPUT(size) (0x90 | size)
|
||||
#else
|
||||
#define INPUT(size) (0x80 | size)
|
||||
#define OUTPUT(size) (0x90 | size)
|
||||
#endif
|
||||
#define FEATURE(size) (0xb0 | size)
|
||||
#define COLLECTION(size) (0xa0 | size)
|
||||
#define END_COLLECTION(size) (0xc0 | size)
|
||||
|
||||
/* Global items */
|
||||
#define USAGE_PAGE(size) (0x04 | size)
|
||||
#define LOGICAL_MINIMUM(size) (0x14 | size)
|
||||
#define LOGICAL_MAXIMUM(size) (0x24 | size)
|
||||
#define PHYSICAL_MINIMUM(size) (0x34 | size)
|
||||
#define PHYSICAL_MAXIMUM(size) (0x44 | size)
|
||||
#define UNIT_EXPONENT(size) (0x54 | size)
|
||||
#define UNIT(size) (0x64 | size)
|
||||
#define REPORT_SIZE(size) (0x74 | size) //bits
|
||||
#define REPORT_ID(size) (0x84 | size)
|
||||
#define REPORT_COUNT(size) (0x94 | size) //bytes
|
||||
#define PUSH(size) (0xa4 | size)
|
||||
#define POP(size) (0xb4 | size)
|
||||
|
||||
/* Local items */
|
||||
#define USAGE(size) (0x08 | size)
|
||||
#define USAGE_MINIMUM(size) (0x18 | size)
|
||||
#define USAGE_MAXIMUM(size) (0x28 | size)
|
||||
#define DESIGNATOR_INDEX(size) (0x38 | size)
|
||||
#define DESIGNATOR_MINIMUM(size) (0x48 | size)
|
||||
#define DESIGNATOR_MAXIMUM(size) (0x58 | size)
|
||||
#define STRING_INDEX(size) (0x78 | size)
|
||||
#define STRING_MINIMUM(size) (0x88 | size)
|
||||
#define STRING_MAXIMUM(size) (0x98 | size)
|
||||
#define DELIMITER(size) (0xa8 | size)
|
||||
|
||||
/* HID Report */
|
||||
/* Where report IDs are used the first byte of 'data' will be the */
|
||||
/* report ID and 'length' will include this report ID byte. */
|
||||
|
||||
#define MAX_HID_REPORT_SIZE (64)
|
||||
|
||||
typedef struct {
|
||||
uint32_t length;
|
||||
uint8_t data[MAX_HID_REPORT_SIZE];
|
||||
} HID_REPORT;
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user