diff --git a/middleware/third_party/arduino/hardware/arduino/mt7697/cores/arduino/IPAddress.cpp b/middleware/third_party/arduino/hardware/arduino/mt7697/cores/arduino/IPAddress.cpp index 37d444a..0b10667 100755 --- a/middleware/third_party/arduino/hardware/arduino/mt7697/cores/arduino/IPAddress.cpp +++ b/middleware/third_party/arduino/hardware/arduino/mt7697/cores/arduino/IPAddress.cpp @@ -75,7 +75,6 @@ size_t IPAddress::printTo(Print& p) const String IPAddress::toString() const { String p; - size_t n = 0; for (int i =0; i < 3; i++) { p += String(_address.bytes[i], DEC); diff --git a/middleware/third_party/arduino/hardware/arduino/mt7697/cores/arduino/wiring_analog.c b/middleware/third_party/arduino/hardware/arduino/mt7697/cores/arduino/wiring_analog.c index 51d74b0..00a734b 100755 --- a/middleware/third_party/arduino/hardware/arduino/mt7697/cores/arduino/wiring_analog.c +++ b/middleware/third_party/arduino/hardware/arduino/mt7697/cores/arduino/wiring_analog.c @@ -58,7 +58,7 @@ uint32_t analogRead(uint32_t ulPin) { // Note that Arduino UNO's implementation accepts both // pin # and ADC channel number. so we make a detection here: - if (ulPin < HAL_ADC_CHANNEL_MAX && ulPin >= 0) { + if (ulPin < HAL_ADC_CHANNEL_MAX) { // user gave use channel number, e.g. // ```analogRead(0);``` adc_channel = (int)ulPin; diff --git a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/examples/ConnectPeripheral/ConnectPeripheral.ino b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/examples/ConnectPeripheral/ConnectPeripheral.ino index 55c083c..07025f8 100644 --- a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/examples/ConnectPeripheral/ConnectPeripheral.ino +++ b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/examples/ConnectPeripheral/ConnectPeripheral.ino @@ -53,7 +53,7 @@ void printDeviceInfo(int i) { if (LBLECentral.isIBeacon(i)) { LBLEUuid uuid; uint16_t major = 0, minor = 0; - uint8_t txPower = 0; + int8_t txPower = 0; LBLECentral.getIBeaconInfo(i, uuid, major, minor, txPower); Serial.print(" "); diff --git a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/keywords.txt b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/keywords.txt index f3d6a31..512ddf2 100644 --- a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/keywords.txt +++ b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/keywords.txt @@ -3,66 +3,88 @@ ####################################### ####################################### -# Library (KEYWORD1) +# Classes (KEYWORD1) ####################################### -LBLE KEYWORD1 LBLE -LBLECentral KEYWORD1 LBLECentral -LBLEPeripheral KEYWORD1 LBLEPeripheral - -####################################### -# Datatypes (KEYWORD1) -####################################### - -LBLECentral KEYWORD1 LBLECentral -LBLEPeripheral KEYWORD1 LBLEPeripheral -LBLEUuid KEYWORD1 +LBLE KEYWORD1 +LBLECentral KEYWORD1 +LBLEPeripheral KEYWORD1 +LBLEUuid KEYWORD1 +LBLEAdvertisementData KEYWORD1 +LBLEService KEYWORD1 +LBLEAddress KEYWORD1 +LBLEUuidLBLEClient KEYWORD1 +LBLECharacteristicInt KEYWORD1 +LBLECharacteristicString KEYWORD1 +LBLECharacteristicBuffer KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) ####################################### - -firmwareVersion KEYWORD2 -status KEYWORD2 -connect KEYWORD2 -write KEYWORD2 -available KEYWORD2 -config KEYWORD2 -setDNS KEYWORD2 -read KEYWORD2 -flush KEYWORD2 -stop KEYWORD2 -connected KEYWORD2 -begin KEYWORD2 -disconnect KEYWORD2 -macAddress KEYWORD2 -localIP KEYWORD2 -subnetMask KEYWORD2 -gatewayIP KEYWORD2 -SSID KEYWORD2 -BSSID KEYWORD2 -RSSI KEYWORD2 -encryptionType KEYWORD2 -getResult KEYWORD2 -getSocket KEYWORD2 -WiFiClient KEYWORD2 WiFiClient -WiFiServer KEYWORD2 WiFiServer -WiFiUDP KEYWORD2 WiFiUDPConstructor -beginPacket KEYWORD2 -endPacket KEYWORD2 -parsePacket KEYWORD2 -remoteIP KEYWORD2 -remotePort KEYWORD2 - -scan KEYWORD2 -getAddress KEYWORD2 -getName KEYWORD2 -getTxPower KEYWORD2 -getRSSI KEYWORD2 -getServiceUuid KEYWORD2 -getManufacturer KEYWORD2 - +begin KEYWORD2 +ready KEYWORD2 +getDeviceAddress KEYWORD2 +scan KEYWORD2 +stopScan KEYWORD2 +getPeripheralCount KEYWORD2 +getAddress KEYWORD2 +getBLEAddress KEYWORD2 +getManufacturer KEYWORD2 +getName KEYWORD2 +getRSSI KEYWORD2 +getTxPower KEYWORD2 +getServiceUuid KEYWORD2 +getIBeaconInfo KEYWORD2 +addService KEYWORD2 +advertise KEYWORD2 +advertiseAsBeacon KEYWORD2 +stopAdvertise KEYWORD2 +notifyAll KEYWORD2 +configAsConnectableDevice KEYWORD2 +configAsEddystoneURL KEYWORD2 +configAsIBeacon KEYWORD2 +addAttribute KEYWORD2 +isWritten KEYWORD2 +getValue KEYWORD2 +setValue KEYWORD2 +toString KEYWORD2 +isEmpty KEYWORD2 +is16Bit KEYWORD2 +getUuid16 KEYWORD2 +connect KEYWORD2 +connected KEYWORD2 +disconnect KEYWORD2 +hasService KEYWORD2 +getServiceCount KEYWORD2 +getServiceName KEYWORD2 +getServiceUuid KEYWORD2 +readCharacteristicString KEYWORD2 +readCharacteristicInt KEYWORD2 +writeCharacteristicFloat KEYWORD2 +writeCharacteristicString KEYWORD2 +writeCharacteristicInt KEYWORD2 +writeCharacteristicFloat KEYWORD2 ####################################### # Constants (LITERAL1) ####################################### + +EDDY_HTTP_WWW LITERAL1 +EDDY_HTTPS_WWW LITERAL1 +EDDY_HTTP LITERAL1 +EDDY_HTTPS LITERAL1 +EDDY_URL_NONE LITERAL1 +EDDY_DOT_COM_SLASH LITERAL1 +EDDY_DOT_ORG_SLASH LITERAL1 +EDDY_DOT_EDU_SLASH LITERAL1 +EDDY_DOT_NET_SLASH LITERAL1 +EDDY_DOT_INFO_SLASH LITERAL1 +EDDY_DOT_BIZ_SLASH LITERAL1 +EDDY_DOT_GOV_SLASH LITERAL1 +EDDY_DOT_COM LITERAL1 +EDDY_DOT_ORG LITERAL1 +EDDY_DOT_EDU LITERAL1 +EDDY_DOT_NET LITERAL1 +EDDY_DOT_INFO LITERAL1 +EDDY_DOT_BIZ LITERAL1 +EDDY_DOT_GOV LITERAL1 diff --git a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLE.cpp b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLE.cpp index 644b2e9..e70c089 100644 --- a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLE.cpp +++ b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLE.cpp @@ -1,3 +1,4 @@ + #include #include #include @@ -14,25 +15,25 @@ extern "C" { class LBLEAutoLock { public: - LBLEAutoLock(SemaphoreHandle_t sem): - m_sem(sem) - { - // keep waiting for the lock - while(pdFALSE == xSemaphoreTakeRecursive(m_sem, 10)) - { - pr_debug("spin wait sem=0x%x", (int)m_sem); - } - } - - ~LBLEAutoLock() - { - xSemaphoreGiveRecursive(m_sem); - } + LBLEAutoLock(SemaphoreHandle_t sem): + m_sem(sem) + { + // keep waiting for the lock + while(pdFALSE == xSemaphoreTakeRecursive(m_sem, 10)) + { + pr_debug("spin wait sem=0x%x", (int)m_sem); + } + } + + ~LBLEAutoLock() + { + xSemaphoreGiveRecursive(m_sem); + } private: - SemaphoreHandle_t m_sem; + SemaphoreHandle_t m_sem; - // forbid copy - LBLEAutoLock(const LBLEAutoLock& rhs){}; + // forbid copy + LBLEAutoLock(const LBLEAutoLock& rhs) {}; }; /////////////////////////////////////////////// @@ -40,65 +41,65 @@ class LBLEAutoLock ////////////////////////////////////////////// LBLEClass::LBLEClass(): - m_dispatcherSemaphore(NULL) + m_dispatcherSemaphore(NULL) { } int LBLEClass::begin() { - m_dispatcherSemaphore = xSemaphoreCreateRecursiveMutex(); - if(NULL == m_dispatcherSemaphore) - { - pr_debug("failed to create semaphore for dispatcher!"); - return 0; - } - return ard_ble_begin(); + m_dispatcherSemaphore = xSemaphoreCreateRecursiveMutex(); + if(NULL == m_dispatcherSemaphore) + { + pr_debug("failed to create semaphore for dispatcher!"); + return 0; + } + return ard_ble_begin(); } int LBLEClass::ready() { - return ard_ble_is_ready(); + return ard_ble_is_ready(); } LBLEAddress LBLEClass::getDeviceAddress() { - // the underlying framework passes an pointer - // to global device address. - bt_bd_addr_ptr_t randBDAddr = bt_gap_le_get_random_address(); - bt_addr_t btAddr; - btAddr.type = BT_ADDR_RANDOM; - memcpy(&btAddr.addr, randBDAddr, BT_BD_ADDR_LEN); - return LBLEAddress(btAddr); + // the underlying framework passes an pointer + // to global device address. + bt_bd_addr_ptr_t randBDAddr = bt_gap_le_get_random_address(); + bt_addr_t btAddr; + btAddr.type = BT_ADDR_RANDOM; + memcpy(&btAddr.addr, randBDAddr, BT_BD_ADDR_LEN); + return LBLEAddress(btAddr); } void LBLEClass::registerForEvent(bt_msg_type_t msg, LBLEEventObserver* pObserver) { - LBLEAutoLock lock(m_dispatcherSemaphore); - if( (((int)pObserver) & 0xF0000000) == 0) - { - pr_debug("abnormal observer added: msg:0x%x, pobserver:0x%x", (int)msg, (int)pObserver); - } + LBLEAutoLock lock(m_dispatcherSemaphore); + if( (((int)pObserver) & 0xF0000000) == 0) + { + pr_debug("abnormal observer added: msg:0x%x, pobserver:0x%x", (int)msg, (int)pObserver); + } - #if 1 - pr_debug("observer added: msg:0x%x, pobserver:0x%x", (int)msg, (int)pObserver); - #endif +#if 1 + pr_debug("observer added: msg:0x%x, pobserver:0x%x", (int)msg, (int)pObserver); +#endif - m_dispatcher.addObserver(msg, pObserver); + m_dispatcher.addObserver(msg, pObserver); } void LBLEClass::unregisterForEvent(bt_msg_type_t msg, LBLEEventObserver* pObserver) { - LBLEAutoLock lock(m_dispatcherSemaphore); - m_dispatcher.removeObserver(msg, pObserver); - #if 1 - pr_debug("observer removed: msg:0x%x, pobserver:0x%x", (int)msg, (int)pObserver); - #endif + LBLEAutoLock lock(m_dispatcherSemaphore); + m_dispatcher.removeObserver(msg, pObserver); +#if 1 + pr_debug("observer removed: msg:0x%x, pobserver:0x%x", (int)msg, (int)pObserver); +#endif } void LBLEClass::handleEvent(bt_msg_type_t msg, bt_status_t status, void *buff) { - LBLEAutoLock lock(m_dispatcherSemaphore); - m_dispatcher.dispatch(msg, status, buff); + LBLEAutoLock lock(m_dispatcherSemaphore); + m_dispatcher.dispatch(msg, status, buff); } LBLEClass LBLE; @@ -108,209 +109,235 @@ LBLEClass LBLE; ///////////////////////////////////////////////////////////////////////////// LBLEUuid::LBLEUuid() { - memset(&uuid_data, 0, sizeof(uuid_data)); + memset(&uuid_data, 0, sizeof(uuid_data)); } uint8_t ascii_to_uint8(char c) { - if('0' <= c && c <= '9') - return c - '0'; + if('0' <= c && c <= '9') + return c - '0'; - if('A' <= c && c <= 'F') - return 10 + (c - 'A'); + if('A' <= c && c <= 'F') + return 10 + (c - 'A'); - if('a' <= c && c <= 'f') - return 10 + (c - 'a'); + if('a' <= c && c <= 'f') + return 10 + (c - 'a'); - return 0; + return 0; } void str_to_uuid(bt_uuid_t &data, const char* uuidStr) { - // https://www.ietf.org/rfc/rfc4122.txt - const uint len = strlen(uuidStr); - if(len != 36) - { - return; - } + // https://www.ietf.org/rfc/rfc4122.txt + const uint len = strlen(uuidStr); + if(len != 36) + { + return; + } - for(int i = 0; i < 16; ++i) - { - uint8_t val = 0; + for(int i = 0; i < 16; ++i) + { + uint8_t val = 0; - if('-' == *uuidStr) - ++uuidStr; + if('-' == *uuidStr) + ++uuidStr; - val = ascii_to_uint8(*uuidStr); - val = (val << 4); - ++uuidStr; + val = ascii_to_uint8(*uuidStr); + val = (val << 4); + ++uuidStr; - val += ascii_to_uint8(*uuidStr); - ++uuidStr; + val += ascii_to_uint8(*uuidStr); + ++uuidStr; - // note that the string representation is - // from HIGH to LOW - so we need to reverse here. - data.uuid[15 - i] = val; - } + // note that the string representation is + // from HIGH to LOW - so we need to reverse here. + data.uuid[15 - i] = val; + } } LBLEUuid::LBLEUuid(const char* uuidString) { - str_to_uuid(uuid_data, uuidString); + str_to_uuid(uuid_data, uuidString); } LBLEUuid::LBLEUuid(uint16_t uuid16) { - bt_uuid_from_uuid16(&uuid_data, uuid16); + bt_uuid_from_uuid16(&uuid_data, uuid16); } LBLEUuid::LBLEUuid(const bt_uuid_t& rhs): - uuid_data(rhs) + uuid_data(rhs) { } LBLEUuid::LBLEUuid(const LBLEUuid& rhs): - uuid_data(rhs.uuid_data) + uuid_data(rhs.uuid_data) { } LBLEUuid & LBLEUuid::operator = (const bt_uuid_t &rhs) { - uuid_data = rhs; + uuid_data = rhs; - return *this; + return *this; } LBLEUuid & LBLEUuid::operator = (const LBLEUuid &rhs) { - if(this == &rhs) return *this; + if(this == &rhs) return *this; - uuid_data = rhs.uuid_data; + uuid_data = rhs.uuid_data; - return *this; + return *this; } LBLEUuid & LBLEUuid::operator = (const char* rhs) { - str_to_uuid(uuid_data, rhs); - return *this; + str_to_uuid(uuid_data, rhs); + return *this; } unsigned char LBLEUuid::equals(const LBLEUuid &rhs) const { - return bt_uuid_equal(&uuid_data, &rhs.uuid_data); + return bt_uuid_equal(&uuid_data, &rhs.uuid_data); } bool LBLEUuid::operator<(const LBLEUuid &rhs) const { - if(is16Bit()) - { - return (uuid_data.uuid16 < rhs.uuid_data.uuid16); - } - else if(bt_uuid_is_uuid32(&uuid_data)) - { - return (uuid_data.uuid32 < rhs.uuid_data.uuid32); - } - else - { - // 128-bit: compare from MSB to LSB - for(int i = 0; i < 16; ++i) - { - const uint8_t byteLhs = uuid_data.uuid[15 - i]; - const uint8_t byteRhs = rhs.uuid_data.uuid[15 - i]; - if(byteLhs != byteRhs) - { - return (byteLhs < byteRhs); - } - } - } - - return false; + const bool rhs16 = rhs.is16Bit(); + const bool rhs32 = bt_uuid_is_uuid32(&rhs.uuid_data); + + if(is16Bit()) + { + if(rhs16) { + return (uuid_data.uuid16 < rhs.uuid_data.uuid16); + } + + // 16-bit is always smaller than 32/128 + return true; + } + else if(bt_uuid_is_uuid32(&uuid_data)) + { + if(rhs32) { + return (uuid_data.uuid32 < rhs.uuid_data.uuid32); + } + + // 32-bit is larger than 16-bit + if(rhs16) { + return false; + } + + // 128-bit case + return true; + } + else + { + if(rhs16) { + return false; + } + + if(rhs32) { + return false; + } + + // 128-bit: compare from MSB to LSB + for(int i = 0; i < 16; ++i) + { + const uint8_t byteLhs = uuid_data.uuid[15 - i]; + const uint8_t byteRhs = rhs.uuid_data.uuid[15 - i]; + if(byteLhs != byteRhs) + { + return (byteLhs < byteRhs); + } + } + } + + return false; } bool LBLEUuid::isEmpty() const { - const static bt_uuid_t zero_data = {0}; - return (0 == memcmp(&uuid_data, &zero_data, sizeof(bt_uuid_t))); + const static bt_uuid_t zero_data = {0}; + return (0 == memcmp(&uuid_data, &zero_data, sizeof(bt_uuid_t))); } bool LBLEUuid::is16Bit() const { - return bt_uuid_is_uuid16(&uuid_data); + return bt_uuid_is_uuid16(&uuid_data); } uint16_t LBLEUuid::getUuid16() const { - if(!is16Bit()) - return 0; + if(!is16Bit()) + return 0; - return uuid_data.uuid16; + return uuid_data.uuid16; } void LBLEUuid::toRawBuffer(uint8_t* uuidBuf, uint32_t bufLength) const { - // input check - if(NULL == uuidBuf || 16 > bufLength) - { - return; - } + // input check + if(NULL == uuidBuf || 16 > bufLength) + { + return; + } - // full 16 bytes of 128-bit uuid. - memcpy(uuidBuf, uuid_data.uuid, 16); + // full 16 bytes of 128-bit uuid. + memcpy(uuidBuf, uuid_data.uuid, 16); } String LBLEUuid::toString() const { - char str[37] = {0}; - - if(bt_uuid_is_uuid16(&uuid_data)) - { - sprintf(str, - "0x%04x", - uuid_data.uuid16 - ); - } - else if(bt_uuid_is_uuid32(&uuid_data)) - { - sprintf(str, - "0x%08lx", - uuid_data.uuid32 - ); - } - else - { - sprintf(str, - "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", - uuid_data.uuid[15], - uuid_data.uuid[14], - uuid_data.uuid[13], - uuid_data.uuid[12], - uuid_data.uuid[11], - uuid_data.uuid[10], - uuid_data.uuid[9], - uuid_data.uuid[8], - uuid_data.uuid[7], - uuid_data.uuid[6], - uuid_data.uuid[5], - uuid_data.uuid[4], - uuid_data.uuid[3], - uuid_data.uuid[2], - uuid_data.uuid[1], - uuid_data.uuid[0] - ); - } - - return String(str); + char str[37] = {0}; + + if(bt_uuid_is_uuid16(&uuid_data)) + { + sprintf(str, + "0x%04x", + uuid_data.uuid16 + ); + } + else if(bt_uuid_is_uuid32(&uuid_data)) + { + sprintf(str, + "0x%08lx", + uuid_data.uuid32 + ); + } + else + { + sprintf(str, + "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", + uuid_data.uuid[15], + uuid_data.uuid[14], + uuid_data.uuid[13], + uuid_data.uuid[12], + uuid_data.uuid[11], + uuid_data.uuid[10], + uuid_data.uuid[9], + uuid_data.uuid[8], + uuid_data.uuid[7], + uuid_data.uuid[6], + uuid_data.uuid[5], + uuid_data.uuid[4], + uuid_data.uuid[3], + uuid_data.uuid[2], + uuid_data.uuid[1], + uuid_data.uuid[0] + ); + } + + return String(str); } size_t LBLEUuid::printTo(Print& p) const { - String str = toString(); - p.print(str); + String str = toString(); + p.print(str); - return str.length(); + return str.length(); } @@ -318,100 +345,100 @@ size_t LBLEUuid::printTo(Print& p) const // LBLEAddress helper class ///////////////////////////////////////////////////////////////////////////// LBLEAddress::LBLEAddress(): - m_addr() + m_addr() { - memset(&m_addr, sizeof(m_addr), 0); + memset(&m_addr, sizeof(m_addr), 0); } LBLEAddress::LBLEAddress(const bt_addr_t& btAddr) { - m_addr.type = btAddr.type; - memcpy(m_addr.addr, btAddr.addr, BT_BD_ADDR_LEN); + m_addr.type = btAddr.type; + memcpy(m_addr.addr, btAddr.addr, BT_BD_ADDR_LEN); } LBLEAddress::~LBLEAddress() { - + } size_t LBLEAddress::printTo(Print& p) const { - const String str = toString(); - p.print(str); + const String str = toString(); + p.print(str); - return str.length(); + return str.length(); } String LBLEAddress::toString() const { - return convertBluetoothAddressToString(m_addr); + return convertBluetoothAddressToString(m_addr); } const char* LBLEAddress::getAddressTypeString(bt_addr_type_t addrType) { - switch(addrType) - { - case BT_ADDR_PUBLIC: - return "PUB"; - case BT_ADDR_RANDOM: - return "RAN"; - case BT_ADDR_PUBLIC_IDENTITY: - return "PID"; - case BT_ADDR_RANDOM_IDENTITY: - return "RID"; - default: - return "---"; - } + switch(addrType) + { + case BT_ADDR_PUBLIC: + return "PUB"; + case BT_ADDR_RANDOM: + return "RAN"; + case BT_ADDR_PUBLIC_IDENTITY: + return "PID"; + case BT_ADDR_RANDOM_IDENTITY: + return "RID"; + default: + return "---"; + } } String LBLEAddress::convertBluetoothAddressToString(const bt_addr_t& btAddr) { - // 6-byte MAC address in HEX with ":" as seperator, - // and 5-byte address type, e.g. "(PUB)", - // plus NULL terminator + // 6-byte MAC address in HEX with ":" as seperator, + // and 5-byte address type, e.g. "(PUB)", + // plus NULL terminator char buf[BT_BD_ADDR_LEN * 2 + BT_BD_ADDR_LEN - 1 + 5 + 1] = {0}; sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X(%s)", - btAddr.addr[5], - btAddr.addr[4], - btAddr.addr[3], - btAddr.addr[2], - btAddr.addr[1], - btAddr.addr[0], - getAddressTypeString(btAddr.type) - ); + btAddr.addr[5], + btAddr.addr[4], + btAddr.addr[3], + btAddr.addr[2], + btAddr.addr[1], + btAddr.addr[0], + getAddressTypeString(btAddr.type) + ); return String(buf); } String LBLEAddress::convertDeviceAddressToString(const bt_bd_addr_ptr_t addr) { - if(NULL == addr) - { - return String(); - } + if(NULL == addr) + { + return String(); + } - // 6-byte MAC address in HEX with ":" as seperator, - // plus NULL terminator + // 6-byte MAC address in HEX with ":" as seperator, + // plus NULL terminator char addr_buf[BT_BD_ADDR_LEN * 2 + BT_BD_ADDR_LEN - 1 + 1] = {0}; sprintf(addr_buf, "%02X:%02X:%02X:%02X:%02X:%02X", - addr[5], - addr[4], - addr[3], - addr[2], - addr[1], - addr[0]); + addr[5], + addr[4], + addr[3], + addr[2], + addr[1], + addr[0]); return String(addr_buf); } unsigned char LBLEAddress::equals(const LBLEAddress& rhs) const { - if(this == &rhs) - { - return 1; - } + if(this == &rhs) + { + return 1; + } - return equal_bt_address(this->m_addr, rhs.m_addr); + return equal_bt_address(this->m_addr, rhs.m_addr); } // returns true if lhs equals rhs address. @@ -422,93 +449,93 @@ bool LBLEAddress::equal_bt_address(const bt_addr_t& lhs, const bt_addr_t&rhs) LBLEAddress& LBLEAddress::operator = (const LBLEAddress &rhs) { - if(this == &rhs) - return *this; + if(this == &rhs) + return *this; - m_addr.type = rhs.m_addr.type; - memcpy(m_addr.addr, rhs.m_addr.addr, BT_BD_ADDR_LEN); + m_addr.type = rhs.m_addr.type; + memcpy(m_addr.addr, rhs.m_addr.addr, BT_BD_ADDR_LEN); - return *this; + return *this; } void ard_ble_postAllEvents(bt_msg_type_t msg, bt_status_t status, void *buff) { - // this is a filter hook, executed after all BT message handlers - - LBLE.handleEvent(msg, status, buff); + // this is a filter hook, executed after all BT message handlers + + LBLE.handleEvent(msg, status, buff); return; } void LBLEEventDispatcher::addObserver(bt_msg_type_t msg, LBLEEventObserver* pObserver) { - // pr_debug("add observer: i->second:%p", (int)msg, pObserver); - m_table.insert(std::make_pair(msg, pObserver)); + // pr_debug("add observer: i->second:%p", (int)msg, pObserver); + m_table.insert(std::make_pair(msg, pObserver)); } void LBLEEventDispatcher::removeObserver(bt_msg_type_t msg, LBLEEventObserver* pObserver) { - // we cannot remove the key (msg), - // since there may be other observers - // registered to the same key. - // So we loop over the matching elements - // and check the handler pointer. - auto i = m_table.find(msg); - while(i != m_table.end()) - { - if(i->second == pObserver) - { - m_table.erase(i); - return; - } - ++i; - } + // we cannot remove the key (msg), + // since there may be other observers + // registered to the same key. + // So we loop over the matching elements + // and check the handler pointer. + auto i = m_table.find(msg); + while(i != m_table.end()) + { + if(i->second == pObserver) + { + m_table.erase(i); + return; + } + ++i; + } } void LBLEEventDispatcher::dispatch(bt_msg_type_t msg, bt_status_t status, void *buff) { - // pr_debug("dispatch: msg:0x%x", msg); - auto i = m_table.find(msg); - - std::vector removeList; - // execute observer's callback and pop the element found - while(i != m_table.end()) - { - if(i->first != msg) - { - break; - } - - if(i->second) - { - #if 0 - { - pr_debug("dispatch found: msg:0x%x, i->second:%p", (int)msg, i->second); - } - #endif - // check if we need to remove after processing the event - // make a copy before we advance to next item - if(i->second->isOnce()) - { - removeList.push_back(i); - } - - // process event - i->second->onEvent(msg, status, buff); - } - else - { - pr_debug("dangling observer on event 0x%x", msg); - } - - // advance to next registered observer. - ++i; - } - - // now we clear any "once" observers, if any. - for(auto&& r : removeList) + // pr_debug("dispatch: msg:0x%x", msg); + auto i = m_table.find(msg); + + std::vector removeList; + // execute observer's callback and pop the element found + while(i != m_table.end()) + { + if(i->first != msg) + { + break; + } + + if(i->second) + { +#if 0 + { + pr_debug("dispatch found: msg:0x%x, i->second:%p", (int)msg, i->second); + } +#endif + // check if we need to remove after processing the event + // make a copy before we advance to next item + if(i->second->isOnce()) + { + removeList.push_back(i); + } + + // process event + i->second->onEvent(msg, status, buff); + } + else + { + pr_debug("dangling observer on event 0x%x", msg); + } + + // advance to next registered observer. + ++i; + } + + // now we clear any "once" observers, if any. + for(auto&& r : removeList) { - m_table.erase(r); + m_table.erase(r); } } diff --git a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLE.h b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLE.h index 1fde551..89b459f 100644 --- a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLE.h +++ b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLE.h @@ -13,7 +13,7 @@ #include extern "C" { -/* FreeRTOS headers */ + /* FreeRTOS headers */ #include #include #include @@ -26,7 +26,7 @@ extern "C" { /// This class represents BT UUIDs that are used /// to identifie characteristics and other BLE GATT /// attributes. -/// +/// /// Many GATT Service and characteristic APIs relies on this /// class to identify different attributes. /// @@ -44,85 +44,85 @@ class LBLEUuid : public Printable { public: // Constructors - /// \brief Creates an empty UUID. - LBLEUuid(); - - /// \brief Creates 128-bit UUID - /// - /// Creates UUID from 128-bit string representation, e.g. - /// ~~~{.cpp} - /// LBLEUuid uuid("E2C56DB5-DFFB-48D2-B060-D0F5A71096E0"); - /// ~~~ - LBLEUuid(const char* uuidString); - - /// \brief Creates 16-bit Bluetooth assigned UUID. - /// - /// Creates an assigned 16-bit BT UUID from an unsigned short. - /// In the example below, we create an UUID for "Device Information" service. - /// See https://www.bluetooth.com/specifications/gatt/services - /// for a list of assigned numbers for services. - /// ~~~{.cpp} - /// LBLEUuid uuid(0x180A); // create UUID for Device Information service. - /// ~~~ - LBLEUuid(uint16_t uuid16); - - /// Initialize from MTK BLE framework's bt_uuid_t struct. - LBLEUuid(const bt_uuid_t& uuid_data); - - /// Copy constructor - LBLEUuid(const LBLEUuid& rhs); + /// \brief Creates an empty UUID. + LBLEUuid(); + + /// \brief Creates 128-bit UUID + /// + /// Creates UUID from 128-bit string representation, e.g. + /// ~~~{.cpp} + /// LBLEUuid uuid("E2C56DB5-DFFB-48D2-B060-D0F5A71096E0"); + /// ~~~ + LBLEUuid(const char* uuidString); + + /// \brief Creates 16-bit Bluetooth assigned UUID. + /// + /// Creates an assigned 16-bit BT UUID from an unsigned short. + /// In the example below, we create an UUID for "Device Information" service. + /// See https://www.bluetooth.com/specifications/gatt/services + /// for a list of assigned numbers for services. + /// ~~~{.cpp} + /// LBLEUuid uuid(0x180A); // create UUID for Device Information service. + /// ~~~ + LBLEUuid(uint16_t uuid16); + + /// Initialize from MTK BLE framework's bt_uuid_t struct. + LBLEUuid(const bt_uuid_t& uuid_data); + + /// Copy constructor + LBLEUuid(const LBLEUuid& rhs); public: - LBLEUuid & operator = (const bt_uuid_t &rhs); - LBLEUuid & operator = (const LBLEUuid &rhs); - LBLEUuid & operator = (const char* rhs); + LBLEUuid & operator = (const bt_uuid_t &rhs); + LBLEUuid & operator = (const LBLEUuid &rhs); + LBLEUuid & operator = (const char* rhs); - unsigned char equals(const LBLEUuid &rhs) const; + unsigned char equals(const LBLEUuid &rhs) const; unsigned char operator == (const LBLEUuid &rhs) const { return equals(rhs); } - bool operator<(const LBLEUuid &rhs) const; + bool operator<(const LBLEUuid &rhs) const; -public: +public: - /// Returns String representation format for UI. - String toString() const; + /// Returns String representation format for UI. + String toString() const; - /// Implements Pritable interface. - virtual size_t printTo(Print& p) const; + /// Implements Pritable interface. + virtual size_t printTo(Print& p) const; public: // Helper function - /// Convert LBLEUuid object to raw 128-bit buffer - void toRawBuffer(uint8_t* uuidBuf, uint32_t bufLength) const; - - /// \brief Check if the UUID is empty (just created). - /// - /// \returns true if the UUID is empty - /// \returns false if the UUID is not empty - bool isEmpty() const; - - /// \brief Check if this UUID is a 16-bit UUID. - /// - /// Check if the UUID is an 16-bit UUID, which is assigned by BT SIG, or - /// a generic, developer-generated 128-bit UUID. - /// - /// \returns true if the UUID is 16-bit assigned number. - /// Note that this method does not check - /// if the 16-bit is actually a BT SIG assigned - /// number; it simply check if it is 16-bit long. - /// \returns false if the UUID is 128-bit UUID. - bool is16Bit() const; - - /// \brief Get the unsigned short representation of a 16-bit assigned UUID. - /// - /// \returns unsigned short value of the 16-bit assigned UUID. - /// \returns 0 if the LBLEUuid is not a 16-bit UUID. - uint16_t getUuid16() const; + /// Convert LBLEUuid object to raw 128-bit buffer + void toRawBuffer(uint8_t* uuidBuf, uint32_t bufLength) const; + + /// \brief Check if the UUID is empty (just created). + /// + /// \returns true if the UUID is empty + /// \returns false if the UUID is not empty + bool isEmpty() const; + + /// \brief Check if this UUID is a 16-bit UUID. + /// + /// Check if the UUID is an 16-bit UUID, which is assigned by BT SIG, or + /// a generic, developer-generated 128-bit UUID. + /// + /// \returns true if the UUID is 16-bit assigned number. + /// Note that this method does not check + /// if the 16-bit is actually a BT SIG assigned + /// number; it simply check if it is 16-bit long. + /// \returns false if the UUID is 128-bit UUID. + bool is16Bit() const; + + /// \brief Get the unsigned short representation of a 16-bit assigned UUID. + /// + /// \returns unsigned short value of the 16-bit assigned UUID. + /// \returns 0 if the LBLEUuid is not a 16-bit UUID. + uint16_t getUuid16() const; public: - bt_uuid_t uuid_data; + bt_uuid_t uuid_data; }; /// \brief Represents the device address of a BLE device. @@ -145,65 +145,65 @@ class LBLEAddress : public Printable { public: // Constructors - /// Default constructor creates an invalid address. - LBLEAddress(); + /// Default constructor creates an invalid address. + LBLEAddress(); - /// Initialize from LinkIt SDK's bt_addr_t struct - LBLEAddress(const bt_addr_t& btAddr); + /// Initialize from LinkIt SDK's bt_addr_t struct + LBLEAddress(const bt_addr_t& btAddr); - ~LBLEAddress(); + ~LBLEAddress(); public: // implementing Pritable - String toString() const; + String toString() const; - /// Implements Printable interface - virtual size_t printTo(Print& p) const; + /// Implements Printable interface + virtual size_t printTo(Print& p) const; - // returns true if lhs equals rhs address. - static bool equal_bt_address(const bt_addr_t& lhs, const bt_addr_t&rhs); - unsigned char equals(const LBLEAddress &rhs) const; + // returns true if lhs equals rhs address. + static bool equal_bt_address(const bt_addr_t& lhs, const bt_addr_t&rhs); + unsigned char equals(const LBLEAddress &rhs) const; unsigned char operator == (const LBLEAddress &rhs) const { return equals(rhs); } - LBLEAddress& operator = (const LBLEAddress &rhs); + LBLEAddress& operator = (const LBLEAddress &rhs); public: // Helper function - static String convertDeviceAddressToString(const bt_bd_addr_ptr_t addr); - static String convertBluetoothAddressToString(const bt_addr_t& addr); - static const char* getAddressTypeString(bt_addr_type_t addrType); + static String convertDeviceAddressToString(const bt_bd_addr_ptr_t addr); + static String convertBluetoothAddressToString(const bt_addr_t& addr); + static const char* getAddressTypeString(bt_addr_type_t addrType); public: - bt_addr_t m_addr; + bt_addr_t m_addr; }; /// This class encapsulates raw buffer operations used by LBLEClient/LBLEPeripheral /// /// When writing or reading GATT attributes, we need to convert /// to raw buffers and meaningful data types used by users. -/// +/// /// This class helps users to convert to these raw buffer /// values when reading or writing GATT attributes. class LBLEValueBuffer : public std::vector { public: - /// Default constructor creates an empty buffer. - LBLEValueBuffer(); + /// Default constructor creates an empty buffer. + LBLEValueBuffer(); - /// Create a raw buffer from an integer value. - LBLEValueBuffer(int intValue); + /// Create a raw buffer from an integer value. + LBLEValueBuffer(int intValue); - /// Create a raw buffer from a float value. - LBLEValueBuffer(float floatValue); + /// Create a raw buffer from a float value. + LBLEValueBuffer(float floatValue); - /// Create a raw buffer from a single-byte character value. - LBLEValueBuffer(char charValue); + /// Create a raw buffer from a single-byte character value. + LBLEValueBuffer(char charValue); - /// Create a raw buffer from a NULL-terminated string. - /// The resulting buffer contains the trailing NULL bytel. - LBLEValueBuffer(const String& strValue); + /// Create a raw buffer from a NULL-terminated string. + /// The resulting buffer contains the trailing NULL bytel. + LBLEValueBuffer(const String& strValue); - templatevoid shallowInit(T value); + templatevoid shallowInit(T value); }; templatevoid LBLEValueBuffer::shallowInit(T value) @@ -218,38 +218,38 @@ class LBLEEventObserver public: virtual ~LBLEEventObserver() {}; - // \returns true: LBLEEventDispatcher should unregister this event after process it - // \returns false: LBLEEventDispatcher should keep this observer + // \returns true: LBLEEventDispatcher should unregister this event after process it + // \returns false: LBLEEventDispatcher should keep this observer virtual bool isOnce() { return true; }; - // callback function for events - virtual void onEvent(bt_msg_type_t msg, bt_status_t status, void *buff) = 0; + // callback function for events + virtual void onEvent(bt_msg_type_t msg, bt_status_t status, void *buff) = 0; }; // Registration table for BT events and corresponding observers. class LBLEEventDispatcher { public: - // after dispatch, the observer is removed from registration table. - void dispatch(bt_msg_type_t msg, bt_status_t status, void *buff); + // after dispatch, the observer is removed from registration table. + void dispatch(bt_msg_type_t msg, bt_status_t status, void *buff); - // insert an observer to the registration table. - void addObserver(bt_msg_type_t msg, LBLEEventObserver* pObserver); + // insert an observer to the registration table. + void addObserver(bt_msg_type_t msg, LBLEEventObserver* pObserver); // remove an observer from the registration table. void removeObserver(bt_msg_type_t msg, LBLEEventObserver* pObserver); public: - typedef std::multimap EventTable; - EventTable m_table; + typedef std::multimap EventTable; + EventTable m_table; }; /** \brief LBLEClass is the class for the singleton `LBLE`. - + Do not instantiate this class by yourself. Use LBLE instead of instantiating the LBLEClass by yourself. For example, call @@ -267,50 +267,50 @@ class LBLEClass private: public: - /** Constructors for LBLEClass. Do not instantite this class by yourself. - * - * This class is intended to be used as a singleton. Use the global - * `LBLE` object, instead of instantiate this class by yourself. - */ - LBLEClass(); - - /** Initializes the Bluetooth subsystem. - * - * This method should be the called first prior to using other BLE APIs. - * After calling begin() you need to call ready(), - * and check if the subsystem is ready to use. - */ - int begin(); - - /** Check if the BLE subsystem is now ready to use. - * - * \returns 0 when BLE subsystem is not ready to use. - * \returns 1 when BLE subsystem is ready to use. - */ - int ready(); - - /** Get the device address of LinkIt 7697 device. - * - * \returns an LBLEAddress object representing the device address. - */ - LBLEAddress getDeviceAddress(); - - void registerForEvent(bt_msg_type_t msg, LBLEEventObserver* pObserver); + /** Constructors for LBLEClass. Do not instantite this class by yourself. + * + * This class is intended to be used as a singleton. Use the global + * `LBLE` object, instead of instantiate this class by yourself. + */ + LBLEClass(); + + /** Initializes the Bluetooth subsystem. + * + * This method should be the called first prior to using other BLE APIs. + * After calling begin() you need to call ready(), + * and check if the subsystem is ready to use. + */ + int begin(); + + /** Check if the BLE subsystem is now ready to use. + * + * \returns 0 when BLE subsystem is not ready to use. + * \returns 1 when BLE subsystem is ready to use. + */ + int ready(); + + /** Get the device address of LinkIt 7697 device. + * + * \returns an LBLEAddress object representing the device address. + */ + LBLEAddress getDeviceAddress(); + + void registerForEvent(bt_msg_type_t msg, LBLEEventObserver* pObserver); void unregisterForEvent(bt_msg_type_t msg, LBLEEventObserver* pObserver); - void handleEvent(bt_msg_type_t msg, bt_status_t status, void *buff); + void handleEvent(bt_msg_type_t msg, bt_status_t status, void *buff); - friend class LBLECentral; - friend class LBLEPeripheral; + friend class LBLECentral; + friend class LBLEPeripheral; protected: - LBLEEventDispatcher m_dispatcher; + LBLEEventDispatcher m_dispatcher; SemaphoreHandle_t m_dispatcherSemaphore; }; /** \addgroup LBLE is the singleton instance for the BLE subsystem - + Use LBLE instead of instantiating the LBLEClass by yourself. For example, call ~~~{.cpp} @@ -332,7 +332,7 @@ template class EventBlocker : public LBLEEventObserver public: EventBlocker(bt_msg_type_t e, const F& handler): m_handler(handler), - m_event(e), + m_event(e), m_eventArrived(false) { @@ -382,7 +382,7 @@ template bool waitAndProcessEvent(const A& action, bt_ms delay(50); } - LBLE.unregisterForEvent(msg, &h); + LBLE.unregisterForEvent(msg, &h); return h.done(); } diff --git a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLECentral.cpp b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLECentral.cpp index 75dde0a..6528f77 100644 --- a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLECentral.cpp +++ b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLECentral.cpp @@ -196,7 +196,7 @@ bool LBLEAdvertisements::getIBeaconInfo(LBLEUuid& uuid, uint16_t& major, uint16_ } uuid = tmpUuid; iBeaconBuffer += 16; - + // note that the endian for major and minor are different. major = *((uint16_t*)iBeaconBuffer); @@ -205,7 +205,7 @@ bool LBLEAdvertisements::getIBeaconInfo(LBLEUuid& uuid, uint16_t& major, uint16_ minor = *((uint16_t*)iBeaconBuffer); - minor = (minor >> 8) | ((minor & 0xFF) << 8); + minor = (minor >> 8) | ((minor & 0xFF) << 8); iBeaconBuffer += 2; txPower = *(int8_t*)iBeaconBuffer; @@ -256,12 +256,12 @@ void LBLECentralClass::scan() bt_hci_cmd_le_set_scan_enable_t enbleSetting; enbleSetting.le_scan_enable = BT_HCI_ENABLE; enbleSetting.filter_duplicates = BT_HCI_ENABLE; // Disable driver-level filter for duplicated adv. - // We'll filter in our onEvent() handler. + // We'll filter in our onEvent() handler. bt_hci_cmd_le_set_scan_parameters_t scan_para; scan_para.own_address_type = BT_HCI_SCAN_ADDR_RANDOM; scan_para.le_scan_type = BT_HCI_SCAN_TYPE_PASSIVE; // Requesting scan-response from peripherals. - // We use BT_HCI_SCAN_TYPE_PASSIVE because - // we don't parse scan response data (yet). + // We use BT_HCI_SCAN_TYPE_PASSIVE because + // we don't parse scan response data (yet). scan_para.scanning_filter_policy = BT_HCI_SCAN_FILTER_ACCEPT_ALL_ADVERTISING_PACKETS; scan_para.le_scan_interval = 0x0024; // Interval between scans scan_para.le_scan_window = 0x0011; // How long a scan keeps @@ -277,18 +277,18 @@ void LBLECentralClass::scan() // proper calling sequence between scan() and stopScan(), // we wait for BT_GAP_LE_SET_SCAN_CNF. bool done = waitAndProcessEvent( - [&]() - { - bt_gap_le_set_scan(&enbleSetting, &scan_para); - }, - - BT_GAP_LE_SET_SCAN_CNF, - - [this](bt_msg_type_t, bt_status_t, void*) - { - m_scanning = true; - return; - } + [&]() + { + bt_gap_le_set_scan(&enbleSetting, &scan_para); + }, + + BT_GAP_LE_SET_SCAN_CNF, + + [this](bt_msg_type_t, bt_status_t, void*) + { + m_scanning = true; + return; + } ); if(!done) @@ -309,20 +309,20 @@ void LBLECentralClass::stopScan() // m_peripherals_found does not get re-polulated, // we wait for BT_GAP_LE_SET_SCAN_CNF. waitAndProcessEvent( - [&]() - { - pr_debug("calling bt_gap_le_set_scan with disable parameters") - bt_gap_le_set_scan(&enbleSetting, NULL); - }, + [&]() + { + pr_debug("calling bt_gap_le_set_scan with disable parameters") + bt_gap_le_set_scan(&enbleSetting, NULL); + }, - BT_GAP_LE_SET_SCAN_CNF, + BT_GAP_LE_SET_SCAN_CNF, - [this](bt_msg_type_t, bt_status_t, void*) - { - m_scanning = false; - return; - } - ); + [this](bt_msg_type_t, bt_status_t, void*) + { + m_scanning = false; + return; + } + ); // we keep the BT_GAP_LE_ADVERTISING_REPORT_IND registered, // assuming that the underlying framework won't send any new messages @@ -396,69 +396,47 @@ uint8_t LBLECentralClass::getAdvertisementFlag(int index) const return parser.getAdvertisementFlag(); } -static const char* get_event_type(uint8_t type) -{ - switch (type) - { - case BT_GAP_LE_ADV_REPORT_EVT_TYPE_ADV_IND: - return "ADV_IND"; - case BT_GAP_LE_ADV_REPORT_EVT_TYPE_ADV_DIRECT_IND: - return "ADV_DIRECT_IND"; - case BT_GAP_LE_ADV_REPORT_EVT_TYPE_ADV_SCAN_IND: - return "ADV_SCAN_IND"; - case BT_GAP_LE_ADV_REPORT_EVT_TYPE_ADV_NONCONN_IND: - return "ADV_NONCONN_IND"; - case BT_GAP_LE_ADV_REPORT_EVT_TYPE_ADV_SCAN_RSP: - return "SCAN_RSP"; - default: - return "NULL"; - } -} - void LBLECentralClass::onEvent(bt_msg_type_t msg, bt_status_t status, void *buff) { if(BT_GAP_LE_ADVERTISING_REPORT_IND == msg) { const bt_gap_le_advertising_report_ind_t* pReport = (bt_gap_le_advertising_report_ind_t*)buff; - // pr_debug("BT_GAP_LE_ADVERTISING_REPORT_IND with 0x%x", (unsigned int)status); - // pr_debug("advertisement event = %s", get_event_type(pReport->event_type)); - switch(pReport->event_type) { case BT_GAP_LE_ADV_REPORT_EVT_TYPE_ADV_IND: + { + // advertising packet - check if we need to update existing entry + // or appending new one. + const size_t peripheralCount = m_peripherals_found.size(); + for(size_t i = 0; i < peripheralCount; ++i) { - // advertising packet - check if we need to update existing entry - // or appending new one. - const size_t peripheralCount = m_peripherals_found.size(); - for(size_t i = 0; i < peripheralCount; ++i) + // check if already found + if(LBLEAddress::equal_bt_address(m_peripherals_found[i].address, pReport->address)) { - // check if already found - if(LBLEAddress::equal_bt_address(m_peripherals_found[i].address, pReport->address)) - { - m_peripherals_found[i] = *pReport; - return; - } + m_peripherals_found[i] = *pReport; + return; } + } - // not found, append - if(m_peripherals_found.size() < MAX_DEVICE_LIST_SIZE) - { + // not found, append + if(m_peripherals_found.size() < MAX_DEVICE_LIST_SIZE) + { m_peripherals_found.push_back(*pReport); - // DEBUG: - #if 1 - LBLEAddress newAddr(pReport->address); - pr_debug("new record [%s], total found: %d", newAddr.toString().c_str(), m_peripherals_found.size()); - #endif - } - else - { - pr_debug("m_peripherals_found size exceeding %d, drop.", MAX_DEVICE_LIST_SIZE); - } - return; + // DEBUG: +#if 1 + LBLEAddress newAddr(pReport->address); + pr_debug("new record [%s], total found: %d", newAddr.toString().c_str(), m_peripherals_found.size()); +#endif } - break; + else + { + pr_debug("m_peripherals_found size exceeding %d, drop.", MAX_DEVICE_LIST_SIZE); + } + return; + } + break; case BT_GAP_LE_ADV_REPORT_EVT_TYPE_ADV_SCAN_RSP: // TODO: scan response - this usually carries extra information // we need to find matching address in g_peripherals_found list, @@ -476,7 +454,7 @@ void LBLECentralClass::onEvent(bt_msg_type_t msg, bt_status_t status, void *buff LBLEClient::LBLEClient(): m_connection(BT_HANDLE_INVALID) { - + } LBLEClient::~LBLEClient() @@ -507,24 +485,24 @@ bool LBLEClient::connect(const LBLEAddress& address) bool done = waitAndProcessEvent( // Call connect API [&]() - { - bt_status_t result = bt_gap_le_connect(&conn_para); - if(BT_STATUS_SUCCESS != result) - { - pr_debug("bt_gap_le_connect() failed with ret=0x%x", result); - } - }, - // wait for connect indication event... - BT_GAP_LE_CONNECT_IND, - // to update the `m_connection` member in BT task - [this](bt_msg_type_t, bt_status_t, void* buf) - { - pr_debug("bt_gap_le_connect() recieves BT_GAP_LE_CONNECT_IND"); - const bt_gap_le_connection_ind_t *pConnectionInfo = (bt_gap_le_connection_ind_t*)buf; - this->m_connection = pConnectionInfo->connection_handle; - LBLE.registerForEvent(BT_GAP_LE_DISCONNECT_IND, this); - return; - } + { + bt_status_t result = bt_gap_le_connect(&conn_para); + if(BT_STATUS_SUCCESS != result) + { + pr_debug("bt_gap_le_connect() failed with ret=0x%x", result); + } + }, + // wait for connect indication event... + BT_GAP_LE_CONNECT_IND, + // to update the `m_connection` member in BT task + [this](bt_msg_type_t, bt_status_t, void* buf) + { + pr_debug("bt_gap_le_connect() recieves BT_GAP_LE_CONNECT_IND"); + const bt_gap_le_connection_ind_t *pConnectionInfo = (bt_gap_le_connection_ind_t*)buf; + this->m_connection = pConnectionInfo->connection_handle; + LBLE.registerForEvent(BT_GAP_LE_DISCONNECT_IND, this); + return; + } ); if(done) @@ -537,32 +515,32 @@ bool LBLEClient::connect(const LBLEAddress& address) // not receiving BT_GAP_LE_CONNECT_IND: // we must "cancel" the connection otherwise the internal buffer for connection can leak. bool cancelled = waitAndProcessEvent( - // Call connect API - [&]() - { - bt_status_t result = bt_gap_le_cancel_connection(); - if(BT_STATUS_SUCCESS != result) - { - pr_debug("bt_gap_le_cancel_connection() failed with ret=0x%x", result); - } - }, - // wait for connect indication event... - BT_GAP_LE_CONNECT_CANCEL_CNF, - - // and that's it - we don't have client side buffers to release. - [this](bt_msg_type_t, bt_status_t, void* buf) - { - pr_debug("bt_gap_le_cancel_connection() recieves BT_GAP_LE_CONNECT_CANCEL_CNF"); - return; - } - ); + // Call connect API + [&]() + { + bt_status_t result = bt_gap_le_cancel_connection(); + if(BT_STATUS_SUCCESS != result) + { + pr_debug("bt_gap_le_cancel_connection() failed with ret=0x%x", result); + } + }, + // wait for connect indication event... + BT_GAP_LE_CONNECT_CANCEL_CNF, + + // and that's it - we don't have client side buffers to release. + [this](bt_msg_type_t, bt_status_t, void* buf) + { + pr_debug("bt_gap_le_cancel_connection() recieves BT_GAP_LE_CONNECT_CANCEL_CNF"); + return; + } + ); if(!cancelled) { // oh no - we failed to cancel - this is unlikely to happen. pr_debug("WARNING: connect failed and bt_gap_le_cancel_connection() also failed!"); } } - + return done; } @@ -595,27 +573,27 @@ void LBLEClient::disconnect() bool done = waitAndProcessEvent( // Call connect API [&disconn_para]() - { - bt_gap_le_disconnect(&disconn_para); - }, - // wait for connect indication event... - BT_GAP_LE_DISCONNECT_IND, - // to update the `m_connection` member in BT task - [this](bt_msg_type_t, bt_status_t, void* buf) - { - const bt_gap_le_disconnect_ind_t *pDisconnectInfo = (bt_gap_le_disconnect_ind_t*)buf; - if(this->m_connection == pDisconnectInfo->connection_handle) - { - this->m_connection = BT_HANDLE_INVALID; - // sucess or not, we proceed to resource clean up - m_connection = BT_HANDLE_INVALID; - m_services.clear(); - m_characteristics.clear(); - } - return; - } + { + bt_gap_le_disconnect(&disconn_para); + }, + // wait for connect indication event... + BT_GAP_LE_DISCONNECT_IND, + // to update the `m_connection` member in BT task + [this](bt_msg_type_t, bt_status_t, void* buf) + { + const bt_gap_le_disconnect_ind_t *pDisconnectInfo = (bt_gap_le_disconnect_ind_t*)buf; + if(this->m_connection == pDisconnectInfo->connection_handle) + { + this->m_connection = BT_HANDLE_INVALID; + // sucess or not, we proceed to resource clean up + m_connection = BT_HANDLE_INVALID; + m_services.clear(); + m_characteristics.clear(); + } + return; + } ); - + if(!done) { pr_debug("bt_gap_le_disconnect() called but fails to receive BT_GAP_LE_DISCONNECT_IND"); @@ -632,7 +610,7 @@ void LBLEClient::onEvent(bt_msg_type_t msg, bt_status_t status, void *buff) if(pInfo->connection_handle == m_connection) { pr_debug("Disconnected with status = 0x%x, reason = 0x%x", (unsigned int)status, (unsigned int)pInfo->reason); - // clear up scanned services and characteristics + // clear up scanned services and characteristics m_connection = BT_HANDLE_INVALID; m_services.clear(); m_characteristics.clear(); @@ -647,7 +625,9 @@ int LBLEClient::getServiceCount() bool LBLEClient::hasService(const LBLEUuid& uuid) { - auto found = std::find_if(m_services.begin(), m_services.end(), [&uuid](const LBLEServiceInfo& o){ return (bool)(o.uuid == uuid); }); + auto found = std::find_if(m_services.begin(), m_services.end(), [&uuid](const LBLEServiceInfo& o) { + return (bool)(o.uuid == uuid); + }); return (m_services.end() != found); } @@ -678,7 +658,7 @@ String LBLEClient::getServiceName(int index) int LBLEClient::discoverServices() { // discover all services and store UUIDs - // note that this search could require multiple request-response, + // note that this search could require multiple request-response, // see https://community.nxp.com/thread/332233 for an example. if(!connected()) @@ -710,57 +690,57 @@ int LBLEClient::discoverServices() } done = waitAndProcessEvent( - // start service discovery - [this, &searchRequest]() - { - bt_gattc_discover_primary_service(m_connection, &searchRequest); - }, - // wait for the event... - BT_GATTC_DISCOVER_PRIMARY_SERVICE, - // and process it in BT task context with this lambda - [this, &searchRequest, &shouldContinue](bt_msg_type_t, bt_status_t status, void* buf) - { - // Parse the response to service UUIDs. It can be 16-bit or 128-bit UUID. - // We can tell the difference from the response length `att_rsp->length`. - const bt_gattc_read_by_group_type_rsp_t* rsp = (bt_gattc_read_by_group_type_rsp_t*)buf; - uint16_t endIndex = 0, startIndex = 0; - uint16_t uuid16 = 0; - bt_uuid_t uuid128; - const uint8_t *attrDataList = rsp->att_rsp->attribute_data_list; - const uint32_t entryLength = rsp->att_rsp->length; - // note that att_rsp will always have same length of each uuid-16 service, - // because a response can only represent a single uuid-128 service. - const uint8_t entryCount = (rsp->length - 2) / entryLength; - for (int i = 0; i < entryCount; ++i){ - memcpy(&startIndex, attrDataList + i * entryLength, 2); - memcpy(&endIndex, attrDataList + i * entryLength + 2, 2); - - LBLEServiceInfo serviceInfo; - - if (entryLength == 6) { - // 16-bit UUID case - memcpy(&uuid16, attrDataList + i * entryLength + 4, entryLength - 4); - serviceInfo.uuid = LBLEUuid(uuid16); - } else { - // 128-bit UUID case - memcpy(&uuid128.uuid, attrDataList + i * entryLength + 4, entryLength - 4); - serviceInfo.uuid = LBLEUuid(uuid128); - } - - serviceInfo.startHandle = startIndex; - serviceInfo.endHandle = endIndex; - - m_services.push_back(serviceInfo); - } - - // check if we need to perform more search - shouldContinue = (status == BT_ATT_ERRCODE_CONTINUE); - - // update starting handle for next round of search - searchRequest.starting_handle = endIndex; - } - ); - }while(shouldContinue && done); + // start service discovery + [this, &searchRequest]() + { + bt_gattc_discover_primary_service(m_connection, &searchRequest); + }, + // wait for the event... + BT_GATTC_DISCOVER_PRIMARY_SERVICE, + // and process it in BT task context with this lambda + [this, &searchRequest, &shouldContinue](bt_msg_type_t, bt_status_t status, void* buf) + { + // Parse the response to service UUIDs. It can be 16-bit or 128-bit UUID. + // We can tell the difference from the response length `att_rsp->length`. + const bt_gattc_read_by_group_type_rsp_t* rsp = (bt_gattc_read_by_group_type_rsp_t*)buf; + uint16_t endIndex = 0, startIndex = 0; + uint16_t uuid16 = 0; + bt_uuid_t uuid128; + const uint8_t *attrDataList = rsp->att_rsp->attribute_data_list; + const uint32_t entryLength = rsp->att_rsp->length; + // note that att_rsp will always have same length of each uuid-16 service, + // because a response can only represent a single uuid-128 service. + const uint8_t entryCount = (rsp->length - 2) / entryLength; + for (int i = 0; i < entryCount; ++i) { + memcpy(&startIndex, attrDataList + i * entryLength, 2); + memcpy(&endIndex, attrDataList + i * entryLength + 2, 2); + + LBLEServiceInfo serviceInfo; + + if (entryLength == 6) { + // 16-bit UUID case + memcpy(&uuid16, attrDataList + i * entryLength + 4, entryLength - 4); + serviceInfo.uuid = LBLEUuid(uuid16); + } else { + // 128-bit UUID case + memcpy(&uuid128.uuid, attrDataList + i * entryLength + 4, entryLength - 4); + serviceInfo.uuid = LBLEUuid(uuid128); + } + + serviceInfo.startHandle = startIndex; + serviceInfo.endHandle = endIndex; + + m_services.push_back(serviceInfo); + } + + // check if we need to perform more search + shouldContinue = (status == BT_ATT_ERRCODE_CONTINUE); + + // update starting handle for next round of search + searchRequest.starting_handle = endIndex; + } + ); + } while(shouldContinue && done); if(m_services.size()) { @@ -780,8 +760,8 @@ int LBLEClient::discoverCharacteristics() // for each service, find the value handle of each characteristic. for(size_t i = 0; i < m_services.size(); ++i) { - pr_debug("Enumerate charc between handle (%d-%d)", m_services[i].startHandle, m_services[i].endHandle) - discoverCharacteristicsOfService(m_services[i]); + pr_debug("Enumerate charc between handle (%d-%d)", m_services[i].startHandle, m_services[i].endHandle) + discoverCharacteristicsOfService(m_services[i]); } return m_characteristics.size(); @@ -790,7 +770,7 @@ int LBLEClient::discoverCharacteristics() int LBLEClient::discoverCharacteristicsOfService(const LBLEServiceInfo& s) { // discover all characteristics and store mapping between (UUID -> value handle) - // note that this search could require multiple request-response, + // note that this search could require multiple request-response, // see https://community.nxp.com/thread/332233 for an example. if(!connected()) @@ -824,54 +804,54 @@ int LBLEClient::discoverCharacteristicsOfService(const LBLEServiceInfo& s) } done = waitAndProcessEvent( - // start characteristic discovery - [this, &searchRequest]() - { - bt_gattc_discover_charc(m_connection, &searchRequest); - }, - // wait for the event... - BT_GATTC_DISCOVER_CHARC, - // and process it in BT task context with this lambda - [this, &searchRequest, &shouldContinue](bt_msg_type_t, bt_status_t status, void* buf) - { - pr_debug("discoverCharacteristicsOfService=0x%x", (unsigned int)status); - - // Parse the response to service UUIDs. It can be 16-bit or 128-bit - const bt_gattc_read_by_type_rsp_t* rsp = (bt_gattc_read_by_type_rsp_t*)buf; - uint16_t attributeHandle = 0, valueHandle = 0; - uint8_t properties = 0; - uint16_t uuid16 = 0; - bt_uuid_t uuid128; - const uint8_t *attrDataList = rsp->att_rsp->attribute_data_list; - const uint32_t entryLength = rsp->att_rsp->length; - // note that att_rsp will always have same length of each uuid-16 service, - // because a response can only represent a single uuid-128 service. - const uint8_t entryCount = (rsp->length - 2) / entryLength; - for (int i = 0; i < entryCount; ++i){ - memcpy(&attributeHandle, attrDataList + i * rsp->att_rsp->length, 2); - memcpy(&properties, attrDataList + i * rsp->att_rsp->length + 2, 1); - memcpy(&valueHandle, attrDataList + i * rsp->att_rsp->length + 3, 2); - - - if (rsp->att_rsp->length < 20) { - // 16-bit UUID case - memcpy(&uuid16, attrDataList + i * rsp->att_rsp->length + 5, 2); - m_characteristics.insert(std::make_pair(LBLEUuid(uuid16), valueHandle)); - } else { - // 128-bit UUID case - memcpy(&uuid128.uuid, attrDataList + i * entryLength + 5, 16); - m_characteristics.insert(std::make_pair(LBLEUuid(uuid128), valueHandle)); - } - } - - // check if we need to perform more search - shouldContinue = (status == BT_ATT_ERRCODE_CONTINUE) && (entryCount > 0); - - // update starting handle for next round of search - searchRequest.starting_handle = valueHandle; - } - ); - }while(shouldContinue && done); + // start characteristic discovery + [this, &searchRequest]() + { + bt_gattc_discover_charc(m_connection, &searchRequest); + }, + // wait for the event... + BT_GATTC_DISCOVER_CHARC, + // and process it in BT task context with this lambda + [this, &searchRequest, &shouldContinue](bt_msg_type_t, bt_status_t status, void* buf) + { + pr_debug("discoverCharacteristicsOfService=0x%x", (unsigned int)status); + + // Parse the response to service UUIDs. It can be 16-bit or 128-bit + const bt_gattc_read_by_type_rsp_t* rsp = (bt_gattc_read_by_type_rsp_t*)buf; + uint16_t attributeHandle = 0, valueHandle = 0; + uint8_t properties = 0; + uint16_t uuid16 = 0; + bt_uuid_t uuid128; + const uint8_t *attrDataList = rsp->att_rsp->attribute_data_list; + const uint32_t entryLength = rsp->att_rsp->length; + // note that att_rsp will always have same length of each uuid-16 service, + // because a response can only represent a single uuid-128 service. + const uint8_t entryCount = (rsp->length - 2) / entryLength; + for (int i = 0; i < entryCount; ++i) { + memcpy(&attributeHandle, attrDataList + i * rsp->att_rsp->length, 2); + memcpy(&properties, attrDataList + i * rsp->att_rsp->length + 2, 1); + memcpy(&valueHandle, attrDataList + i * rsp->att_rsp->length + 3, 2); + + + if (rsp->att_rsp->length < 20) { + // 16-bit UUID case + memcpy(&uuid16, attrDataList + i * rsp->att_rsp->length + 5, 2); + m_characteristics.insert(std::make_pair(LBLEUuid(uuid16), valueHandle)); + } else { + // 128-bit UUID case + memcpy(&uuid128.uuid, attrDataList + i * entryLength + 5, 16); + m_characteristics.insert(std::make_pair(LBLEUuid(uuid128), valueHandle)); + } + } + + // check if we need to perform more search + shouldContinue = (status == BT_ATT_ERRCODE_CONTINUE) && (entryCount > 0); + + // update starting handle for next round of search + searchRequest.starting_handle = valueHandle; + } + ); + } while(shouldContinue && done); return done; } @@ -893,7 +873,7 @@ int LBLEClient::readCharacteristicInt(const LBLEUuid& uuid) String LBLEClient::readCharacteristicString(const LBLEUuid& uuid) { LBLEValueBuffer b = readCharacterstic(uuid); - + if(b.size()) { // safe guard against missing terminating NULL @@ -905,7 +885,7 @@ String LBLEClient::readCharacteristicString(const LBLEUuid& uuid) return String((const char*)&b[0]); } - + return String(); } @@ -955,47 +935,47 @@ LBLEValueBuffer LBLEClient::readCharacterstic(const LBLEUuid& serviceUuid) LBLEValueBuffer resultBuffer; waitAndProcessEvent( - // start read request - [&]() - { - bt_gattc_read_using_charc_uuid(m_connection, &req); - }, - // wait for event... - BT_GATTC_READ_USING_CHARC_UUID, - // and parse event result in bt task context - [this, &resultBuffer](bt_msg_type_t msg, bt_status_t, void* buf) - { - const bt_gattc_read_by_type_rsp_t *pReadResponse = (bt_gattc_read_by_type_rsp_t*)buf; - if(BT_GATTC_READ_USING_CHARC_UUID != msg || pReadResponse->connection_handle != m_connection) - { - // not for our request - return; - } - - do{ - // check error case - if(BT_ATT_OPCODE_ERROR_RESPONSE == pReadResponse->att_rsp->opcode) - { - const bt_gattc_error_rsp_t* pErr = (bt_gattc_error_rsp_t*)buf; - pr_debug("error reading attribute"); - pr_debug("error_opcode=%d", pErr->att_rsp->error_opcode); - pr_debug("error_code=%d", pErr->att_rsp->error_code); - break; - } - - if(BT_ATT_OPCODE_READ_BY_TYPE_RESPONSE != pReadResponse->att_rsp->opcode) - { - pr_debug("Op code don't match! Opcode=%d", pReadResponse->att_rsp->opcode); - break; - } - - // Copy the data buffer content - const uint8_t listLength = pReadResponse->att_rsp->length - 2; - resultBuffer.resize(listLength, 0); - memcpy(&resultBuffer[0], ((uint8_t*)pReadResponse->att_rsp->attribute_data_list) + 2, listLength); - }while(false); - } - ); + // start read request + [&]() + { + bt_gattc_read_using_charc_uuid(m_connection, &req); + }, + // wait for event... + BT_GATTC_READ_USING_CHARC_UUID, + // and parse event result in bt task context + [this, &resultBuffer](bt_msg_type_t msg, bt_status_t, void* buf) + { + const bt_gattc_read_by_type_rsp_t *pReadResponse = (bt_gattc_read_by_type_rsp_t*)buf; + if(BT_GATTC_READ_USING_CHARC_UUID != msg || pReadResponse->connection_handle != m_connection) + { + // not for our request + return; + } + + do { + // check error case + if(BT_ATT_OPCODE_ERROR_RESPONSE == pReadResponse->att_rsp->opcode) + { + const bt_gattc_error_rsp_t* pErr = (bt_gattc_error_rsp_t*)buf; + pr_debug("error reading attribute"); + pr_debug("error_opcode=%d", pErr->att_rsp->error_opcode); + pr_debug("error_code=%d", pErr->att_rsp->error_code); + break; + } + + if(BT_ATT_OPCODE_READ_BY_TYPE_RESPONSE != pReadResponse->att_rsp->opcode) + { + pr_debug("Op code don't match! Opcode=%d", pReadResponse->att_rsp->opcode); + break; + } + + // Copy the data buffer content + const uint8_t listLength = pReadResponse->att_rsp->length - 2; + resultBuffer.resize(listLength, 0); + memcpy(&resultBuffer[0], ((uint8_t*)pReadResponse->att_rsp->attribute_data_list) + 2, listLength); + } while(false); + } + ); return resultBuffer; } @@ -1015,12 +995,14 @@ int LBLEClient::writeCharacteristic(const LBLEUuid& uuid, const LBLEValueBuffer& auto found = m_characteristics.find(uuid); if(found == m_characteristics.end()) { + pr_debug("cannot find characteristics"); return 0; } // value buffer too big if(value.size() > MAXIMUM_WRITE_SIZE) { + pr_debug("write value too long"); return 0; } @@ -1031,63 +1013,70 @@ int LBLEClient::writeCharacteristic(const LBLEUuid& uuid, const LBLEValueBuffer& req.attribute_value_length = value.size(); req.att_req = (bt_att_write_req_t*)&reqBuf[0]; req.att_req->opcode = BT_ATT_OPCODE_WRITE_REQUEST; + // the "attribute_handle" field requires a "value handle" actually. + pr_debug("write_charc %s with value handle=%d", found->first.toString().c_str(), found->second); req.att_req->attribute_handle = found->second; memcpy(req.att_req->attribute_value, &value[0], value.size()); bool done = waitAndProcessEvent( // start read request [&]() - { - bt_gattc_write_charc(m_connection, &req); - }, - // wait for event... - BT_GATTC_WRITE_CHARC, - // and parse event result in bt task context - [this](bt_msg_type_t msg, bt_status_t, void* buf) - { - const bt_gattc_write_rsp_t *pWriteResp = (bt_gattc_write_rsp_t*)buf; - if(BT_GATTC_WRITE_CHARC != msg || pWriteResp->connection_handle != m_connection) - { - // not for our request - return; - } - - do{ - // check error case - if(BT_ATT_OPCODE_ERROR_RESPONSE == pWriteResp->att_rsp->opcode) - { - const bt_gattc_error_rsp_t* pErr = (bt_gattc_error_rsp_t*)buf; - pr_debug("error reading attribute"); - pr_debug("error_opcode=%d", pErr->att_rsp->error_opcode); - pr_debug("error_code=%d", pErr->att_rsp->error_code); - break; - } - - if(BT_ATT_OPCODE_WRITE_RESPONSE != pWriteResp->att_rsp->opcode) - { - pr_debug("Op code don't match! Opcode=%d", pWriteResp->att_rsp->opcode); - break; - } - }while(false); - } + { + bt_status_t writeResult = bt_gattc_write_charc(m_connection, &req); + pr_debug("write result = 0x%x", writeResult); + }, + // wait for event... + BT_GATTC_WRITE_CHARC, + // and parse event result in bt task context + [this](bt_msg_type_t msg, bt_status_t, void* buf) + { + if(BT_GATTC_WRITE_CHARC != msg) { + // not for our request + pr_debug("got wrong messge"); + return; + } + + const bt_gattc_write_rsp_t *pWriteResp = (bt_gattc_write_rsp_t*)buf; + if(pWriteResp->connection_handle != this->m_connection) { + pr_debug("got wrong handle=%d (%d)", pWriteResp->connection_handle, this->m_connection); + } + + do { + // check error case + if(BT_ATT_OPCODE_ERROR_RESPONSE == pWriteResp->att_rsp->opcode) + { + const bt_gattc_error_rsp_t* pErr = (bt_gattc_error_rsp_t*)buf; + pr_debug("error reading attribute"); + pr_debug("error_opcode=%d", pErr->att_rsp->error_opcode); + pr_debug("error_code=%d", pErr->att_rsp->error_code); + break; + } + + if(BT_ATT_OPCODE_WRITE_RESPONSE != pWriteResp->att_rsp->opcode) + { + pr_debug("Op code don't match! Opcode=%d", pWriteResp->att_rsp->opcode); + break; + } + } while(false); + } ); return done; } -int LBLEClient::writeCharacteristicInt(const LBLEUuid& uuid, int value){ +int LBLEClient::writeCharacteristicInt(const LBLEUuid& uuid, int value) { LBLEValueBuffer b(value); return writeCharacteristic(uuid, b); } -int LBLEClient::writeCharacteristicString(const LBLEUuid& uuid, const String& value){ +int LBLEClient::writeCharacteristicString(const LBLEUuid& uuid, const String& value) { LBLEValueBuffer b(value); return writeCharacteristic(uuid, b); } -int LBLEClient::writeCharacteristicChar(const LBLEUuid& uuid, char value){ +int LBLEClient::writeCharacteristicChar(const LBLEUuid& uuid, char value) { LBLEValueBuffer b(value); return writeCharacteristic(uuid, b); } -int LBLEClient::writeCharacteristicFloat(const LBLEUuid& uuid, float value){ +int LBLEClient::writeCharacteristicFloat(const LBLEUuid& uuid, float value) { LBLEValueBuffer b(value); return writeCharacteristic(uuid, b); } @@ -1098,9 +1087,9 @@ void _characteristic_event_handler(bt_msg_type_t msg, bt_status_t, void *buff) { pr_debug("==============NOTIFICATION COMING==============="); bt_gatt_handle_value_notification_t* pNoti = (bt_gatt_handle_value_notification_t*)buff; - pr_debug("gatt length=(%d), opcode=(%d), handle=(%d)", - pNoti->length, - pNoti->att_rsp->opcode, - pNoti->att_rsp->handle); + pr_debug("gatt length=(%d), opcode=(%d), handle=(%d)", + pNoti->length, + pNoti->att_rsp->opcode, + pNoti->att_rsp->handle); } } diff --git a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLECentral.h b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLECentral.h index 5e1f9d0..6168062 100644 --- a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLECentral.h +++ b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLECentral.h @@ -21,240 +21,242 @@ extern "C" void ard_ble_central_onCentralEvents(bt_msg_type_t msg, bt_status_t s /// Singleton class that creates a BLE central device. /// /// This class allows LinkIt 7697 to act as a BLE central device. -/// It can scan nearby BLE peripherals, checking if they are beacons or +/// It can scan nearby BLE peripherals, checking if they are beacons or /// devices that provides GATT services. /// -/// This class does not provide functions to connect to remote +/// This class does not provide functions to connect to remote /// peripheral devices. Use LBLEClient class instead to connect to a remote /// device and read/write its characteristics. class LBLECentralClass : public LBLEEventObserver { public: - /// Do not instantiate this class by yourself. Use `LBLE` singleton instance instead. - LBLECentralClass(); - - ~LBLECentralClass(){}; - - /// \brief Start scanning nearby BLE peripherals - /// - /// This puts the system into a scanning statie. - /// The system keeps updating the peripheral list in the background. - /// - /// The result of `getPeripheralCount()` will be updated once a new peripheral is found. - /// - /// Note that it may took sometime for peripherals to get scanned. - /// - /// To get the scanned peripheral, call getPeripheralCount() and use - /// methods such as `getPeripheralName` or `isBeacon`, for example: - /// - /// ~~~{.cpp} - /// // start scanning - /// LBLECentral.scan(); - /// - /// // wait for 5 seconds to scan - /// for(int i = 0; i < 5; ++i) - /// { - /// delay(1000); - /// Serial.print("."); - /// } - /// - /// // list name of the peripherals found. - /// const int found = LBLECentral.getPeripheralCount(); - /// for (int i = 0; i < found; ++i) { + /// Do not instantiate this class by yourself. Use `LBLE` singleton instance instead. + LBLECentralClass(); + + ~LBLECentralClass() {}; + + /// \brief Start scanning nearby BLE peripherals + /// + /// This puts the system into a scanning statie. + /// The system keeps updating the peripheral list in the background. + /// + /// The result of `getPeripheralCount()` will be updated once a new peripheral is found. + /// + /// Note that it may took sometime for peripherals to get scanned. + /// + /// To get the scanned peripheral, call getPeripheralCount() and use + /// methods such as `getPeripheralName` or `isBeacon`, for example: + /// + /// ~~~{.cpp} + /// // start scanning + /// LBLECentral.scan(); + /// + /// // wait for 5 seconds to scan + /// for(int i = 0; i < 5; ++i) + /// { + /// delay(1000); + /// Serial.print("."); + /// } + /// + /// // list name of the peripherals found. + /// const int found = LBLECentral.getPeripheralCount(); + /// for (int i = 0; i < found; ++i) { /// Serial.println(LBLECentral.getName(i)); - /// } - /// ~~~ - /// - /// The return value is the number of the peripherals currently found. - void scan(); - - /// Stop scanning nearby BLE peripherals. - /// - /// Stops the system from scanning nearby peripherals. - /// The list of discovered peripherals are still kept but will no longer be updated. - void stopScan(); - - /// Retrive the number of peripherals currently discovered - int getPeripheralCount(); - - /////////////////////////////////////////////////// - /// Get scanned peripheral information by index - /////////////////////////////////////////////////// - - /// Get address of the peripheral in the list of scanned devices. - /// - /// \param index ranges from `0` to `(getRemotePeripheralCount() - 1)`. - /// \returns device address (in string format) of the scanned peripheral. - String getAddress(int index); - - /// Get address of the peripheral in the list of scanned devices. - /// - /// \param index ranges from `0` to `(getRemotePeripheralCount() - 1)`. - /// \returns device address of the scanned peripheral. - LBLEAddress getBLEAddress(int index); - - /// Get device name of the peripheral in the list of scanned devices. - /// - /// \param index ranges from `0` to `(getRemotePeripheralCount() - 1)`. - /// \returns device name - String getName(int index); - - /// Get scanned RSSI of the peripheral in the list of scanned devices. - /// - /// \param index ranges from `0` to `(getRemotePeripheralCount() - 1)`. - /// \returns RSSI value in dbm. - int32_t getRSSI(int index); - - /// Get txPower value in the advertisement packet of the peripheral in the list of scanned devices. - /// - /// \param index ranges from `0` to `(getRemotePeripheralCount() - 1)`. - /// \returns TX power field, if any, in the advertisement packet. - int32_t getTxPower(int index); - - /// Get service UUID in the advertisement packet of the peripheral in the list of scanned devices. - /// - /// \param index ranges from `0` to `(getRemotePeripheralCount() - 1)`. - /// \returns service UUID, if any, in the advertisement packet. - LBLEUuid getServiceUuid(int index) const; - - /// Get manufacturer info in the advertisement packet of the peripheral in the list of scanned devices. - /// - /// \param index ranges from `0` to `(getRemotePeripheralCount() - 1)`. - /// \returns manufacturer id, if any, in the advertisement packet. - String getManufacturer(int index) const; - - /// Get the advertisement flag of the scanned device. - /// - /// Advertisement Flags may be the result of bitwise-or of following values: - /// - /// * `BT_GAP_LE_AD_FLAG_LIMITED_DISCOVERABLE (0x01)` - /// * `BT_GAP_LE_AD_FLAG_GENERAL_DISCOVERABLE (0x02)` - /// * `BT_GAP_LE_AD_FLAG_BR_EDR_NOT_SUPPORTED (0x04)` - /// - /// There are also other flags, including: - /// - /// * 0x08: Bluetooth BR/EDR Controller - /// * 0x10: Bluetooth BR/EDR Host - /// - /// which are not used by BLE-only devices. - /// - /// \param index ranges from `0` to `(getRemotePeripheralCount() - 1)`. - /// \returns - uint8_t getAdvertisementFlag(int index)const; - - /// Check if the peripheral is an iBeacon device. - /// - /// \param index ranges from `0` to `(getRemotePeripheralCount() - 1)`. - /// \returns true if the device broadcasts iBeacon format advertisements, false otherwise. - bool isIBeacon(int index) const; - - /// Get iBeacon infomrmation from the advertisement data of an iBeacon device. - /// - /// You can refer to this article on the iBeacon info fields: - /// https://developer.mbed.org/blog/entry/BLE-Beacons-URIBeacon-AltBeacons-iBeacon/#iBeacon - /// - /// \param index ranges from `0` to `(getRemotePeripheralCount() - 1)`. - /// \param uuid Output parameter of the iBeacon info - this UUID is defined by the iBeacon device. - /// \param major Output parameter, the major number in the iBeacon info. - /// \param minor Output parameter, the minor number in the iBeacon info. - /// \param txPower Output parameter, the signed TX Power value in the iBeacon info. - /// \returns true if the device has iBeacon info. false if the device is not an iBeacon device. - bool getIBeaconInfo(int index, LBLEUuid& uuid, uint16_t& major, uint16_t& minor, int8_t& txPower)const; + /// } + /// ~~~ + /// + /// The return value is the number of the peripherals currently found. + void scan(); + + /// Stop scanning nearby BLE peripherals. + /// + /// Stops the system from scanning nearby peripherals. + /// The list of discovered peripherals are still kept but will no longer be updated. + void stopScan(); + + /// Retrive the number of peripherals currently discovered + int getPeripheralCount(); + + /////////////////////////////////////////////////// + /// Get scanned peripheral information by index + /////////////////////////////////////////////////// + + /// Get address of the peripheral in the list of scanned devices. + /// + /// \param index ranges from `0` to `(getRemotePeripheralCount() - 1)`. + /// \returns device address (in string format) of the scanned peripheral. + String getAddress(int index); + + /// Get address of the peripheral in the list of scanned devices. + /// + /// \param index ranges from `0` to `(getRemotePeripheralCount() - 1)`. + /// \returns device address of the scanned peripheral. + LBLEAddress getBLEAddress(int index); + + /// Get device name of the peripheral in the list of scanned devices. + /// + /// \param index ranges from `0` to `(getRemotePeripheralCount() - 1)`. + /// \returns device name + String getName(int index); + + /// Get scanned RSSI of the peripheral in the list of scanned devices. + /// + /// \param index ranges from `0` to `(getRemotePeripheralCount() - 1)`. + /// \returns RSSI value in dbm. + int32_t getRSSI(int index); + + /// Get txPower value in the advertisement packet of the peripheral in the list of scanned devices. + /// + /// \param index ranges from `0` to `(getRemotePeripheralCount() - 1)`. + /// \returns TX power field, if any, in the advertisement packet. + int32_t getTxPower(int index); + + /// Get service UUID in the advertisement packet of the peripheral in the list of scanned devices. + /// + /// \param index ranges from `0` to `(getRemotePeripheralCount() - 1)`. + /// \returns service UUID, if any, in the advertisement packet. + LBLEUuid getServiceUuid(int index) const; + + /// Get manufacturer info in the advertisement packet of the peripheral in the list of scanned devices. + /// + /// \param index ranges from `0` to `(getRemotePeripheralCount() - 1)`. + /// \returns manufacturer id, if any, in the advertisement packet. + String getManufacturer(int index) const; + + /// Get the advertisement flag of the scanned device. + /// + /// Advertisement Flags may be the result of bitwise-or of following values: + /// + /// * `BT_GAP_LE_AD_FLAG_LIMITED_DISCOVERABLE (0x01)` + /// * `BT_GAP_LE_AD_FLAG_GENERAL_DISCOVERABLE (0x02)` + /// * `BT_GAP_LE_AD_FLAG_BR_EDR_NOT_SUPPORTED (0x04)` + /// + /// There are also other flags, including: + /// + /// * 0x08: Bluetooth BR/EDR Controller + /// * 0x10: Bluetooth BR/EDR Host + /// + /// which are not used by BLE-only devices. + /// + /// \param index ranges from `0` to `(getRemotePeripheralCount() - 1)`. + /// \returns + uint8_t getAdvertisementFlag(int index)const; + + /// Check if the peripheral is an iBeacon device. + /// + /// \param index ranges from `0` to `(getRemotePeripheralCount() - 1)`. + /// \returns true if the device broadcasts iBeacon format advertisements, false otherwise. + bool isIBeacon(int index) const; + + /// Get iBeacon infomrmation from the advertisement data of an iBeacon device. + /// + /// You can refer to this article on the iBeacon info fields: + /// https://developer.mbed.org/blog/entry/BLE-Beacons-URIBeacon-AltBeacons-iBeacon/#iBeacon + /// + /// \param index ranges from `0` to `(getRemotePeripheralCount() - 1)`. + /// \param uuid Output parameter of the iBeacon info - this UUID is defined by the iBeacon device. + /// \param major Output parameter, the major number in the iBeacon info. + /// \param minor Output parameter, the minor number in the iBeacon info. + /// \param txPower Output parameter, the signed TX Power value in the iBeacon info. + /// \returns true if the device has iBeacon info. false if the device is not an iBeacon device. + bool getIBeaconInfo(int index, LBLEUuid& uuid, uint16_t& major, uint16_t& minor, int8_t& txPower)const; public: - // Event handlers and required data structure - virtual bool isOnce() { return false; }; - virtual void onEvent(bt_msg_type_t msg, bt_status_t status, void *buff); + // Event handlers and required data structure + virtual bool isOnce() { + return false; + }; + virtual void onEvent(bt_msg_type_t msg, bt_status_t status, void *buff); - static const size_t MAX_DEVICE_LIST_SIZE = 256; - std::vector m_peripherals_found; - static void processAdvertisement(const bt_gap_le_advertising_report_ind_t *report); + static const size_t MAX_DEVICE_LIST_SIZE = 256; + std::vector m_peripherals_found; + static void processAdvertisement(const bt_gap_le_advertising_report_ind_t *report); protected: - bool m_registered; - bool m_scanning; - void init(); + bool m_registered; + bool m_scanning; + void init(); }; class LBLEAdvertisements { public: - LBLEAdvertisements(const bt_gap_le_advertising_report_ind_t& adv); + LBLEAdvertisements(const bt_gap_le_advertising_report_ind_t& adv); - virtual bool isValid() const; + virtual bool isValid() const; - // Get the Bluetooth device address (MAC address) of the advertising device. - String getAddress() const; + // Get the Bluetooth device address (MAC address) of the advertising device. + String getAddress() const; - // Get local name boardcasted. This may be empty (NULL). - String getName() const; + // Get local name boardcasted. This may be empty (NULL). + String getName() const; - // Get transmitted Tx power of the advertisement - int8_t getTxPower() const; + // Get transmitted Tx power of the advertisement + int8_t getTxPower() const; - // Get RSSI during scan - int8_t getRSSI() const; + // Get RSSI during scan + int8_t getRSSI() const; - LBLEUuid getServiceUuid() const; + LBLEUuid getServiceUuid() const; - String getManufacturer() const; + String getManufacturer() const; - uint8_t getAdvertisementFlag()const; + uint8_t getAdvertisementFlag()const; - // returns false if this advertisment is not of iBeacon format. - bool getIBeaconInfo(LBLEUuid& uuid, uint16_t& major, uint16_t& minor, int8_t& txPower) const; + // returns false if this advertisment is not of iBeacon format. + bool getIBeaconInfo(LBLEUuid& uuid, uint16_t& major, uint16_t& minor, int8_t& txPower) const; - // Copy the "original" advertisement packet data - // bufLen should be the size of dstBuf. - // The buffer will be truncated if bufLen is not long enough. - // Note that the spec limits maxumimum advertisement data to be 31 bytes. - // - // This method always returns the required buffer size for the advertisement data. - uint32_t getRawManufacturerData(uint8_t* dstBuf, uint32_t bufLen); + // Copy the "original" advertisement packet data + // bufLen should be the size of dstBuf. + // The buffer will be truncated if bufLen is not long enough. + // Note that the spec limits maxumimum advertisement data to be 31 bytes. + // + // This method always returns the required buffer size for the advertisement data. + uint32_t getRawManufacturerData(uint8_t* dstBuf, uint32_t bufLen); - // Copy the "original" advertisement packet data - // bufLen should be the size of dstBuf. - // The buffer will be truncated if bufLen is not long enough. - // Note that the spec limits maxumimum advertisement data to be 31 bytes. - // - // This method always returns the required buffer size for the advertisement data. - uint32_t getRawAdvertisementData(uint8_t* dstBuf, uint32_t bufLen); - - // Copy the "original" scan response packet data. - // Note that scan response is optional and may be empty (all zero). - // - // bufLen should be the size of dstBuf. - // The buffer will be truncated if bufLen is not long enough. - // Note that the spec limits maxumimum advertisement data to be 31 bytes. - // - // This method always returns the required buffer size for the advertisement data. - uint32_t getRawScanResponseData(uint8_t* dstBuf, uint32_t bufLen); + // Copy the "original" advertisement packet data + // bufLen should be the size of dstBuf. + // The buffer will be truncated if bufLen is not long enough. + // Note that the spec limits maxumimum advertisement data to be 31 bytes. + // + // This method always returns the required buffer size for the advertisement data. + uint32_t getRawAdvertisementData(uint8_t* dstBuf, uint32_t bufLen); - static const uint32_t MAX_ADV_DATA_LEN = 0x1F; + // Copy the "original" scan response packet data. + // Note that scan response is optional and may be empty (all zero). + // + // bufLen should be the size of dstBuf. + // The buffer will be truncated if bufLen is not long enough. + // Note that the spec limits maxumimum advertisement data to be 31 bytes. + // + // This method always returns the required buffer size for the advertisement data. + uint32_t getRawScanResponseData(uint8_t* dstBuf, uint32_t bufLen); + + static const uint32_t MAX_ADV_DATA_LEN = 0x1F; private: - - const bt_gap_le_advertising_report_ind_t& adv_data; - - // searches if a specific AD Type field exists in advertisement or scan response data. - // copy the content if found, and returns the length of the AD data found. - // otherwise 0 is returned. - // - // param type: one of the advertisement type in Bluetooth specification. - // refer to bt_gap_le.h for macro constants like BT_GAP_LE_AD_TYPE_FLAG. - uint32_t getAdvDataWithType(uint8_t type, uint8_t* dstBuf, uint32_t bufLen) const; - - static uint32_t getAdvDataWithTypeFromPayload(uint8_t type, - uint8_t* dstBuf, uint32_t bufLen, - const bt_gap_le_advertising_report_ind_t& payload); + + const bt_gap_le_advertising_report_ind_t& adv_data; + + // searches if a specific AD Type field exists in advertisement or scan response data. + // copy the content if found, and returns the length of the AD data found. + // otherwise 0 is returned. + // + // param type: one of the advertisement type in Bluetooth specification. + // refer to bt_gap_le.h for macro constants like BT_GAP_LE_AD_TYPE_FLAG. + uint32_t getAdvDataWithType(uint8_t type, uint8_t* dstBuf, uint32_t bufLen) const; + + static uint32_t getAdvDataWithTypeFromPayload(uint8_t type, + uint8_t* dstBuf, uint32_t bufLen, + const bt_gap_le_advertising_report_ind_t& payload); }; struct LBLEServiceInfo { - LBLEUuid uuid; - uint16_t startHandle; - uint16_t endHandle; + LBLEUuid uuid; + uint16_t startHandle; + uint16_t endHandle; }; /// This class allows users to create connections to remote peripheral devices. @@ -267,149 +269,149 @@ struct LBLEServiceInfo /// LBLEAddress serverAddress = LBLECentral.getBLEAddress(0); /// client.connect(serverAddress); /// while(!client.connected()){ -/// delay(100); +/// delay(100); /// } /// // now we are connnected. /// ~~~ -/// +/// /// Upon successful connection, connected() returns true. /// /// The user can then query if certain services exists on the remote device /// with getServiceCount(), getServiceUuid() and hasService(). -/// +/// /// Once the user confirmed that a service is available, the user may use /// read/write APIs such as readCharacteristicString() or writeCharacteristicFloat() /// to read and write values of the characteristic. -/// +/// /// Note that there is no extra "type" checking, so it is up to the user to make sure /// the value types are matched between read/write APIs and the remote device. class LBLEClient : public LBLEEventObserver { public: - LBLEClient(); - - virtual ~LBLEClient(); - - /// Connect to a remote peripheral device. - /// - /// You can use LBLECentralClass to scan nearby devices and - /// get their addresses - /// - /// This function also implicitly enumerates all the services - /// and characteristics on the remote device, so it may take a while - /// for this function to return. - /// - /// \param address Address of the device to connect to. - /// You can use LBLECentral::getBLEAddress() to get the address of a scanned device. - /// \returns true if the connection attempt starts successfully. Note that this does not mean - /// the connection has been established. - /// \returns false if fail to start connection. - bool connect(const LBLEAddress& address); - - /// Check if the connection to remote device has been established. - bool connected(); - - /// Disconnect from the remote device - void disconnect(); - - /// Get the number of services available on the connected remote device - int getServiceCount(); - - /// Get service uuid by index. Index should range from 0 to (getServiceCount() - 1). - /// - /// \param index ranges from 0 to (getServiceCount() - 1). - /// \returns UUID of the service - LBLEUuid getServiceUuid(int index); - - /// Helper function that returns name of the service if it is know. - /// - /// \param index ranges from 0 to (getServiceCount() - 1). - /// \returns Service name. - String getServiceName(int index); - - /// Check if a given service is available on the connected remote device. - /// - /// \param uuid The UUID of the service to check - /// \returns true if the remote device supports the service. false otherwise. - bool hasService(const LBLEUuid& uuid); - - /// Read raw value buffer fomr a characteristic on remote device. - /// - /// \param uuid The UUID of the characteristic to read from. - /// \returns LBLEValueBuffer object that represents the raw value buffer. - LBLEValueBuffer readCharacterstic(const LBLEUuid& uuid); - - /// Read integer value from a characteristic on remote device. - /// - /// \param uuid The UUID of the characteristic to read from. - /// \returns integer value of the characteristic. 0 is returned if fails to read the characteristic. - int readCharacteristicInt(const LBLEUuid& uuid); - - /// Read string value from a characteristic on remote device. - /// - /// \param uuid The UUID of the characteristic to read from. - /// \returns string value of the characteristic. Empty string is returned if fails to read the characteristic. - String readCharacteristicString(const LBLEUuid& uuid); - - /// Read a single char byte value from a characteristic on remote device. - /// - /// \param uuid The UUID of the characteristic to read from. - /// \returns char value of the characteristic. 0 is returned if fails to read the characteristic. - char readCharacteristicChar(const LBLEUuid& uuid); - - /// Read float value from a characteristic on remote device. - /// - /// \param uuid The UUID of the characteristic to read from. - /// \returns float value of the characteristic. 0 is returned if fails to read the characteristic. - float readCharacteristicFloat(const LBLEUuid& uuid); - - /// Write the value of a characteristic on the remote device. - /// - /// \param uuid The UUID of the characteristic to write to. - /// \param value The raw buffer value to write. - int writeCharacteristic(const LBLEUuid& uuid, const LBLEValueBuffer& value); - - /// Hepler API that write a characteristic on the remote device as integer. - /// - /// \param uuid The UUID of the characteristic to write to. - /// \param value The int value to write. - int writeCharacteristicInt(const LBLEUuid& uuid, int value); - - /// Hepler API that write a characteristic on the remote device as a string. - /// - /// \param uuid The UUID of the characteristic to write to. - /// \param value The int value to write. - int writeCharacteristicString(const LBLEUuid& uuid, const String& value); - - /// Hepler API that write a characteristic on the remote device as char. - /// - /// \param uuid The UUID of the characteristic to write to. - /// \param value The char value to write. - int writeCharacteristicChar(const LBLEUuid& uuid, char value); - - /// Hepler API that write a characteristic on the remote device as float. - /// - /// \param uuid The UUID of the characteristic to write to. - /// \param value The float value to write. - int writeCharacteristicFloat(const LBLEUuid& uuid, float value); + LBLEClient(); + + virtual ~LBLEClient(); + + /// Connect to a remote peripheral device. + /// + /// You can use LBLECentralClass to scan nearby devices and + /// get their addresses + /// + /// This function also implicitly enumerates all the services + /// and characteristics on the remote device, so it may take a while + /// for this function to return. + /// + /// \param address Address of the device to connect to. + /// You can use LBLECentral::getBLEAddress() to get the address of a scanned device. + /// \returns true if the connection attempt starts successfully. Note that this does not mean + /// the connection has been established. + /// \returns false if fail to start connection. + bool connect(const LBLEAddress& address); + + /// Check if the connection to remote device has been established. + bool connected(); + + /// Disconnect from the remote device + void disconnect(); + + /// Get the number of services available on the connected remote device + int getServiceCount(); + + /// Get service uuid by index. Index should range from 0 to (getServiceCount() - 1). + /// + /// \param index ranges from 0 to (getServiceCount() - 1). + /// \returns UUID of the service + LBLEUuid getServiceUuid(int index); + + /// Helper function that returns name of the service if it is know. + /// + /// \param index ranges from 0 to (getServiceCount() - 1). + /// \returns Service name. + String getServiceName(int index); + + /// Check if a given service is available on the connected remote device. + /// + /// \param uuid The UUID of the service to check + /// \returns true if the remote device supports the service. false otherwise. + bool hasService(const LBLEUuid& uuid); + + /// Read raw value buffer fomr a characteristic on remote device. + /// + /// \param uuid The UUID of the characteristic to read from. + /// \returns LBLEValueBuffer object that represents the raw value buffer. + LBLEValueBuffer readCharacterstic(const LBLEUuid& uuid); + + /// Read integer value from a characteristic on remote device. + /// + /// \param uuid The UUID of the characteristic to read from. + /// \returns integer value of the characteristic. 0 is returned if fails to read the characteristic. + int readCharacteristicInt(const LBLEUuid& uuid); + + /// Read string value from a characteristic on remote device. + /// + /// \param uuid The UUID of the characteristic to read from. + /// \returns string value of the characteristic. Empty string is returned if fails to read the characteristic. + String readCharacteristicString(const LBLEUuid& uuid); + + /// Read a single char byte value from a characteristic on remote device. + /// + /// \param uuid The UUID of the characteristic to read from. + /// \returns char value of the characteristic. 0 is returned if fails to read the characteristic. + char readCharacteristicChar(const LBLEUuid& uuid); + + /// Read float value from a characteristic on remote device. + /// + /// \param uuid The UUID of the characteristic to read from. + /// \returns float value of the characteristic. 0 is returned if fails to read the characteristic. + float readCharacteristicFloat(const LBLEUuid& uuid); + + /// Write the value of a characteristic on the remote device. + /// + /// \param uuid The UUID of the characteristic to write to. + /// \param value The raw buffer value to write. + int writeCharacteristic(const LBLEUuid& uuid, const LBLEValueBuffer& value); + + /// Hepler API that write a characteristic on the remote device as integer. + /// + /// \param uuid The UUID of the characteristic to write to. + /// \param value The int value to write. + int writeCharacteristicInt(const LBLEUuid& uuid, int value); + + /// Hepler API that write a characteristic on the remote device as a string. + /// + /// \param uuid The UUID of the characteristic to write to. + /// \param value The int value to write. + int writeCharacteristicString(const LBLEUuid& uuid, const String& value); + + /// Hepler API that write a characteristic on the remote device as char. + /// + /// \param uuid The UUID of the characteristic to write to. + /// \param value The char value to write. + int writeCharacteristicChar(const LBLEUuid& uuid, char value); + + /// Hepler API that write a characteristic on the remote device as float. + /// + /// \param uuid The UUID of the characteristic to write to. + /// \param value The float value to write. + int writeCharacteristicFloat(const LBLEUuid& uuid, float value); public: - virtual void onEvent(bt_msg_type_t msg, bt_status_t status, void *buff); + virtual void onEvent(bt_msg_type_t msg, bt_status_t status, void *buff); protected: - bt_handle_t m_connection; - std::vector m_services; - std::map m_characteristics; - - // enumerate all service info from remote device - int discoverServices(); - - // Read all characteristic on remote device. - // This could take a while. - int discoverCharacteristics(); - - // Enumerate all characteristics, given a service ID. - int discoverCharacteristicsOfService(const LBLEServiceInfo& s); + bt_handle_t m_connection; + std::vector m_services; + std::map m_characteristics; + + // enumerate all service info from remote device + int discoverServices(); + + // Read all characteristic on remote device. + // This could take a while. + int discoverCharacteristics(); + + // Enumerate all characteristics, given a service ID. + int discoverCharacteristicsOfService(const LBLEServiceInfo& s); }; extern LBLECentralClass LBLECentral; diff --git a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLEPeriphral.cpp b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLEPeriphral.cpp index a3db132..c7d569c 100644 --- a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLEPeriphral.cpp +++ b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLEPeriphral.cpp @@ -30,7 +30,7 @@ LBLEAdvertisementData::~LBLEAdvertisementData() void LBLEAdvertisementData::addAdvertisementData(const LBLEAdvDataItem &item) { - m_advDataList.push_back(item); + m_advDataList.push_back(item); } void LBLEAdvertisementData::addFlag(uint8_t flag) @@ -49,7 +49,7 @@ void LBLEAdvertisementData::addName(const char* deviceName) // name default to complete name LBLEAdvDataItem item; item.adType = BT_GAP_LE_AD_TYPE_NAME_COMPLETE; - + // note that in AD data the string does name // contain NULL-termination character. // for size check - we simply truncate the device name @@ -93,18 +93,18 @@ void LBLEAdvertisementData::configAsConnectableDevice(const char* deviceName, co uuid.toRawBuffer(item.adData, item.adDataLen); } addAdvertisementData(item); - + // Usually we need a name for iOS devices to list our peripheral device. addName(deviceName); } void LBLEAdvertisementData::configAsEddystoneURL(EDDYSTONE_URL_PREFIX prefix, - const String& url, - EDDYSTONE_URL_ENCODING suffix, - const String& tail) + const String& url, + EDDYSTONE_URL_ENCODING suffix, + const String& tail) { - const uint32_t MAX_ENCODED_URL_SIZE = 17; + const uint32_t MAX_ENCODED_URL_SIZE = 17; const int8_t txPower = -30; // remove all existing AD @@ -151,7 +151,7 @@ void LBLEAdvertisementData::configAsEddystoneURL(EDDYSTONE_URL_PREFIX prefix, pData += addedURLLength; urlBudget -= addedURLLength; } - + // optionally appending suffix & tail if(suffix != EDDY_URL_NONE) { @@ -179,14 +179,14 @@ void LBLEAdvertisementData::configAsEddystoneURL(EDDYSTONE_URL_PREFIX prefix, } item.adDataLen = (pData - item.adData); - + addAdvertisementData(item); } -void LBLEAdvertisementData::configAsIBeacon(const LBLEUuid& uuid, - uint16_t major, - uint16_t minor, - int8_t txPower) +void LBLEAdvertisementData::configAsIBeacon(const LBLEUuid& uuid, + uint16_t major, + uint16_t minor, + int8_t txPower) { // remove all existing AD m_advDataList.clear(); @@ -206,7 +206,7 @@ void LBLEAdvertisementData::configAsIBeacon(const LBLEUuid& uuid, item.clear(); item.adType = BT_GAP_LE_AD_TYPE_MANUFACTURER_SPECIFIC; item.adDataLen = 0x19; // always 25 bytes of manufacturer payload - + item.adData[0] = 0x4c; // Apple vendor id(0x004c) item.adData[1] = 0x00; // Apple vendor id(0x004c) @@ -228,7 +228,7 @@ void LBLEAdvertisementData::configAsIBeacon(const LBLEUuid& uuid, (*(uint16_t*)(item.adData + 22)) = (minor >> 8) | ((minor & 0xFF) << 8); // 1 byte TxPower (signed) - item.adData[24] = (uint8_t)txPower; + item.adData[24] = (uint8_t)txPower; addAdvertisementData(item); } @@ -303,7 +303,7 @@ uint16_t LBLEService::begin(uint16_t startingHandle) { return 0; } - + // handle number must be globally unique and incresing uint16_t currentHandle = startingHandle; @@ -314,10 +314,10 @@ uint16_t LBLEService::begin(uint16_t startingHandle) pRecord->rec_hdr.perm = BT_GATTS_REC_PERM_READABLE; pRecord->rec_hdr.value_len = 16; pRecord->uuid128 = m_uuid.uuid_data; - + currentHandle++; m_records.push_back((bt_gatts_service_rec_t*)pRecord); - + // Generate characterstics attribute records for(size_t i = 0; i < m_attributes.size(); ++i) { @@ -331,8 +331,9 @@ uint16_t LBLEService::begin(uint16_t startingHandle) } } - // assign the last handle number back to attribute instance - m_attributes[i]->assignHandle(currentHandle - 1); + // assign the value handle number back to attribute instance + const int valueHandleOffset = m_attributes[i]->getRecordCount() - 2 + 1; + m_attributes[i]->assignHandle(currentHandle - valueHandleOffset); } // handle numbers @@ -366,7 +367,7 @@ void LBLEService::end() ///////////////////////////////////////////////////////////////////////////////////////////// // implement trampoline callback as requested in ard_bt_attr_callback.h -uint32_t ard_bt_callback_trampoline(const uint8_t rw, uint16_t handle, void *data, uint16_t size, uint16_t offset, void* user_data) +uint32_t ard_bt_callback_trampoline(const uint8_t rw, uint16_t handle, void *data, uint16_t size, uint16_t offset, void* user_data, int callback_type) { pr_debug("attribute_callback [%d, %d, 0x%p, %d, %d, 0x%p", rw, handle, data, size, offset, user_data); @@ -378,20 +379,45 @@ uint32_t ard_bt_callback_trampoline(const uint8_t rw, uint16_t handle, void *dat LBLEAttributeInterface* pThis = (LBLEAttributeInterface*)user_data; - if(0 == size) - { - return pThis->onSize(); - } + if(ARD_BT_CB_TYPE_VALUE_CALLBACK == callback_type) { + // Value callbacks - redirecting to read/write methods. + if(0 == size) + { + return pThis->onSize(); + } - if (rw == BT_GATTS_CALLBACK_WRITE) - { - return pThis->onWrite(data, size, offset); - } - else if (rw == BT_GATTS_CALLBACK_READ) - { - return pThis->onRead(data, size, offset); + if (rw == BT_GATTS_CALLBACK_WRITE) + { + return pThis->onWrite(data, size, offset); + } + else if (rw == BT_GATTS_CALLBACK_READ) + { + return pThis->onRead(data, size, offset); + } + } else if (ARD_BT_CB_TYPE_CCCD_CALLBACK == callback_type) { + // CCCD callbacks - these are used to enable / disable + // notification and indication. + if (rw == BT_GATTS_CALLBACK_WRITE) + { + // CCCD descriptor is a 16-bit flag - see + // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml + if(data && size == sizeof(uint16_t)) { + pThis->onWriteIndicationNotificationFlag(*(uint16_t*)data); + return sizeof(uint16_t); + } + return 0; + } + else if (rw == BT_GATTS_CALLBACK_READ) + { + uint16_t cccdFlag = pThis->onReadIndicationNotificationFlag(); + if(data && size == sizeof(cccdFlag)) { + *(uint16_t*)data = cccdFlag; + } + return sizeof(cccdFlag); + } } - + + return 0; } @@ -399,7 +425,8 @@ LBLECharacteristicBase::LBLECharacteristicBase(LBLEUuid uuid, uint32_t permissio m_uuid(uuid), m_perm(permission), m_updated(false), - m_attrHandle(BT_HANDLE_INVALID) + m_attrHandle(BT_HANDLE_INVALID), + m_cccdFlag(0) { } @@ -408,7 +435,8 @@ LBLECharacteristicBase::LBLECharacteristicBase(LBLEUuid uuid): m_uuid(uuid), m_perm(LBLE_READ | LBLE_WRITE), m_updated(false), - m_attrHandle(BT_HANDLE_INVALID) + m_attrHandle(BT_HANDLE_INVALID), + m_cccdFlag(0) { } @@ -427,51 +455,79 @@ bt_gatts_service_rec_t* LBLECharacteristicBase::allocRecord(uint32_t recordIndex { switch(recordIndex) { - case 0: + case 0: // UUID record + { + // the first record is a "Characteristic UUID" attribute + // it then points the the actual value entry by the "handle" field. + bt_gatts_characteristic_128_t* pRec = (bt_gatts_characteristic_128_t*)malloc(sizeof(bt_gatts_characteristic_128_t)); + if(NULL == pRec) { - // the first record is a "Characteristic UUID" attribute - // it then points the the actual value entry by the "handle" field. - bt_gatts_characteristic_128_t* pRec = (bt_gatts_characteristic_128_t*)malloc(sizeof(bt_gatts_characteristic_128_t)); - if(NULL == pRec) - { - return NULL; - } - - // For Arduino, we by default enables all permissions and properties, - // allowing read/write and would potentially send notification and indication. - pRec->rec_hdr.uuid_ptr = &BT_GATT_UUID_CHARC; - pRec->rec_hdr.perm = BT_GATTS_REC_PERM_READABLE | BT_GATTS_REC_PERM_WRITABLE; - pRec->rec_hdr.value_len = 19; - pRec->value.properties = BT_GATT_CHARC_PROP_READ | BT_GATT_CHARC_PROP_WRITE | BT_GATT_CHARC_PROP_NOTIFY | BT_GATT_CHARC_PROP_INDICATE; - pRec->value.handle = currentHandle + 1; - pRec->value.uuid128 = m_uuid.uuid_data; - - return (bt_gatts_service_rec_t*)pRec; + return NULL; } - case 1: + + // For Arduino, we by default enables all permissions and properties, + // allowing read/write and would potentially send notification and indication. + pRec->rec_hdr.uuid_ptr = &BT_GATT_UUID_CHARC; + pRec->rec_hdr.perm = BT_GATTS_REC_PERM_READABLE | BT_GATTS_REC_PERM_WRITABLE; + pRec->rec_hdr.value_len = 19; + pRec->value.properties = BT_GATT_CHARC_PROP_READ | BT_GATT_CHARC_PROP_WRITE | BT_GATT_CHARC_PROP_NOTIFY | BT_GATT_CHARC_PROP_INDICATE; + pRec->value.handle = currentHandle + 1; + pRec->value.uuid128 = m_uuid.uuid_data; + + return (bt_gatts_service_rec_t*)pRec; + } + case 1: // attribute value record + { + // allocating callback function - not needed if SDK allows passing user data directly. + bt_gatts_rec_callback_t callbackFunc = ard_bt_alloc_callback_slot((LBLEAttributeInterface*)this, ARD_BT_CB_TYPE_VALUE_CALLBACK); + if(NULL == callbackFunc) { - // allocating callback function - not needed if SDK allows passing user data directly. - bt_gatts_rec_callback_t callbackFunc = ard_bt_alloc_callback_slot((LBLEAttributeInterface*)this); - if(NULL == callbackFunc) - { - return NULL; - } + return NULL; + } - // the first record is a "Characteristic UUID" attribute - // it then points the the actual value entry by the "handle" field. - bt_gatts_characteristic_t* pRec = (bt_gatts_characteristic_t*)malloc(sizeof(bt_gatts_characteristic_t)); - if(NULL == pRec) - { - // TODO: if we can free callbackFunc, we should free it. - return NULL; - } - - pRec->rec_hdr.uuid_ptr = &m_uuid.uuid_data; - pRec->rec_hdr.perm = BT_GATTS_REC_PERM_READABLE | BT_GATTS_REC_PERM_WRITABLE; - pRec->rec_hdr.value_len = 0; - pRec->value.callback = callbackFunc; - return (bt_gatts_service_rec_t*)pRec; + // the first record is a "Characteristic UUID" attribute + // it then points the the actual value entry by the "handle" field. + bt_gatts_characteristic_t* pRec = (bt_gatts_characteristic_t*)malloc(sizeof(bt_gatts_characteristic_t)); + if(NULL == pRec) + { + // TODO: if we can free callbackFunc, we should free it. + return NULL; } + + pRec->rec_hdr.uuid_ptr = &m_uuid.uuid_data; + pRec->rec_hdr.perm = BT_GATTS_REC_PERM_READABLE | BT_GATTS_REC_PERM_WRITABLE; + pRec->rec_hdr.value_len = 0; + pRec->value.callback = callbackFunc; + return (bt_gatts_service_rec_t*)pRec; + } + case 2: // CCCD descriptor record + { + // allocating callback function - not needed if SDK allows passing user data directly. + bt_gatts_rec_callback_t callbackFunc = ard_bt_alloc_callback_slot((LBLEAttributeInterface*)this, ARD_BT_CB_TYPE_CCCD_CALLBACK); + if(NULL == callbackFunc) + { + return NULL; + } + + // The "Characteristic User Description" descriptor represents a "switch" for turning on/off of the notification of the characteristic. + // Some central devices require the presense of this descriptor before receiving the notification push. + // Reference: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml + bt_gatts_client_characteristic_config_t* pRec = (bt_gatts_client_characteristic_config_t*)malloc(sizeof(bt_gatts_client_characteristic_config_t)); + if(NULL == pRec) + { + return NULL; + } + + // The CCCD is always read/writable by the client. + pRec->rec_hdr.uuid_ptr = &BT_GATT_UUID_CLIENT_CHARC_CONFIG; + pRec->rec_hdr.perm = BT_GATTS_REC_PERM_READABLE | BT_GATTS_REC_PERM_WRITABLE; + pRec->rec_hdr.value_len = 0; + pRec->callback = callbackFunc; + // TODO: the setting of CCCD is per-connection x per-characterist, and must be retained across connection for bounded devices + // However, we currently don't keep tracking of this. + + return (bt_gatts_service_rec_t*)pRec; + } default: return NULL; } @@ -485,7 +541,7 @@ int LBLECharacteristicBase::_notifyIndicate(uint8_t opcode, bt_handle_t connecti // For now, we assume it is only possible to call LBLE within the Arduino thread. const size_t COMMON_BUFFER_SIZE = 32; // most requrest should be smaller than 30 bytes. static uint8_t requestBufStatic[COMMON_BUFFER_SIZE] = {0}; - + // calculate required buffer size const size_t requestHeaderSize = 3; // we can't use sizeof(bt_gattc_charc_value_notification_indication_t); because it contains the "attribute_value" field const size_t requestBufferSize = requestHeaderSize + data.size(); @@ -508,7 +564,7 @@ int LBLECharacteristicBase::_notifyIndicate(uint8_t opcode, bt_handle_t connecti pr_debug("_notify reqBuf size = %d required dynamic allocation", requestBufferSize); } assert(reqBuf != NULL); - + // alias pointer to the request buffer bt_gattc_charc_value_notification_indication_t* pReq = (bt_gattc_charc_value_notification_indication_t*)reqBuf; pReq->attribute_value_length = requestBufferSize; @@ -517,26 +573,26 @@ int LBLECharacteristicBase::_notifyIndicate(uint8_t opcode, bt_handle_t connecti memcpy(pReq->att_req.attribute_value, &data[0], data.size()); // send notifiction - we don't expect peer to send ACK. const bt_status_t status = bt_gatts_send_charc_value_notification_indication(connection, pReq); - + if(BT_STATUS_SUCCESS != status) - { - switch(status){ - case BT_STATUS_FAIL: + { + switch(status) { + case BT_STATUS_FAIL: pr_debug("bt_gatts_send_charc_value_notification_indication fails STATUS_FAIL"); break; - case BT_STATUS_OUT_OF_MEMORY: + case BT_STATUS_OUT_OF_MEMORY: pr_debug("bt_gatts_send_charc_value_notification_indication fails OUT_OF_MEMORY"); break; - case BT_STATUS_CONNECTION_IN_USE: + case BT_STATUS_CONNECTION_IN_USE: pr_debug("bt_gatts_send_charc_value_notification_indication fails CONNECTION_INUSE"); break; - default: + default: pr_debug("bt_gatts_send_charc_value_notification_indication fails with 0x%x", status); break; } return -1; } - + return 0; } @@ -552,13 +608,24 @@ int LBLECharacteristicBase::_indicate(bt_handle_t connection, const LBLEValueBuf return this->_notifyIndicate(BT_ATT_OPCODE_HANDLE_VALUE_INDICATION, connection, data); } +void LBLECharacteristicBase::onWriteIndicationNotificationFlag(uint16_t flag) { + pr_debug("Write CCCD Flag=0x%x", flag); + m_cccdFlag = flag; + return; +} + +uint16_t LBLECharacteristicBase::onReadIndicationNotificationFlag() { + pr_debug("Read CCCD Flag=0x%x", m_cccdFlag); + return m_cccdFlag; +} + ///////////////////////////////////////////////////////////////////////////////////////////// // LBLECharacteristic (Raw Buffer) ///////////////////////////////////////////////////////////////////////////////////////////// LBLECharacteristicBuffer::LBLECharacteristicBuffer(LBLEUuid uuid, uint32_t permission): LBLECharacteristicBase(uuid, permission) { - m_data.resize(512); + m_data.reserve(MAX_ATTRIBUTE_DATA_LEN); m_writtenInfo.size = 0; m_writtenInfo.offset = 0; } @@ -566,7 +633,7 @@ LBLECharacteristicBuffer::LBLECharacteristicBuffer(LBLEUuid uuid, uint32_t permi LBLECharacteristicBuffer::LBLECharacteristicBuffer(LBLEUuid uuid): LBLECharacteristicBase(uuid, LBLE_READ | LBLE_WRITE) { - m_data.resize(512); + m_data.reserve(MAX_ATTRIBUTE_DATA_LEN); m_writtenInfo.size = 0; m_writtenInfo.offset = 0; } @@ -617,7 +684,7 @@ uint32_t LBLECharacteristicBuffer::onRead(void *data, uint16_t size, uint16_t of } const uint32_t dataSize = onSize(); - + uint32_t copySize = (dataSize > offset) ? (dataSize - offset) : 0; copySize = (size > copySize) ? copySize : size; @@ -644,7 +711,7 @@ uint32_t LBLECharacteristicBuffer::onWrite(void *data, uint16_t size, uint16_t o { m_writtenInfo.size = size; m_writtenInfo.offset = offset; - memcpy(&m_data[0] + offset, data, size); + memcpy(&m_data[0] + offset, data, size); m_updated = true; } return size; @@ -709,8 +776,8 @@ int LBLECharacteristicString::indicate(bt_handle_t connection) uint32_t LBLECharacteristicString::onRead(void *data, uint16_t size, uint16_t offset) { const uint32_t dataSize = onSize(); - - if (size == 0){ + + if (size == 0) { return dataSize; } @@ -814,8 +881,8 @@ uint32_t LBLECharacteristicInt::onSize() const uint32_t LBLECharacteristicInt::onRead(void *data, uint16_t size, uint16_t offset) { const uint32_t dataSize = onSize(); - - if (size == 0){ + + if (size == 0) { return dataSize; } @@ -866,7 +933,7 @@ LBLEPeripheralClass::LBLEPeripheralClass(): LBLEPeripheralClass::~LBLEPeripheralClass() { - + } int LBLEPeripheralClass::advertise(const LBLEAdvertisementData& advData) @@ -883,8 +950,8 @@ int LBLEPeripheralClass::advertise(const LBLEAdvertisementData& advData) } int LBLEPeripheralClass::advertiseAsBeacon(const LBLEAdvertisementData& advData, - uint32_t intervalMS, - uint8_t txPower) + uint32_t intervalMS, + int8_t txPower) { // make a copy of advertisement data for re-advertising after disconnect event. // previous advertisement data will be cleared since m_pAdvData is unique_ptr. @@ -908,7 +975,7 @@ int LBLEPeripheralClass::advertiseAsBeacon(const LBLEAdvertisementData& advData, // use normal advertisement API return advertiseAgain(); #else - // TODO: currently the multi-advertisment API does not work due to + // TODO: currently the multi-advertisment API does not work due to // instance limitation - looks like a bug. // use multi-advertisement API, @@ -922,8 +989,8 @@ int LBLEPeripheralClass::advertiseAsBeacon(const LBLEAdvertisementData& advData, // populate the advertisement data bt_hci_cmd_le_set_advertising_data_t hci_adv_data = {0}; - hci_adv_data.advertising_data_length = m_pAdvData->getPayload(hci_adv_data.advertising_data, - sizeof(hci_adv_data.advertising_data)); + hci_adv_data.advertising_data_length = m_pAdvData->getPayload(hci_adv_data.advertising_data, + sizeof(hci_adv_data.advertising_data)); bt_hci_cmd_le_set_scan_response_data_t hci_scan_rsp_data = {0}; @@ -933,34 +1000,34 @@ int LBLEPeripheralClass::advertiseAsBeacon(const LBLEAdvertisementData& advData, delay(500); bt_status_t status = bt_gap_le_start_multiple_advertising( - 1, // Only allow 1 advertisement instance - txPower, - randomAddress, - &adv_param, - &hci_adv_data, - &hci_scan_rsp_data - ); - delay(500); - if(status != BT_STATUS_SUCCESS) - { - Serial.print("failed calling start multiple advertising = "); - Serial.println(status, HEX); - } + 1, // Only allow 1 advertisement instance + txPower, + randomAddress, + &adv_param, + &hci_adv_data, + &hci_scan_rsp_data + ); + delay(500); + if(status != BT_STATUS_SUCCESS) + { + Serial.print("failed calling start multiple advertising = "); + Serial.println(status, HEX); + } bool done = waitAndProcessEvent( - [&](){ - return; - }, + [&]() { + return; + }, - BT_GAP_LE_START_MULTIPLE_ADVERTISING_CNF, + BT_GAP_LE_START_MULTIPLE_ADVERTISING_CNF, - [this](bt_msg_type_t msg, bt_status_t status, void* buf) - { - Serial.print("status="); - Serial.println(status); - return; - } - ); + [this](bt_msg_type_t msg, bt_status_t status, void* buf) + { + Serial.print("status="); + Serial.println(status); + return; + } + ); if(!done) { @@ -968,7 +1035,7 @@ int LBLEPeripheralClass::advertiseAsBeacon(const LBLEAdvertisementData& advData, } #endif } - + void LBLEPeripheralClass::stopAdvertise() { // disable advertisement @@ -979,18 +1046,18 @@ void LBLEPeripheralClass::stopAdvertise() bool done = waitAndProcessEvent( // Call connect API [&enable]() - { - bt_gap_le_set_advertising(&enable, NULL, NULL, NULL); - }, - // wait for confirmation before we can disconnect again... - BT_GAP_LE_SET_ADVERTISING_CNF, - // to update the `m_connection` member in BT task - [](bt_msg_type_t, bt_status_t, void* buf) - { - return; - } + { + bt_gap_le_set_advertising(&enable, NULL, NULL, NULL); + }, + // wait for confirmation before we can disconnect again... + BT_GAP_LE_SET_ADVERTISING_CNF, + // to update the `m_connection` member in BT task + [](bt_msg_type_t, bt_status_t, void* buf) + { + return; + } ); - + if(!done) { pr_debug("fails to stop advertisement!"); @@ -1008,7 +1075,7 @@ int LBLEPeripheralClass::advertiseAgain() { return -2; } - + // enable advertisement bt_hci_cmd_le_set_advertising_enable_t enable = {0}; enable.advertising_enable = BT_HCI_ENABLE; @@ -1018,8 +1085,8 @@ int LBLEPeripheralClass::advertiseAgain() // populate the advertisement data bt_hci_cmd_le_set_advertising_data_t hci_adv_data; - const uint32_t payLoadRequired = m_pAdvData->getPayload(hci_adv_data.advertising_data, - sizeof(hci_adv_data.advertising_data)); + const uint32_t payLoadRequired = m_pAdvData->getPayload(hci_adv_data.advertising_data, + sizeof(hci_adv_data.advertising_data)); pr_debug("payload requires %d bytes", payLoadRequired); if(sizeof(hci_adv_data.advertising_data) < payLoadRequired) { @@ -1049,7 +1116,7 @@ void LBLEPeripheralClass::setName(const char* name) void LBLEPeripheralClass::addService(const LBLEService& service) { - m_services.push_back(service); + m_services.push_back(service); } const bt_gatts_service_t** LBLEPeripheralClass::getServiceTable() @@ -1068,24 +1135,24 @@ const bt_gatts_service_t** LBLEPeripheralClass::getServiceTable() //////////////////////////////////////////////////////////////////////// extern "C" { -extern const bt_gatts_service_t bt_if_gap_service; // 0x0001- -extern const bt_gatts_service_t bt_if_gatt_service_ro; // 0x0011- -extern const bt_gatts_service_t bt_if_ble_smtcn_service; // 0x0014- + extern const bt_gatts_service_t bt_if_gap_service; // 0x0001- + extern const bt_gatts_service_t bt_if_gatt_service_ro; // 0x0011- + extern const bt_gatts_service_t bt_if_ble_smtcn_service; // 0x0014- // Collects all service -const bt_gatts_service_t * g_gatt_server[] = { - &bt_if_gap_service, //0x0001 - &bt_if_gatt_service_ro, //0x0011 - &bt_if_ble_smtcn_service, //0x0014-0x0017 - NULL -}; + const bt_gatts_service_t * g_gatt_server[] = { + &bt_if_gap_service, //0x0001 + &bt_if_gatt_service_ro, //0x0011 + &bt_if_ble_smtcn_service, //0x0014-0x0017 + NULL + }; // This callback is called by BLE GATT framework // when a remote device is connecting to this peripheral. -const bt_gatts_service_t** bt_get_gatt_server() -{ - return LBLEPeripheral.getServiceTable(); -} + const bt_gatts_service_t** bt_get_gatt_server() + { + return LBLEPeripheral.getServiceTable(); + } } // extern "C" @@ -1103,7 +1170,7 @@ void LBLEPeripheralClass::begin() m_servicePtrTable.push_back(&bt_if_gap_service); m_servicePtrTable.push_back(&bt_if_gatt_service_ro); - // this "handle" must be globally unique, + // this "handle" must be globally unique, // as requested by BLE framework. assert(USER_ATTRIBUTE_HANDLE_START > bt_if_gap_service.ending_handle); assert(USER_ATTRIBUTE_HANDLE_START > bt_if_gatt_service_ro.ending_handle); @@ -1148,39 +1215,39 @@ void LBLEPeripheralClass::disconnectAll() if(conn != BT_HANDLE_INVALID) { // disconnect the connection handle - bool done = waitAndProcessEvent( - // Call connect API - [conn]() - { - bt_hci_cmd_disconnect_t disconn_para = {0}; - disconn_para.connection_handle = conn; - disconn_para.reason = 0x13; // REMOTE USER TERMINATED CONNECTION - bt_gap_le_disconnect(&disconn_para); - }, - // wait for confirmation before we can disconnect again... - BT_GAP_LE_DISCONNECT_CNF, - // to update the `m_connection` member in BT task - [this, conn](bt_msg_type_t, bt_status_t, void* buf) + waitAndProcessEvent( + // Call connect API + [conn]() + { + bt_hci_cmd_disconnect_t disconn_para = {0}; + disconn_para.connection_handle = conn; + disconn_para.reason = 0x13; // REMOTE USER TERMINATED CONNECTION + bt_gap_le_disconnect(&disconn_para); + }, + // wait for confirmation before we can disconnect again... + BT_GAP_LE_DISCONNECT_CNF, + // to update the `m_connection` member in BT task + [this, conn](bt_msg_type_t, bt_status_t, void* buf) + { + // CNF is null payload, so we simply remove the handle. + // we search the entire m_connection container again, + // in case that iterator "c" becomes invalid + // becuse of other BT_GAP_LE_CONNECT_IND events + for(auto removeItr = m_connections.begin(); removeItr != m_connections.end(); ++removeItr) + { + if(*removeItr == conn) { - // CNF is null payload, so we simply remove the handle. - // we search the entire m_connection container again, - // in case that iterator "c" becomes invalid - // becuse of other BT_GAP_LE_CONNECT_IND events - for(auto removeItr = m_connections.begin(); removeItr != m_connections.end(); ++removeItr) - { - if(*removeItr == conn) - { - *removeItr = BT_HANDLE_INVALID; - } - } + *removeItr = BT_HANDLE_INVALID; } - ); + } + } + ); } } } bool LBLEPeripheralClass::isOnce() -{ +{ // keep listening for connection events return false; } @@ -1188,7 +1255,6 @@ bool LBLEPeripheralClass::isOnce() int LBLEPeripheralClass::notifyAll(LBLEAttributeInterface& characteristic) { // broadcasting to all connected devices - size_t count = 0; size_t notified = 0; for(auto c : m_connections) { @@ -1207,7 +1273,6 @@ int LBLEPeripheralClass::notifyAll(LBLEAttributeInterface& characteristic) int LBLEPeripheralClass::indicateAll(LBLEAttributeInterface& characteristic) { // broadcasting to all connected devices - size_t count = 0; size_t indicated = 0; for(auto c : m_connections) { @@ -1233,53 +1298,53 @@ void LBLEPeripheralClass::onEvent(bt_msg_type_t msg, bt_status_t status, void *b switch(msg) { case BT_GAP_LE_CONNECT_IND: + { + const bt_gap_le_connection_ind_t* pInfo = (bt_gap_le_connection_ind_t*)buff; + if(!pInfo) { - const bt_gap_le_connection_ind_t* pInfo = (bt_gap_le_connection_ind_t*)buff; - if(!pInfo) + break; + } + + // check if there is a redundant connection event + for(auto c : m_connections) + { + // already registered, early break. + if(c == pInfo->connection_handle) { - break; + pr_debug("duplicated connection handle event: %d", c); + return; } + } - // check if there is a redundant connection event - for(auto c : m_connections) + // Peripheral are "slaves" + if(BT_ROLE_SLAVE == pInfo->role) + { + // check if there are empy slots (slots with BT_HANDLE_INVALID) + // otherwise we append a new entry. + bool inserted = false; + for(auto itr = m_connections.begin(); itr != m_connections.end(); ++itr) { - // already registered, early break. - if(c == pInfo->connection_handle) + // find matched connections and mark as invalid + if(BT_HANDLE_INVALID == *itr) { - pr_debug("duplicated connection handle event: %d", c); - return; + *itr = pInfo->connection_handle; + inserted = true; } } - // Peripheral are "slaves" - if(BT_ROLE_SLAVE == pInfo->role) + // no empty slot, add a new entry + if(!inserted) { - // check if there are empy slots (slots with BT_HANDLE_INVALID) - // otherwise we append a new entry. - bool inserted = false; - for(auto itr = m_connections.begin(); itr != m_connections.end(); ++itr) - { - // find matched connections and mark as invalid - if(BT_HANDLE_INVALID == *itr) - { - *itr = pInfo->connection_handle; - inserted = true; - } - } - - // no empty slot, add a new entry - if(!inserted) - { - m_connections.push_back(pInfo->connection_handle); - } + m_connections.push_back(pInfo->connection_handle); } } - break; + } + break; case BT_GAP_LE_DISCONNECT_IND: + { + const bt_gap_le_disconnect_ind_t* pInfo = (bt_gap_le_disconnect_ind_t*)buff; + if(pInfo) { - const bt_gap_le_disconnect_ind_t* pInfo = (bt_gap_le_disconnect_ind_t*)buff; - if(pInfo) - { const bt_handle_t disconnectedHandle = pInfo->connection_handle; for(auto itr = m_connections.begin(); itr != m_connections.end(); ++itr) { @@ -1290,11 +1355,11 @@ void LBLEPeripheralClass::onEvent(bt_msg_type_t msg, bt_status_t status, void *b } } } - } + } // the underlying framework stops advertisement as soon as a new connection is built. // so we re-advertise ourselves after disconnection. - advertiseAgain(); - break; + advertiseAgain(); + break; } return; diff --git a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLEPeriphral.h b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLEPeriphral.h index 00fcb55..3933a4d 100644 --- a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLEPeriphral.h +++ b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/LBLEPeriphral.h @@ -21,59 +21,59 @@ extern "C" struct LBLEAdvDataItem { - // according to BLE spec - static const uint32_t MAX_ADV_DATA_LEN = 0x1F; - - uint8_t adType; - uint8_t adData[MAX_ADV_DATA_LEN]; - uint32_t adDataLen; - - void clear() - { - adType = 0; - adDataLen = 0; - memset(adData, 0, MAX_ADV_DATA_LEN); - } + // according to BLE spec + static const uint32_t MAX_ADV_DATA_LEN = 0x1F; + + uint8_t adType; + uint8_t adData[MAX_ADV_DATA_LEN]; + uint32_t adDataLen; + + void clear() + { + adType = 0; + adDataLen = 0; + memset(adData, 0, MAX_ADV_DATA_LEN); + } }; /// Enum for LBLEAdvertisementData::configAsEddystoneURL. -/// +/// // refer to https://github.com/google/eddystone/tree/master/eddystone-url#url-scheme-prefix enum EDDYSTONE_URL_PREFIX { - EDDY_HTTP_WWW = 0, // "http://www." - EDDY_HTTPS_WWW = 1, // "https://www." - EDDY_HTTP = 2, // "http://" - EDDY_HTTPS = 3 // "https://" + EDDY_HTTP_WWW = 0, // "http://www." + EDDY_HTTPS_WWW = 1, // "https://www." + EDDY_HTTP = 2, // "http://" + EDDY_HTTPS = 3 // "https://" }; /// Enum for LBLEAdvertisementData::configAsEddystoneURL. -/// +/// /// refer to https://github.com/google/eddystone/tree/master/eddystone-url#eddystone-url-http-url-encoding enum EDDYSTONE_URL_ENCODING { - EDDY_URL_NONE = 0xFFFFFFFF, // No suffix to append - EDDY_DOT_COM_SLASH = 0, // ".com/" - EDDY_DOT_ORG_SLASH = 1, // ".org/" - EDDY_DOT_EDU_SLASH = 2, // ".edu/" - EDDY_DOT_NET_SLASH = 3, // ".net/" - EDDY_DOT_INFO_SLASH = 4, // ".info/" - EDDY_DOT_BIZ_SLASH = 5, // ".biz/" - EDDY_DOT_GOV_SLASH = 6, // ".gov/" - EDDY_DOT_COM = 7, // ".com" - EDDY_DOT_ORG = 8, // ".org" - EDDY_DOT_EDU = 9, // ".edu" - EDDY_DOT_NET = 10, // ".net" - EDDY_DOT_INFO = 11, // ".info" - EDDY_DOT_BIZ = 12, // ".biz" - EDDY_DOT_GOV = 13 // ".gov" + EDDY_URL_NONE = 0xFFFFFFFF, // No suffix to append + EDDY_DOT_COM_SLASH = 0, // ".com/" + EDDY_DOT_ORG_SLASH = 1, // ".org/" + EDDY_DOT_EDU_SLASH = 2, // ".edu/" + EDDY_DOT_NET_SLASH = 3, // ".net/" + EDDY_DOT_INFO_SLASH = 4, // ".info/" + EDDY_DOT_BIZ_SLASH = 5, // ".biz/" + EDDY_DOT_GOV_SLASH = 6, // ".gov/" + EDDY_DOT_COM = 7, // ".com" + EDDY_DOT_ORG = 8, // ".org" + EDDY_DOT_EDU = 9, // ".edu" + EDDY_DOT_NET = 10, // ".net" + EDDY_DOT_INFO = 11, // ".info" + EDDY_DOT_BIZ = 12, // ".biz" + EDDY_DOT_GOV = 13 // ".gov" }; /// This helper class helps to configure and parse BLE GAP advertisement packets. -/// +/// /// BLE peripherals advertises information about their capabilities and other information /// in advertisement packets. The packet is of finite length, but the format is very flexible. -/// +/// /// This class helps you to create several common advertisement formats, e.g. ibeacon: /// ~~~{.cpp} /// LBLEAdvertisementData beaconData; @@ -90,166 +90,186 @@ enum EDDYSTONE_URL_ENCODING class LBLEAdvertisementData { public: - static const uint8_t DEFAULT_AD_FLAG = (BT_GAP_LE_AD_FLAG_GENERAL_DISCOVERABLE | BT_GAP_LE_AD_FLAG_BR_EDR_NOT_SUPPORTED); - - LBLEAdvertisementData(); - LBLEAdvertisementData(const LBLEAdvertisementData& rhs); - ~LBLEAdvertisementData(); - - /// Create an iBeacon advertisement. - /// - /// This methods RESETS all the advertisement data fields - /// and replace them with iBeacon format (flag + manufacturer data) - /// - /// if you don't know which UUID to use, - /// use LBLEUuid("74278BDA-B644-4520-8F0C-720EAF059935"), - /// since this is the UUID used by iOS AirLocate example. - /// (https://developer.apple.com/library/content/samplecode/AirLocate/Introduction/Intro.html) - /// - /// major, minor, and txPower are all user defined values. - void configAsIBeacon(const LBLEUuid& uuid, - uint16_t major, - uint16_t minor, - int8_t txPower); - - /// Configure an Eddystone URL - /// Note that total length must not exceed 17 bytes. - /// - /// You can use prefix, suffix, and tail parameters to compress common URL parts to a single byte. - /// e.g. "https://www.mediatek.com" - /// => configAsEddystoneURL(EDDY_HTTPS_WWW, "mediatek", EDDY_DOT_COM) - /// e.g. "https://www.asp.net/learn" - /// => configAsEddystoneURL(EDDY_HTTPS_WWW, "asp", EDDY_DOT_NET_SLASH, "learn") - /// - /// Please refer to https://github.com/google/eddystone/tree/master/eddystone-url#url-scheme-prefix - /// to know how the prefix/suffix/tails are expanded. + static const uint8_t DEFAULT_AD_FLAG = (BT_GAP_LE_AD_FLAG_GENERAL_DISCOVERABLE | BT_GAP_LE_AD_FLAG_BR_EDR_NOT_SUPPORTED); + + LBLEAdvertisementData(); + LBLEAdvertisementData(const LBLEAdvertisementData& rhs); + ~LBLEAdvertisementData(); + + /// Create an iBeacon advertisement. + /// + /// This methods RESETS all the advertisement data fields + /// and replace them with iBeacon format (flag + manufacturer data) + /// + /// if you don't know which UUID to use, + /// use LBLEUuid("74278BDA-B644-4520-8F0C-720EAF059935"), + /// since this is the UUID used by iOS AirLocate example. + /// (https://developer.apple.com/library/content/samplecode/AirLocate/Introduction/Intro.html) + /// + /// major, minor, and txPower are all user defined values. + void configAsIBeacon(const LBLEUuid& uuid, + uint16_t major, + uint16_t minor, + int8_t txPower); + + /// Configure an Eddystone URL + /// Note that total length must not exceed 17 bytes. + /// + /// You can use prefix, suffix, and tail parameters to compress common URL parts to a single byte. + /// e.g. "https://www.mediatek.com" + /// => configAsEddystoneURL(EDDY_HTTPS_WWW, "mediatek", EDDY_DOT_COM) + /// e.g. "https://www.asp.net/learn" + /// => configAsEddystoneURL(EDDY_HTTPS_WWW, "asp", EDDY_DOT_NET_SLASH, "learn") + /// + /// Please refer to https://github.com/google/eddystone/tree/master/eddystone-url#url-scheme-prefix + /// to know how the prefix/suffix/tails are expanded. void configAsEddystoneURL(EDDYSTONE_URL_PREFIX prefix, - const String& url, - EDDYSTONE_URL_ENCODING suffix = EDDY_URL_NONE, - const String& tail = String()); - - /// Create an advertisement that allows BLE centrals, e.g. smartphones, to connect to this device. - /// - /// This methods RESETS all the advertisement data fields - /// - /// Note that you need to define corresponding GATT services with LBLEPeripheral - /// before start advertising your device. - /// - /// \param deviceName must be shorter than 27 bytes. - void configAsConnectableDevice(const char* deviceName); - - /// Create an advertisement with service UUID that allows BLE centrals, e.g. smartphones, to connect to this device. - /// - /// This methods RESETS all the advertisement data fields - /// Note that you need to define corresponding GATT services with LBLEPeripheral - /// before start advertising your device. - /// - /// \param deviceName must be shorter than 9 bytes when UUID is 128-bit. - /// \param uuid service UUID to be included in advertisement - void configAsConnectableDevice(const char* deviceName, const LBLEUuid& uuid); - - /// Append a AD type flag data - /// - /// AD flags are advertisement flags such as BT_GAP_LE_AD_FLAG_GENERAL_DISCOVERABLE. - /// You can find valid values in Bluetooth specification. - void addFlag(uint8_t flag = DEFAULT_AD_FLAG); - - /// Helper method that append a Device Name (Complete) data - void addName(const char* deviceName); - - /// Add a generic AD data - /// - /// Note that item.adDataLen is the length of the "adData" item, - /// not the length of the entire AD data length in the final payload. - void addAdvertisementData(const LBLEAdvDataItem &item); - - /// Convert advertisement data into to a continuous raw advertisement data payload. - uint32_t getPayload(uint8_t* buf, uint32_t bufLength) const; + const String& url, + EDDYSTONE_URL_ENCODING suffix = EDDY_URL_NONE, + const String& tail = String()); + + /// Create an advertisement that allows BLE centrals, e.g. smartphones, to connect to this device. + /// + /// This methods RESETS all the advertisement data fields + /// + /// Note that you need to define corresponding GATT services with LBLEPeripheral + /// before start advertising your device. + /// + /// \param deviceName must be shorter than 27 bytes. + void configAsConnectableDevice(const char* deviceName); + + /// Create an advertisement with service UUID that allows BLE centrals, e.g. smartphones, to connect to this device. + /// + /// This methods RESETS all the advertisement data fields + /// Note that you need to define corresponding GATT services with LBLEPeripheral + /// before start advertising your device. + /// + /// \param deviceName must be shorter than 9 bytes when UUID is 128-bit. + /// \param uuid service UUID to be included in advertisement + void configAsConnectableDevice(const char* deviceName, const LBLEUuid& uuid); + + /// Append a AD type flag data + /// + /// AD flags are advertisement flags such as BT_GAP_LE_AD_FLAG_GENERAL_DISCOVERABLE. + /// You can find valid values in Bluetooth specification. + void addFlag(uint8_t flag = DEFAULT_AD_FLAG); + + /// Helper method that append a Device Name (Complete) data + void addName(const char* deviceName); + + /// Add a generic AD data + /// + /// Note that item.adDataLen is the length of the "adData" item, + /// not the length of the entire AD data length in the final payload. + void addAdvertisementData(const LBLEAdvDataItem &item); + + /// Convert advertisement data into to a continuous raw advertisement data payload. + uint32_t getPayload(uint8_t* buf, uint32_t bufLength) const; private: - std::vector m_advDataList; + std::vector m_advDataList; }; enum LBLEPermission { - LBLE_READ = BT_GATTS_REC_PERM_READABLE, - LBLE_WRITE = BT_GATTS_REC_PERM_WRITABLE, + LBLE_READ = BT_GATTS_REC_PERM_READABLE, + LBLE_WRITE = BT_GATTS_REC_PERM_WRITABLE, }; class LBLEAttributeInterface { public: - static const uint32_t MAX_ATTRIBUTE_DATA_LEN = 512; - virtual uint32_t onSize() const = 0; - virtual uint32_t onRead(void *data, uint16_t size, uint16_t offset) = 0; - virtual uint32_t onWrite(void *data, uint16_t size, uint16_t offset) = 0; - - virtual uint32_t getRecordCount() = 0; - - // a callback from BLE service to assign attribute handle - // back to the attribute instance. the instance - // may choose to ignore this information - virtual void assignHandle(uint16_t attrHandle) = 0; - - // send notification to the given connection - virtual int notify(bt_handle_t connection) = 0; - - // send indication and wait for ACK to the given connection - virtual int indicate(bt_handle_t connection) = 0; - - // @param recordIndex ranges from 0 ~ (getRecordCount - 1) - // - // returns a generic bt_gatts_service_rec_t pointer - // that points to variable-length GATT attribute records. - // The user is reponsible to free() the returning buffer. - virtual bt_gatts_service_rec_t* allocRecord(uint32_t recordIndex, uint16_t currentHandle) = 0; + static const uint32_t MAX_ATTRIBUTE_DATA_LEN = 512; + virtual uint32_t onSize() const = 0; + virtual uint32_t onRead(void *data, uint16_t size, uint16_t offset) = 0; + virtual uint32_t onWrite(void *data, uint16_t size, uint16_t offset) = 0; + + virtual uint32_t getRecordCount() = 0; + + // a callback from BLE service to assign attribute handle + // back to the attribute instance. the instance + // may choose to ignore this information + virtual void assignHandle(uint16_t attrHandle) = 0; + + // send notification to the given connection + virtual int notify(bt_handle_t connection) = 0; + + // send indication and wait for ACK to the given connection + virtual int indicate(bt_handle_t connection) = 0; + + // @param recordIndex ranges from 0 ~ (getRecordCount - 1) + // + // returns a generic bt_gatts_service_rec_t pointer + // that points to variable-length GATT attribute records. + // The user is reponsible to free() the returning buffer. + virtual bt_gatts_service_rec_t* allocRecord(uint32_t recordIndex, uint16_t currentHandle) = 0; + + // Since we're defaulting all characteristics with notification, + // we need to add CCCD(Client Characteristic Configuration Descriptor) + // for every user-created characteristics. + virtual void onWriteIndicationNotificationFlag(uint16_t flag) = 0; + virtual uint16_t onReadIndicationNotificationFlag() = 0; }; class LBLECharacteristicBase : public LBLEAttributeInterface { public: // method for Arduino users - LBLECharacteristicBase(LBLEUuid uuid, uint32_t permission); - - LBLECharacteristicBase(LBLEUuid uuid); + LBLECharacteristicBase(LBLEUuid uuid, uint32_t permission); - // Check if a character is written - bool isWritten(); + LBLECharacteristicBase(LBLEUuid uuid); + + // Check if a character is written + bool isWritten(); public: // Following methods are not meant to be called by Arduino users - // Each characteristic maps to 2 GATT attribute records - virtual uint32_t getRecordCount() {return 2;}; + // Each characteristic maps to at least 2 GATT attribute records: + // 1. UUID of the characteristic + // 2. Actual Value + // 3 or more. (Optional) descriptors of the characteristic + // + // Since we're defaulting all characteristics with notification, + // we need to add CCCD(Client Characteristic Configuration Descriptor) + // for every user-created characteristics. + virtual uint32_t getRecordCount() { + return 3; + }; + + // common implementation for characteristics attributes + virtual bt_gatts_service_rec_t* allocRecord(uint32_t recordIndex, uint16_t currentHandle); - // common implementation for characteristics attributes - virtual bt_gatts_service_rec_t* allocRecord(uint32_t recordIndex, uint16_t currentHandle); + // store the assigned attribute handle for notification/indication + virtual void assignHandle(uint16_t attrHandle); - // store the assigned attribute handle for notification/indication - virtual void assignHandle(uint16_t attrHandle); + virtual void onWriteIndicationNotificationFlag(uint16_t flag); - // Utility function for child class to call. - // send notification with `buf` as data to the given connection - int _notify(bt_handle_t connection, const LBLEValueBuffer& data); + virtual uint16_t onReadIndicationNotificationFlag(); - // Utility function for child class to call. - // send indication with `buf` as data and wait for ACK to the given connection - int _indicate(bt_handle_t connection, const LBLEValueBuffer& data); + // Utility function for child class to call. + // send notification with `buf` as data to the given connection + int _notify(bt_handle_t connection, const LBLEValueBuffer& data); + + // Utility function for child class to call. + // send indication with `buf` as data and wait for ACK to the given connection + int _indicate(bt_handle_t connection, const LBLEValueBuffer& data); private: - int _notifyIndicate(uint8_t opcode, bt_handle_t connection, const LBLEValueBuffer& data); + int _notifyIndicate(uint8_t opcode, bt_handle_t connection, const LBLEValueBuffer& data); protected: - LBLEUuid m_uuid; - uint32_t m_perm; - bool m_updated; - uint16_t m_attrHandle; + LBLEUuid m_uuid; + uint32_t m_perm; + bool m_updated; + uint16_t m_attrHandle; + uint16_t m_cccdFlag; }; // This class is used by LBLECharacteristicBuffer struct LBLECharacteristicWrittenInfo { - uint16_t size; - uint16_t offset; + uint16_t size; + uint16_t offset; }; /// \brief represents a typeless raw buffer GATT attribute. @@ -262,50 +282,50 @@ class LBLECharacteristicBuffer : public LBLECharacteristicBase { public: // method for Arduino users - LBLECharacteristicBuffer(LBLEUuid uuid, uint32_t permission); - - LBLECharacteristicBuffer(LBLEUuid uuid); - - /// Set value with raw buffer - /// - /// \param buffer pointer to raw buffer of value. - /// The input buffer is copied to the internal - /// buffer of the LBLECharacteristicBuffer object. - /// \param size must not exceed MAX_ATTRIBUTE_DATA_LEN. - void setValueBuffer(const uint8_t* buffer, size_t size); - - /// Set value buffer size and initialize all content to 0 - void setValueBufferWithSize(size_t size); - - /// Get value buffer content. - /// - /// Retrieve buffer content of this LBLECharacteristicBuffer object. - /// Note that (size + offset) must not exceed MAX_ATTRIBUTE_DATA_LEN; - /// Note that isWritten() returns `false` after calling getValue(). - /// - /// \param buffer pointer to the output buffer to be written - /// \param size available size of the buffer to write to - /// \param offset initial offset to the internal buffer of LBLECharacteristicBuffer. - /// for example, if the internal buffer is {0, 1, 2, 3}, - /// ~~~{.cpp} - /// getValue(buf, 4, 2); // offset 2 bytes - /// ~~~ - /// will write `buf` with content {2, 3}. - void getValue(uint8_t* buffer, uint16_t size, uint16_t offset); - - /// Check what part of the buffer is updated during last write operation - const LBLECharacteristicWrittenInfo& getLastWrittenInfo() const; + LBLECharacteristicBuffer(LBLEUuid uuid, uint32_t permission); + + LBLECharacteristicBuffer(LBLEUuid uuid); + + /// Set value with raw buffer + /// + /// \param buffer pointer to raw buffer of value. + /// The input buffer is copied to the internal + /// buffer of the LBLECharacteristicBuffer object. + /// \param size must not exceed MAX_ATTRIBUTE_DATA_LEN. + void setValueBuffer(const uint8_t* buffer, size_t size); + + /// Set value buffer size and initialize all content to 0 + void setValueBufferWithSize(size_t size); + + /// Get value buffer content. + /// + /// Retrieve buffer content of this LBLECharacteristicBuffer object. + /// Note that (size + offset) must not exceed MAX_ATTRIBUTE_DATA_LEN; + /// Note that isWritten() returns `false` after calling getValue(). + /// + /// \param buffer pointer to the output buffer to be written + /// \param size available size of the buffer to write to + /// \param offset initial offset to the internal buffer of LBLECharacteristicBuffer. + /// for example, if the internal buffer is {0, 1, 2, 3}, + /// ~~~{.cpp} + /// getValue(buf, 4, 2); // offset 2 bytes + /// ~~~ + /// will write `buf` with content {2, 3}. + void getValue(uint8_t* buffer, uint16_t size, uint16_t offset); + + /// Check what part of the buffer is updated during last write operation + const LBLECharacteristicWrittenInfo& getLastWrittenInfo() const; public: // for BLE framework - virtual uint32_t onSize() const; - virtual uint32_t onRead(void *data, uint16_t size, uint16_t offset); - virtual uint32_t onWrite(void *data, uint16_t size, uint16_t offset); - virtual int notify(bt_handle_t connection); - virtual int indicate(bt_handle_t connection); + virtual uint32_t onSize() const; + virtual uint32_t onRead(void *data, uint16_t size, uint16_t offset); + virtual uint32_t onWrite(void *data, uint16_t size, uint16_t offset); + virtual int notify(bt_handle_t connection); + virtual int indicate(bt_handle_t connection); private: - LBLEValueBuffer m_data; - LBLECharacteristicWrittenInfo m_writtenInfo; + LBLEValueBuffer m_data; + LBLECharacteristicWrittenInfo m_writtenInfo; }; /// This characterstic is a peristent 4-byte integer initialized to zero. @@ -314,32 +334,32 @@ class LBLECharacteristicInt : public LBLECharacteristicBase { public: // method for Arduino users - /// Create characteristic - /// - /// In most cases the characteristic should be created in global scope, - /// to ensure it is alive after LBLEPeripheral.begin(). - /// - /// \param uuid UUID for this characteristic - /// \param permission read/write permission. (currently ignored). - LBLECharacteristicInt(LBLEUuid uuid, uint32_t permission); + /// Create characteristic + /// + /// In most cases the characteristic should be created in global scope, + /// to ensure it is alive after LBLEPeripheral.begin(). + /// + /// \param uuid UUID for this characteristic + /// \param permission read/write permission. (currently ignored). + LBLECharacteristicInt(LBLEUuid uuid, uint32_t permission); - LBLECharacteristicInt(LBLEUuid uuid); + LBLECharacteristicInt(LBLEUuid uuid); - /// Set value of the characteristic. - void setValue(int value); + /// Set value of the characteristic. + void setValue(int value); - /// Retrieve value, note that isWritten() flag turns off after calling getValue() - int getValue(); + /// Retrieve value, note that isWritten() flag turns off after calling getValue() + int getValue(); public: // for BLE framework - virtual uint32_t onSize() const; - virtual uint32_t onRead(void *data, uint16_t size, uint16_t offset); - virtual uint32_t onWrite(void *data, uint16_t size, uint16_t offset); - virtual int notify(bt_handle_t connection); - virtual int indicate(bt_handle_t connection); + virtual uint32_t onSize() const; + virtual uint32_t onRead(void *data, uint16_t size, uint16_t offset); + virtual uint32_t onWrite(void *data, uint16_t size, uint16_t offset); + virtual int notify(bt_handle_t connection); + virtual int indicate(bt_handle_t connection); private: - int m_data; + int m_data; }; /// \brief represents a GATT characterstic that is a NULL-terminated strings. @@ -347,7 +367,7 @@ class LBLECharacteristicInt : public LBLECharacteristicBase /// This is a "string" attribute. A NULL terminater /// is always automatically inserted after each write operation. /// -/// That is, the string value is always "reset" after each write operation, +/// That is, the string value is always "reset" after each write operation, /// instead of appending/replacing part of the existing string value. /// /// Example: @@ -364,32 +384,32 @@ class LBLECharacteristicString : public LBLECharacteristicBase { public: // method for Arduino users - /// Create characteristic - /// - /// In most cases the characteristic should be created in global scope, - /// to ensure it is alive after LBLEPeripheral.begin(). - /// - /// \param uuid UUID for this characteristic - /// \param permission read/write permission. (currently ignored). - LBLECharacteristicString(LBLEUuid uuid, uint32_t permission); + /// Create characteristic + /// + /// In most cases the characteristic should be created in global scope, + /// to ensure it is alive after LBLEPeripheral.begin(). + /// + /// \param uuid UUID for this characteristic + /// \param permission read/write permission. (currently ignored). + LBLECharacteristicString(LBLEUuid uuid, uint32_t permission); - LBLECharacteristicString(LBLEUuid uuid); + LBLECharacteristicString(LBLEUuid uuid); - /// Set value of the characteristic. - void setValue(const String& value); + /// Set value of the characteristic. + void setValue(const String& value); - /// Retrieve value, note that isWritten() flag turns off after calling getValue() - String getValue(); + /// Retrieve value, note that isWritten() flag turns off after calling getValue() + String getValue(); public: // for BLE framework - virtual uint32_t onSize() const; - virtual uint32_t onRead(void *data, uint16_t size, uint16_t offset); - virtual uint32_t onWrite(void *data, uint16_t size, uint16_t offset); - virtual int notify(bt_handle_t connection); - virtual int indicate(bt_handle_t connection); + virtual uint32_t onSize() const; + virtual uint32_t onRead(void *data, uint16_t size, uint16_t offset); + virtual uint32_t onWrite(void *data, uint16_t size, uint16_t offset); + virtual int notify(bt_handle_t connection); + virtual int indicate(bt_handle_t connection); private: - String m_data; + String m_data; }; /// Represents a BLE service. @@ -397,7 +417,7 @@ class LBLECharacteristicString : public LBLECharacteristicBase /// This class represents a BLE service in a peripheral device. /// /// This object must be alive across entire BLE framework life cycle. -/// Therefore, you need to allocate it in global scope, and +/// Therefore, you need to allocate it in global scope, and /// then add characteristics by calling addAttribute(). /// /// ~~~{.cpp} @@ -410,109 +430,109 @@ class LBLECharacteristicString : public LBLECharacteristicBase class LBLEService { public: - LBLEService(const LBLEUuid& uuid); - LBLEService(const char* uuidString); - - void addAttribute(LBLEAttributeInterface& attr); - - // Allocates underlying record tables for BLE framework. - // Accepts the globally ordered handle - // returns the last handle + 1. - uint16_t begin(uint16_t startingHandle); - - void end(); - - bt_gatts_service_t* getServiceDataPointer(); -private: - LBLEUuid m_uuid; - bt_gatts_service_t m_serviceData; // service record for BLE framework - std::vector m_records; // attribute records (multiple types) for BLE framework - std::vector m_attributes; // pointers to attribute objects + LBLEService(const LBLEUuid& uuid); + LBLEService(const char* uuidString); + + void addAttribute(LBLEAttributeInterface& attr); + + // Allocates underlying record tables for BLE framework. + // Accepts the globally ordered handle + // returns the last handle + 1. + uint16_t begin(uint16_t startingHandle); + + void end(); + + bt_gatts_service_t* getServiceDataPointer(); +private: + LBLEUuid m_uuid; + bt_gatts_service_t m_serviceData; // service record for BLE framework + std::vector m_records; // attribute records (multiple types) for BLE framework + std::vector m_attributes; // pointers to attribute objects }; /// Singleton class representing the local BLE periphral device class LBLEPeripheralClass : public LBLEEventObserver { public: - /// Do not instantiate by yourself. Use singleton object `LBLEPeripheral` instead. - LBLEPeripheralClass(); - - virtual ~LBLEPeripheralClass(); - - /// start advertisement as a connectable device - /// - /// \param advertisementData The advertisement data to be advertised. - /// \returns 0 when succeeded, -1 when payload too long, -2 for other errors. - int advertise(const LBLEAdvertisementData& advertisementData); - - /// start advertisement as an non-connectable device (such as an iBeacon) - /// - /// \param advertisementData The advertisement packet to broadcast. - /// \param intervalMS The advertisement interval, in milliseconds. - /// \param txPower This controls the actual advertisement power in dbm. - /// Note: current version does not support adjusting txPower. - int advertiseAsBeacon(const LBLEAdvertisementData& advertisementData, - uint32_t intervalMS = 700, - uint8_t txPower = -30); - - /// start advertisement based on previous input of advertise - /// \returns 0 when succeeded, -1 when payload too long, -2 for other errors. - int advertiseAgain(); - - /// stop advertisement and clears advertisement data - /// advertiseAgain() fails after stopAdvertise(); - void stopAdvertise(); - - /// Generic Access Profile (GAP) configuration - void setName(const char* name); - - /// After setup services and characteristics - /// you have to call begin make enable the GATT server - void begin(); - - /// returns true if there is a central device connecting to this peripheral. - bool connected(); - - /// disconnect all connected centrals (if any) - void disconnectAll(); - - /// broadcasting notification of the given GATT characteristic value to - /// all connected devices, e.g. LBLEPeripheral.notify(myCharacteristic) - /// Note that `myChar` must be added to the LBLEPeriphral as - /// part of a service before calling this method. - int notifyAll(LBLEAttributeInterface& characteristic); - - /// broadcasting indication of the given GATT characteristic value to - /// all connected devices, e.g. LBLEPeripheral.notify(myCharacteristic) - /// Note that `myChar` must be added to the LBLEPeriphral as - /// part of a service before calling this method. - int indicateAll(LBLEAttributeInterface& characteristic); - - /// configuring GATT Services. You must configure services - /// before advertising the device. The services cannot change - /// after being connected. - /// - /// \param service The service to be added into this peripheral. The service - /// object is referenced instead of copied, so tt must be valid and alive - /// all the time. - void addService(const LBLEService& service); - - const bt_gatts_service_t** getServiceTable(); + /// Do not instantiate by yourself. Use singleton object `LBLEPeripheral` instead. + LBLEPeripheralClass(); + + virtual ~LBLEPeripheralClass(); + + /// start advertisement as a connectable device + /// + /// \param advertisementData The advertisement data to be advertised. + /// \returns 0 when succeeded, -1 when payload too long, -2 for other errors. + int advertise(const LBLEAdvertisementData& advertisementData); + + /// start advertisement as an non-connectable device (such as an iBeacon) + /// + /// \param advertisementData The advertisement packet to broadcast. + /// \param intervalMS The advertisement interval, in milliseconds. + /// \param txPower This controls the actual advertisement power in dbm. + /// Note: current version does not support adjusting txPower. + int advertiseAsBeacon(const LBLEAdvertisementData& advertisementData, + uint32_t intervalMS = 700, + int8_t txPower = -30); + + /// start advertisement based on previous input of advertise + /// \returns 0 when succeeded, -1 when payload too long, -2 for other errors. + int advertiseAgain(); + + /// stop advertisement and clears advertisement data + /// advertiseAgain() fails after stopAdvertise(); + void stopAdvertise(); + + /// Generic Access Profile (GAP) configuration + void setName(const char* name); + + /// After setup services and characteristics + /// you have to call begin make enable the GATT server + void begin(); + + /// returns true if there is a central device connecting to this peripheral. + bool connected(); + + /// disconnect all connected centrals (if any) + void disconnectAll(); + + /// broadcasting notification of the given GATT characteristic value to + /// all connected devices, e.g. LBLEPeripheral.notify(myCharacteristic) + /// Note that `myChar` must be added to the LBLEPeriphral as + /// part of a service before calling this method. + int notifyAll(LBLEAttributeInterface& characteristic); + + /// broadcasting indication of the given GATT characteristic value to + /// all connected devices, e.g. LBLEPeripheral.notify(myCharacteristic) + /// Note that `myChar` must be added to the LBLEPeriphral as + /// part of a service before calling this method. + int indicateAll(LBLEAttributeInterface& characteristic); + + /// configuring GATT Services. You must configure services + /// before advertising the device. The services cannot change + /// after being connected. + /// + /// \param service The service to be added into this peripheral. The service + /// object is referenced instead of copied, so tt must be valid and alive + /// all the time. + void addService(const LBLEService& service); + + const bt_gatts_service_t** getServiceTable(); public: - virtual void onEvent(bt_msg_type_t msg, bt_status_t status, void *buff); - virtual bool isOnce(); + virtual void onEvent(bt_msg_type_t msg, bt_status_t status, void *buff); + virtual bool isOnce(); private: - const static uint16_t USER_ATTRIBUTE_HANDLE_START = 0x00A0; - std::vector m_servicePtrTable; - std::vector m_services; // container for services in the server - - std::unique_ptr m_pAdvData; - bt_hci_cmd_le_set_advertising_parameters_t m_advParam; - - std::vector m_connections; - + const static uint16_t USER_ATTRIBUTE_HANDLE_START = 0x00A0; + std::vector m_servicePtrTable; + std::vector m_services; // container for services in the server + + std::unique_ptr m_pAdvData; + bt_hci_cmd_le_set_advertising_parameters_t m_advParam; + + std::vector m_connections; + }; extern LBLEPeripheralClass LBLEPeripheral; diff --git a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/utility/ard_ble.c b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/utility/ard_ble.c index e4c28b8..5bdf785 100644 --- a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/utility/ard_ble.c +++ b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/utility/ard_ble.c @@ -16,23 +16,14 @@ ////////////////////////////////////////////////// // Workaround for CONSYS patch issue - -/* wifi related header */ -#include -#include -#include -#include -#include -#include -#include -#include - +#include static void _connsys_workaround() { // Wi-Fi must be initialized for BLE start-up // declared in Arduino core's "variant.h" init_global_connsys(); } +////////////////////////////////////////////////// /* * These initialization routines are based on LinkIt SDK v4, iot_sdk_demo::bt_init.c diff --git a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/utility/ard_bt_attr_callback.c b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/utility/ard_bt_attr_callback.c index 13033df..83a0ff3 100644 --- a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/utility/ard_bt_attr_callback.c +++ b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/utility/ard_bt_attr_callback.c @@ -1,12 +1,16 @@ #include "ard_bt_attr_callback.h" // table for user-registered user data and its allocation cursor -static void* g_userdata[ARD_BT_MAX_ATTR_CALLBACK_NUM] = {0}; +typedef struct _CallbackData { + void* user_data; + int callback_type; +} CallbackData; +static CallbackData g_userdata[ARD_BT_MAX_ATTR_CALLBACK_NUM] = {0}; static uint32_t g_callback_cursor = 0; // macro to define trampoline functions #define DEFINE_TRAMPOLINE_FUNC(INDEX) static uint32_t attribute_callback_##INDEX(const uint8_t rw, uint16_t handle, void *data, uint16_t size, uint16_t offset){\ - return ard_bt_callback_trampoline(rw, handle, data, size, offset, g_userdata[INDEX]);\ + return ard_bt_callback_trampoline(rw, handle, data, size, offset, g_userdata[INDEX].user_data, g_userdata[INDEX].callback_type);\ } // now we generate the table - it MUST have the same number as ARD_BT_MAX_ATTR_CALLBACK_NUM @@ -40,6 +44,36 @@ DEFINE_TRAMPOLINE_FUNC(26) DEFINE_TRAMPOLINE_FUNC(27) DEFINE_TRAMPOLINE_FUNC(28) DEFINE_TRAMPOLINE_FUNC(29) +DEFINE_TRAMPOLINE_FUNC(30) +DEFINE_TRAMPOLINE_FUNC(31) +DEFINE_TRAMPOLINE_FUNC(32) +DEFINE_TRAMPOLINE_FUNC(33) +DEFINE_TRAMPOLINE_FUNC(34) +DEFINE_TRAMPOLINE_FUNC(35) +DEFINE_TRAMPOLINE_FUNC(36) +DEFINE_TRAMPOLINE_FUNC(37) +DEFINE_TRAMPOLINE_FUNC(38) +DEFINE_TRAMPOLINE_FUNC(39) +DEFINE_TRAMPOLINE_FUNC(40) +DEFINE_TRAMPOLINE_FUNC(41) +DEFINE_TRAMPOLINE_FUNC(42) +DEFINE_TRAMPOLINE_FUNC(43) +DEFINE_TRAMPOLINE_FUNC(44) +DEFINE_TRAMPOLINE_FUNC(45) +DEFINE_TRAMPOLINE_FUNC(46) +DEFINE_TRAMPOLINE_FUNC(47) +DEFINE_TRAMPOLINE_FUNC(48) +DEFINE_TRAMPOLINE_FUNC(49) +DEFINE_TRAMPOLINE_FUNC(50) +DEFINE_TRAMPOLINE_FUNC(51) +DEFINE_TRAMPOLINE_FUNC(52) +DEFINE_TRAMPOLINE_FUNC(53) +DEFINE_TRAMPOLINE_FUNC(54) +DEFINE_TRAMPOLINE_FUNC(55) +DEFINE_TRAMPOLINE_FUNC(56) +DEFINE_TRAMPOLINE_FUNC(57) +DEFINE_TRAMPOLINE_FUNC(58) +DEFINE_TRAMPOLINE_FUNC(59) // now insert these TRAMPOLINE functions into a static table static void* g_trampoline_callbacks[ARD_BT_MAX_ATTR_CALLBACK_NUM] = @@ -74,9 +108,39 @@ static void* g_trampoline_callbacks[ARD_BT_MAX_ATTR_CALLBACK_NUM] = attribute_callback_27, attribute_callback_28, attribute_callback_29, + attribute_callback_30, + attribute_callback_31, + attribute_callback_32, + attribute_callback_33, + attribute_callback_34, + attribute_callback_35, + attribute_callback_36, + attribute_callback_37, + attribute_callback_38, + attribute_callback_39, + attribute_callback_40, + attribute_callback_41, + attribute_callback_42, + attribute_callback_43, + attribute_callback_44, + attribute_callback_45, + attribute_callback_46, + attribute_callback_47, + attribute_callback_48, + attribute_callback_49, + attribute_callback_50, + attribute_callback_51, + attribute_callback_52, + attribute_callback_53, + attribute_callback_54, + attribute_callback_55, + attribute_callback_56, + attribute_callback_57, + attribute_callback_58, + attribute_callback_59, }; -bt_gatts_rec_callback_t ard_bt_alloc_callback_slot(void* user_data) +bt_gatts_rec_callback_t ard_bt_alloc_callback_slot(void* user_data, int callback_type) { // note that currently we don't have a mechanism to // free allocated user callback slots. @@ -85,6 +149,7 @@ bt_gatts_rec_callback_t ard_bt_alloc_callback_slot(void* user_data) return NULL; } - g_userdata[g_callback_cursor] = user_data; + g_userdata[g_callback_cursor].user_data = user_data; + g_userdata[g_callback_cursor].callback_type = callback_type; return g_trampoline_callbacks[g_callback_cursor++]; } diff --git a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/utility/ard_bt_attr_callback.h b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/utility/ard_bt_attr_callback.h index 9d316e3..8506e27 100644 --- a/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/utility/ard_bt_attr_callback.h +++ b/middleware/third_party/arduino/hardware/arduino/mt7697/libraries/LBLE/src/utility/ard_bt_attr_callback.h @@ -5,15 +5,21 @@ #include "ard_ble.h" -#define ARD_BT_MAX_ATTR_CALLBACK_NUM (30) +#define ARD_BT_MAX_ATTR_CALLBACK_NUM (60) // 60 attributes ~= 20 Characteristics + +#define ARD_BT_CB_TYPE_VALUE_CALLBACK (0) +#define ARD_BT_CB_TYPE_CCCD_CALLBACK (1) // Call this function to allocate a callback function that you can pass to for BLE framework // that will call ard_bt_callback_trampoline -bt_gatts_rec_callback_t ard_bt_alloc_callback_slot(void* user_data); +// +// @param user_data pointer to user data +// @param int callback type, can be ARD_BT_CB_TYPE_VALUE_CALLBACK or ARD_BT_CB_TYPE_CCCD_CALLBACK +bt_gatts_rec_callback_t ard_bt_alloc_callback_slot(void* user_data, int callback_type); // Define the function body. This function is called when the callback returned from ard_bt_alloc_callback_slot() is called, // with the user_data you pass when calling ard_bt_alloc_callback_slot. -extern uint32_t ard_bt_callback_trampoline(const uint8_t rw, uint16_t handle, void *data, uint16_t size, uint16_t offset, void* user_data); +extern uint32_t ard_bt_callback_trampoline(const uint8_t rw, uint16_t handle, void *data, uint16_t size, uint16_t offset, void* user_data, int callback_type); #endif // ARD_BT_ATTR_CALLBACK_H \ No newline at end of file diff --git a/middleware/third_party/arduino/hardware/arduino/mt7697/variants/linkit_7697/variant.cpp b/middleware/third_party/arduino/hardware/arduino/mt7697/variants/linkit_7697/variant.cpp index 0ecbb29..7873f37 100755 --- a/middleware/third_party/arduino/hardware/arduino/mt7697/variants/linkit_7697/variant.cpp +++ b/middleware/third_party/arduino/hardware/arduino/mt7697/variants/linkit_7697/variant.cpp @@ -74,7 +74,7 @@ static int32_t _wifi_ready_handler(wifi_event_t event, uint32_t length) { if (event == WIFI_EVENT_IOT_INIT_COMPLETE) { - pr_debug("WIFI_EVENT_IOT_INIT_COMPLETE received\r\n"); + pr_debug("WIFI_EVENT_IOT_INIT_COMPLETE received"); _set_wifi_ready(); } @@ -87,27 +87,30 @@ void init_global_connsys() { } wifi_connection_register_event_handler(WIFI_EVENT_IOT_INIT_COMPLETE , _wifi_ready_handler); - wifi_config_t config = {0}; + wifi_config_t config; + memset(&config, 0, sizeof(config)); config.opmode = WIFI_MODE_STA_ONLY; strcpy((char *)config.sta_config.ssid, (const char *)" "); config.sta_config.ssid_length = strlen((const char *)config.sta_config.ssid); - wifi_config_ext_t ex_config = {0}; + wifi_config_ext_t ex_config; + memset(&ex_config, 0, sizeof(ex_config)); ex_config.sta_auto_connect_present = 1; // validate "sta_auto_connect" config ex_config.sta_auto_connect = 0; // don't auto-connect - we just want to initialize - pr_debug("[wifi_init]\n"); + pr_debug("[wifi_init]"); wifi_init(&config, &ex_config); // we must initialize lwip_tcpip, otherwise we won't receive WIFI_EVENT_IOT_INIT_COMPLETE - lwip_tcpip_config_t tcpip_config = {0}; + lwip_tcpip_config_t tcpip_config; + memset(&tcpip_config, 0, sizeof(tcpip_config)); lwip_tcpip_init(&tcpip_config, config.opmode); // block until wifi is ready while (!wifi_ready()) { delay(10); } - pr_debug("[wifi/connsys ready]\n"); + pr_debug("[wifi/connsys ready]"); return; }