From c60403761cd7a3c5e5ba7ad33325e1c1bc202f8d Mon Sep 17 00:00:00 2001 From: lianggao Date: Thu, 23 Mar 2017 15:34:42 +0800 Subject: [PATCH 01/15] Fix Jira 768 BLE Appearance Value is 0 Solution: Add service and appearance characteristic in the BLE lib. Changed files BLEDevice.cpp - check the local device BLEDeviceManager.cpp - Change the calls BLEDeviceManager.h - remove appearance member BLEProfileManager.cpp - Add GAP service and appearance characteristic BLEProfileManager.h - Add set/get API --- libraries/CurieBLE/src/BLEDevice.cpp | 6 +++++- .../CurieBLE/src/internal/BLEDeviceManager.cpp | 14 ++++---------- .../CurieBLE/src/internal/BLEDeviceManager.h | 1 - .../CurieBLE/src/internal/BLEProfileManager.cpp | 15 +++++++++++++++ .../CurieBLE/src/internal/BLEProfileManager.h | 14 ++++++++++++++ 5 files changed, 38 insertions(+), 12 deletions(-) diff --git a/libraries/CurieBLE/src/BLEDevice.cpp b/libraries/CurieBLE/src/BLEDevice.cpp index f4713cf8..fc93836c 100644 --- a/libraries/CurieBLE/src/BLEDevice.cpp +++ b/libraries/CurieBLE/src/BLEDevice.cpp @@ -229,7 +229,11 @@ void BLEDevice::setDeviceName(const char* deviceName) void BLEDevice::setAppearance(unsigned short appearance) { - BLEDeviceManager::instance()->setAppearance(appearance); + if (BLEUtils::isLocalBLE(*this)) + { + // Only local device can set the appearance + BLEDeviceManager::instance()->setAppearance(appearance); + } } int BLEDevice::addService(BLEService& attribute) diff --git a/libraries/CurieBLE/src/internal/BLEDeviceManager.cpp b/libraries/CurieBLE/src/internal/BLEDeviceManager.cpp index d5ddd181..d9108cd3 100644 --- a/libraries/CurieBLE/src/internal/BLEDeviceManager.cpp +++ b/libraries/CurieBLE/src/internal/BLEDeviceManager.cpp @@ -45,7 +45,6 @@ BLEDeviceManager::BLEDeviceManager(): _connecting(false), _has_service_uuid(false), _has_service_solicit_uuid(false), - _appearance(0), _manufacturer_data_length(0), _service_data_length(0), _adv_type(0), @@ -355,7 +354,7 @@ BLEDeviceManager::setDeviceName() void BLEDeviceManager::setAppearance(unsigned short appearance) { - _appearance = appearance; + BLEProfileManager::instance()->setAppearance(appearance); } BLE_STATUS_T @@ -1046,7 +1045,7 @@ String BLEDeviceManager::advertisedServiceUuid(const BLEDevice* device, int inde if (index < service_cnt) { if (type == BT_DATA_UUID16_ALL || - type == BT_DATA_UUID16_SOME) + type == BT_DATA_UUID16_SOME) { service_uuid.uuid.type = BT_UUID_TYPE_16; memcpy(&BT_UUID_16(&service_uuid.uuid)->val, &adv_data[2], 2); @@ -1218,7 +1217,7 @@ String BLEDeviceManager::deviceName(const BLEDevice* device) int BLEDeviceManager::appearance() { - return _appearance; + return BLEProfileManager::instance()->getAppearance(); } BLEDeviceManager* BLEDeviceManager::instance() @@ -1319,12 +1318,6 @@ bool BLEDeviceManager::advertiseDataProc(uint8_t type, const uint8_t *dataPtr, uint8_t data_len) { - //Serial1.print("[AD]:"); - //Serial1.print(type); - //Serial1.print(" data_len "); - //Serial1.println(data_len); - - //const bt_data_t zero = {0, 0,0}; if (_adv_accept_critical.type == 0 && _adv_accept_critical.data_len == 0 && _adv_accept_critical.data == NULL) @@ -1332,6 +1325,7 @@ bool BLEDeviceManager::advertiseDataProc(uint8_t type, // Not set the critical. Accept all. return true; } + if (type == _adv_accept_critical.type && data_len == _adv_accept_critical.data_len && 0 == memcmp(dataPtr, _adv_accept_critical.data, data_len)) diff --git a/libraries/CurieBLE/src/internal/BLEDeviceManager.h b/libraries/CurieBLE/src/internal/BLEDeviceManager.h index 60aa6f17..e6308220 100644 --- a/libraries/CurieBLE/src/internal/BLEDeviceManager.h +++ b/libraries/CurieBLE/src/internal/BLEDeviceManager.h @@ -431,7 +431,6 @@ class BLEDeviceManager bt_uuid_128_t _service_uuid; bool _has_service_solicit_uuid; bt_uuid_128_t _service_solicit_uuid; - uint16_t _appearance; uint8_t _manufacturer_data[BLE_MAX_ADV_SIZE]; uint8_t _manufacturer_data_length; bt_uuid_128_t _service_data_uuid; diff --git a/libraries/CurieBLE/src/internal/BLEProfileManager.cpp b/libraries/CurieBLE/src/internal/BLEProfileManager.cpp index aba7981b..1586475a 100644 --- a/libraries/CurieBLE/src/internal/BLEProfileManager.cpp +++ b/libraries/CurieBLE/src/internal/BLEProfileManager.cpp @@ -26,6 +26,8 @@ #include "BLEUtils.h" BLEDevice BLE(BLEUtils::bleGetLoalAddress()); +static BLEService gapService("1800"); +static BLEUnsignedShortCharacteristic appearenceChrc("2a01", BLERead); BLEProfileManager* BLEProfileManager::_instance = NULL; @@ -67,6 +69,8 @@ BLEProfileManager::BLEProfileManager (): _service_header_array[i].value = NULL; } + addService(BLE, gapService); + gapService.addCharacteristic(appearenceChrc); pr_debug(LOG_MODULE_BLE, "%s-%d: Construct", __FUNCTION__, __LINE__); } @@ -1130,5 +1134,16 @@ uint8_t BLEProfileManager::serviceReadRspProc(bt_conn_t *conn, return BT_GATT_ITER_STOP; } +void BLEProfileManager::setAppearance(unsigned short appearance) +{ + if (false == hasRegisterProfile()) + { + appearenceChrc.setValue(appearance); + } +} +unsigned short BLEProfileManager::getAppearance() +{ + return appearenceChrc.value(); +} diff --git a/libraries/CurieBLE/src/internal/BLEProfileManager.h b/libraries/CurieBLE/src/internal/BLEProfileManager.h index 1c05fc99..3f9d489f 100644 --- a/libraries/CurieBLE/src/internal/BLEProfileManager.h +++ b/libraries/CurieBLE/src/internal/BLEProfileManager.h @@ -117,6 +117,20 @@ class BLEProfileManager{ bt_gatt_read_params_t *params, const void *data, uint16_t length); + /** + * @brief Set the appearance type for the BLE Peripheral Device + * + * See https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml + * for available options. + * + * @param[in] appearance Appearance category identifier as defined by BLE Standard + * + * @return BleStatus indicating success or error + * + * @note This method must be called before the begin method + */ + void setAppearance(unsigned short appearance); + unsigned short getAppearance(); protected: friend ssize_t profile_write_process(bt_conn_t *conn, const bt_gatt_attr_t *attr, From 1e172622ec904df11ccafeaf09df8b91b34d1d89 Mon Sep 17 00:00:00 2001 From: lianggao Date: Wed, 29 Mar 2017 09:19:45 +0800 Subject: [PATCH 02/15] Jira 714 Find the limits of the number of Services and Characteristics Make the BLE support more characteristics and services by separate the service registration Changed files BLEProfileManager.cpp - Remove register all service at same time BLEProfileManager.h - Change the comments BLEServiceImp.cpp - Add the register service after update the characteristic --- .../src/internal/BLEProfileManager.cpp | 31 +++++-------------- .../CurieBLE/src/internal/BLEProfileManager.h | 2 +- .../CurieBLE/src/internal/BLEServiceImp.cpp | 6 +++- 3 files changed, 13 insertions(+), 26 deletions(-) diff --git a/libraries/CurieBLE/src/internal/BLEProfileManager.cpp b/libraries/CurieBLE/src/internal/BLEProfileManager.cpp index 1586475a..465de326 100644 --- a/libraries/CurieBLE/src/internal/BLEProfileManager.cpp +++ b/libraries/CurieBLE/src/internal/BLEProfileManager.cpp @@ -245,8 +245,6 @@ int BLEProfileManager::serviceCount(const BLEDevice &bledevice) const int BLEProfileManager::registerProfile(BLEDevice &bledevice) { - int ret = 0; - bt_gatt_attr_t *start; BleStatus err_code = BLE_STATUS_SUCCESS; @@ -292,35 +290,20 @@ int BLEProfileManager::registerProfile(BLEDevice &bledevice) { BLEServiceImp *service = node->value; start = _attr_base + _attr_index; - service->updateProfile(start, _attr_index); - node = node->next; - } - -#if 0 - // Start debug - int i; - - for (i = 0; i < _attr_index; i++) { + err_code = service->updateProfile(start, _attr_index); + if (BLE_STATUS_SUCCESS != err_code) { - pr_info(LOG_MODULE_APP, "gatt-: i %d, type %d, u16 0x%x", - i, - _attr_base[i].uuid->type, - BT_UUID_16(_attr_base[i].uuid)->val); + break; } + node = node->next; } - delay(1000); - // End for debug -#endif - - ret = bt_gatt_register(_attr_base, - _attr_index); - pr_debug(LOG_MODULE_APP, "%s: ret, %d,_attr_index-%d", __FUNCTION__, ret, _attr_index); - if (0 == ret) + // Will not regiter the profile if ARC registered any profile + if (_attr_index > 0) { _profile_registered = true; } - return ret; + return err_code; } void BLEProfileManager::clearProfile(BLEServiceLinkNodeHeader* serviceHeader) diff --git a/libraries/CurieBLE/src/internal/BLEProfileManager.h b/libraries/CurieBLE/src/internal/BLEProfileManager.h index 3f9d489f..4b095a68 100644 --- a/libraries/CurieBLE/src/internal/BLEProfileManager.h +++ b/libraries/CurieBLE/src/internal/BLEProfileManager.h @@ -65,7 +65,7 @@ class BLEProfileManager{ * * @param[in] bledevice The BLE Device * - * @return int std C errno + * @return int BLE errno @BleStatus * * @note none */ diff --git a/libraries/CurieBLE/src/internal/BLEServiceImp.cpp b/libraries/CurieBLE/src/internal/BLEServiceImp.cpp index d5d7afe6..862b58ed 100644 --- a/libraries/CurieBLE/src/internal/BLEServiceImp.cpp +++ b/libraries/CurieBLE/src/internal/BLEServiceImp.cpp @@ -120,6 +120,7 @@ int BLEServiceImp::updateProfile(bt_gatt_attr_t *attr_start, int& index) int base_index = index; int offset = 0; int counter = 0; + int ret = 0; start->uuid = BLEServiceImp::getPrimayUuid(); start->perm = BT_GATT_PERM_READ; start->read = bt_gatt_attr_read_service; @@ -139,7 +140,10 @@ int BLEServiceImp::updateProfile(bt_gatt_attr_t *attr_start, int& index) counter += offset; node = node->next; } - return counter; + ret = bt_gatt_register(attr_start, + counter); + + return errorno_to_ble_status(ret); } int BLEServiceImp::getAttributeCount() From e2c8762fa034a009f761c05fef48c1aee5432665 Mon Sep 17 00:00:00 2001 From: lianggao Date: Thu, 30 Mar 2017 14:56:53 +0800 Subject: [PATCH 03/15] Fix GIT #516 and 517 return success when respond with error Root cause 1. The return value indecate the read/write request send successfully. 2. The subscribe will ignore the response and this will not be fixed. Solution 1. Add the error detect based on read/write response. Changed files BLECallbacks.cpp - Delete the error check for read response. BLECharacteristicImp.cpp - Add the error check. - Optimize the memory allocate and clear the allocated memory. BLECharacteristicImp.h - Add varibles to flag the response error --- .../CurieBLE/src/internal/BLECallbacks.cpp | 4 - .../src/internal/BLECharacteristicImp.cpp | 130 +++++++++++++----- .../src/internal/BLECharacteristicImp.h | 3 + 3 files changed, 95 insertions(+), 42 deletions(-) diff --git a/libraries/CurieBLE/src/internal/BLECallbacks.cpp b/libraries/CurieBLE/src/internal/BLECallbacks.cpp index 328c196b..7fdd4e71 100644 --- a/libraries/CurieBLE/src/internal/BLECallbacks.cpp +++ b/libraries/CurieBLE/src/internal/BLECallbacks.cpp @@ -157,10 +157,6 @@ uint8_t profile_read_rsp_process(bt_conn_t *conn, const void *data, uint16_t length) { - if (NULL == data && 0 != length) - { - return BT_GATT_ITER_STOP; - } BLECharacteristicImp *chrc = NULL; BLEDevice bleDevice(bt_conn_get_dst(conn)); diff --git a/libraries/CurieBLE/src/internal/BLECharacteristicImp.cpp b/libraries/CurieBLE/src/internal/BLECharacteristicImp.cpp index a7098e96..2b8f947f 100644 --- a/libraries/CurieBLE/src/internal/BLECharacteristicImp.cpp +++ b/libraries/CurieBLE/src/internal/BLECharacteristicImp.cpp @@ -28,13 +28,16 @@ bt_uuid_16_t BLECharacteristicImp::_gatt_chrc_uuid = {BT_UUID_TYPE_16, BT_UUID_GATT_CHRC_VAL}; bt_uuid_16_t BLECharacteristicImp::_gatt_ccc_uuid = {BT_UUID_TYPE_16, BT_UUID_GATT_CCC_VAL}; volatile bool BLECharacteristicImp::_gattc_writing = false; +volatile bool BLECharacteristicImp::_gattc_write_result = false; BLECharacteristicImp::BLECharacteristicImp(const bt_uuid_t* uuid, unsigned char properties, uint16_t handle, const BLEDevice& bledevice): BLEAttribute(uuid, BLETypeCharacteristic), + _value_size(0), _value_length(0), + _value(NULL), _value_buffer(NULL), _value_updated(false), _value_handle(handle), @@ -45,23 +48,12 @@ BLECharacteristicImp::BLECharacteristicImp(const bt_uuid_t* uuid, _reading(false), _ble_device() { - _value_size = BLE_MAX_ATTR_DATA_LEN;// Set as MAX value. TODO: long read/write need to twist - _value = (unsigned char*)malloc(_value_size); // TODO: Enable when max value is not set. // if (_value_size > BLE_MAX_ATTR_DATA_LEN) // { // _value_buffer = (unsigned char*)malloc(_value_size); // } - - if (_value) - { - memset(_value, 0, _value_size); - } - else - { - errno = ENOMEM; - } memset(&_ccc_cfg, 0, sizeof(_ccc_cfg)); memset(&_ccc_value, 0, sizeof(_ccc_value)); @@ -124,11 +116,25 @@ BLECharacteristicImp::BLECharacteristicImp(BLECharacteristic& characteristic, _value = (unsigned char*)malloc(_value_size); if (_value == NULL) { + _value_size = 0; errno = ENOMEM; } + else + { + memset(_value, 0, _value_size); + } if (_value_size > BLE_MAX_ATTR_DATA_LEN) { _value_buffer = (unsigned char*)malloc(_value_size); + if (_value_buffer == NULL) + { + pr_info(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + errno = ENOMEM; + } + else + { + memset(_value_buffer, 0, _value_size); + } } memset(&_ccc_cfg, 0, sizeof(_ccc_cfg)); @@ -168,7 +174,7 @@ BLECharacteristicImp::BLECharacteristicImp(BLECharacteristic& characteristic, _sub_params.notify = profile_notify_process; - if (NULL != characteristic._value) + if (NULL != characteristic._value && NULL != _value) { memcpy(_value, characteristic._value, _value_size); _value_length = _value_size; @@ -260,23 +266,34 @@ bool BLECharacteristicImp::writeValue(const byte value[], int length, int offset bool BLECharacteristicImp::setValue(const unsigned char value[], uint16_t length) { - _setValue(value, length, 0); - _value_updated = true; + bool read_process_result = true; + if (NULL != value && length != 0) + { + _setValue(value, length, 0); + _value_updated = true; + } + else + { + read_process_result = false; + } if (BLEUtils::isLocalBLE(_ble_device) == true) { // GATT server // Write request for GATT server - if (_event_handlers[BLEWritten]) - { - BLECharacteristic chrcTmp(this, &_ble_device); - _event_handlers[BLEWritten](_ble_device, chrcTmp); - } - - if (_oldevent_handlers[BLEWritten]) + if (_value_updated) { - BLECharacteristic chrcTmp(this, &_ble_device); - BLECentral central(_ble_device); - _oldevent_handlers[BLEWritten](central, chrcTmp); + if (_event_handlers[BLEWritten]) + { + BLECharacteristic chrcTmp(this, &_ble_device); + _event_handlers[BLEWritten](_ble_device, chrcTmp); + } + + if (_oldevent_handlers[BLEWritten]) + { + BLECharacteristic chrcTmp(this, &_ble_device); + BLECentral central(_ble_device); + _oldevent_handlers[BLEWritten](central, chrcTmp); + } } } else @@ -288,19 +305,23 @@ BLECharacteristicImp::setValue(const unsigned char value[], uint16_t length) { // Read response received. Not block the other reading. _reading = false; + _gattc_read_result = read_process_result; } - if (_event_handlers[BLEValueUpdated]) - { - BLECharacteristic chrcTmp(this, &_ble_device); - _event_handlers[BLEValueUpdated](_ble_device, chrcTmp); - } - - if (_oldevent_handlers[BLEValueUpdated]) + if (_value_updated) { - BLECharacteristic chrcTmp(this, &_ble_device); - BLECentral central(_ble_device); - _oldevent_handlers[BLEValueUpdated](central, chrcTmp); + if (_event_handlers[BLEValueUpdated]) + { + BLECharacteristic chrcTmp(this, &_ble_device); + _event_handlers[BLEValueUpdated](_ble_device, chrcTmp); + } + + if (_oldevent_handlers[BLEValueUpdated]) + { + BLECharacteristic chrcTmp(this, &_ble_device); + BLECentral central(_ble_device); + _oldevent_handlers[BLEValueUpdated](central, chrcTmp); + } } } @@ -561,6 +582,22 @@ BLEDescriptorImp* BLECharacteristicImp::descriptor(uint16_t handle) void BLECharacteristicImp::_setValue(const uint8_t value[], uint16_t length, uint16_t offset) { + if (NULL == _value) + { + _value_size = length + offset; + // The discover didn't create the buffer + _value = (unsigned char*)malloc(_value_size); + if (_value) + { + memset(_value, 0, _value_size); + } + else + { + _value_size = 0; + errno = ENOMEM; + } + } + if (length + offset > _value_size) { if (_value_size > offset) @@ -650,12 +687,13 @@ bool BLECharacteristicImp::read(bool blocked) return false; } + _reading = true; // Send read request retval = bt_gatt_read(conn, &_read_params); if (0 == retval) { - _reading = true; ret_bool = true; + _gattc_read_result = false; // Block the call if (blocked == true) @@ -665,8 +703,17 @@ bool BLECharacteristicImp::read(bool blocked) delay(5); ret_bool = _ble_device.connected(); } + if (ret_bool) + { + ret_bool = _gattc_read_result; + } } } + else + { + // Read request failed + _reading = false; + } bt_conn_unref(conn); return ret_bool; } @@ -676,12 +723,14 @@ void BLECharacteristicImp::writeResponseReceived(struct bt_conn *conn, const void *data) { _gattc_writing = false; + _gattc_write_result = (err == 0); } bool BLECharacteristicImp::write(const unsigned char value[], uint16_t length) { int retval = 0; + bool write_process_result = true; bt_conn_t* conn = NULL; if (true == BLEUtils::isLocalBLE(_ble_device) || true == _gattc_writing) @@ -700,15 +749,20 @@ bool BLECharacteristicImp::write(const unsigned char value[], if (_gatt_chrc.properties & BT_GATT_CHRC_WRITE) { _gattc_writing = true; + _gattc_write_result = false; retval = bt_gatt_write(conn, _value_handle, 0, value, length, ble_on_write_no_rsp_complete); - while (_gattc_writing) + if (0 == retval) { - delay(2); + while (_gattc_writing) + { + delay(2); + } + write_process_result = _gattc_write_result; } } else if (_gatt_chrc.properties & BT_GATT_CHRC_WRITE_WITHOUT_RESP) { @@ -719,7 +773,7 @@ bool BLECharacteristicImp::write(const unsigned char value[], false); } bt_conn_unref(conn); - return (0 == retval); + return (0 == retval) && write_process_result; } void BLECharacteristicImp::setBuffer(const uint8_t value[], diff --git a/libraries/CurieBLE/src/internal/BLECharacteristicImp.h b/libraries/CurieBLE/src/internal/BLECharacteristicImp.h index af5e9839..46dfe22b 100644 --- a/libraries/CurieBLE/src/internal/BLECharacteristicImp.h +++ b/libraries/CurieBLE/src/internal/BLECharacteristicImp.h @@ -331,7 +331,10 @@ class BLECharacteristicImp: public BLEAttribute{ bool _subscribed; volatile bool _reading; + volatile bool _gattc_read_result; + static volatile bool _gattc_writing; + static volatile bool _gattc_write_result; bt_gatt_read_params_t _read_params; // GATT read parameter typedef LinkNode BLEDescriptorLinkNodeHeader; From 42893dfee1f335cb2b8340f48f63a1ef6c2cd67e Mon Sep 17 00:00:00 2001 From: lianggao Date: Thu, 13 Apr 2017 21:17:37 +0800 Subject: [PATCH 04/15] Jira 913 BLESubscribed, BLEUnsubscribed Event Handlers are not called 1. Implement the subscribe changed event notify feature. Changed files: BLECallbacks.cpp - Add subscribe changed handler and disconnect process BLECallbacks.h - Callback declaration BLECharacteristicImp.cpp - Add the event changed handler BLECharacteristicImp.h - Handler declaration --- .../CurieBLE/src/internal/BLECallbacks.cpp | 86 +++++++++++++++++++ .../CurieBLE/src/internal/BLECallbacks.h | 6 ++ .../src/internal/BLECharacteristicImp.cpp | 24 +++++- .../src/internal/BLECharacteristicImp.h | 2 +- 4 files changed, 116 insertions(+), 2 deletions(-) diff --git a/libraries/CurieBLE/src/internal/BLECallbacks.cpp b/libraries/CurieBLE/src/internal/BLECallbacks.cpp index 7fdd4e71..ca2aacc7 100644 --- a/libraries/CurieBLE/src/internal/BLECallbacks.cpp +++ b/libraries/CurieBLE/src/internal/BLECallbacks.cpp @@ -27,6 +27,11 @@ #include "BLEDeviceManager.h" #include "BLEProfileManager.h" +#include "BLECallbacks.h" + +#include +#include "../src/services/ble/conn_internal.h" + // GATT Server Only ssize_t profile_read_process(bt_conn_t *conn, const bt_gatt_attr_t *attr, @@ -233,6 +238,60 @@ void bleConnectEventHandler(bt_conn_t *conn, p->handleConnectEvent(conn, err); } +static uint8_t ble_gatt_disconnected_cb(const struct bt_gatt_attr *attr, void *user_data) +{ + struct bt_conn *conn = (struct bt_conn *)user_data; + struct _bt_gatt_ccc *ccc; + size_t i; + + /* Check attribute user_data must be of type struct _bt_gatt_ccc */ + if (attr->write != profile_gatt_attr_write_ccc) { + return BT_GATT_ITER_CONTINUE; + } + + ccc = (struct _bt_gatt_ccc *)attr->user_data; + /* If already disabled skip */ + if (!ccc->value) { + return BT_GATT_ITER_CONTINUE; + } + + for (i = 0; i < ccc->cfg_len; i++) + { + /* Ignore configurations with disabled value */ + if (!ccc->cfg[i].value) + { + continue; + } + + if (bt_addr_le_cmp(&conn->le.dst, &ccc->cfg[i].peer)) + { + struct bt_conn *tmp; + + /* Skip if there is another peer connected */ + tmp = bt_conn_lookup_addr_le(&ccc->cfg[i].peer); + if (tmp) { + if (tmp->state == BT_CONN_CONNECTED) { + bt_conn_unref(tmp); + return BT_GATT_ITER_CONTINUE; + } + + bt_conn_unref(tmp); + } + } + } + + /* Reset value while disconnected */ + memset(&ccc->value, 0, sizeof(ccc->value)); + + if (ccc->cfg_changed) { + ccc->cfg_changed(ccc->value); + } + + pr_debug(LOG_MODULE_BLE, "ccc %p reseted", ccc); + + return BT_GATT_ITER_CONTINUE; +} + void bleDisconnectEventHandler(bt_conn_t *conn, uint8_t reason, @@ -241,6 +300,7 @@ void bleDisconnectEventHandler(bt_conn_t *conn, BLEDeviceManager* p = (BLEDeviceManager*)param; pr_info(LOG_MODULE_BLE, "Connect lost. Reason: %d", reason); + bt_gatt_foreach_attr(0x0001, 0xffff, ble_gatt_disconnected_cb, conn); p->handleDisconnectEvent(conn, reason); } @@ -279,3 +339,29 @@ void ble_on_write_no_rsp_complete(struct bt_conn *conn, uint8_t err, BLECharacteristicImp::writeResponseReceived(conn, err, data); } +ssize_t profile_gatt_attr_write_ccc(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, + uint16_t len, + uint16_t offset) +{ + struct _bt_gatt_ccc *ccc = (struct _bt_gatt_ccc *)attr->user_data; + const uint16_t *data = (const uint16_t *)buf; + bool cccdChanged = (ccc->value != *data); + ssize_t retValue = bt_gatt_attr_write_ccc(conn, attr, buf, len, offset); + if (cccdChanged) + { + // Find characteristic and do notification + const struct bt_gatt_attr *attrChrc = attr - 1; + BLEAttribute *bleattr = (BLEAttribute *)attrChrc->user_data; + BLEAttributeType type = bleattr->type(); + pr_debug(LOG_MODULE_BLE, "The Attribute type:%d", type); + if (BLETypeCharacteristic == type) + { + BLECharacteristicImp *blecharacteritic = (BLECharacteristicImp*)bleattr; + blecharacteritic->cccdValueChanged(); + } + } + return retValue; +} + diff --git a/libraries/CurieBLE/src/internal/BLECallbacks.h b/libraries/CurieBLE/src/internal/BLECallbacks.h index deffe92a..5d877ad3 100644 --- a/libraries/CurieBLE/src/internal/BLECallbacks.h +++ b/libraries/CurieBLE/src/internal/BLECallbacks.h @@ -89,5 +89,11 @@ uint8_t profile_characteristic_read_rsp_process(bt_conn_t *conn, const void *data, uint16_t length); +ssize_t profile_gatt_attr_write_ccc(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + const void *buf, + uint16_t len, + uint16_t offset); + #endif diff --git a/libraries/CurieBLE/src/internal/BLECharacteristicImp.cpp b/libraries/CurieBLE/src/internal/BLECharacteristicImp.cpp index 2b8f947f..3857d295 100644 --- a/libraries/CurieBLE/src/internal/BLECharacteristicImp.cpp +++ b/libraries/CurieBLE/src/internal/BLECharacteristicImp.cpp @@ -856,7 +856,7 @@ int BLECharacteristicImp::updateProfile(bt_gatt_attr_t *attr_start, int& index) start->uuid = this->getClientCharacteristicConfigUuid(); start->perm = BT_GATT_PERM_READ | BT_GATT_PERM_WRITE; start->read = bt_gatt_attr_read_ccc; - start->write = bt_gatt_attr_write_ccc; + start->write = profile_gatt_attr_write_ccc; start->user_data = this->getCccCfg(); pr_info(LOG_MODULE_BLE, "cccd-%p", start); @@ -1124,4 +1124,26 @@ uint8_t BLECharacteristicImp::discoverResponseProc(bt_conn_t *conn, return retVal; } +void BLECharacteristicImp::cccdValueChanged() +{ + + enum BLECharacteristicEvent event = BLEUnsubscribed; + if (subscribed()) + { + event = BLESubscribed; + } + + if (_event_handlers[event]) + { + BLECharacteristic chrcTmp(this, &_ble_device); + _event_handlers[event](_ble_device, chrcTmp); + } + + if (_oldevent_handlers[event]) + { + BLECharacteristic chrcTmp(this, &_ble_device); + BLECentral central(_ble_device); + _oldevent_handlers[event](central, chrcTmp); + } +} diff --git a/libraries/CurieBLE/src/internal/BLECharacteristicImp.h b/libraries/CurieBLE/src/internal/BLECharacteristicImp.h index 46dfe22b..dce6eca6 100644 --- a/libraries/CurieBLE/src/internal/BLECharacteristicImp.h +++ b/libraries/CurieBLE/src/internal/BLECharacteristicImp.h @@ -172,7 +172,7 @@ class BLECharacteristicImp: public BLEAttribute{ static void writeResponseReceived(struct bt_conn *conn, uint8_t err, const void *data); - + void cccdValueChanged(); int descriptorCount() const; uint8_t discoverResponseProc(bt_conn_t *conn, const bt_gatt_attr_t *attr, From 7f05ecb61373649b4f6629d2a17df7cdfce1991c Mon Sep 17 00:00:00 2001 From: lianggao Date: Thu, 20 Apr 2017 08:22:59 +0800 Subject: [PATCH 05/15] Update to Thunderdome V4.2 --- libraries/CurieBLE/src/BLEDevice.cpp | 31 +- libraries/CurieBLE/src/BLEDevice.h | 2 +- libraries/CurieBLE/src/BLEService.h | 2 +- .../CurieBLE/src/internal/BLECallbacks.cpp | 35 +- .../CurieBLE/src/internal/BLECallbacks.h | 18 +- .../src/internal/BLECharacteristicImp.cpp | 139 ++-- .../src/internal/BLECharacteristicImp.h | 13 +- .../src/internal/BLEDeviceManager.cpp | 31 +- .../CurieBLE/src/internal/BLEDeviceManager.h | 2 +- .../src/internal/BLEProfileManager.cpp | 383 ++++------ .../CurieBLE/src/internal/BLEProfileManager.h | 14 +- .../CurieBLE/src/internal/BLEServiceImp.cpp | 26 +- .../CurieBLE/src/internal/BLEServiceImp.h | 2 + libraries/CurieBLE/src/internal/BLEUtils.cpp | 12 +- libraries/CurieBLE/src/internal/BLEUtils.h | 4 + libraries/CurieBLE/src/internal/ble_client.c | 12 +- .../libarc32_arduino101/common/misc/slist.h | 259 +++++++ system/libarc32_arduino101/common/misc/util.h | 1 + .../drivers/bluetooth/bluetooth.h | 129 +++- .../drivers/bluetooth/conn.h | 87 ++- .../drivers/bluetooth/dtm.h | 77 ++ .../drivers/bluetooth/gatt.h | 95 ++- .../drivers/bluetooth/hci.h | 158 +++- .../drivers/bluetooth/storage.h | 152 ++++ system/libarc32_arduino101/drivers/rpc/rpc.h | 120 +-- .../drivers/rpc/rpc_deserialize.c | 489 ++++++------ .../drivers/rpc/rpc_functions_to_ble_core.h | 110 +-- .../drivers/rpc/rpc_functions_to_quark.h | 116 +-- .../drivers/rpc/rpc_serialize.c | 372 +++++---- .../framework/include/os/os.h | 7 + .../libarc32_arduino101/framework/src/os/os.c | 86 +-- .../framework/src/services/ble/conn.c | 240 +++--- .../src/services/ble/conn_internal.h | 7 +- .../framework/src/services/ble/dtm.c | 71 ++ .../framework/src/services/ble/gap.c | 703 ++++++++++++------ .../framework/src/services/ble/gatt.c | 436 +++++------ .../framework/src/services/ble/hci_core.h | 7 +- .../framework/src/services/ble/l2cap.c | 15 +- .../framework/src/services/ble/smp.h | 5 +- .../framework/src/services/ble/smp_null.c | 73 +- .../src/services/ble_service/ble_service.c | 84 +-- .../src/services/ble_service/dtm_internal.h | 42 ++ .../src/services/ble_service/gap_internal.h | 631 ++++++++-------- .../src/services/ble_service/gatt_internal.h | 260 ++++--- .../src/services/ble_service/nble_driver.c | 55 +- .../src/services/ble_service/nble_driver.h | 1 + .../services/ble_service/storage_internal.h | 51 ++ variants/arduino_101/libarc32drv_arduino101.a | Bin 190830 -> 841686 bytes variants/arduino_101/linker_scripts/flash.ld | 2 +- 49 files changed, 3429 insertions(+), 2238 deletions(-) create mode 100644 system/libarc32_arduino101/common/misc/slist.h create mode 100644 system/libarc32_arduino101/drivers/bluetooth/dtm.h create mode 100644 system/libarc32_arduino101/drivers/bluetooth/storage.h create mode 100644 system/libarc32_arduino101/framework/src/services/ble/dtm.c create mode 100644 system/libarc32_arduino101/framework/src/services/ble_service/dtm_internal.h create mode 100644 system/libarc32_arduino101/framework/src/services/ble_service/storage_internal.h diff --git a/libraries/CurieBLE/src/BLEDevice.cpp b/libraries/CurieBLE/src/BLEDevice.cpp index fc93836c..61e877d2 100644 --- a/libraries/CurieBLE/src/BLEDevice.cpp +++ b/libraries/CurieBLE/src/BLEDevice.cpp @@ -33,38 +33,25 @@ BLEDevice::BLEDevice() _conn_param.interval_max = BT_GAP_INIT_CONN_INT_MAX; _conn_param.interval_min = BT_GAP_INIT_CONN_INT_MIN; _conn_param.latency = 0; - _conn_param.timeout = 400; + _conn_param.timeout = 500; } -/* -BLEDevice::BLEDevice(String bleaddress) -{ - BLEUtils::macAddressString2BT(bleaddress.c_str(), _bt_addr); -} - -BLEDevice::BLEDevice(const char* bleaddress) -{ - BLEUtils::macAddressString2BT(bleaddress, _bt_addr); -} - -*/ - BLEDevice::BLEDevice(const bt_addr_le_t* bleaddress): BLEDevice() { - memcpy(&_bt_addr, bleaddress, sizeof(_bt_addr)); + bt_addr_le_copy(&_bt_addr, bleaddress); BLEDeviceManager::instance()->getConnectionInterval(this, &_conn_param); } BLEDevice::BLEDevice(const BLEDevice* bledevice) { - memcpy(&_bt_addr, bledevice->bt_le_address(), sizeof(_bt_addr)); + bt_addr_le_copy(&_bt_addr, bledevice->bt_le_address()); memcpy(&_conn_param, &bledevice->_conn_param, sizeof (_conn_param)); } BLEDevice::BLEDevice(const BLEDevice& bledevice) { - memcpy(&_bt_addr, bledevice.bt_le_address(), sizeof(_bt_addr)); + bt_addr_le_copy(&_bt_addr, bledevice.bt_le_address()); memcpy(&_conn_param, &bledevice._conn_param, sizeof (_conn_param)); } @@ -117,7 +104,7 @@ String BLEDevice::address() const void BLEDevice::setAddress(const bt_addr_le_t& addr) { - memcpy(&_bt_addr, &addr, sizeof(_bt_addr)); + bt_addr_le_copy(&_bt_addr, &addr); } void BLEDevice::setAdvertisedServiceUuid(const char* advertisedServiceUuid) @@ -284,12 +271,14 @@ BLEDevice& BLEDevice::operator=(const BLEDevice& device) bool BLEDevice::operator==(const BLEDevice& device) const { - return (memcmp(this->_bt_addr.val, device._bt_addr.val, 6) == 0); + return (bt_addr_le_cmp(&this->_bt_addr, &device._bt_addr) == 0); + //return (memcmp(this->_bt_addr.a.val, device._bt_addr.a.val, 6) == 0); } bool BLEDevice::operator!=(const BLEDevice& device) const { - return (memcmp(this->_bt_addr.val, device._bt_addr.val, 6) != 0); + return (bt_addr_le_cmp(&this->_bt_addr, &device._bt_addr) != 0); + //return (memcmp(this->_bt_addr.a.val, device._bt_addr.a.val, 6) != 0); } @@ -389,7 +378,7 @@ bool BLEDevice::connect() bool BLEDevice::discoverAttributes() { - return BLEProfileManager::instance()->discoverAttributes(this); + return BLEProfileManager::instance()->discoverAllAttributes(this); } bool BLEDevice::discoverAttributesByService(const char* svc_uuid) diff --git a/libraries/CurieBLE/src/BLEDevice.h b/libraries/CurieBLE/src/BLEDevice.h index 23279446..61e14858 100644 --- a/libraries/CurieBLE/src/BLEDevice.h +++ b/libraries/CurieBLE/src/BLEDevice.h @@ -665,7 +665,7 @@ class BLEDevice const void *data, uint16_t length); friend uint8_t profile_descriptor_read_rsp_process(bt_conn_t *conn, - int err, + uint8_t err, bt_gatt_read_params_t *params, const void *data, uint16_t length); diff --git a/libraries/CurieBLE/src/BLEService.h b/libraries/CurieBLE/src/BLEService.h index 3d5785f3..cb76bafd 100644 --- a/libraries/CurieBLE/src/BLEService.h +++ b/libraries/CurieBLE/src/BLEService.h @@ -125,7 +125,7 @@ class BLEService friend class BLEServiceImp; friend class BLEProfileManager; friend uint8_t profile_service_read_rsp_process(bt_conn_t *conn, - int err, + uint8_t err, bt_gatt_read_params_t *params, const void *data, uint16_t length); diff --git a/libraries/CurieBLE/src/internal/BLECallbacks.cpp b/libraries/CurieBLE/src/internal/BLECallbacks.cpp index ca2aacc7..7a4e2ab0 100644 --- a/libraries/CurieBLE/src/internal/BLECallbacks.cpp +++ b/libraries/CurieBLE/src/internal/BLECallbacks.cpp @@ -61,26 +61,27 @@ ssize_t profile_read_process(bt_conn_t *conn, ssize_t profile_write_process(bt_conn_t *conn, const bt_gatt_attr_t *attr, const void *buf, uint16_t len, - uint16_t offset) + uint16_t offset, uint8_t flags) { pr_info(LOG_MODULE_BLE, "%s1", __FUNCTION__); BLEAttribute *bleattr = (BLEAttribute *)attr->user_data; BLECharacteristicImp* blecharacteritic; BLEAttributeType type = bleattr->type(); - if ((BLETypeCharacteristic != type) || 0 != offset) + if (BLETypeCharacteristic != type) { return 0; } blecharacteritic = (BLECharacteristicImp*)bleattr; - blecharacteritic->setValue((const uint8_t *) buf, len); + blecharacteritic->setValue((const uint8_t *) buf, len, offset); return len; } +#ifdef TD_V3 ssize_t profile_longwrite_process(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, uint16_t len, - uint16_t offset) + uint16_t offset, uint8_t flags) { BLEAttribute *bleattr = (BLEAttribute *)attr->user_data; BLEAttributeType type = bleattr->type(); @@ -121,7 +122,7 @@ int profile_longflush_process(struct bt_conn *conn, return -EINVAL; } - +#endif // GATT client only uint8_t profile_notify_process (bt_conn_t *conn, @@ -157,7 +158,7 @@ uint8_t profile_discover_process(bt_conn_t *conn, // GATT Client only uint8_t profile_read_rsp_process(bt_conn_t *conn, - int err, + uint8_t err, bt_gatt_read_params_t *params, const void *data, uint16_t length) @@ -175,7 +176,7 @@ uint8_t profile_read_rsp_process(bt_conn_t *conn, } uint8_t profile_descriptor_read_rsp_process(bt_conn_t *conn, - int err, + uint8_t err, bt_gatt_read_params_t *params, const void *data, uint16_t length) @@ -200,7 +201,7 @@ uint8_t profile_descriptor_read_rsp_process(bt_conn_t *conn, } uint8_t profile_service_read_rsp_process(bt_conn_t *conn, - int err, + uint8_t err, bt_gatt_read_params_t *params, const void *data, uint16_t length) @@ -211,7 +212,7 @@ uint8_t profile_service_read_rsp_process(bt_conn_t *conn, } uint8_t profile_characteristic_read_rsp_process(bt_conn_t *conn, - int err, + uint8_t err, bt_gatt_read_params_t *params, const void *data, uint16_t length) @@ -277,6 +278,11 @@ static uint8_t ble_gatt_disconnected_cb(const struct bt_gatt_attr *attr, void *u bt_conn_unref(tmp); } + } else { + /* Clear value if not paired */ + if (!ccc->cfg[i].valid) + memset(&ccc->cfg[i].value, 0, + sizeof(ccc->cfg[i].value)); } } @@ -340,15 +346,16 @@ void ble_on_write_no_rsp_complete(struct bt_conn *conn, uint8_t err, } ssize_t profile_gatt_attr_write_ccc(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - const void *buf, - uint16_t len, - uint16_t offset) + const struct bt_gatt_attr *attr, + const void *buf, + uint16_t len, + uint16_t offset, + uint8_t flags) { struct _bt_gatt_ccc *ccc = (struct _bt_gatt_ccc *)attr->user_data; const uint16_t *data = (const uint16_t *)buf; bool cccdChanged = (ccc->value != *data); - ssize_t retValue = bt_gatt_attr_write_ccc(conn, attr, buf, len, offset); + ssize_t retValue = bt_gatt_attr_write_ccc(conn, attr, buf, len, offset, flags); if (cccdChanged) { // Find characteristic and do notification diff --git a/libraries/CurieBLE/src/internal/BLECallbacks.h b/libraries/CurieBLE/src/internal/BLECallbacks.h index 5d877ad3..ba1b57f7 100644 --- a/libraries/CurieBLE/src/internal/BLECallbacks.h +++ b/libraries/CurieBLE/src/internal/BLECallbacks.h @@ -24,13 +24,14 @@ uint8_t profile_notify_process (bt_conn_t *conn, bt_gatt_subscribe_params_t *params, const void *data, uint16_t length); -uint8_t profile_read_rsp_process(bt_conn_t *conn, int err, +uint8_t profile_read_rsp_process(bt_conn_t *conn, + uint8_t err, bt_gatt_read_params_t *params, const void *data, uint16_t length); uint8_t profile_descriptor_read_rsp_process(bt_conn_t *conn, - int err, + uint8_t err, bt_gatt_read_params_t *params, const void *data, uint16_t length); @@ -41,11 +42,13 @@ int profile_longflush_process(struct bt_conn *conn, ssize_t profile_longwrite_process(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, uint16_t len, - uint16_t offset); + uint16_t offset, + uint8_t flags); ssize_t profile_write_process(bt_conn_t *conn, const bt_gatt_attr_t *attr, const void *buf, uint16_t len, - uint16_t offset); + uint16_t offset, + uint8_t flags); ssize_t profile_read_process(bt_conn_t *conn, const bt_gatt_attr_t *attr, void *buf, uint16_t len, @@ -76,7 +79,7 @@ void ble_central_device_found(const bt_addr_le_t *addr, uint8_t len); uint8_t profile_service_read_rsp_process(bt_conn_t *conn, - int err, + uint8_t err, bt_gatt_read_params_t *params, const void *data, uint16_t length); @@ -84,7 +87,7 @@ uint8_t profile_service_read_rsp_process(bt_conn_t *conn, void ble_on_write_no_rsp_complete(struct bt_conn *conn, uint8_t err, const void *data); uint8_t profile_characteristic_read_rsp_process(bt_conn_t *conn, - int err, + uint8_t err, bt_gatt_read_params_t *params, const void *data, uint16_t length); @@ -93,7 +96,8 @@ ssize_t profile_gatt_attr_write_ccc(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, uint16_t len, - uint16_t offset); + uint16_t offset, + uint8_t flags); #endif diff --git a/libraries/CurieBLE/src/internal/BLECharacteristicImp.cpp b/libraries/CurieBLE/src/internal/BLECharacteristicImp.cpp index 3857d295..70f4f805 100644 --- a/libraries/CurieBLE/src/internal/BLECharacteristicImp.cpp +++ b/libraries/CurieBLE/src/internal/BLECharacteristicImp.cpp @@ -38,7 +38,9 @@ BLECharacteristicImp::BLECharacteristicImp(const bt_uuid_t* uuid, _value_size(0), _value_length(0), _value(NULL), +#ifdef TD_V3 _value_buffer(NULL), +#endif _value_updated(false), _value_handle(handle), _cccd_handle(0), @@ -101,7 +103,9 @@ BLECharacteristicImp::BLECharacteristicImp(BLECharacteristic& characteristic, const BLEDevice& bledevice): BLEAttribute(characteristic.uuid(), BLETypeCharacteristic), _value_length(0), +#ifdef TD_V3 _value_buffer(NULL), +#endif _value_updated(false), _value_handle(0), _cccd_handle(0), @@ -123,6 +127,7 @@ BLECharacteristicImp::BLECharacteristicImp(BLECharacteristic& characteristic, { memset(_value, 0, _value_size); } +#ifdef TD_V3 if (_value_size > BLE_MAX_ATTR_DATA_LEN) { _value_buffer = (unsigned char*)malloc(_value_size); @@ -136,6 +141,7 @@ BLECharacteristicImp::BLECharacteristicImp(BLECharacteristic& characteristic, memset(_value_buffer, 0, _value_size); } } +#endif memset(&_ccc_cfg, 0, sizeof(_ccc_cfg)); memset(&_ccc_value, 0, sizeof(_ccc_value)); @@ -196,11 +202,13 @@ BLECharacteristicImp::~BLECharacteristicImp() _value = (unsigned char *)NULL; } +#ifdef TD_V3 if (_value_buffer) { free(_value_buffer); _value_buffer = (unsigned char *)NULL; } +#endif } unsigned char @@ -211,34 +219,11 @@ BLECharacteristicImp::properties() const bool BLECharacteristicImp::writeValue(const byte value[], int length) { - int status; - bool retVal = false; - - _setValue(value, length, 0); - - // Address same is GATT server. Send notification if CCCD enabled - // Different is GATT client. Send write request - if (true == BLEUtils::isLocalBLE(_ble_device) && - NULL != _attr_chrc_value) - { - // Notify for peripheral. - status = bt_gatt_notify(NULL, _attr_chrc_value, value, length, NULL); - // Sid. KW found status is always 0 - // if (!status) - // { - retVal = true; - // } - } - - //Not schedule write request for central - // The write request may failed. - // If user want to get latest set value. Call read and get the real value - return retVal; + return writeValue(value, length, 0); } bool BLECharacteristicImp::writeValue(const byte value[], int length, int offset) { - int status; bool retVal = false; _setValue(value, length, offset); @@ -249,12 +234,8 @@ bool BLECharacteristicImp::writeValue(const byte value[], int length, int offset NULL != _attr_chrc_value) { // Notify for peripheral. - status = bt_gatt_notify(NULL, _attr_chrc_value, value, length, NULL); - // Sid. KW found status is always 0. - // if (!status) - // { - retVal = true; - // } + bt_gatt_notify(NULL, _attr_chrc_value, value, length, NULL); + retVal = true; } //Not schedule write request for central @@ -263,19 +244,8 @@ bool BLECharacteristicImp::writeValue(const byte value[], int length, int offset return retVal; } -bool -BLECharacteristicImp::setValue(const unsigned char value[], uint16_t length) +void BLECharacteristicImp::triggerValueUpdatedEvent() { - bool read_process_result = true; - if (NULL != value && length != 0) - { - _setValue(value, length, 0); - _value_updated = true; - } - else - { - read_process_result = false; - } if (BLEUtils::isLocalBLE(_ble_device) == true) { // GATT server @@ -298,16 +268,6 @@ BLECharacteristicImp::setValue(const unsigned char value[], uint16_t length) } else { - // GATT client - // Discovered attribute - // Read response/Notification/Indication for GATT client - if (_reading) - { - // Read response received. Not block the other reading. - _reading = false; - _gattc_read_result = read_process_result; - } - if (_value_updated) { if (_event_handlers[BLEValueUpdated]) @@ -324,7 +284,46 @@ BLECharacteristicImp::setValue(const unsigned char value[], uint16_t length) } } } +} + +bool +BLECharacteristicImp::setValue (const unsigned char value[], + uint16_t length) +{ + return setValue(value, length, 0); +} + +bool +BLECharacteristicImp::setValue (const unsigned char value[], + uint16_t length, + uint16_t offset) +{ + bool read_process_result = true; + pr_info(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); + pr_info(LOG_MODULE_BLE, "Length-%p, %d", value, length); + if (NULL != value && length != 0) + { + _setValue(value, length, offset); + _value_updated = true; + } + else + { + read_process_result = false; + } + + if (BLEUtils::isLocalBLE(_ble_device) == false) + { + // GATT client + // Discovered attribute + if (_reading) + { + // Read response received. Not block the other reading. + _reading = false; + _gattc_read_result = read_process_result; + } + } + triggerValueUpdatedEvent(); return true; } @@ -748,14 +747,17 @@ bool BLECharacteristicImp::write(const unsigned char value[], // Send write request if (_gatt_chrc.properties & BT_GATT_CHRC_WRITE) { + struct bt_gatt_write_params params; + params.data = value; + params.length = length; + params.func = ble_on_write_no_rsp_complete; + params.handle = _value_handle; + params.offset = 0; + _gattc_writing = true; _gattc_write_result = false; - retval = bt_gatt_write(conn, - _value_handle, - 0, - value, - length, - ble_on_write_no_rsp_complete); + + retval = bt_gatt_write(conn, ¶ms); if (0 == retval) { while (_gattc_writing) @@ -764,7 +766,8 @@ bool BLECharacteristicImp::write(const unsigned char value[], } write_process_result = _gattc_write_result; } - } else if (_gatt_chrc.properties & BT_GATT_CHRC_WRITE_WITHOUT_RESP) + } + else if (_gatt_chrc.properties & BT_GATT_CHRC_WRITE_WITHOUT_RESP) { retval = bt_gatt_write_without_response(conn, _value_handle, @@ -776,6 +779,7 @@ bool BLECharacteristicImp::write(const unsigned char value[], return (0 == retval) && write_process_result; } +#ifdef TD_V3 void BLECharacteristicImp::setBuffer(const uint8_t value[], uint16_t length, uint16_t offset) @@ -799,6 +803,7 @@ void BLECharacteristicImp::discardBuffer() if(_value_buffer) memcpy(_value_buffer, _value, _value_size); } +#endif bool BLECharacteristicImp::longCharacteristic() { @@ -838,9 +843,13 @@ int BLECharacteristicImp::updateProfile(bt_gatt_attr_t *attr_start, int& index) } else { +#ifdef TD_V3 // Long characteristic. MAX. 512 start->write = profile_longwrite_process; start->flush = profile_longflush_process; +#else + start->write = profile_write_process; +#endif } _attr_chrc_value = start; pr_debug(LOG_MODULE_BLE, "chrcdescripor-%p, chimp-%p type-%d", start, this, this->type()); @@ -875,7 +884,7 @@ int BLECharacteristicImp::updateProfile(bt_gatt_attr_t *attr_start, int& index) counter += offset; node = node->next; } - pr_debug(LOG_MODULE_BLE, "%s:type-%d", __FUNCTION__, this->type()); + //pr_debug(LOG_MODULE_BLE, "%s:type-%d", __FUNCTION__, this->type()); return counter; } @@ -888,13 +897,13 @@ int BLECharacteristicImp::addDescriptor(BLEDescriptor& descriptor) } descriptorImp = new BLEDescriptorImp(_ble_device, descriptor); - pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); + //pr_debug(LOG_MODULE_BLE, "%s-%d- length %d",__FUNCTION__, __LINE__, descriptor.valueLength()); if (NULL == descriptorImp) { return BLE_STATUS_NO_MEMORY; } - pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); + //pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); BLEDescriptorNodePtr node = link_node_create(descriptorImp); if (NULL == node) { @@ -902,7 +911,7 @@ int BLECharacteristicImp::addDescriptor(BLEDescriptor& descriptor) return BLE_STATUS_NO_MEMORY; } link_node_insert_last(&_descriptors_header, node); - pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); + //pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); return BLE_STATUS_SUCCESS; } @@ -917,7 +926,7 @@ int BLECharacteristicImp::addDescriptor(const bt_uuid_t* uuid, } descriptorImp = new BLEDescriptorImp(uuid, property, handle, _ble_device); - pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); + //pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); if (NULL == descriptorImp) { return BLE_STATUS_NO_MEMORY; @@ -930,7 +939,7 @@ int BLECharacteristicImp::addDescriptor(const bt_uuid_t* uuid, return BLE_STATUS_NO_MEMORY; } link_node_insert_last(&_descriptors_header, node); - pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); + //pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); return BLE_STATUS_SUCCESS; } diff --git a/libraries/CurieBLE/src/internal/BLECharacteristicImp.h b/libraries/CurieBLE/src/internal/BLECharacteristicImp.h index dce6eca6..7f01e920 100644 --- a/libraries/CurieBLE/src/internal/BLECharacteristicImp.h +++ b/libraries/CurieBLE/src/internal/BLECharacteristicImp.h @@ -83,6 +83,9 @@ class BLECharacteristicImp: public BLEAttribute{ * @return bool true set value success, false on error */ bool setValue(const unsigned char value[], unsigned short length); + bool setValue (const unsigned char value[], + uint16_t length, + uint16_t offset); /** * Get the property mask of the Characteristic @@ -208,7 +211,8 @@ class BLECharacteristicImp: public BLEAttribute{ friend ssize_t profile_longwrite_process(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, uint16_t len, - uint16_t offset); + uint16_t offset, + uint8_t flags); int updateProfile(bt_gatt_attr_t *attr_start, int& index); @@ -216,11 +220,13 @@ class BLECharacteristicImp: public BLEAttribute{ bool longCharacteristic(); +#ifdef TD_V3 void setBuffer(const uint8_t value[], uint16_t length, uint16_t offset); void discardBuffer(); void syncupBuffer2Value(); +#endif /** * @brief Get the characteristic value handle @@ -303,7 +309,8 @@ class BLECharacteristicImp: public BLEAttribute{ void setHandle(uint16_t handle); void _setValue(const uint8_t value[], uint16_t length, uint16_t offset); bool isClientCharacteristicConfigurationDescriptor(const bt_uuid_t* uuid); - + void triggerValueUpdatedEvent(); + private: // Those 2 UUIDs are used for define the characteristic. static bt_uuid_16_t _gatt_chrc_uuid; // Characteristic UUID @@ -312,7 +319,9 @@ class BLECharacteristicImp: public BLEAttribute{ unsigned short _value_size; unsigned short _value_length; unsigned char* _value; +#ifdef TD_V3 unsigned char* _value_buffer; +#endif bool _value_updated; uint16_t _value_handle; // GATT client only diff --git a/libraries/CurieBLE/src/internal/BLEDeviceManager.cpp b/libraries/CurieBLE/src/internal/BLEDeviceManager.cpp index d9108cd3..480022db 100644 --- a/libraries/CurieBLE/src/internal/BLEDeviceManager.cpp +++ b/libraries/CurieBLE/src/internal/BLEDeviceManager.cpp @@ -65,8 +65,7 @@ BLEDeviceManager::BLEDeviceManager(): ble_client_get_factory_config(&_local_bda, _device_name); - _adv_param.type = BT_LE_ADV_IND; - _adv_param.addr_type = _local_bda.type; + setConnectable(true); _adv_param.interval_min = 0xA0; _adv_param.interval_max = 0xF0; @@ -80,7 +79,7 @@ BLEDeviceManager::BLEDeviceManager(): memset(_peer_adv_data, 0, sizeof(_peer_adv_data)); memset(_peer_adv_data_len, 0, sizeof(_peer_adv_data_len)); memset(_peer_scan_rsp_data, 0, sizeof(_peer_scan_rsp_data)); - memset(_peer_scan_rsp_data_len, -1, sizeof(_peer_scan_rsp_data_len)); + memset(_peer_scan_rsp_data_len, 0, sizeof(_peer_scan_rsp_data_len)); memset(_peer_adv_rssi, 0, sizeof(_peer_adv_rssi)); memset(_peer_adv_connectable, 0, sizeof(_peer_adv_connectable)); @@ -321,12 +320,14 @@ bool BLEDeviceManager::setTxPower(int txPower) void BLEDeviceManager::setConnectable(bool connectable) { - uint8_t type = BT_LE_ADV_IND; if (connectable == false) { - type = BT_LE_ADV_NONCONN_IND; + _adv_param.options = 0; + } + else + { + _adv_param.options = BT_LE_ADV_OPT_CONNECTABLE; } - _adv_param.type = type; } void BLEDeviceManager::setDeviceName(const char* deviceName) @@ -1154,7 +1155,7 @@ bool BLEDeviceManager::connectToDevice(BLEDevice &device) bool link_existed = false; bool retval = false; - pr_debug(LOG_MODULE_BLE, "%s-%d-1", __FUNCTION__, __LINE__); + //pr_debug(LOG_MODULE_BLE, "%s-%d-1", __FUNCTION__, __LINE__); // Find free peripheral Items for (int i = 0; i < BLE_MAX_CONN_CFG; i++) @@ -1188,7 +1189,7 @@ bool BLEDeviceManager::connectToDevice(BLEDevice &device) } } } - pr_debug(LOG_MODULE_BLE, "%s-%d:link_existed-%d unused-%p", __FUNCTION__, __LINE__, link_existed, unused); + //pr_debug(LOG_MODULE_BLE, "%s-%d:link_existed-%d unused-%p", __FUNCTION__, __LINE__, link_existed, unused); if (!link_existed && NULL != unused) { @@ -1382,7 +1383,9 @@ BLEDevice BLEDeviceManager::available() { uint64_t timestamp_delta = timestamp - _peer_adv_mill[i]; temp = &_peer_adv_buffer[i]; - if ((timestamp_delta <= 2000) && (max_delta < timestamp_delta) && (_peer_scan_rsp_data_len[i] >= 0 || !_peer_adv_connectable[i])) + if ((timestamp_delta >= 800) && // Wait scan response coming + (timestamp_delta <= 2000) && // Check timeout + (max_delta < timestamp_delta)) { // Eable the duplicate filter if (_adv_duplicate_filter_enabled && @@ -1444,7 +1447,7 @@ bool BLEDeviceManager::setAdvertiseBuffer(const bt_addr_le_t* bt_addr, if (max_delta > 2000) // expired { index = i; - _peer_scan_rsp_data_len[index] = -1; // Invalid the scan response + _peer_scan_rsp_data_len[index] = 0; // Invalid the scan response } } @@ -1473,7 +1476,8 @@ bool BLEDeviceManager::setAdvertiseBuffer(const bt_addr_le_t* bt_addr, _peer_adv_data_len[index] = data_len; _peer_adv_rssi[index] = rssi; // Update the timestamp - _peer_adv_mill[index] = timestamp; + if (timestamp - _peer_adv_mill[index] > 1000) + _peer_adv_mill[index] = timestamp; _peer_adv_connectable[index] = connectable; retval = true; } @@ -1515,7 +1519,8 @@ bool BLEDeviceManager::setScanRespBuffer(const bt_addr_le_t* bt_addr, _peer_scan_rsp_data_len[index] = data_len; //_peer_adv_rssi[index] = rssi; // Update the timestamp - _peer_adv_mill[index] = timestamp; + if (timestamp - _peer_adv_mill[index] > 1000) + _peer_adv_mill[index] = timestamp; retval = true; } @@ -1644,7 +1649,7 @@ void BLEDeviceManager::handleDeviceFound(const bt_addr_le_t *addr, //pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); // Filter address if (BLEUtils::macAddressValid(_adv_accept_device) == true && - (memcmp(addr->val, _adv_accept_device.val, sizeof (addr->val)) != 0)) + (memcmp(addr->a.val, _adv_accept_device.a.val, sizeof (addr->a.val)) != 0)) { pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); return; diff --git a/libraries/CurieBLE/src/internal/BLEDeviceManager.h b/libraries/CurieBLE/src/internal/BLEDeviceManager.h index e6308220..ea81ea71 100644 --- a/libraries/CurieBLE/src/internal/BLEDeviceManager.h +++ b/libraries/CurieBLE/src/internal/BLEDeviceManager.h @@ -392,7 +392,7 @@ class BLEDeviceManager uint8_t _peer_adv_data[BLE_MAX_ADV_BUFFER_CFG][BLE_MAX_ADV_SIZE]; uint8_t _peer_adv_data_len[BLE_MAX_ADV_BUFFER_CFG]; uint8_t _peer_scan_rsp_data[BLE_MAX_ADV_BUFFER_CFG][BLE_MAX_ADV_SIZE]; - int8_t _peer_scan_rsp_data_len[BLE_MAX_ADV_BUFFER_CFG]; + uint8_t _peer_scan_rsp_data_len[BLE_MAX_ADV_BUFFER_CFG]; int8_t _peer_adv_rssi[BLE_MAX_ADV_BUFFER_CFG]; bool _peer_adv_connectable[BLE_MAX_ADV_BUFFER_CFG]; diff --git a/libraries/CurieBLE/src/internal/BLEProfileManager.cpp b/libraries/CurieBLE/src/internal/BLEProfileManager.cpp index 465de326..756771dd 100644 --- a/libraries/CurieBLE/src/internal/BLEProfileManager.cpp +++ b/libraries/CurieBLE/src/internal/BLEProfileManager.cpp @@ -104,17 +104,7 @@ BLEProfileManager::addService (BLEDevice &bledevice, BLEService& service) serviceheader = &_service_header_array[index]; bt_addr_le_copy(&_addresses[index], bledevice.bt_le_address()); } - BLEServiceImp *serviceImp = NULL;//this->service(bledevice, service.uuid()); - //if (NULL != serviceImp) - //{ - // The service alreay exist - // return serviceImp; - //} - - //if (NULL == serviceImp) // May trigger KW warning - { - serviceImp = service.fetchOutLocalServiceImp(); - } + BLEServiceImp *serviceImp = service.fetchOutLocalServiceImp(); if (NULL == serviceImp) { @@ -603,81 +593,27 @@ void BLEProfileManager::handleDisconnectedPutOffEvent() } } -bool BLEProfileManager::discoverAttributes(BLEDevice* device) +bool BLEProfileManager::discoverAllAttributes(BLEDevice* device) { - int err; - bt_conn_t* conn; - int i = getDeviceIndex(device); - bool ret = false; - bt_gatt_discover_params_t* temp = NULL; - - errno = 0; - pr_debug(LOG_MODULE_BLE, "%s-%d: index-%d,fun-%p", __FUNCTION__, __LINE__, i,profile_discover_process); - - if (_start_discover) - { - // Already in discover state - return false; - } - + return discoverAttributes(device, NULL); +} - if (i >= BLE_MAX_CONN_CFG) - { - // The device already in the buffer. - // This function only be called after connection established. - return ret; - } - - conn = bt_conn_lookup_addr_le(device->bt_le_address()); - if (NULL == conn) - { - // Link lost - pr_debug(LOG_MODULE_BLE, "Can't find connection\n"); - return ret; - } - temp = &_discover_params[i]; - temp->start_handle = 1; - temp->end_handle = 0xFFFF; - temp->uuid = NULL; - temp->type = BT_GATT_DISCOVER_PRIMARY; - temp->func = profile_discover_process; +bool BLEProfileManager::discoverAttributesByService(BLEDevice* device, + const bt_uuid_t* svc_uuid) +{ + bool ret; + _discover_one_service = true; + ret = discoverAttributes(device, svc_uuid); + _discover_one_service = false; - err = bt_gatt_discover(conn, temp); - bt_conn_unref(conn); - if (err) - { - pr_debug(LOG_MODULE_BLE, "Discover failed(err %d)\n", err); - return ret; - } - // Block it - memcpy(&_discovering_ble_addresses, device->bt_le_address(), sizeof(_discovering_ble_addresses)); - _discover_rsp_timestamp = millis(); - _start_discover = true; - ret = true; - while (_start_discover) // Sid. KW warning acknowldged - { - delay(10); - if ((millis() - _discover_rsp_timestamp) > 5000) - { - // Doesn't receive the Service read response - _start_discover = false; - _cur_discover_service = NULL; - ret = false; - _reading = false; - } - - if (ENOMEM == errno) - { - pr_debug(LOG_MODULE_BLE, "%s-%d:Sys errno(err %d)\n", __FUNCTION__, __LINE__, errno); - ret = false; - break; - } - } return ret; } -bool BLEProfileManager::discoverAttributesByService(BLEDevice* device, const bt_uuid_t* svc_uuid) +bool BLEProfileManager::discoverAttributes(BLEDevice* device, + const bt_uuid_t* svc_uuid) { + bool ret = false; + errno = 0; if (_start_discover) { @@ -685,43 +621,41 @@ bool BLEProfileManager::discoverAttributesByService(BLEDevice* device, const bt_ return false; } - bool ret = discoverService(device, svc_uuid); + ret = discoverService(device, svc_uuid); if (false == ret) { return false; } + // Block it memcpy(&_discovering_ble_addresses, device->bt_le_address(), sizeof(_discovering_ble_addresses)); _discover_rsp_timestamp = millis(); _start_discover = true; - _discover_one_service = true; while (_start_discover) // Sid. KW warning acknowldged { delay(10); - if ((millis() - _discover_rsp_timestamp) > 5000) + if (BLEUtils::getElapsedMillSeconds(_discover_rsp_timestamp) > 5000) { // Doesn't receive the Service read response + // Timeout _start_discover = false; _cur_discover_service = NULL; ret = false; _reading = false; + break; } if (ENOMEM == errno) { - pr_debug(LOG_MODULE_BLE, "%s-%d:Sys errno(err %d)", __FUNCTION__, __LINE__, errno); + pr_debug(LOG_MODULE_BLE, "%s-%d:Sys errno(err %d)\n", __FUNCTION__, __LINE__, errno); ret = false; break; } } - pr_debug(LOG_MODULE_BLE, "%s-%d:Discover Done", __FUNCTION__, __LINE__); - _discover_one_service = false; - return ret; } - int BLEProfileManager::getDeviceIndex(const bt_addr_le_t* macAddr) { int i; @@ -755,22 +689,133 @@ void BLEProfileManager::setDiscovering(bool discover) _discovering = discover; } +void BLEProfileManager::singleServiceDiscoverResponseProc(BLEDevice &device, + BLEServiceImp* service) +{ + bool result = service->discoverAttributes(&device); + if (result == true) + { + // Record the current discovering service + _cur_discover_service = service; + } +} + +uint8_t BLEProfileManager::primaryServiceResponseProc(BLEDevice &device, + const bt_gatt_attr_t *attr, + bt_gatt_discover_params_t *params) +{ + uint16_t le16; + BLEServiceImp* service_tmp = NULL; + uint8_t retVal = BT_GATT_ITER_STOP; + struct bt_gatt_service *svc_value; + const bt_uuid_t* svc_uuid; + + if (NULL == attr) + { + // Service discover complete + return BT_GATT_ITER_STOP; + } + + // Get response data + svc_value = (struct bt_gatt_service *)attr->user_data; + svc_uuid = svc_value->uuid; + memcpy(&le16, &BT_UUID_16(svc_uuid)->val, sizeof(le16)); + + setDiscovering(false); + + if (svc_uuid->type == BT_UUID_TYPE_16 && + le16 == 0) + { + // Workaround: + // Discover failed. The service may unknow type. + // Need read the value and discovery again. + readService(device, attr->handle); + } + else + { + // Add to the buffer + service_tmp = addService(device, svc_value->uuid); + params->uuid = NULL; + + if (NULL != service_tmp) + { + service_tmp->setHandle(attr->handle); + service_tmp->setEndHandle(svc_value->end_handle); + + if (true == _discover_one_service) + { + singleServiceDiscoverResponseProc(device, service_tmp); + } + else + { + retVal = BT_GATT_ITER_CONTINUE; + } + } + else + { + pr_debug(LOG_MODULE_BLE, "%s-%d: Add service failed", + __FUNCTION__, __LINE__); + errno = ENOMEM; + } + } + + return retVal; +} + +void BLEProfileManager::discoverCompleteProc() +{ + _start_discover = false; + memset(&_discovering_ble_addresses, 0, sizeof(_discovering_ble_addresses)); +} + +bool BLEProfileManager::discoverNextService(BLEDevice &device) +{ + const BLEServiceLinkNodeHeader* serviceHeader = getServiceHeader(device); + BLEServiceImp* serviceCurImp = NULL; + if (NULL == serviceHeader) + { + // Doesn't find the service + return false; + } + BLEServiceNodePtr node = serviceHeader->next; + + // Discover next service + while (node != NULL) + { + serviceCurImp = node->value; + + if (NULL == _cur_discover_service) + { + bool result = serviceCurImp->discoverAttributes(&device); + if (result == true) + { + // Record the current discovering service + _cur_discover_service = serviceCurImp; + break; + } + } + else if (_cur_discover_service == serviceCurImp) + { + // Find next discoverable service + _cur_discover_service = NULL; + } + + node = node->next; + } + return (node != NULL); +} + uint8_t BLEProfileManager::discoverResponseProc(bt_conn_t *conn, const bt_gatt_attr_t *attr, bt_gatt_discover_params_t *params) { const bt_addr_le_t* dst_addr = bt_conn_get_dst(conn); - int i = getDeviceIndex(dst_addr); BLEDevice device(dst_addr); uint8_t retVal = BT_GATT_ITER_STOP; - BLEServiceImp* service_tmp = NULL; + _discover_rsp_timestamp = millis(); - //pr_debug(LOG_MODULE_BLE, "%s-%d: index-%d", __FUNCTION__, __LINE__, i); - if (i >= BLE_MAX_CONN_CFG) - { - return BT_GATT_ITER_STOP; - } + //pr_debug(LOG_MODULE_BLE, "%s-%d: index-%d", __FUNCTION__, __LINE__, i); // Process the service switch (params->type) @@ -788,48 +833,8 @@ uint8_t BLEProfileManager::discoverResponseProc(bt_conn_t *conn, } case BT_GATT_DISCOVER_PRIMARY: { - if (NULL != attr) - { - struct bt_gatt_service *svc_value = (struct bt_gatt_service *)attr->user_data; - const bt_uuid_t* svc_uuid = svc_value->uuid; - uint16_t le16; - memcpy(&le16, &BT_UUID_16(svc_uuid)->val, sizeof(le16)); - setDiscovering(false); - - if (svc_uuid->type == BT_UUID_TYPE_16 && - le16 == 0) - { - // Discover failed. The service may unknow type. - // Need read the value and discovery again. - readService(device, attr->handle); - retVal = BT_GATT_ITER_CONTINUE; - } - else - { - service_tmp = addService(device, svc_value->uuid); - params->uuid = NULL; - - if (NULL != service_tmp) - { - service_tmp->setHandle(attr->handle); - service_tmp->setEndHandle(svc_value->end_handle); - if (_discover_one_service == false) - retVal = BT_GATT_ITER_CONTINUE; - } - else - { - retVal = BT_GATT_ITER_STOP; - errno = ENOMEM; - pr_debug(LOG_MODULE_BLE, "%s-%d: Add service failed", - __FUNCTION__, __LINE__); - } - } - } - else - { - // Service discover complete - retVal = BT_GATT_ITER_STOP; - } + retVal = primaryServiceResponseProc(device, attr, params); + break; } default: { @@ -841,92 +846,20 @@ uint8_t BLEProfileManager::discoverResponseProc(bt_conn_t *conn, { if (errno == ENOMEM) { - // No memory. Stop discovery + // Out of memory. Stop discovery _cur_discover_service = NULL; _discover_one_service = false; - return retVal; - } - - pr_debug(LOG_MODULE_BLE, "%s-%d: Discover one service-%d", - __FUNCTION__, __LINE__, _discover_one_service); - if (true == _discover_one_service) - { - if (NULL != service_tmp) - { - pr_debug(LOG_MODULE_BLE, "%s-%d: Discover service", - __FUNCTION__, __LINE__); - bool result = service_tmp->discoverAttributes(&device); - if (result == true) - { - // Record the current discovering service - _cur_discover_service = service_tmp; - } - else - { - // Failed - _discover_one_service = false; - } - } - else - { - if (discovering() == false) - { - // Complete - _cur_discover_service = NULL; - _discover_one_service = false; - } - } - - if (_discover_one_service == false) - { - // Discover complete - _start_discover = false; - memset(&_discovering_ble_addresses, 0, sizeof(_discovering_ble_addresses)); - } - return retVal; + return BT_GATT_ITER_STOP; } checkReadService(); if (discovering() == false) { - const BLEServiceLinkNodeHeader* serviceHeader = getServiceHeader(device); - BLEServiceImp* serviceCurImp = NULL; - if (NULL == serviceHeader) - { - // Doesn't find the service - return BT_GATT_ITER_STOP; - } - BLEServiceNodePtr node = serviceHeader->next; - - // Discover next service - while (node != NULL) - { - serviceCurImp = node->value; - - if (NULL == _cur_discover_service) - { - bool result = serviceCurImp->discoverAttributes(&device); - if (result == true) - { - // Record the current discovering service - _cur_discover_service = serviceCurImp; - break; - } - } - else if (_cur_discover_service == serviceCurImp) - { - // Find next discoverable service - _cur_discover_service = NULL; - } - - node = node->next; - } - if (NULL == node) + if (false == discoverNextService(device)) { pr_debug(LOG_MODULE_BLE, "%s-%d: Discover completed", __FUNCTION__, __LINE__); - _start_discover = false; - memset(&_discovering_ble_addresses, 0, sizeof(_discovering_ble_addresses)); + discoverCompleteProc(); } } } @@ -1044,9 +977,8 @@ bool BLEProfileManager::discoverService(BLEDevice* device, const bt_uuid_t* svc_ { int err = 0; bt_conn_t* conn; - int i = getDeviceIndex(device); - bool ret = false; bt_gatt_discover_params_t* temp = NULL; + int i = getDeviceIndex(device); pr_debug(LOG_MODULE_BLE, "%s-%d: index-%d,fun-%p", __FUNCTION__, __LINE__, i,profile_discover_process); @@ -1054,38 +986,35 @@ bool BLEProfileManager::discoverService(BLEDevice* device, const bt_uuid_t* svc_ { // The device already in the buffer. // This function only be called after connection established. - return ret; - } - - //BLEServiceImp* serviceImp = service(device, svc_uuid); - //if (NULL == serviceImp) - { - //return ret; + return false; } conn = bt_conn_lookup_addr_le(device->bt_le_address()); if (NULL == conn) { // Link lost - pr_debug(LOG_MODULE_BLE, "Can't find connection\n"); - return ret; + pr_debug(LOG_MODULE_BLE, "Can't find connection, Link lost!\n"); + return false; } - memcpy(&_discover_uuid[i], svc_uuid, sizeof(bt_uuid_128_t)); - temp = &_discover_params[i]; temp->start_handle = 1; temp->end_handle = 0xFFFF; - temp->uuid = (bt_uuid_t*) &_discover_uuid[i]; temp->type = BT_GATT_DISCOVER_PRIMARY; temp->func = profile_discover_process; + temp->uuid = NULL; + if (NULL != svc_uuid) + { + memcpy(&_discover_uuid[i], svc_uuid, sizeof(bt_uuid_128_t)); + temp->uuid = (bt_uuid_t*) &_discover_uuid[i]; + } err = bt_gatt_discover(conn, temp); bt_conn_unref(conn); if (err) { pr_debug(LOG_MODULE_BLE, "Discover failed(err %d)\n", err); - return ret; + return false; } return true; } diff --git a/libraries/CurieBLE/src/internal/BLEProfileManager.h b/libraries/CurieBLE/src/internal/BLEProfileManager.h index 4b095a68..e8c69154 100644 --- a/libraries/CurieBLE/src/internal/BLEProfileManager.h +++ b/libraries/CurieBLE/src/internal/BLEProfileManager.h @@ -107,7 +107,7 @@ class BLEProfileManager{ const bt_gatt_attr_t *attr, bt_gatt_discover_params_t *params); - bool discoverAttributes(BLEDevice* device); + bool discoverAllAttributes(BLEDevice* device); bool discoverAttributesByService(BLEDevice* device, const bt_uuid_t* svc_uuid); void handleConnectedEvent(const bt_addr_le_t* deviceAddr); void handleDisconnectedEvent(const bt_addr_le_t* deviceAddr); @@ -205,7 +205,17 @@ class BLEProfileManager{ bool discovering(); void setDiscovering(bool discover); void checkReadService(); - + bool discoverNextService(BLEDevice &device); + void discoverCompleteProc(); + uint8_t primaryServiceResponseProc(BLEDevice &device, + const bt_gatt_attr_t *attr, + bt_gatt_discover_params_t *params); + void singleServiceDiscoverResponseProc(BLEDevice &device, + BLEServiceImp* service); + + bool discoverAttributes(BLEDevice* device, + const bt_uuid_t* svc_uuid); + private: // The last header is for local BLE BLEServiceLinkNodeHeader _service_header_array[BLE_MAX_CONN_CFG + 1]; // The connected devices' service and self service diff --git a/libraries/CurieBLE/src/internal/BLEServiceImp.cpp b/libraries/CurieBLE/src/internal/BLEServiceImp.cpp index 862b58ed..3df714dc 100644 --- a/libraries/CurieBLE/src/internal/BLEServiceImp.cpp +++ b/libraries/CurieBLE/src/internal/BLEServiceImp.cpp @@ -38,7 +38,8 @@ BLEServiceImp::BLEServiceImp(BLEService& service): _start_handle(0), _end_handle(0xFFFF), _reading(false), - _cur_discover_chrc(NULL) + _cur_discover_chrc(NULL), + _discovering(false) { memset(&_characteristics_header, 0, sizeof(_characteristics_header)); service.setServiceImp(this); @@ -49,7 +50,8 @@ BLEServiceImp::BLEServiceImp(const bt_uuid_t* uuid): _start_handle(0), _end_handle(0xFFFF), _reading(false), - _cur_discover_chrc(NULL) + _cur_discover_chrc(NULL), + _discovering(false) { memset(&_characteristics_header, 0, sizeof(_characteristics_header)); } @@ -272,7 +274,14 @@ BLECharacteristicImp* BLEServiceImp::characteristic(const char* uuid) bool BLEServiceImp::discovering() { - return (_cur_discover_chrc != NULL || _reading); + return (_cur_discover_chrc != NULL || + _reading || + _discovering); +} + +void BLEServiceImp::setDiscovering(bool enable) +{ + _discovering = enable; } bool BLEServiceImp::discoverAttributes(BLEDevice* device) @@ -290,6 +299,7 @@ bool BLEServiceImp::discoverAttributes(BLEDevice* device, bt_gatt_discover_params_t* temp = NULL; const bt_uuid_t* service_uuid = bt_uuid(); + // Filt out GAP/GATT service if (service_uuid->type == BT_UUID_TYPE_16) { uint16_t uuid_tmp;// = ((bt_uuid_16_t*)service_uuid)->val; @@ -323,6 +333,7 @@ bool BLEServiceImp::discoverAttributes(BLEDevice* device, pr_debug(LOG_MODULE_BLE, "Discover failed(err %d)\n", err); return false; } + setDiscovering(true); return true; } @@ -341,6 +352,7 @@ uint8_t BLEServiceImp::discoverResponseProc(bt_conn_t *conn, { case BT_GATT_DISCOVER_CHARACTERISTIC: { + setDiscovering(false); if (NULL != attr) { //const bt_uuid_t* chrc_uuid = attr->uuid; @@ -355,7 +367,7 @@ uint8_t BLEServiceImp::discoverResponseProc(bt_conn_t *conn, { // Read the UUID readCharacteristic(device, chrc_handle); - retVal = BT_GATT_ITER_CONTINUE; + //retVal = BT_GATT_ITER_CONTINUE; } else { @@ -379,9 +391,7 @@ uint8_t BLEServiceImp::discoverResponseProc(bt_conn_t *conn, break; } case BT_GATT_DISCOVER_DESCRIPTOR: - { - // - + { if (NULL != _cur_discover_chrc) { retVal = _cur_discover_chrc->discoverResponseProc(conn, @@ -420,7 +430,6 @@ void BLEServiceImp::discoverNextCharacteristic(BLEDevice &bledevice) BLECharacteristicImp* chrcCurImp = NULL; BLECharacteristicNodePtr node = chrcHeader->next; - //pr_debug(LOG_MODULE_BLE, "%s-%d: node-%p",__FUNCTION__, __LINE__, node); // Discover next service while (node != NULL) { @@ -429,7 +438,6 @@ void BLEServiceImp::discoverNextCharacteristic(BLEDevice &bledevice) if (NULL == _cur_discover_chrc) { bool result = chrcCurImp->discoverAttributes(&bledevice); - pr_debug(LOG_MODULE_BLE, "%s-%d",__FUNCTION__, __LINE__); if (result == true) { // Record the current discovering service diff --git a/libraries/CurieBLE/src/internal/BLEServiceImp.h b/libraries/CurieBLE/src/internal/BLEServiceImp.h index f40ffd36..a1af7001 100644 --- a/libraries/CurieBLE/src/internal/BLEServiceImp.h +++ b/libraries/CurieBLE/src/internal/BLEServiceImp.h @@ -96,6 +96,7 @@ class BLEServiceImp: public BLEAttribute{ bool discoverAttributes(BLEDevice* device, uint16_t start_handle, uint16_t end_handle); + void setDiscovering(bool enable); private: typedef LinkNode BLECharacteristicLinkNodeHeader; typedef LinkNode* BLECharacteristicNodePtr; @@ -114,6 +115,7 @@ class BLEServiceImp: public BLEAttribute{ bt_gatt_discover_params_t _discover_params; BLECharacteristicLinkNodeHeader _characteristics_header; // The characteristic link list + bool _discovering; }; #endif // _BLE_SERVICE_H_INCLUDED diff --git a/libraries/CurieBLE/src/internal/BLEUtils.cpp b/libraries/CurieBLE/src/internal/BLEUtils.cpp index 0142db07..85d12f96 100644 --- a/libraries/CurieBLE/src/internal/BLEUtils.cpp +++ b/libraries/CurieBLE/src/internal/BLEUtils.cpp @@ -26,8 +26,8 @@ String BLEUtils::macAddressBT2String(const bt_addr_le_t &bd_addr) { char mac_string[BT_ADDR_STR_LEN]; snprintf(mac_string, BT_ADDR_STR_LEN, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", - bd_addr.val[5], bd_addr.val[4], bd_addr.val[3], - bd_addr.val[2], bd_addr.val[1], bd_addr.val[0]); + bd_addr.a.val[5], bd_addr.a.val[4], bd_addr.a.val[3], + bd_addr.a.val[2], bd_addr.a.val[1], bd_addr.a.val[0]); String temp(mac_string); return temp; } @@ -51,7 +51,7 @@ void BLEUtils::macAddressString2BT(const char* mac_str, bt_addr_le_t &bd_addr) temp[0] = mac_str[i - 1]; temp[1] = mac_str[i]; - bd_addr.val[length] = strtoul(temp, NULL, 16); + bd_addr.a.val[length] = strtoul(temp, NULL, 16); length++; } @@ -65,7 +65,7 @@ bool BLEUtils::macAddressSame(const bt_addr_le_t &bd_addr1, #if 1 for (int i = 0; i < 6; i++) { - if (bd_addr1.val[i] != bd_addr2.val[i]) + if (bd_addr1.a.val[i] != bd_addr2.a.val[i]) { temp = false; break; @@ -85,7 +85,7 @@ bool BLEUtils::macAddressValid(const bt_addr_le_t &bd_addr) #else for (int i = 0; i < 6; i++) { - if (bd_addr.val[i] != 0) + if (bd_addr.a.val[i] != 0) { //pr_info(LOG_MODULE_BLE, "%s-idx %d-%.2x:%.2x", __FUNCTION__, i ,bd_addr.val[i], zero.val[i]); //pr_info(LOG_MODULE_BLE,"%s",BLEUtils::macAddressBT2String(zero).c_str()); @@ -100,7 +100,7 @@ bool BLEUtils::macAddressValid(const bt_addr_le_t &bd_addr) bt_addr_le_t* BLEUtils::bleGetLoalAddress() { - static bt_addr_le_t board_addr; + static bt_addr_le_t board_addr = {0, {0, 0, 0, 0, 0, 0}}; if (false == macAddressValid(board_addr)) ble_client_get_mac_address(&board_addr); return &board_addr; diff --git a/libraries/CurieBLE/src/internal/BLEUtils.h b/libraries/CurieBLE/src/internal/BLEUtils.h index e756843a..69f28319 100644 --- a/libraries/CurieBLE/src/internal/BLEUtils.h +++ b/libraries/CurieBLE/src/internal/BLEUtils.h @@ -32,5 +32,9 @@ namespace BLEUtils BLEDevice& getLoacalBleDevice(); bool isLocalBLE(const BLEDevice& device); + inline uint64_t getElapsedMillSeconds(uint64_t startMillSecond) + { + return (millis() - startMillSecond); + } } diff --git a/libraries/CurieBLE/src/internal/ble_client.c b/libraries/CurieBLE/src/internal/ble_client.c index 5a9e6164..101c4ed7 100644 --- a/libraries/CurieBLE/src/internal/ble_client.c +++ b/libraries/CurieBLE/src/internal/ble_client.c @@ -112,10 +112,16 @@ static struct bt_conn_cb conn_callbacks = { .le_param_updated = on_le_param_updated }; +static void ble_fill_le_address_from_oem(bt_addr_le_t *bda, + const struct curie_oem_data *oem) +{ + bda->type = oem->bt_mac_address_type; + memcpy(&bda->a, oem->bt_address, sizeof(bda->a)); +} + void ble_client_get_mac_address(bt_addr_le_t *bda) { struct curie_oem_data *p_oem = NULL; - unsigned i; /* Set the MAC address defined in Factory Data (if provided) * Otherwise, the device will default to a static random address */ @@ -124,9 +130,7 @@ void ble_client_get_mac_address(bt_addr_le_t *bda) if (!strncmp((char*)global_factory_data->oem_data.magic, FACTORY_DATA_MAGIC, 4)) { p_oem = (struct curie_oem_data *) &global_factory_data->oem_data.project_data; if (p_oem->bt_mac_address_type < 2) { - bda->type = p_oem->bt_mac_address_type; - for (i = 0; i < BLE_ADDR_LEN; i++) - bda->val[i] = p_oem->bt_address[BLE_ADDR_LEN - 1 - i]; + ble_fill_le_address_from_oem(bda, p_oem); } } } diff --git a/system/libarc32_arduino101/common/misc/slist.h b/system/libarc32_arduino101/common/misc/slist.h new file mode 100644 index 00000000..00248713 --- /dev/null +++ b/system/libarc32_arduino101/common/misc/slist.h @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * + * @brief Header where single linked list utility code is found + */ + +#ifndef __SLIST_H__ +#define __SLIST_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +struct _snode { + struct _snode *next; +}; + +typedef struct _snode sys_snode_t; + +struct _slist { + sys_snode_t *head; + sys_snode_t *tail; +}; + +typedef struct _slist sys_slist_t; + +/** + * @brief Provide the primitive to iterate on a list + * Note: the loop is unsafe and thus __sn should not be removed + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_SLIST_FOR_EACH_NODE(l, n) { + * + * } + * + * @param __sl A pointer on a sys_list_t to iterate on + * @param __sn A sys_snode_t pointer to peek each node of the list + */ +#define SYS_SLIST_FOR_EACH_NODE(__sl, __sn) \ + for (__sn = sys_slist_peek_head(__sl); __sn; \ + __sn = sys_slist_peek_next(__sn)) + +/** + * @brief Provide the primitive to safely iterate on a list + * Note: __sn can be removed, it will not break the loop. + * + * User _MUST_ add the loop statement curly braces enclosing its own code: + * + * SYS_SLIST_FOR_EACH_NODE_SAFE(l, n, s) { + * + * } + * + * @param __sl A pointer on a sys_list_t to iterate on + * @param __sn A sys_snode_t pointer to peek each node of the list + * @param __sns A sys_snode_t pointer for the loop to run safely + */ +#define SYS_SLIST_FOR_EACH_NODE_SAFE(__sl, __sn, __sns) \ + for (__sn = sys_slist_peek_head(__sl), \ + __sns = sys_slist_peek_next(__sn); \ + __sn; __sn = __sns, \ + __sns = sys_slist_peek_next(__sn)) + +/** + * @brief Initialize a list + * + * @param list A pointer on the list to initialize + */ +static inline void sys_slist_init(sys_slist_t *list) +{ + list->head = NULL; + list->tail = NULL; +} + +/** + * @brief Test if the given list is empty + * + * @param list A pointer on the list to test + * + * @return a boolean, true if it's empty, false otherwise + */ +static inline bool sys_slist_is_empty(sys_slist_t *list) +{ + return (!list->head); +} + +/** + * @brief Peek the first node from the list + * + * @param list A point on the list to peek the first node from + * + * @return A pointer on the first node of the list (or NULL if none) + */ +static inline sys_snode_t *sys_slist_peek_head(sys_slist_t *list) +{ + return list->head; +} + +/** + * @brief Peek the last node from the list + * + * @param list A point on the list to peek the last node from + * + * @return A pointer on the last node of the list (or NULL if none) + */ +static inline sys_snode_t *sys_slist_peek_tail(sys_slist_t *list) +{ + return list->tail; +} + +/** + * @brief Peek the next node from current node + * + * @param node A pointer on the node where to peek the next node + * + * @return a pointer on the next node (or NULL if none) + */ +static inline sys_snode_t *sys_slist_peek_next(sys_snode_t *node) +{ + return !node ? NULL : node->next; +} + +/** + * @brief Prepend a node to the given list + * + * @param list A pointer on the list to affect + * @param node A pointer on the node to prepend + */ +static inline void sys_slist_prepend(sys_slist_t *list, + sys_snode_t *node) +{ + node->next = list->head; + list->head = node; + + if (!list->tail) { + list->tail = list->head; + } +} + +/** + * @brief Append a node to the given list + * + * @param list A pointer on the list to affect + * @param node A pointer on the node to append + */ +static inline void sys_slist_append(sys_slist_t *list, + sys_snode_t *node) +{ + node->next = NULL; + + if (!list->tail) { + list->tail = node; + list->head = node; + } else { + list->tail->next = node; + list->tail = node; + } +} + +/** + * @brief Insert a node to the given list + * + * @param list A pointer on the list to affect + * @param prev A pointer on the previous node + * @param node A pointer on the node to insert + */ +static inline void sys_slist_insert(sys_slist_t *list, + sys_snode_t *prev, + sys_snode_t *node) +{ + if (!prev) { + sys_slist_prepend(list, node); + } else if (!prev->next) { + sys_slist_append(list, node); + } else { + node->next = prev->next; + prev->next = node; + } +} + +/** + * @brief Remove a node + * + * @param list A pointer on the list to affect + * @param prev_node A pointer on the previous node + * (can be NULL, which means the node is the list's head) + * @param node A pointer on the node to remove + */ +static inline void sys_slist_remove(sys_slist_t *list, + sys_snode_t *prev_node, + sys_snode_t *node) +{ + if (!prev_node) { + list->head = node->next; + + /* Was node also the tail? */ + if (list->tail == node) { + list->tail = list->head; + } + } else { + prev_node->next = node->next; + + /* Was node the tail? */ + if (list->tail == node) { + list->tail = prev_node; + } + } + + node->next = NULL; +} + +/** + * @brief Find and remove a node from a list + * + * @param list A pointer on the list to affect + * @param node A pointer on the node to remove from the list + */ +static inline void sys_slist_find_and_remove(sys_slist_t *list, + sys_snode_t *node) +{ + sys_snode_t *prev = NULL; + sys_snode_t *test; + + SYS_SLIST_FOR_EACH_NODE(list, test) { + if (test == node) { + sys_slist_remove(list, prev, node); + break; + } + + prev = test; + } +} + + +#ifdef __cplusplus +} +#endif + +#endif /* __SLIST_H__ */ diff --git a/system/libarc32_arduino101/common/misc/util.h b/system/libarc32_arduino101/common/misc/util.h index ab45bbb1..974f92d3 100644 --- a/system/libarc32_arduino101/common/misc/util.h +++ b/system/libarc32_arduino101/common/misc/util.h @@ -101,6 +101,7 @@ static inline int _IsPowerOfTwo(unsigned int x) #define MHZ(x) (KHZ(x) * 1000) #define _BV(bit) (1U << (bit)) +#define BIT(n) (1UL << (n)) #ifdef __cplusplus } diff --git a/system/libarc32_arduino101/drivers/bluetooth/bluetooth.h b/system/libarc32_arduino101/drivers/bluetooth/bluetooth.h index faf03b2f..5a091e1a 100644 --- a/system/libarc32_arduino101/drivers/bluetooth/bluetooth.h +++ b/system/libarc32_arduino101/drivers/bluetooth/bluetooth.h @@ -24,6 +24,7 @@ #include #include +#include #include #ifdef __cplusplus @@ -88,25 +89,18 @@ struct bt_data { BT_DATA(_type, ((uint8_t []) { _bytes }), \ sizeof((uint8_t []) { _bytes })) -/** Local advertising address type */ +/** Advertising options */ enum { - /** Use local identity address for advertising. Unless a static - * random address has been configured this will be the public - * address. - */ - BT_LE_ADV_ADDR_IDENTITY, - - /** Use local Non-resolvable Private Address (NRPA) for advertising */ - BT_LE_ADV_ADDR_NRPA, + /** Advertise as connectable. Type of advertising is determined by + * providing SCAN_RSP data and/or enabling local privacy support. + */ + BT_LE_ADV_OPT_CONNECTABLE = BIT(0), }; /** LE Advertising Parameters. */ struct bt_le_adv_param { - /** Advertising type */ - uint8_t type; - - /** Which type of own address to use for advertising */ - uint8_t addr_type; + /** Bit-field of advertising options */ + uint8_t options; /** Minimum Advertising Interval (N * 0.625) */ uint16_t interval_min; @@ -117,22 +111,23 @@ struct bt_le_adv_param { /** Helper to declare advertising parameters inline * - * @param _type Advertising Type - * @param _addr_type Local address type to use for advertising + * @param _options Advertising Options * @param _int_min Minimum advertising interval * @param _int_max Maximum advertising interval */ -#define BT_LE_ADV_PARAM(_type, _addr_type, _int_min, _int_max) \ +#define BT_LE_ADV_PARAM(_options, _int_min, _int_max) \ (&(struct bt_le_adv_param) { \ - .type = (_type), \ - .addr_type = (_addr_type), \ + .options = (_options), \ .interval_min = (_int_min), \ .interval_max = (_int_max), \ }) -#define BT_LE_ADV(t) BT_LE_ADV_PARAM(t, BT_LE_ADV_ADDR_IDENTITY, \ - BT_GAP_ADV_FAST_INT_MIN_2, \ - BT_GAP_ADV_FAST_INT_MAX_2) +#define BT_LE_ADV_CONN BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE, \ + BT_GAP_ADV_FAST_INT_MIN_2, \ + BT_GAP_ADV_FAST_INT_MAX_2) + +#define BT_LE_ADV_NCONN BT_LE_ADV_PARAM(0, BT_GAP_ADV_FAST_INT_MIN_2, \ + BT_GAP_ADV_FAST_INT_MAX_2) /** @brief Start advertising * @@ -247,6 +242,92 @@ int bt_le_scan_start(const struct bt_le_scan_param *param, bt_le_scan_cb_t cb); */ int bt_le_scan_stop(void); +struct bt_le_oob { + /** LE address. If local privacy is enabled this is Resolvable Private + * Address. + */ + bt_addr_le_t addr; +}; + +/** + * @brief Get LE local Out Of Band information + * + * This function allows to get local information that are useful for Out Of Band + * pairing or connection creation process. + * + * If privacy is enabled this will result in generating new Resolvable Private + * Address that is valid for CONFIG_BLUETOOTH_RPA_TIMEOUT seconds. This address + * will be used for advertising, active scanning and connection creation. + * + * @param oob LE related information + */ +int bt_le_oob_get_local(struct bt_le_oob *oob); + +/** @brief BR/EDR discovery result structure */ +struct bt_br_discovery_result { + /** private */ + + uint8_t private_b[4]; + + /** Remote device address */ + bt_addr_t addr; + + /** RSSI from inquiry */ + int8_t rssi; + + /** Class of Device */ + uint8_t cod[3]; + + /** Extended Inquiry Response */ + uint8_t eir[240]; +}; + +/** @brief Define a type allowing user to implement a function that can + * be used to get back BR/EDR discovery (inquiry) results. + * + * A function of this type will be called back when user application + * triggers BR/EDR discovery and discovery process completes. + * + * @param results Storage used for discovery results + * @param count Number of valid discovery results. + */ +typedef void bt_br_discovery_cb_t(struct bt_br_discovery_result *results, + size_t count); + +/** BR/EDR discovery parameters */ +struct bt_br_discovery_param { + /** True if limited discovery procedure is to be used. */ + bool limited_discovery; +}; + +/** @brief Start BR/EDR discovery + * + * Start BR/EDR discovery (inquiry) and provide results through the specified + * callback. When bt_br_discovery_cb_t is called it indicates that discovery + * has completed. + * + * @param param Discovery parameters. + * @param results Storage for discovery results. + * @param count Number of results in storage + * @param cb Callback to notify discovery results. + * + * @return Zero on success or error code otherwise, positive in case + * of protocol error or negative (POSIX) in case of stack internal error + */ +int bt_br_discovery_start(const struct bt_br_discovery_param *param, + struct bt_br_discovery_result *results, size_t count, + bt_br_discovery_cb_t cb); + +/** @brief Stop BR/EDR discovery. + * + * Stops ongoing BR/EDR discovery. If discovery was stopped by this call + * results won't be reported + * + * @return Zero on success or error code otherwise, positive in case + * of protocol error or negative (POSIX) in case of stack internal error + */ +int bt_br_discovery_stop(void); + /** @def BT_ADDR_STR_LEN * * @brief Recommended length of user string buffer for Bluetooth address @@ -312,8 +393,8 @@ static inline int bt_addr_le_to_str(const bt_addr_le_t *addr, char *str, } return snprintf(str, len, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X (%s)", - addr->val[5], addr->val[4], addr->val[3], - addr->val[2], addr->val[1], addr->val[0], type); + addr->a.val[5], addr->a.val[4], addr->a.val[3], + addr->a.val[2], addr->a.val[1], addr->a.val[0], type); } #if defined(CONFIG_BLUETOOTH_BREDR) diff --git a/system/libarc32_arduino101/drivers/bluetooth/conn.h b/system/libarc32_arduino101/drivers/bluetooth/conn.h index 1b710d6f..a4cf9a9d 100644 --- a/system/libarc32_arduino101/drivers/bluetooth/conn.h +++ b/system/libarc32_arduino101/drivers/bluetooth/conn.h @@ -20,6 +20,13 @@ #ifndef __BT_CONN_H #define __BT_CONN_H +/** + * @brief Connection management + * @defgroup bt_conn Connection management + * @ingroup bluetooth + * @{ + */ + #ifdef __cplusplus extern "C" { #endif @@ -246,7 +253,7 @@ typedef enum __packed { */ } bt_security_t; -#if defined(CONFIG_BLUETOOTH_SMP) +#if defined(CONFIG_BLUETOOTH_SMP) || defined(CONFIG_BLUETOOTH_BREDR) /** @brief Set security level for a connection. * * This function enable security (encryption) for a connection. If device is @@ -279,20 +286,7 @@ int bt_conn_security(struct bt_conn *conn, bt_security_t sec); * @return Encryption key size. */ uint8_t bt_conn_enc_key_size(struct bt_conn *conn); - -/** @brief Clear device information (bonding, keys). - * - * Clears all a bonding information (keys, etc). A bonded connection is - * disconnected. - * BT_ADDR_LE_ANY removes the of all bonded devices - * - * @param addr identity address of a bonded device - * - * @return 0 in success, error code otherwise - * - */ -int bt_conn_remove_info(const bt_addr_le_t *addr); -#endif /* CONFIG_BLUETOOTH_SMP */ +#endif /* CONFIG_BLUETOOTH_SMP || CONFIG_BLUETOOTH_BREDR */ /** Connection callback structure */ struct bt_conn_cb { @@ -304,8 +298,10 @@ struct bt_conn_cb { void (*identity_resolved)(struct bt_conn *conn, const bt_addr_le_t *rpa, const bt_addr_le_t *identity); +#endif /* CONFIG_BLUETOOTH_SMP */ +#if defined(CONFIG_BLUETOOTH_SMP) || defined(CONFIG_BLUETOOTH_BREDR) void (*security_changed)(struct bt_conn *conn, bt_security_t level); -#endif +#endif /* defined(CONFIG_BLUETOOTH_SMP) || defined(CONFIG_BLUETOOTH_BREDR) */ struct bt_conn_cb *_next; }; @@ -326,6 +322,7 @@ struct bt_conn_auth_cb { void (*passkey_entry)(struct bt_conn *conn); void (*passkey_confirm)(struct bt_conn *conn, unsigned int passkey); void (*cancel)(struct bt_conn *conn); + void (*pairing_confirm)(struct bt_conn *conn); #if defined(CONFIG_BLUETOOTH_BREDR) void (*pincode_entry)(struct bt_conn *conn, bool highsec); #endif @@ -364,18 +361,27 @@ int bt_conn_auth_passkey_entry(struct bt_conn *conn, unsigned int passkey); */ int bt_conn_auth_cancel(struct bt_conn *conn); -/** @brief Reply if passkey was confirmed by user. +/** @brief Reply if passkey was confirmed to match by user. * * This function should be called only after passkey_confirm callback from - * bt_conn_auth_cb structure was called. If passkey is confirmed to match - * then match should be true. Otherwise match should be false. + * bt_conn_auth_cb structure was called. + * + * @param conn Connection object. + * + * @return Zero on success or negative error code otherwise + */ +int bt_conn_auth_passkey_confirm(struct bt_conn *conn); + +/** @brief Reply if incoming pairing was confirmed by user. + * + * This function should be called only after pairing_confirm callback from + * bt_conn_auth_cb structure was called if user confirmed incoming pairing. * * @param conn Connection object. - * @param match True if passkey was confirmed to match, false otherwise. * * @return Zero on success or negative error code otherwise */ -int bt_conn_auth_passkey_confirm(struct bt_conn *conn, bool match); +int bt_conn_auth_pairing_confirm(struct bt_conn *conn); #if defined(CONFIG_BLUETOOTH_BREDR) /** @brief Reply with entered PIN code. @@ -392,8 +398,47 @@ int bt_conn_auth_pincode_entry(struct bt_conn *conn, const char *pin); #endif /* CONFIG_BLUETOOTH_BREDR */ #endif /* CONFIG_BLUETOOTH_SMP || CONFIG_BLUETOOTH_BREDR */ +#if defined(CONFIG_BLUETOOTH_BREDR) +/** Connection parameters for BR/EDR connections */ +struct bt_br_conn_param { + bool allow_role_switch; +}; + +/** Helper to declare BR/EDR connection parameters inline + * + * @param role_switch True if role switch is allowed + */ +#define BT_BR_CONN_PARAM(role_switch) \ + (&(struct bt_br_conn_param) { \ + .allow_role_switch = (role_switch), \ + }) + +/** Default BR/EDR connection parameters: + * Role switch allowed + */ +#define BT_BR_CONN_PARAM_DEFAULT BT_BR_CONN_PARAM(true) + + +/** @brief Initiate an BR/EDR connection to a remote device. + * + * Allows initiate new BR/EDR link to remote peer using its address. + * Returns a new reference that the the caller is responsible for managing. + * + * @param peer Remote address. + * @param param Initial connection parameters. + * + * @return Valid connection object on success or NULL otherwise. + */ +struct bt_conn *bt_conn_create_br(const bt_addr_t *peer, + const struct bt_br_conn_param *param); +#endif /* CONFIG_BLUETOOTH_BREDR */ + #ifdef __cplusplus } #endif +/** + * @} + */ + #endif /* __BT_CONN_H */ diff --git a/system/libarc32_arduino101/drivers/bluetooth/dtm.h b/system/libarc32_arduino101/drivers/bluetooth/dtm.h new file mode 100644 index 00000000..b7a72002 --- /dev/null +++ b/system/libarc32_arduino101/drivers/bluetooth/dtm.h @@ -0,0 +1,77 @@ +/* + * INTEL CONFIDENTIAL + * + * Copyright (c) 2016, Intel Corporation. All rights reserved. + * + * The source code contained or described herein and all documents related to + * the source code ("Material") are owned by Intel Corporation or its suppliers + * or licensors. + * Title to the Material remains with Intel Corporation or its suppliers and + * licensors. + * The Material contains trade secrets and proprietary and confidential + * information of Intel or its suppliers and licensors. The Material is + * protected by worldwide copyright and trade secret laws and treaty provisions. + * No part of the Material may be used, copied, reproduced, modified, published, + * uploaded, posted, transmitted, distributed, or disclosed in any way without + * Intel's prior express written permission. + * + * No license under any patent, copyright, trade secret or other intellectual + * property right is granted to or conferred upon you by disclosure or delivery + * of the Materials, either expressly, by implication, inducement, estoppel or + * otherwise. + * + * Any license under such intellectual property rights must be express and + * approved by Intel in writing + */ + +#ifndef DTM_H_ +#define DTM_H_ + +#include + +struct dtm_cmd_params; + +struct ble_dtm_rsp { + int status; + uint16_t nb; +}; + +typedef void (*dtm_rsp_func_t)(struct ble_dtm_rsp *rsp, + void *user_data); + +enum { + DTM_START_RX = 0, + DTM_START_TX, + DTM_SET_TXPOWER, + DTM_START_TX_CARRIER, + DTM_END, +}; + +struct dtm_rx_cmd { + uint8_t freq; +}; + +struct dtm_tx_cmd { + uint8_t freq; + uint8_t len; + uint8_t pattern; +}; + +struct dtm_set_txpower_cmd { + int8_t dbm; +}; + +struct dtm_cmd_params { + uint8_t cmd_type; + union { + struct dtm_rx_cmd rx; + struct dtm_tx_cmd tx; + struct dtm_set_txpower_cmd tx_pwr; + }; + dtm_rsp_func_t func; + void *user_data; +}; + +int ble_dtm_cmd(struct dtm_cmd_params *params); + +#endif diff --git a/system/libarc32_arduino101/drivers/bluetooth/gatt.h b/system/libarc32_arduino101/drivers/bluetooth/gatt.h index e9eac613..c8588998 100644 --- a/system/libarc32_arduino101/drivers/bluetooth/gatt.h +++ b/system/libarc32_arduino101/drivers/bluetooth/gatt.h @@ -20,6 +20,13 @@ #ifndef __BT_GATT_H #define __BT_GATT_H +/** + * @brief Generic Attribute Profile (GATT) + * @defgroup bt_gatt Generic Attribute Profile (GATT) + * @ingroup bluetooth + * @{ + */ + #ifdef __cplusplus extern "C" { #endif @@ -28,6 +35,7 @@ extern "C" { #include #include #include +#include #include #include #include @@ -66,18 +74,13 @@ extern "C" { * If set, requires encryption using authenticated link-key for write access. */ #define BT_GATT_PERM_WRITE_AUTHEN 0x20 -/** @def BT_GATT_PERM_READ_AUTHOR - * @brief Attribute read permission with authorization. - * - * If set, requires authorization for read access. - */ -#define BT_GATT_PERM_READ_AUTHOR 0x40 -/** @def BT_GATT_PERM_WRITE_AUTHOR - * @brief Attribute write permission with authorization. +/** @def BT_GATT_PERM_PREPARE_WRITE + * @brief Attribute prepare write permission. * - * If set, requires authorization for write access. + * If set, allows prepare writes with use of BT_GATT_WRITE_FLAG_PREPARE + * passed to write callback. */ -#define BT_GATT_PERM_WRITE_AUTHOR 0x80 +#define BT_GATT_PERM_PREPARE_WRITE 0x40 /* GATT attribute flush flags */ /** @def BT_GATT_FLUSH_DISCARD @@ -100,6 +103,14 @@ extern "C" { */ #define BT_GATT_ERR(_att_err) (-(_att_err)) +/** @def BT_GATT_WRITE_FLAG_PREPARE + * @brif Attribute prepare write flag + * + * If set, write callback should only check if the device is + * authorized but no data shall be written. + */ +#define BT_GATT_WRITE_FLAG_PREPARE 0x01 + /** @brief GATT Attribute structure. */ struct bt_gatt_attr { /** Attribute UUID */ @@ -135,7 +146,7 @@ struct bt_gatt_attr { ssize_t (*write)(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, uint16_t len, - uint16_t offset); + uint16_t offset, uint8_t flags); /** Attribute flush callback * @@ -151,9 +162,11 @@ struct bt_gatt_attr { * @return Number of bytes flushed, or in case of an error * BT_GATT_ERR() with a specific ATT error code. */ +#ifdef CONFIG_BLUETOOTH_STACK_HCI ssize_t (*flush)(struct bt_conn *conn, const struct bt_gatt_attr *attr, uint8_t flags); +#endif /** Attribute user data */ void *user_data; @@ -450,16 +463,16 @@ ssize_t bt_gatt_attr_read_included(struct bt_conn *conn, /** @def BT_GATT_INCLUDE_SERVICE * @brief Include Service Declaration Macro. * - * Helper macro to declare a include service attribute. + * Helper macro to declare database internal include service attribute. * - * @param _service Service attribute value. + * @param _service_incl, the first service attribute of service to include */ -#define BT_GATT_INCLUDE_SERVICE(_service) \ +#define BT_GATT_INCLUDE_SERVICE(_service_incl) \ { \ .uuid = BT_UUID_GATT_INCLUDE, \ .perm = BT_GATT_PERM_READ, \ .read = bt_gatt_attr_read_included, \ - .user_data = _service, \ + .user_data = _service_incl, \ } /** @brief Read Characteristic Attribute helper. @@ -551,7 +564,7 @@ ssize_t bt_gatt_attr_read_ccc(struct bt_conn *conn, */ ssize_t bt_gatt_attr_write_ccc(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, - uint16_t len, uint16_t offset); + uint16_t len, uint16_t offset, uint8_t flags); /** @def BT_GATT_CCC * @brief Client Characteristic Configuration Declaration Macro. @@ -751,11 +764,11 @@ int bt_gatt_notify(struct bt_conn *conn, const struct bt_gatt_attr *attr, * * @param conn Connection object. * @param attr Attribute object. - * @param err: 0 success, error in the other case + * @param err ATT error code */ typedef void (*bt_gatt_indicate_func_t)(struct bt_conn *conn, const struct bt_gatt_attr *attr, - int err); + uint8_t err); /** @brief GATT Indicate Value parameters */ struct bt_gatt_indicate_params { @@ -792,9 +805,10 @@ int bt_gatt_indicate(struct bt_conn *conn, /** @brief Response callback function * * @param conn Connection object. - * @param err Error code. + * @param err ATT error code. */ -typedef void (*bt_gatt_rsp_func_t)(struct bt_conn *conn, uint8_t err); +typedef void (*bt_gatt_rsp_func_t)(struct bt_conn *conn, uint8_t err, + const void *data); /** @brief Exchange MTU * @@ -881,12 +895,12 @@ struct bt_gatt_read_params; /** @brief Read callback function * * @param conn Connection object. - * @param err Error code. + * @param err ATT error code. * @param params Read parameters used. * @param data Attribute value data. NULL means read has completed. * @param length Attribute value length. */ -typedef uint8_t (*bt_gatt_read_func_t)(struct bt_conn *conn, int err, +typedef uint8_t (*bt_gatt_read_func_t)(struct bt_conn *conn, uint8_t err, struct bt_gatt_read_params *params, const void *data, uint16_t length); @@ -926,30 +940,35 @@ struct bt_gatt_read_params { */ int bt_gatt_read(struct bt_conn *conn, struct bt_gatt_read_params *params); -/** @brief Write Response callback function - * - * @param conn Connection object. - * @param err Error code. - * @param data Data pointer in the write request. - */ -typedef void (*bt_gatt_write_rsp_func_t)(struct bt_conn *conn, uint8_t err, const void *data); + +/** @brief GATT Write parameters */ +struct bt_gatt_write_params { + /** Response callback */ + bt_gatt_rsp_func_t func; + /** Attribute handle */ + uint16_t handle; + /** Attribute data offset */ + uint16_t offset; + /** Data to be written */ + const void *data; + /** Length of the data */ + uint16_t length; +}; /** @brief Write Attribute Value by handle * * This procedure write the attribute value and return the result in the * callback. * + * Note: This procedure is asynchronous therefore the parameters need to + * remains valid while it is active. + * * @param conn Connection object. - * @param handle Attribute handle. - * @param offset Attribute data offset. - * @param data Data to be written. - * @param length Data length. - * @param func Callback function. + * @param params Write parameters. * * @return 0 in case of success or negative value in case of error. */ -int bt_gatt_write(struct bt_conn *conn, uint16_t handle, uint16_t offset, - const void *data, uint16_t length, bt_gatt_write_rsp_func_t func); +int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params); /** @brief Write Attribute Value by handle without response * @@ -1042,4 +1061,8 @@ void bt_gatt_cancel(struct bt_conn *conn); } #endif +/** + * @} + */ + #endif /* __BT_GATT_H */ diff --git a/system/libarc32_arduino101/drivers/bluetooth/hci.h b/system/libarc32_arduino101/drivers/bluetooth/hci.h index f7ff52c1..dae8d04d 100644 --- a/system/libarc32_arduino101/drivers/bluetooth/hci.h +++ b/system/libarc32_arduino101/drivers/bluetooth/hci.h @@ -34,12 +34,12 @@ typedef struct { } bt_addr_t; typedef struct { - uint8_t type; - uint8_t val[6]; + uint8_t type; + bt_addr_t a; } bt_addr_le_t; #define BT_ADDR_ANY (&(bt_addr_t) {{0, 0, 0, 0, 0, 0} }) -#define BT_ADDR_LE_ANY (&(bt_addr_le_t) { 0, {0, 0, 0, 0, 0, 0} }) +#define BT_ADDR_LE_ANY (&(bt_addr_le_t) { 0, { {0, 0, 0, 0, 0, 0} } }) static inline int bt_addr_cmp(const bt_addr_t *a, const bt_addr_t *b) { @@ -65,6 +65,7 @@ static inline void bt_addr_le_copy(bt_addr_le_t *dst, const bt_addr_le_t *src) #define BT_HCI_ERR_UNKNOWN_CONN_ID 0x02 #define BT_HCI_ERR_AUTHENTICATION_FAIL 0x05 #define BT_HCI_ERR_INSUFFICIENT_RESOURCES 0x0d +#define BT_HCI_ERR_UNSUPP_FEATURE_PARAMS_VAL 0x11 #define BT_HCI_ERR_REMOTE_USER_TERM_CONN 0x13 #define BT_HCI_ERR_PAIRING_NOT_ALLOWED 0x18 #define BT_HCI_ERR_UNSUPP_REMOTE_FEATURE 0x1a @@ -138,6 +139,12 @@ struct bt_hci_cmd_hdr { #define BT_HCI_GENERAL_BONDING 0x04 #define BT_HCI_GENERAL_BONDING_MITM 0x05 +/* + * MITM protection is enabled in SSP authentication requirements octet when + * LSB bit is set. + */ +#define BT_MITM 0x01 + /* I/O capabilities */ #define BT_IO_DISPLAY_ONLY 0x00 #define BT_IO_DISPLAY_YESNO 0x01 @@ -174,12 +181,40 @@ struct bt_hci_cmd_hdr { /* Construct OpCode from OGF and OCF */ #define BT_OP(ogf, ocf) ((ocf) | ((ogf) << 10)) +#define BT_HCI_OP_INQUIRY BT_OP(BT_OGF_LINK_CTRL, 0x0001) +struct bt_hci_op_inquiry { + uint8_t lap[3]; + uint8_t length; + uint8_t num_rsp; +} __packed; + +#define BT_HCI_OP_INQUIRY_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x0002) + +#define BT_HCI_OP_CONNECT BT_OP(BT_OGF_LINK_CTRL, 0x0005) +struct bt_hci_cp_connect { + bt_addr_t bdaddr; + uint16_t packet_type; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint16_t clock_offset; + uint8_t allow_role_switch; +} __packed; + #define BT_HCI_OP_DISCONNECT BT_OP(BT_OGF_LINK_CTRL, 0x0006) struct bt_hci_cp_disconnect { uint16_t handle; uint8_t reason; } __packed; +#define BT_HCI_OP_CONNECT_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x0008) +struct bt_hci_cp_connect_cancel { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_connect_cancel { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + #define BT_HCI_OP_ACCEPT_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x0009) struct bt_hci_cp_accept_conn_req { bt_addr_t bdaddr; @@ -223,6 +258,34 @@ struct bt_hci_rp_pin_code_neg_reply { bt_addr_t bdaddr; } __packed; +#define BT_HCI_OP_AUTH_REQUESTED BT_OP(BT_OGF_LINK_CTRL, 0x0011) +struct bt_hci_cp_auth_requested { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_SET_CONN_ENCRYPT BT_OP(BT_OGF_LINK_CTRL, 0x0013) +struct bt_hci_cp_set_conn_encrypt { + uint16_t handle; + uint8_t encrypt; +} __packed; + +#define BT_HCI_OP_REMOTE_NAME_REQUEST BT_OP(BT_OGF_LINK_CTRL, 0x0019) +struct bt_hci_cp_remote_name_request { + bt_addr_t bdaddr; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint16_t clock_offset; +} __packed; + +#define BT_HCI_OP_REMOTE_NAME_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x001a) +struct bt_hci_cp_remote_name_cancel { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_remote_name_cancel { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + #define BT_HCI_OP_IO_CAPABILITY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002b) struct bt_hci_cp_io_capability_reply { bt_addr_t bdaddr; @@ -231,6 +294,27 @@ struct bt_hci_cp_io_capability_reply { uint8_t authentication; } __packed; +#define BT_HCI_OP_USER_CONFIRM_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002c) +#define BT_HCI_OP_USER_CONFIRM_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002d) +struct bt_hci_cp_user_confirm_reply { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_user_confirm_reply { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_USER_PASSKEY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002e) +struct bt_hci_cp_user_passkey_reply { + bt_addr_t bdaddr; + uint32_t passkey; +} __packed; + +#define BT_HCI_OP_USER_PASSKEY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002f) +struct bt_hci_cp_user_passkey_neg_reply { + bt_addr_t bdaddr; +} __packed; + #define BT_HCI_OP_IO_CAPABILITY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x0034) struct bt_hci_cp_io_capability_neg_reply { bt_addr_t bdaddr; @@ -271,6 +355,11 @@ struct bt_hci_cp_host_num_completed_packets { struct bt_hci_handle_count h[0]; } __packed; +#define BT_HCI_OP_WRITE_INQUIRY_MODE BT_OP(BT_OGF_BASEBAND, 0x0045) +struct bt_hci_cp_write_inquiry_mode { + uint8_t mode; +} __packed; + #define BT_HCI_OP_WRITE_SSP_MODE BT_OP(BT_OGF_BASEBAND, 0x0056) struct bt_hci_cp_write_ssp_mode { uint8_t mode; @@ -351,8 +440,8 @@ struct bt_hci_rp_le_read_local_features { /* Needed in advertising reports when getting info about */ #define BT_LE_ADV_SCAN_RSP 0x04 -#define BT_HCI_OP_LE_SET_ADV_PARAMETERS BT_OP(BT_OGF_LE, 0x0006) -struct bt_hci_cp_le_set_adv_parameters { +#define BT_HCI_OP_LE_SET_ADV_PARAM BT_OP(BT_OGF_LE, 0x0006) +struct bt_hci_cp_le_set_adv_param { uint16_t min_interval; uint16_t max_interval; uint8_t type; @@ -502,6 +591,13 @@ struct bt_hci_cp_le_generate_dhkey { /* Event definitions */ +#define BT_HCI_EVT_VENDOR 0xff + +#define BT_HCI_EVT_INQUIRY_COMPLETE 0x01 +struct bt_hci_evt_inquiry_complete { + uint8_t status; +} __packed; + #define BT_HCI_EVT_CONN_COMPLETE 0x03 struct bt_hci_evt_conn_complete { uint8_t status; @@ -525,6 +621,19 @@ struct bt_hci_evt_disconn_complete { uint8_t reason; } __packed; +#define BT_HCI_EVT_AUTH_COMPLETE 0x06 +struct bt_hci_evt_auth_complete { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_EVT_REMOTE_NAME_REQ_COMPLETE 0x07 +struct bt_hci_evt_remote_name_req_complete { + uint8_t status; + bt_addr_t bdaddr; + uint8_t name[248]; +} __packed; + #define BT_HCI_EVT_ENCRYPT_CHANGE 0x08 struct bt_hci_evt_encrypt_change { uint8_t status; @@ -579,6 +688,28 @@ struct bt_hci_ev_link_key_notify { uint8_t key_type; } __packed; +#define BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI 0x22 +struct bt_hci_evt_inquiry_result_with_rssi { + bt_addr_t addr; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint8_t cod[3]; + uint16_t clock_offset; + int8_t rssi; +} __packed; + +#define BT_HCI_EVT_EXTENDED_INQUIRY_RESULT 0x2f +struct bt_hci_evt_extended_inquiry_result { + uint8_t num_reports; + bt_addr_t addr; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint8_t cod[3]; + uint16_t clock_offset; + int8_t rssi; + uint8_t eir[240]; +} __packed; + #define BT_HCI_EVT_ENCRYPT_KEY_REFRESH_COMPLETE 0x30 struct bt_hci_evt_encrypt_key_refresh_complete { uint8_t status; @@ -598,12 +729,29 @@ struct bt_hci_evt_io_capa_resp { uint8_t authentication; } __packed; +#define BT_HCI_EVT_USER_CONFIRM_REQ 0x33 +struct bt_hci_evt_user_confirm_req { + bt_addr_t bdaddr; + uint32_t passkey; +} __packed; + +#define BT_HCI_EVT_USER_PASSKEY_REQ 0x34 +struct bt_hci_evt_user_passkey_req { + bt_addr_t bdaddr; +} __packed; + #define BT_HCI_EVT_SSP_COMPLETE 0x36 struct bt_hci_evt_ssp_complete { uint8_t status; bt_addr_t bdaddr; } __packed; +#define BT_HCI_EVT_USER_PASSKEY_NOTIFY 0x3b +struct bt_hci_evt_user_passkey_notify { + bt_addr_t bdaddr; + uint32_t passkey; +} __packed; + #define BT_HCI_EVT_LE_META_EVENT 0x3e struct bt_hci_evt_le_meta_event { uint8_t subevent; diff --git a/system/libarc32_arduino101/drivers/bluetooth/storage.h b/system/libarc32_arduino101/drivers/bluetooth/storage.h new file mode 100644 index 00000000..e86d2f92 --- /dev/null +++ b/system/libarc32_arduino101/drivers/bluetooth/storage.h @@ -0,0 +1,152 @@ +/** @file + * @brief Bluetooth subsystem persistent storage APIs. + */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __BT_STORAGE_H +#define __BT_STORAGE_H + +/** + * @brief Persistent Storage + * @defgroup bt_storage Persistent Storage + * @ingroup bluetooth + * @{ + */ + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Well known storage keys */ +enum { + /** Identity Address. + * Type: bt_addr_le_t (7 bytes) + */ + BT_STORAGE_ID_ADDR, + + /** Local Identity Resolving Key. + * Type: uint8_t key[16] + */ + BT_STORAGE_LOCAL_IRK, + + /** List of addresses of remote devices. + * Type: bt_addr_le_t addrs[n] (length is variable). + * + * This is only used for reading. Modification of the list happens + * implicitly by writing entries for each remote device. This value + * is only used with the local storage, i.e. NULL as the target + * bt_addr_le_t passed to the read callback. + */ + BT_STORAGE_ADDRESSES, + + /** Slave Long Term Key for legacy pairing. + * Type: struct bt_storage_ltk + */ + BT_STORAGE_SLAVE_LTK, + + /** Long Term Key for legacy pairing. + * Type: struct bt_storage_ltk + */ + BT_STORAGE_LTK, + + /** Identity Resolving Key + * Type: uint8_t key[16] + */ + BT_STORAGE_IRK, +}; + +/** LTK key flags */ +enum { + /* Key has been generated with MITM protection */ + BT_STORAGE_LTK_AUTHENTICATED = BIT(0), + + /* Key has been generated using the LE Secure Connection pairing */ + BT_STORAGE_LTK_SC = BIT(1), +}; + +struct bt_storage_ltk { + uint8_t flags; + /* Encryption key size used to generate key */ + uint8_t size; + uint16_t ediv; + uint8_t rand[8]; + uint8_t val[16]; +}; + +struct bt_storage { + /** Read the value of a key from storage. + * + * @param addr Remote address or NULL for local storage + * @param key BT_STORAGE_* key to read + * @param data Memory location to place the data + * @param length Maximum number of bytes to read + * + * @return Number of bytes read or negative error value on + * failure. + */ + ssize_t (*read)(const bt_addr_le_t *addr, uint16_t key, + void *data, size_t length); + + /** Write the value of a key to storage. + * + * @param addr Remote address or NULL for local storage + * @param key BT_STORAGE_* key to write + * @param data Memory location of the data + * @param length Number of bytes to write + * + * @return Number of bytes written or negative error value on + * failure. + */ + ssize_t (*write)(const bt_addr_le_t *addr, uint16_t key, + const void *data, size_t length); + + /** Clear all keys for a specific address + * + * @param addr Remote address, BT_ADDR_LE_ANY for all + * remote devices, or NULL for local storage. + * + * @return 0 on success or negative error value on failure. + */ + int (*clear)(const bt_addr_le_t *addr); + +}; + +void bt_storage_register(const struct bt_storage *storage); + +/** Clear all storage keys for a specific address + * + * @param addr Remote address, NULL for local storage or + * BT_ADDR_LE_ANY to clear all remote devices. + * + * @return 0 on success or negative error value on failure. + */ +int bt_storage_clear(bt_addr_le_t *addr); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* __BT_STORAGE_H */ diff --git a/system/libarc32_arduino101/drivers/rpc/rpc.h b/system/libarc32_arduino101/drivers/rpc/rpc.h index 5d45d463..7fea08e9 100644 --- a/system/libarc32_arduino101/drivers/rpc/rpc.h +++ b/system/libarc32_arduino101/drivers/rpc/rpc.h @@ -18,6 +18,7 @@ #define RPC_H_ #include +#include /** Identifiers of the signature supported by the RPC */ enum { @@ -25,106 +26,108 @@ enum { SIG_TYPE_S, SIG_TYPE_P, SIG_TYPE_S_B, - SIG_TYPE_B_B_P, SIG_TYPE_S_P, - SIG_TYPE_S_B_P, - SIG_TYPE_S_B_B_P + SIG_TYPE_CONTROL = 0xFF }; /** * RPC memory allocation function, must be implemented by the user of the RPC. * - * This function is called by the RPC mechanism to allocate a buffer for transmission - * of a serialized function. The function should not fail. + * This function is called by the RPC mechanism to allocate a buffer for + * transmission of a serialized function. The function should not fail. * - * @param length Length of the buffer to allocate + * @param length Length of the buffer to allocate. * - * @return Pointer to the allocated buffer, the allocation shall not fail, error must - * be handled internally + * @return Pointer to the allocated buffer, the allocation shall not fail, + * error must be handled internally */ -uint8_t * rpc_alloc_cb(uint16_t length); +uint8_t *rpc_alloc_cb(uint16_t length); /** - * RPC transmission function, must be implemented by the user of the RPC. + * RPC memory free function, must be implemented by the user of the RPC. + * + * This function is called by the RPC mechanism to free a buffer passed to the + * deserialization function as soon as all the data was consumed. * - * @param p_buf Pointer to the buffer allocated for transmission by @ref rpc_alloc_cb - * @param length Length of the buffer to transmit + * @param buf Pointer to the buffer passed to the deserialization function. */ -void rpc_transmit_cb(uint8_t * p_buf, uint16_t length); +void rpc_free_cb(const uint8_t *buf); /** - * RPC serialization function to serialize a function that does not require any parameter. + * RPC transmission function, must be implemented by the user of the RPC. * - * @param fn_index Index of the function + * @param buf Pointer to the buffer allocated for transmission + * by @ref rpc_alloc_cb */ -void rpc_serialize_none(uint8_t fn_index); +void rpc_transmit_cb(uint8_t *buf); /** - * RPC serialization function to serialize a function that expects a structure as parameter. + * RPC initialization function that notifies the peer with an initialization + * packet containing the information to check the compatibility of the + * frameworks. * - * @param fn_index Index of the function - * @param struct_data Pointer to the structure to serialize - * @param struct_length Length of the structure to serialize + * @param version Local version to send to the peer. */ -void rpc_serialize_s(uint8_t fn_index, const void * struct_data, uint8_t struct_length); +void rpc_init(uint32_t version); /** - * RPC serialization function to serialize a function that expects a structure as parameter. + * RPC initialization packet reception function, can optionally be implemented + * by the user of the RPC. If this function is not implemented, it will default + * to an empty function. * - * @param fn_index Index of the function - * @param struct_data Pointer to the structure to serialize - * @param struct_length Length of the structure to serialize - * @param p_priv Pointer to serialize + * This function is called by the RPC mechanism when an initialization packet is + * received from the connected peer. + * + * @param version Peer advertised version. + * @param compatible True if the peer runs a compatible RPC framework. + */ +void rpc_init_cb(uint32_t version, bool compatible); + +/** RPC serialize hash number generation. + * + * @return The unique identifier of the RPC deserialization. */ -void rpc_serialize_s_p(uint8_t fn_index, const void * struct_data, uint8_t struct_length, void * p_priv); +uint32_t rpc_serialize_hash(void); /** - * RPC serialization function to serialize a function that expects a pointer as parameter. + * RPC serialization function to serialize a function that does not require any + * parameter. * * @param fn_index Index of the function - * @param p_priv Pointer to serialize */ -void rpc_serialize_p(uint8_t fn_index, void * p_priv); +void rpc_serialize_none(uint8_t fn_index); /** * RPC serialization function to serialize a function that expects a structure - * and a buffer as parameters. + * as parameter. * * @param fn_index Index of the function * @param struct_data Pointer to the structure to serialize * @param struct_length Length of the structure to serialize - * @param vbuf Pointer to the buffer to serialize - * @param vbuf_length Length of the buffer to serialize */ -void rpc_serialize_s_b(uint8_t fn_index, const void * struct_data, uint8_t struct_length, const void * vbuf, uint16_t vbuf_length); +void rpc_serialize_s(uint8_t fn_index, const void *struct_data, + uint8_t struct_length); /** - * RPC serialization function to serialize a function that expects a structure - * and a buffer as parameters. + * RPC serialization function to serialize a function that expects a pointer as + * parameter. * * @param fn_index Index of the function - * @param vbuf1 Pointer to the buffer1 to serialize - * @param vbuf1_length Length of the buffer1 to serialize - * @param vbuf2 Pointer to the buffer2 to serialize - * @param vbuf2_length Length of the buffer2 to serialize * @param p_priv Pointer to serialize */ -void rpc_serialize_b_b_p(uint8_t fn_index, const void * vbuf1, uint16_t vbuf1_length, - const void * vbuf2, uint16_t vbuf2_length, void * p_priv); +void rpc_serialize_p(uint8_t fn_index, void *p_priv); /** * RPC serialization function to serialize a function that expects a structure - * and a buffer as parameters. + * and a pointer as parameters. * * @param fn_index Index of the function * @param struct_data Pointer to the structure to serialize * @param struct_length Length of the structure to serialize - * @param vbuf Pointer to the buffer to serialize - * @param vbuf_length Length of the buffer to serialize * @param p_priv Pointer to serialize */ -void rpc_serialize_s_b_p(uint8_t fn_index, const void * struct_data, uint8_t struct_length, - const void * vbuf, uint16_t vbuf_length, void * p_priv); +void rpc_serialize_s_p(uint8_t fn_index, const void *struct_data, + uint8_t struct_length, void *p_priv); /** * RPC serialization function to serialize a function that expects a structure @@ -133,20 +136,25 @@ void rpc_serialize_s_b_p(uint8_t fn_index, const void * struct_data, uint8_t str * @param fn_index Index of the function * @param struct_data Pointer to the structure to serialize * @param struct_length Length of the structure to serialize - * @param vbuf1 Pointer to the buffer1 to serialize - * @param vbuf1_length Length of the buffer1 to serialize - * @param vbuf2 Pointer to the buffer2 to serialize - * @param vbuf2_length2 Length of the buffer2 to serialize - * @param p_priv Pointer to serialize + * @param vbuf Pointer to the buffer to serialize + * @param vbuf_length Length of the buffer to serialize */ -void rpc_serialize_s_b_b_p(uint8_t fn_index, const void * struct_data, uint8_t struct_length, - const void * vbuf1, uint16_t vbuf1_length, const void * vbuf2, uint16_t vbuf2_length, void * p_priv); +void rpc_serialize_s_b(uint8_t fn_index, const void *struct_data, + uint8_t struct_length, const void *vbuf, + uint16_t vbuf_length); -/** RPC deserialization function, shall be invoked when a buffer is received over the transport interface. +/** + * RPC deserialization function, shall be invoked when a buffer is received + * over the transport interface. * * @param p_buf Pointer to the received buffer * @param length Length of the received buffer */ -void rpc_deserialize(const uint8_t * p_buf, uint16_t length); +void rpc_deserialize(const uint8_t *p_buf, uint16_t length); +/** RPC deserialize hash number generation. + * + * @return The unique identifier of the RPC deserialization. + */ +uint32_t rpc_deserialize_hash(void); #endif /* RPC_H_*/ diff --git a/system/libarc32_arduino101/drivers/rpc/rpc_deserialize.c b/system/libarc32_arduino101/drivers/rpc/rpc_deserialize.c index e3f568d0..5dd6fa7c 100644 --- a/system/libarc32_arduino101/drivers/rpc/rpc_deserialize.c +++ b/system/libarc32_arduino101/drivers/rpc/rpc_deserialize.c @@ -19,6 +19,10 @@ #include "rpc.h" +#ifndef __weak +#define __weak __attribute__((weak)) +#endif + extern void panic(int err); /* Include the functions offered */ @@ -33,425 +37,354 @@ extern void panic(int err); #error "File is compiled but should not" #endif -/* Build the list of prototypes and check that list are made only of matching signatures */ -#define FN_SIG_NONE(__fn) void __fn(void); +/* Build the list of prototypes and check that list are made only of matching + * signatures + */ +#define FN_SIG_NONE(__fn) void __fn(void); LIST_FN_SIG_NONE #undef FN_SIG_NONE -#define FN_SIG_S(__fn, __s) void __fn(__s p_s); +#define FN_SIG_S(__fn, __s) void __fn(__s p_s); LIST_FN_SIG_S #undef FN_SIG_S -#define FN_SIG_P(__fn, __type) void __fn(__type p_priv); +#define FN_SIG_P(__fn, __type) void __fn(__type priv); LIST_FN_SIG_P #undef FN_SIG_P -#define FN_SIG_S_B(__fn, __s, __type, __length) void __fn(__s p_s, __type p_buf, __length length); +#define FN_SIG_S_B(__fn, __s, __type, __length) \ + void __fn(__s p_s, __type buf, __length length); LIST_FN_SIG_S_B #undef FN_SIG_S_B -#define FN_SIG_B_B_P(__fn, __type1, __length1, __type2, __length2, __type3) \ - void __fn(__type1 p_buf1, __length1 length1, __type2 p_buf2, __length2 length2, __type3 p_priv); -LIST_FN_SIG_B_B_P -#undef FN_SIG_B_B_P - -#define FN_SIG_S_P(__fn, __s, __type) void __fn(__s p_s, __type p_priv); +#define FN_SIG_S_P(__fn, __s, __type) void __fn(__s p_s, __type priv); LIST_FN_SIG_S_P #undef FN_SIG_S_P -#define FN_SIG_S_B_P(__fn, __s, __type, __length, __type_ptr) \ - void __fn(__s p_s, __type p_buf, __length length, __type_ptr p_priv); -LIST_FN_SIG_S_B_P -#undef FN_SIG_S_B_P - -#define FN_SIG_S_B_B_P(__fn, __s, __type1, __length1, __type2, __length2, __type_ptr) \ - void __fn(__s p_s, __type1 p_buf1, __length1 length1, __type2 p_buf2, __length2 length2, __type_ptr p_priv); -LIST_FN_SIG_S_B_B_P -#undef FN_SIG_S_B_B_P - - - /* 1 - define the size check arrays */ #define FN_SIG_NONE(__fn) -#define FN_SIG_S(__fn, __s) sizeof(*((__s)0)), +#define FN_SIG_S(__fn, __s) sizeof(*((__s)0)), #define FN_SIG_P(__fn, __type) -#define FN_SIG_S_B(__fn, __s, __type, __length) sizeof(*((__s)0)), - -#define FN_SIG_B_B_P(__fn, __type1, __length1, __type2, __length2, __type3) sizeof(*((__s)0)), - -#define FN_SIG_S_P(__fn, __s, __type) sizeof(*((__s)0)), +#define FN_SIG_S_B(__fn, __s, __type, __length) sizeof(*((__s)0)), -#define FN_SIG_S_B_P(__fn, __s, __type, __length, __type_ptr) sizeof(*((__s)0)), - -#define FN_SIG_S_B_B_P(__fn, __s, __type1, __length1, __type2, __length2, __type3) sizeof(*((__s)0)), +#define FN_SIG_S_P(__fn, __s, __type) sizeof(*((__s)0)), static uint8_t m_size_s[] = { LIST_FN_SIG_S }; static uint8_t m_size_s_b[] = { LIST_FN_SIG_S_B }; static uint8_t m_size_s_p[] = { LIST_FN_SIG_S_P }; -static uint8_t m_size_s_b_p[] = { LIST_FN_SIG_S_B_P }; -static uint8_t m_size_s_b_b_p[] = { LIST_FN_SIG_S_B_B_P }; #undef FN_SIG_NONE #undef FN_SIG_S #undef FN_SIG_P #undef FN_SIG_S_B -#undef FN_SIG_B_B_P #undef FN_SIG_S_P -#undef FN_SIG_S_B_P -#undef FN_SIG_S_B_B_P /* 2- build the enumerations list */ -#define FN_SIG_NONE(__fn) fn_index_##__fn, -#define FN_SIG_S(__fn, __s) FN_SIG_NONE(__fn) -#define FN_SIG_P(__fn, __type) FN_SIG_NONE(__fn) -#define FN_SIG_S_B(__fn, __s, __type, __length) FN_SIG_NONE(__fn) -#define FN_SIG_B_B_P(__fn, __type1, __length1, __type2, __length2, __type3) FN_SIG_NONE(__fn) -#define FN_SIG_S_P(__fn, __s, __type) FN_SIG_NONE(__fn) -#define FN_SIG_S_B_P(__fn, __s, __type, __length, __type_ptr) FN_SIG_NONE(__fn) -#define FN_SIG_S_B_B_P(__fn, __s, __type1, __length1, __type2, __length2, __type3) FN_SIG_NONE(__fn) +#define FN_SIG_NONE(__fn) fn_index_##__fn, +#define FN_SIG_S(__fn, __s) FN_SIG_NONE(__fn) +#define FN_SIG_P(__fn, __type) FN_SIG_NONE(__fn) +#define FN_SIG_S_B(__fn, __s, __type, __length) FN_SIG_NONE(__fn) +#define FN_SIG_S_P(__fn, __s, __type) FN_SIG_NONE(__fn) /* Build the list of function indexes in the deserialization array */ enum { LIST_FN_SIG_NONE fn_none_index_max }; enum { LIST_FN_SIG_S fn_s_index_max }; enum { LIST_FN_SIG_P fn_p_index_max }; enum { LIST_FN_SIG_S_B fn_s_b_index_max }; -enum { LIST_FN_SIG_B_B_P fn_b_b_p_index_max }; enum { LIST_FN_SIG_S_P fn_s_p_index_max }; -enum { LIST_FN_SIG_S_B_P fn_s_b_p_index_max }; -enum { LIST_FN_SIG_S_B_B_P fn_s_b_b_p_index_max }; #undef FN_SIG_NONE #undef FN_SIG_S #undef FN_SIG_P #undef FN_SIG_S_B -#undef FN_SIG_B_B_P #undef FN_SIG_S_P -#undef FN_SIG_S_B_P -#undef FN_SIG_S_B_B_P /* 3- build the array */ -#define FN_SIG_NONE(__fn) [fn_index_##__fn] = (void*)__fn, -#define FN_SIG_S(__fn, __s) FN_SIG_NONE(__fn) -#define FN_SIG_P(__fn, __type) FN_SIG_NONE(__fn) -#define FN_SIG_S_B(__fn, __s, __type, __length) FN_SIG_NONE(__fn) -#define FN_SIG_B_B_P(__fn, __type1, __length1, __type2, __length2, __type3) FN_SIG_NONE(__fn) -#define FN_SIG_S_P(__fn, __s, __type) FN_SIG_NONE(__fn) -#define FN_SIG_S_B_P(__fn, __s, __type, __length, __type_ptr) FN_SIG_NONE(__fn) -#define FN_SIG_S_B_B_P(__fn, __s, __type1, __length1, __type2, __length2, __type3) FN_SIG_NONE(__fn) +#define FN_SIG_NONE(__fn) [fn_index_##__fn] = \ + (void *)__fn, +#define FN_SIG_S(__fn, __s) FN_SIG_NONE(__fn) +#define FN_SIG_P(__fn, __type) FN_SIG_NONE(__fn) +#define FN_SIG_S_B(__fn, __s, __type, __length) \ + FN_SIG_NONE(__fn) +#define FN_SIG_S_P(__fn, __s, __type) FN_SIG_NONE(__fn) static void (*m_fct_none[])(void) = { LIST_FN_SIG_NONE }; -static void (*m_fct_s[])(void * structure) = { LIST_FN_SIG_S }; -static void (*m_fct_p[])(void * pointer) = { LIST_FN_SIG_P }; -static void (*m_fct_s_b[])(void * structure, void * buffer, uint8_t length) = { LIST_FN_SIG_S_B }; -static void (*m_fct_b_b_p[])(void * buffer1, uint8_t length1, void * buffer2, uint8_t length2, void * pointer) = { LIST_FN_SIG_B_B_P }; -static void (*m_fct_s_p[])(void * structure, void * pointer) = { LIST_FN_SIG_S_P }; -static void (*m_fct_s_b_p[])(void * structure, void * buffer, uint8_t length, void * pointer) = { LIST_FN_SIG_S_B_P }; -static void (*m_fct_s_b_b_p[])(void * structure, void * buffer1, uint8_t length1, void * buffer2, uint8_t length2, void * pointer) = { LIST_FN_SIG_S_B_B_P }; - -static const uint8_t * deserialize_struct(const uint8_t *p, const uint8_t **pp_struct, uint8_t *p_struct_length) { - uint8_t struct_length; +static void (*m_fct_s[])(void *structure) = { LIST_FN_SIG_S }; +static void (*m_fct_p[])(void *pointer) = { LIST_FN_SIG_P }; +static void (*m_fct_s_b[])(void *structure, void *buffer, + uint16_t length) = { LIST_FN_SIG_S_B }; +static void (*m_fct_s_p[])(void *structure, + void *pointer) = { LIST_FN_SIG_S_P }; + +#undef FN_SIG_NONE +#undef FN_SIG_S +#undef FN_SIG_P +#undef FN_SIG_S_B +#undef FN_SIG_S_P + +#define DJB2_HASH(__h, __v) ((__h << 5) + __h) + __v + +#define FN_SIG_NONE(__fn) \ + hash = DJB2_HASH(hash, 1); + +#define FN_SIG_S(__fn, __s) \ + hash = DJB2_HASH(hash, 2); \ + hash = DJB2_HASH(hash, sizeof(*((__s)0))); + +#define FN_SIG_P(__fn, __type) \ + hash = DJB2_HASH(hash, 3); + +#define FN_SIG_S_B(__fn, __s, __type, __length) \ + hash = DJB2_HASH(hash, 4); \ + hash = DJB2_HASH(hash, sizeof(*((__s)0))); + +#define FN_SIG_S_P(__fn, __s, __type) \ + hash = DJB2_HASH(hash, 6); \ + hash = DJB2_HASH(hash, sizeof(*((__s)0))); + +uint32_t rpc_deserialize_hash(void) +{ + uint32_t hash = 5381; - struct_length = *p++; - *pp_struct = p; - *p_struct_length = struct_length; + LIST_FN_SIG_NONE; + LIST_FN_SIG_S; + LIST_FN_SIG_P; + LIST_FN_SIG_S_B; + LIST_FN_SIG_S_P; - return p + struct_length; + return hash; } -static const uint8_t * deserialize_buf(const uint8_t *p, const uint8_t **pp_buf, uint16_t *p_buflen) { +static const uint8_t *deserialize_struct(const uint8_t *p, + const uint8_t **struct_ptr, + uint8_t *struct_length) +{ + *struct_length = *p++; + *struct_ptr = p; + + return p + *struct_length; +} + +static const uint8_t *deserialize_buf(const uint8_t *p, const uint8_t **buf_ptr, + uint16_t *buf_len) +{ uint8_t b; - uint16_t buflen; /* Get the current byte */ b = *p++; - buflen = b & 0x7F; + *buf_len = b & 0x7F; if (b & 0x80) { /* Get the current byte */ b = *p++; - buflen += (uint16_t)b << 7; + *buf_len += (uint16_t)b << 7; } /* Return the values */ - *pp_buf = p; - *p_buflen = buflen; - p += buflen; + *buf_ptr = p; + p += *buf_len; return p; } -static void deserialize_none(uint8_t fn_index, const uint8_t * p_buf, uint16_t length) { - (void)p_buf; +static const uint8_t *deserialize_ptr(const uint8_t *p, uintptr_t *priv) +{ + *priv = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); + p += 4; + return p; +} + +static void deserialize_none(uint8_t fn_index, const uint8_t *buf, + uint16_t length) +{ if (length != 0) panic(-1); + + rpc_free_cb(buf - 2); + m_fct_none[fn_index](); } -static void deserialize_s(uint8_t fn_index, const uint8_t * p_buf, uint16_t length) { - const uint8_t *p_struct_data; +static void deserialize_s(uint8_t fn_index, const uint8_t *buf, + uint16_t length) +{ + const uint8_t *struct_ptr; uint8_t struct_length; - const uint8_t *p; + const uint8_t *p = buf; - p = deserialize_struct(p_buf, &p_struct_data, &struct_length); + p = deserialize_struct(p, &struct_ptr, &struct_length); - if ((length != (p - p_buf)) || - (struct_length != m_size_s[fn_index])) + if ((length != (p - buf)) || (struct_length != m_size_s[fn_index])) panic(-1); { /* Always align structures on word boundary */ - uintptr_t struct_data[(struct_length + (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; + uintptr_t struct_data[(struct_length + + (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; - memcpy(struct_data, p_struct_data, struct_length); + memcpy(struct_data, struct_ptr, struct_length); + + rpc_free_cb(buf - 2); m_fct_s[fn_index](struct_data); } } -static void deserialize_p(uint8_t fn_index, const uint8_t * p_buf, uint16_t length) { - uintptr_t p_priv; +static void deserialize_p(uint8_t fn_index, const uint8_t *buf, + uint16_t length) +{ + uintptr_t priv; + const uint8_t *p = buf; + + p = deserialize_ptr(p, &priv); - if (length != 4) + if (length != (p - buf)) panic(-1); - /* little endian conversion */ - p_priv = p_buf[0] | (p_buf[1] << 8) | (p_buf[2] << 16) | (p_buf[3] << 24); + rpc_free_cb(buf - 2); - m_fct_p[fn_index]((void *)p_priv); + m_fct_p[fn_index]((void *)priv); } -static void deserialize_s_b(uint8_t fn_index, const uint8_t * p_buf, uint16_t length) { +static void deserialize_s_b(uint8_t fn_index, const uint8_t *buf, + uint16_t length) +{ const uint8_t *p_struct_data; uint8_t struct_length; const uint8_t *p_vbuf; uint16_t vbuf_length; - const uint8_t *p; + const uint8_t *p = buf; - p = deserialize_struct(p_buf, &p_struct_data, &struct_length); + p = deserialize_struct(p, &p_struct_data, &struct_length); p = deserialize_buf(p, &p_vbuf, &vbuf_length); - if ((length != (p - p_buf)) || - (struct_length != m_size_s_b[fn_index])) + if ((length != (p - buf)) || (struct_length != m_size_s_b[fn_index])) panic(-1); { /* Always align structures on word boundary */ - uintptr_t struct_data[(struct_length + (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; - uintptr_t vbuf[(vbuf_length + (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; - void * buf = NULL; + uintptr_t struct_data[(struct_length + + (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; + uintptr_t vbuf[(vbuf_length + + (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; memcpy(struct_data, p_struct_data, struct_length); if (vbuf_length) { memcpy(vbuf, p_vbuf, vbuf_length); - buf = vbuf; } - m_fct_s_b[fn_index](struct_data, buf, vbuf_length); - } -} - -static void deserialize_b_b_p(uint8_t fn_index, const uint8_t * p_buf, uint16_t length) { - const uint8_t *p_vbuf1; - uint16_t vbuf1_length; - const uint8_t *p_vbuf2; - uint16_t vbuf2_length; - uintptr_t p_priv; - const uint8_t *p; + rpc_free_cb(buf - 2); - p = deserialize_buf(p_buf, &p_vbuf1, &vbuf1_length); - p = deserialize_buf(p, &p_vbuf2, &vbuf2_length); - p += 4; - - if (length != (p - p_buf)) - panic(-1); - - { - /* Always align structures on word boundary */ - uintptr_t vbuf1[(vbuf1_length + (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; - uintptr_t vbuf2[(vbuf2_length + (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; - void * buf1 = NULL; - void * buf2 = NULL; - - if (vbuf1_length) { - memcpy(vbuf1, p_vbuf1, vbuf1_length); - buf1 = vbuf1; - } - - if (vbuf2_length) { - memcpy(vbuf2, p_vbuf2, vbuf2_length); - buf2 = vbuf2; - } - p = p_vbuf2 + vbuf2_length; - - /* little endian conversion */ - p_priv = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); - - m_fct_b_b_p[fn_index](buf1, vbuf1_length, buf2, vbuf2_length, (void *)p_priv); + m_fct_s_b[fn_index](struct_data, (void *)vbuf, vbuf_length); } } -static void deserialize_s_p(uint8_t fn_index, const uint8_t * p_buf, uint16_t length) +static void deserialize_s_p(uint8_t fn_index, const uint8_t *buf, + uint16_t length) { const uint8_t *p_struct_data; uint8_t struct_length; - uintptr_t p_priv; - const uint8_t *p; + uintptr_t priv; + const uint8_t *p = buf; - p = deserialize_struct(p_buf, &p_struct_data, &struct_length); - p += 4; + p = deserialize_struct(p, &p_struct_data, &struct_length); + p = deserialize_ptr(p, &priv); - if ((length != (p - p_buf)) || - (struct_length != m_size_s_p[fn_index])) + if ((length != (p - buf)) || (struct_length != m_size_s_p[fn_index])) panic(-1); { /* Always align structures on word boundary */ - uintptr_t struct_data[(struct_length + (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; + uintptr_t struct_data[(struct_length + + (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; memcpy(struct_data, p_struct_data, struct_length); - p = p_struct_data + struct_length; - - /* little endian conversion */ - p_priv = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); - m_fct_s_p[fn_index](struct_data, (void *)p_priv); + rpc_free_cb(buf - 2); + m_fct_s_p[fn_index](struct_data, (void *)priv); } } -static void deserialize_s_b_p(uint8_t fn_index, const uint8_t * p_buf, uint16_t length) +static void deserialize_control(uint8_t fn_index, const uint8_t *buf, + uint16_t length) { const uint8_t *p_struct_data; uint8_t struct_length; - const uint8_t *p_vbuf; - uint16_t vbuf_length; - uintptr_t p_priv; - const uint8_t *p; - - p = deserialize_struct(p_buf, &p_struct_data, &struct_length); - p = deserialize_buf(p, &p_vbuf, &vbuf_length); - p += 4; - - if ((length != (p - p_buf)) || - (struct_length != m_size_s_b_p[fn_index])) - panic(-1); - - { - /* Always align structures on word boundary */ - uintptr_t struct_data[(struct_length + (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; - uintptr_t vbuf[(vbuf_length + (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; - void * buf = NULL; + const uint8_t *p = buf; + struct { + uint32_t version; + uint32_t ser_hash; + uint32_t des_hash; + } struct_data; + + switch(fn_index) { + case 0: + p = deserialize_struct(p, &p_struct_data, &struct_length); + + if ((length != (p - buf)) || (struct_length != sizeof(struct_data))) + panic(-1); + memcpy(&struct_data, p_struct_data, struct_length); - memcpy(struct_data, p_struct_data, struct_length); + rpc_free_cb(buf - 2); - if (vbuf_length) { - memcpy(vbuf, p_vbuf, vbuf_length); - buf = vbuf; + if (struct_data.ser_hash != rpc_deserialize_hash() || + struct_data.des_hash != rpc_serialize_hash()) { + rpc_init_cb(struct_data.version, false); + } else { + rpc_init_cb(struct_data.version, true); } - p = p_vbuf + vbuf_length; - - /* little endian conversion */ - p_priv = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); - - m_fct_s_b_p[fn_index](struct_data, buf, vbuf_length, (void *)p_priv); - } -} - -static void deserialize_s_b_b_p(uint8_t fn_index, const uint8_t * p_buf, uint16_t length) { - const uint8_t *p_struct_data; - uint8_t struct_length; - const uint8_t *p_vbuf1; - uint16_t vbuf1_length; - const uint8_t *p_vbuf2; - uint16_t vbuf2_length; - uintptr_t p_priv; - const uint8_t *p; - - p = deserialize_struct(p_buf, &p_struct_data, &struct_length); - p = deserialize_buf(p, &p_vbuf1, &vbuf1_length); - p = deserialize_buf(p, &p_vbuf2, &vbuf2_length); - p += 4; - if ((length != (p - p_buf)) || - (struct_length != m_size_s_b_b_p[fn_index])) + break; + break; panic(-1); - - { - /* Always align structures on word boundary */ - uintptr_t struct_data[(struct_length + (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; - uintptr_t vbuf1[(vbuf1_length + (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; - uintptr_t vbuf2[(vbuf2_length + (sizeof(uintptr_t) - 1))/(sizeof(uintptr_t))]; - void * buf1 = NULL; - void * buf2 = NULL; - - memcpy(struct_data, p_struct_data, struct_length); - - if (vbuf1_length) { - memcpy(vbuf1, p_vbuf1, vbuf1_length); - buf1 = vbuf1; - } - if (vbuf2_length) { - memcpy(vbuf2, p_vbuf2, vbuf2_length); - buf2 = vbuf2; - } - - p = p_vbuf2 + vbuf2_length; - - /* little endian conversion */ - p_priv = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); - - m_fct_s_b_b_p[fn_index](struct_data, buf1, vbuf1_length, buf2, vbuf2_length, (void *)p_priv); } } -void rpc_deserialize(const uint8_t * p_buf, uint16_t length) { - +void rpc_deserialize(const uint8_t *buf, uint16_t length) +{ uint8_t fn_index; uint8_t sig_type; - if (NULL != p_buf) { - sig_type = p_buf[0]; - fn_index = p_buf[1]; - - p_buf += 2; - length -= 2; - - switch(sig_type) { - case SIG_TYPE_NONE: - if (sizeof(m_fct_none)) - deserialize_none(fn_index, p_buf, length); - break; - case SIG_TYPE_S: - if (sizeof(m_fct_s)) - deserialize_s(fn_index, p_buf, length); - break; - case SIG_TYPE_P: - if (sizeof(m_fct_p)) - deserialize_p(fn_index, p_buf, length); - break; - case SIG_TYPE_S_B: - if (sizeof(m_fct_s_b)) - deserialize_s_b(fn_index, p_buf, length); - break; - case SIG_TYPE_B_B_P: - if (sizeof(m_fct_b_b_p)) - deserialize_b_b_p(fn_index, p_buf, length); - break; - case SIG_TYPE_S_P: - if (sizeof(m_fct_s_p)) - deserialize_s_p(fn_index, p_buf, length); - break; - case SIG_TYPE_S_B_P: - if (sizeof(m_fct_s_b_p)) - deserialize_s_b_p(fn_index, p_buf, length); - break; - case SIG_TYPE_S_B_B_P: - if (sizeof(m_fct_s_b_b_p)) - deserialize_s_b_b_p(fn_index, p_buf, length); - break; - default: - panic(-1); - break; - } + if (!buf) return; + + sig_type = buf[0]; + fn_index = buf[1]; + + buf += 2; + length -= 2; + + switch(sig_type) { + case SIG_TYPE_NONE: + if (sizeof(m_fct_none)) + deserialize_none(fn_index, buf, length); + break; + case SIG_TYPE_S: + if (sizeof(m_fct_s)) + deserialize_s(fn_index, buf, length); + break; + case SIG_TYPE_P: + if (sizeof(m_fct_p)) + deserialize_p(fn_index, buf, length); + break; + case SIG_TYPE_S_B: + if (sizeof(m_fct_s_b)) + deserialize_s_b(fn_index, buf, length); + break; + case SIG_TYPE_S_P: + if (sizeof(m_fct_s_p)) + deserialize_s_p(fn_index, buf, length); + break; + case SIG_TYPE_CONTROL: + deserialize_control(fn_index, buf, length); + break; + default: + panic(-1); + break; } } + +__weak +void rpc_init_cb(uint32_t version, bool compatible) +{ +} diff --git a/system/libarc32_arduino101/drivers/rpc/rpc_functions_to_ble_core.h b/system/libarc32_arduino101/drivers/rpc/rpc_functions_to_ble_core.h index 5f742208..3801da01 100644 --- a/system/libarc32_arduino101/drivers/rpc/rpc_functions_to_ble_core.h +++ b/system/libarc32_arduino101/drivers/rpc/rpc_functions_to_ble_core.h @@ -19,6 +19,8 @@ #include "gap_internal.h" #include "gatt_internal.h" +#include "dtm_internal.h" +#include "storage_internal.h" /* declare the list of functions sorted by signature */ #define LIST_FN_SIG_NONE \ @@ -27,80 +29,82 @@ #define LIST_FN_SIG_S \ FN_SIG_S(nble_gap_set_adv_data_req, \ - struct nble_gap_ad_data_params *) \ + struct nble_gap_set_adv_data_req *) \ FN_SIG_S(nble_gap_set_adv_params_req, \ - struct nble_gap_adv_params *) \ + struct nble_gap_set_adv_params_req *) \ FN_SIG_S(nble_gap_start_scan_req, \ - const struct nble_gap_scan_params *) \ - FN_SIG_S(nble_gap_sm_config_req, \ - const struct nble_gap_sm_config_params *) \ - FN_SIG_S(nble_gap_sm_passkey_reply_req, \ - const struct nble_gap_sm_key_reply_req_params *) \ - FN_SIG_S(nble_gap_sm_bond_info_req, \ - const struct nble_gap_sm_bond_info_param *) \ - FN_SIG_S(nble_gap_sm_security_req, \ - const struct nble_gap_sm_security_params *) \ - FN_SIG_S(nble_gap_sm_clear_bonds_req, \ - const struct nble_gap_sm_clear_bond_req_params *) \ - FN_SIG_S(nble_set_bda_req, const struct nble_set_bda_params *) \ + const struct nble_gap_start_scan_req *) \ + FN_SIG_S(nble_sm_passkey_reply_req, \ + const struct nble_sm_passkey_reply_req *) \ + FN_SIG_S(nble_sm_bond_info_req, \ + const struct nble_sm_bond_info_req *) \ + FN_SIG_S(nble_sm_security_req, \ + const struct nble_sm_security_req *) \ + FN_SIG_S(nble_sm_clear_bonds_req, \ + const struct nble_sm_clear_bonds_req *) \ + FN_SIG_S(nble_set_bda_req, const struct nble_set_bda_req *) \ + FN_SIG_S(nble_get_bda_req, const struct nble_get_bda_req *) \ FN_SIG_S(nble_gap_conn_update_req, \ - const struct nble_gap_connect_update_params *) \ + const struct nble_gap_conn_update_req *) \ FN_SIG_S(nble_gattc_discover_req, \ - const struct nble_discover_params *) \ - FN_SIG_S(nble_gatts_wr_reply_req, \ - const struct nble_gatts_wr_reply_params *) \ + const struct nble_gattc_discover_req *) \ FN_SIG_S(nble_uas_rssi_calibrate_req, \ - const struct nble_uas_rssi_calibrate *) \ - FN_SIG_S(nble_gap_service_write_req, \ - const struct nble_gap_service_write_params *) \ + const struct nble_uas_rssi_calibrate_req *) \ + FN_SIG_S(nble_gap_service_req, \ + const struct nble_gap_service_req *) \ FN_SIG_S(nble_gap_disconnect_req, \ - const struct nble_gap_disconnect_req_params *) \ + const struct nble_gap_disconnect_req *) \ FN_SIG_S(nble_gattc_read_req, \ - const struct ble_gattc_read_params *) \ - FN_SIG_S(nble_gap_tx_power_req, \ - const struct nble_gap_tx_power_params *) \ - FN_SIG_S(nble_get_version_req, \ - const struct nble_gap_get_version_param *) + const struct nble_gattc_read_req *) \ + FN_SIG_S(nble_gap_set_tx_power_req, \ + const struct nble_gap_set_tx_power_req *) \ + FN_SIG_S(nble_dbg_req, const struct nble_dbg_req *) \ + FN_SIG_S(nble_sm_pairing_response_req, \ + const struct nble_sm_pairing_response_req *) \ + FN_SIG_S(nble_sm_error_req, \ + const struct nble_sm_error_req *) \ + FN_SIG_S(nble_dtm_cmd_req, \ + const struct nble_dtm_cmd_req *) #define LIST_FN_SIG_P \ - FN_SIG_P(nble_gap_dtm_init_req, void *) \ - FN_SIG_P(nble_gap_read_bda_req, void *) \ FN_SIG_P(nble_gap_stop_adv_req, void *) \ - FN_SIG_P(nble_gap_cancel_connect_req, void *) + FN_SIG_P(nble_get_version_req, ble_get_version_cb_t) \ + FN_SIG_P(nble_gap_cancel_connect_req, void *) \ + FN_SIG_P(nble_panic_req, void *) #define LIST_FN_SIG_S_B \ - FN_SIG_S_B(nble_gatt_register_req, \ - const struct nble_gatt_register_req *, \ + FN_SIG_S_B(nble_gatts_register_req, \ + const struct nble_gatts_register_req *, \ uint8_t *, uint16_t) \ - FN_SIG_S_B(nble_gatt_send_notif_req, \ - const struct nble_gatt_send_notif_params *, \ + FN_SIG_S_B(nble_gatts_notify_req, \ + const struct nble_gatts_notify_req *, \ const uint8_t *, uint16_t) \ - FN_SIG_S_B(nble_gatt_send_ind_req, \ - const struct nble_gatt_send_ind_params *, \ + FN_SIG_S_B(nble_gatts_indicate_req, \ + const struct nble_gatts_indicate_req *, \ const uint8_t *, uint8_t) \ - FN_SIG_S_B(nble_gatts_rd_reply_req, \ - const struct nble_gatts_rd_reply_params *, \ + FN_SIG_S_B(nble_gatts_read_reply_req, \ + const struct nble_gatts_read_reply_req *, \ uint8_t *, uint16_t) \ FN_SIG_S_B(nble_gattc_write_req, \ - const struct ble_gattc_write_params *, \ + const struct nble_gattc_write_req *, \ + const uint8_t *, uint16_t) \ + FN_SIG_S_B(nble_gattc_read_multi_req, \ + const struct nble_gattc_read_multi_req *, \ + const uint16_t *, uint16_t) \ + FN_SIG_S_B(nble_uart_test_req, \ + const struct nble_uart_test_req *, \ const uint8_t *, uint8_t) \ - FN_SIG_S_B(nble_gattc_read_multiple_req, \ - const struct ble_gattc_read_multiple_params *, \ - const uint16_t *, uint16_t) - -#define LIST_FN_SIG_B_B_P + FN_SIG_S_B(nble_gatts_write_reply_req, \ + const struct nble_gatts_write_reply_req *, \ + const uint8_t *, uint8_t) \ + FN_SIG_S_B(nble_storage_read_rsp_req, \ + const struct nble_storage_read_rsp_req *, \ + const uint8_t *, uint16_t) #define LIST_FN_SIG_S_P \ FN_SIG_S_P(nble_gap_connect_req, \ - const struct nble_gap_connect_req_params *, void *) \ + const struct nble_gap_connect_req *, void *) \ FN_SIG_S_P(nble_gap_set_rssi_report_req, \ - const struct nble_rssi_report_params *, void *) \ - FN_SIG_S_P(nble_gap_dbg_req, \ - const struct nble_debug_params *, \ - void *) - -#define LIST_FN_SIG_S_B_P - -#define LIST_FN_SIG_S_B_B_P + const struct nble_gap_set_rssi_report_req *, void *) #endif /* RPC_FUNCTIONS_TO_BLE_CORE_H_ */ diff --git a/system/libarc32_arduino101/drivers/rpc/rpc_functions_to_quark.h b/system/libarc32_arduino101/drivers/rpc/rpc_functions_to_quark.h index b08005e6..c2b345bd 100644 --- a/system/libarc32_arduino101/drivers/rpc/rpc_functions_to_quark.h +++ b/system/libarc32_arduino101/drivers/rpc/rpc_functions_to_quark.h @@ -20,81 +20,91 @@ #include "gap_internal.h" #include "gatt_internal.h" #include "gap_internal.h" +#include "dtm_internal.h" +#include "storage_internal.h" /* declare the list of functions sorted by signature */ -#define LIST_FN_SIG_NONE \ - FN_SIG_NONE(on_nble_up) +#define LIST_FN_SIG_NONE #define LIST_FN_SIG_S \ FN_SIG_S(on_nble_get_version_rsp, \ - const struct nble_version_response *) \ + const struct nble_get_version_rsp *) \ FN_SIG_S(on_nble_gap_connect_evt, \ const struct nble_gap_connect_evt *) \ FN_SIG_S(on_nble_gap_disconnect_evt, \ const struct nble_gap_disconnect_evt *) \ FN_SIG_S(on_nble_gap_conn_update_evt, \ const struct nble_gap_conn_update_evt *) \ - FN_SIG_S(on_nble_gap_sm_status_evt, \ - const struct nble_gap_sm_status_evt *) \ - FN_SIG_S(on_nble_gap_sm_passkey_display_evt, \ - const struct nble_gap_sm_passkey_disp_evt *) \ - FN_SIG_S(on_nble_gap_sm_passkey_req_evt, \ - const struct nble_gap_sm_passkey_req_evt *) \ + FN_SIG_S(on_nble_sm_status_evt, \ + const struct nble_sm_status_evt *) \ + FN_SIG_S(on_nble_sm_passkey_disp_evt, \ + const struct nble_sm_passkey_disp_evt *) \ + FN_SIG_S(on_nble_sm_passkey_req_evt, \ + const struct nble_sm_passkey_req_evt *) \ FN_SIG_S(on_nble_gap_rssi_evt, \ const struct nble_gap_rssi_evt *) \ FN_SIG_S(on_nble_common_rsp, \ - const struct nble_response *) \ + const struct nble_common_rsp *) \ FN_SIG_S(on_nble_gap_connect_rsp, \ - const struct nble_response *) \ + const struct nble_common_rsp *) \ FN_SIG_S(on_nble_gap_cancel_connect_rsp, \ - const struct nble_response *) \ - FN_SIG_S(on_nble_gap_read_bda_rsp, \ - const struct nble_service_read_bda_response *) \ - FN_SIG_S(on_nble_gap_sm_config_rsp, \ - struct nble_gap_sm_config_rsp *) \ - FN_SIG_S(on_nble_gap_sm_common_rsp, \ - const struct nble_gap_sm_response *) \ + const struct nble_common_rsp *) \ + FN_SIG_S(on_nble_get_bda_rsp, \ + const struct nble_get_bda_rsp *) \ + FN_SIG_S(on_nble_sm_config_rsp, \ + struct nble_sm_config_rsp *) \ + FN_SIG_S(on_nble_sm_common_rsp, \ + const struct nble_sm_common_rsp *) \ FN_SIG_S(on_nble_set_bda_rsp, \ const struct nble_set_bda_rsp *) \ FN_SIG_S(on_nble_gap_set_rssi_report_rsp, \ - const struct nble_response *) \ - FN_SIG_S(on_nble_gap_dbg_rsp, \ - const struct nble_debug_resp *) \ + const struct nble_common_rsp *) \ + FN_SIG_S(on_nble_dbg_rsp, \ + const struct nble_dbg_rsp *) \ FN_SIG_S(on_nble_gap_dir_adv_timeout_evt, \ const struct nble_gap_dir_adv_timeout_evt *) \ - FN_SIG_S(on_nble_gatts_send_notif_rsp, \ - const struct nble_gatt_notif_rsp *) \ - FN_SIG_S(on_nble_gatts_send_ind_rsp, \ - const struct nble_gatt_ind_rsp *) \ - FN_SIG_S(on_nble_gap_start_advertise_rsp, \ - const struct nble_response *) \ + FN_SIG_S(on_nble_gatts_notify_tx_evt, \ + const struct nble_gatts_notify_tx_evt *) \ + FN_SIG_S(on_nble_gatts_indicate_rsp, \ + const struct nble_gatts_indicate_rsp *) \ + FN_SIG_S(on_nble_gap_start_adv_rsp, \ + const struct nble_common_rsp *) \ FN_SIG_S(on_nble_gap_scan_start_stop_rsp, \ - const struct nble_response *) \ + const struct nble_common_rsp *) \ FN_SIG_S(on_nble_gatts_read_evt, \ - const struct nble_gatt_rd_evt *) \ + const struct nble_gatts_read_evt *) \ FN_SIG_S(on_nble_gatts_write_exec_evt, \ - const struct nble_gatt_wr_exec_evt *) \ + const struct nble_gatts_write_exec_evt *) \ FN_SIG_S(on_nble_uas_bucket_change, \ - const struct nble_uas_bucket_change *) \ + const struct nble_uas_bucket_change *) \ FN_SIG_S(on_nble_gattc_write_rsp, \ - const struct ble_gattc_write_rsp *) \ - FN_SIG_S(on_nble_gap_tx_power_rsp, \ - const struct nble_response *) + const struct nble_gattc_write_rsp *) \ + FN_SIG_S(on_nble_gap_set_tx_power_rsp, \ + const struct nble_common_rsp *) \ + FN_SIG_S(on_nble_sm_pairing_request_evt, \ + const struct nble_sm_pairing_request_evt *) \ + FN_SIG_S(on_nble_sm_security_request_evt, \ + const struct nble_sm_security_request_evt *) \ + FN_SIG_S(on_nble_dtm_rsp, \ + const struct nble_dtm_rsp *) \ + FN_SIG_S(on_nble_gap_rpa_update_evt, \ + const struct nble_gap_rpa_update_evt *) \ + FN_SIG_S(on_nble_storage_read_evt, \ + const struct nble_storage_read_evt *) -#define LIST_FN_SIG_P \ - FN_SIG_P(on_nble_gap_dtm_init_rsp, void *) +#define LIST_FN_SIG_P #define LIST_FN_SIG_S_B \ FN_SIG_S_B(nble_log, const struct nble_log_s *, char *, \ uint8_t) \ FN_SIG_S_B(on_nble_gattc_value_evt, \ - const struct ble_gattc_value_evt *, \ + const struct nble_gattc_value_evt *, \ uint8_t *, uint8_t) \ FN_SIG_S_B(on_nble_gatts_write_evt, \ - const struct nble_gatt_wr_evt *, \ + const struct nble_gatts_write_evt *, \ const uint8_t *, uint8_t) \ - FN_SIG_S_B(on_nble_gatt_register_rsp, \ - const struct nble_gatt_register_rsp *, \ + FN_SIG_S_B(on_nble_gatts_register_rsp, \ + const struct nble_gatts_register_rsp *, \ const struct nble_gatt_attr_handles *, \ uint8_t) \ FN_SIG_S_B(on_nble_gattc_discover_rsp, \ @@ -103,22 +113,22 @@ FN_SIG_S_B(on_nble_gap_adv_report_evt, \ const struct nble_gap_adv_report_evt *, \ const uint8_t *, uint8_t) \ - FN_SIG_S_B(on_nble_gap_sm_bond_info_rsp, \ - const struct nble_gap_sm_bond_info_rsp*, \ + FN_SIG_S_B(on_nble_sm_bond_info_rsp, \ + const struct nble_sm_bond_info_rsp *, \ const bt_addr_le_t *, uint16_t) \ FN_SIG_S_B(on_nble_gattc_read_rsp, \ - const struct ble_gattc_read_rsp *, \ - uint8_t *, uint8_t) \ - FN_SIG_S_B(on_nble_gattc_read_multiple_rsp, \ - const struct ble_gattc_read_rsp *, \ - uint8_t *, uint8_t) - -#define LIST_FN_SIG_B_B_P + const struct nble_gattc_read_rsp *, \ + uint8_t *, uint8_t) \ + FN_SIG_S_B(on_nble_gattc_read_multi_rsp, \ + const struct nble_gattc_read_rsp *, \ + uint8_t *, uint8_t) \ + FN_SIG_S_B(on_nble_uart_test_evt, \ + const struct nble_uart_test_evt *, \ + const uint8_t *, uint8_t) \ + FN_SIG_S_B(on_nble_storage_write_evt, \ + const struct nble_storage_write_evt *, \ + const uint8_t *, uint16_t) #define LIST_FN_SIG_S_P -#define LIST_FN_SIG_S_B_P - -#define LIST_FN_SIG_S_B_B_P - #endif /* RPC_FUNCTIONS_TO_QUARK_H_ */ diff --git a/system/libarc32_arduino101/drivers/rpc/rpc_serialize.c b/system/libarc32_arduino101/drivers/rpc/rpc_serialize.c index e2144ee3..c4a5e910 100644 --- a/system/libarc32_arduino101/drivers/rpc/rpc_serialize.c +++ b/system/libarc32_arduino101/drivers/rpc/rpc_serialize.c @@ -32,124 +32,151 @@ /* Build the functions exposed */ /* Define the functions identifiers per signature */ -#define FN_SIG_NONE(__fn) fn_index_##__fn, -#define FN_SIG_S(__fn, __s) FN_SIG_NONE(__fn) -#define FN_SIG_P(__fn, __type) FN_SIG_NONE(__fn) -#define FN_SIG_S_B(__fn, __s, __type, __length) FN_SIG_NONE(__fn) -#define FN_SIG_B_B_P(__fn, __type1, __length1, __type2, __length2,__type3) FN_SIG_NONE(__fn) -#define FN_SIG_S_P(__fn, __s, __type) FN_SIG_NONE(__fn) -#define FN_SIG_S_B_P(__fn, __s, __type, __length, __type_ptr) FN_SIG_NONE(__fn) -#define FN_SIG_S_B_B_P(__fn, __s, __type1, __length1, __type2, __length2,__type3) FN_SIG_NONE(__fn) - -/* Build the list of function indexes -> this should match the array at deserialization */ +#define FN_SIG_NONE(__fn) fn_index_##__fn, +#define FN_SIG_S(__fn, __s) FN_SIG_NONE(__fn) +#define FN_SIG_P(__fn, __type) FN_SIG_NONE(__fn) +#define FN_SIG_S_B(__fn, __s, __type, __length) FN_SIG_NONE(__fn) +#define FN_SIG_S_P(__fn, __s, __type) FN_SIG_NONE(__fn) + +/* Build the list of function indexes -> this should match the array at + * deserialization + */ enum { LIST_FN_SIG_NONE fn_none_index_max }; enum { LIST_FN_SIG_S fn_s_index_max }; enum { LIST_FN_SIG_P fn_p_index_max }; enum { LIST_FN_SIG_S_B fn_s_b_index_max }; -enum { LIST_FN_SIG_B_B_P fn_b_b_p_index_max }; enum { LIST_FN_SIG_S_P fn_s_p_index_max }; -enum { LIST_FN_SIG_S_B_P fn_s_b_p_index_max }; -enum { LIST_FN_SIG_S_B_B_P fn_s_b_b_p_index_max }; /* Implement the functions using serialization API */ #undef FN_SIG_NONE #undef FN_SIG_S #undef FN_SIG_P #undef FN_SIG_S_B -#undef FN_SIG_B_B_P #undef FN_SIG_S_P -#undef FN_SIG_S_B_P -#undef FN_SIG_S_B_B_P - -#define FN_SIG_NONE(__fn) \ - void __fn(void) { \ - rpc_serialize_none(fn_index_##__fn); \ - } \ - -#define FN_SIG_S(__fn, __s) \ - void __fn(__s p_s) { \ - rpc_serialize_s(fn_index_##__fn, p_s, sizeof(*p_s)); \ - } \ - -#define FN_SIG_P(__fn, __type) \ - void __fn(__type p_priv) { \ - rpc_serialize_p(fn_index_##__fn, p_priv); \ - } \ - -#define FN_SIG_S_B(__fn, __s, __type, __length) \ - void __fn(__s p_s, __type p_buf, __length length) { \ - rpc_serialize_s_b(fn_index_##__fn, p_s, sizeof(*p_s), p_buf, length); \ - } \ - -#define FN_SIG_B_B_P(__fn, __type1, __length1, __type2, __length2, __type3) \ - void __fn(__type1 p_buf1, __length1 length1, __type2 p_buf2, __length2 length2, __type3 p_priv) { \ - rpc_serialize_b_b_p(fn_index_##__fn, p_buf1, length1, p_buf2, length2, p_priv); \ - } \ - -#define FN_SIG_S_P(__fn, __s, __type) \ - void __fn(__s p_s, __type p_priv) { \ - rpc_serialize_s_p(fn_index_##__fn, p_s, sizeof(*p_s), p_priv); \ - } \ - -#define FN_SIG_S_B_P(__fn, __s, __type, __length, __type_ptr) \ - void __fn(__s p_s, __type p_buf, __length length, __type_ptr p_priv) { \ - rpc_serialize_s_b_p(fn_index_##__fn, p_s, sizeof(*p_s), p_buf, length, p_priv); \ - } - -#define FN_SIG_S_B_B_P(__fn, __s, __type1, __length1, __type2, __length2, __type3) \ - void __fn(__s p_s, __type1 p_buf1, __length1 length1, __type2 p_buf2, __length2 length2, __type3 p_priv) { \ - rpc_serialize_s_b_b_p(fn_index_##__fn, p_s, sizeof(*p_s), p_buf1, length1, p_buf2, length2, p_priv); \ - } \ +#define FN_SIG_NONE(__fn) \ + void __fn(void) \ + { \ + rpc_serialize_none(fn_index_##__fn); \ + } + +#define FN_SIG_S(__fn, __s) \ + void __fn(__s p_s) \ + { \ + rpc_serialize_s(fn_index_##__fn, p_s, sizeof(*p_s)); \ + } + +#define FN_SIG_P(__fn, __type) \ + void __fn(__type p_priv) \ + { \ + rpc_serialize_p(fn_index_##__fn, p_priv); \ + } + +#define FN_SIG_S_B(__fn, __s, __type, __length) \ + void __fn(__s p_s, __type p_buf, __length length) \ + { \ + rpc_serialize_s_b(fn_index_##__fn, p_s, sizeof(*p_s), \ + p_buf, length); \ + } + +#define FN_SIG_S_P(__fn, __s, __type) \ + void __fn(__s p_s, __type p_priv) \ + { \ + rpc_serialize_s_p(fn_index_##__fn, p_s, sizeof(*p_s), \ + p_priv); \ + } /* Build the functions */ LIST_FN_SIG_NONE LIST_FN_SIG_S LIST_FN_SIG_P LIST_FN_SIG_S_B -LIST_FN_SIG_B_B_P LIST_FN_SIG_S_P -LIST_FN_SIG_S_B_P -LIST_FN_SIG_S_B_B_P -#define SIG_TYPE_SIZE 1 -#define FN_INDEX_SIZE 1 -#define POINTER_SIZE 4 +#undef FN_SIG_NONE +#undef FN_SIG_S +#undef FN_SIG_P +#undef FN_SIG_S_B +#undef FN_SIG_S_P + +#define DJB2_HASH(__h, __v) ((__h << 5) + __h) + __v -static void _send(uint8_t *buf, uint16_t length) { - rpc_transmit_cb(buf, length); +#define FN_SIG_NONE(__fn) \ + hash = DJB2_HASH(hash, 1); + +#define FN_SIG_S(__fn, __s) \ + hash = DJB2_HASH(hash, 2); \ + hash = DJB2_HASH(hash, sizeof(*((__s)0))); + +#define FN_SIG_P(__fn, __type) \ + hash = DJB2_HASH(hash, 3); + +#define FN_SIG_S_B(__fn, __s, __type, __length) \ + hash = DJB2_HASH(hash, 4); \ + hash = DJB2_HASH(hash, sizeof(*((__s)0))); + +#define FN_SIG_S_P(__fn, __s, __type) \ + hash = DJB2_HASH(hash, 6); \ + hash = DJB2_HASH(hash, sizeof(*((__s)0))); + +uint32_t rpc_serialize_hash(void) +{ + uint32_t hash = 5381; + + LIST_FN_SIG_NONE; + LIST_FN_SIG_S; + LIST_FN_SIG_P; + LIST_FN_SIG_S_B; + LIST_FN_SIG_S_P; + + return hash; } -static uint16_t encoded_structlen(uint8_t structlen) { +#define SIG_TYPE_SIZE 1 +#define FN_INDEX_SIZE 1 +#define POINTER_SIZE 4 + +static void _send(uint8_t *buf) +{ + rpc_transmit_cb(buf); +} + +static uint16_t encoded_structlen(uint8_t structlen) +{ return 1 + structlen; } -static uint8_t *serialize_struct(uint8_t *p, const uint8_t *struct_data, uint8_t struct_length) { +static uint8_t *serialize_struct(uint8_t *p, const uint8_t *struct_data, + uint8_t struct_length) +{ *p++ = struct_length; memcpy(p, struct_data, struct_length); p += struct_length; return p; } -static uint16_t encoded_buflen(const uint8_t *buf, uint16_t buflen) { - if (NULL == buf) +static uint16_t encoded_buflen(const uint8_t *buf, uint16_t buflen) +{ + if (!buf) { return 1; - else { - if (buflen < (1 << 7)) { - return 1 + buflen; - } - else - return 2 + buflen; + } + + if (buflen < (1 << 7)) { + return 1 + buflen; + } else { + return 2 + buflen; } } -static uint8_t *serialize_buf(uint8_t *p, const uint8_t *buf, uint16_t buflen) { +static uint8_t *serialize_buf(uint8_t *p, const uint8_t *data, uint16_t len) +{ uint16_t varint; - if (NULL == buf) - buflen = 0; + if (!data) { + len = 0; + } - varint = buflen; + varint = len; *p = varint & 0x7F; if (varint >= (1 << 7)) { @@ -158,166 +185,125 @@ static uint8_t *serialize_buf(uint8_t *p, const uint8_t *buf, uint16_t buflen) { *p = varint >> 7; } p++; - memcpy(p, buf, buflen); - p += buflen; + memcpy(p, data, len); + p += len; return p; } -static uint8_t *serialize_p(uint8_t *p, uintptr_t priv) { - *p++ = priv; - *p++ = (priv >> 8); - *p++ = (priv >> 16); - *p++ = (priv >> 24); +static uint8_t *serialize_p(uint8_t *p, void *ptr) +{ + uintptr_t val = (uintptr_t)ptr; + + *p++ = val; + *p++ = (val >> 8); + *p++ = (val >> 16); + *p++ = (val >> 24); return p; } -void rpc_serialize_none(uint8_t fn_index) { - uint16_t length; - uint8_t * buf; - uint8_t * p; - - length = SIG_TYPE_SIZE + FN_INDEX_SIZE; +void rpc_serialize_none(uint8_t fn_index) +{ + uint8_t *buf; + uint8_t *p; - p = buf = rpc_alloc_cb(length); + buf = rpc_alloc_cb(SIG_TYPE_SIZE + FN_INDEX_SIZE); + p = buf; *p++ = SIG_TYPE_NONE; *p = fn_index; - _send(buf, length); + _send(buf); } -void rpc_serialize_s(uint8_t fn_index, const void * struct_data, uint8_t struct_length) { - uint16_t length; - uint8_t * buf; - uint8_t * p; +void rpc_serialize_s(uint8_t fn_index, const void *struct_data, + uint8_t struct_length) +{ + uint8_t *buf; + uint8_t *p; - length = SIG_TYPE_SIZE + FN_INDEX_SIZE + encoded_structlen(struct_length); - - p = buf = rpc_alloc_cb(length); + buf = rpc_alloc_cb(SIG_TYPE_SIZE + FN_INDEX_SIZE + + encoded_structlen(struct_length)); + p = buf; *p++ = SIG_TYPE_S; *p++ = fn_index; p = serialize_struct(p, struct_data, struct_length); - _send(buf, length); + _send(buf); } +void rpc_serialize_p(uint8_t fn_index, void *priv) +{ + uint8_t *buf; + uint8_t *p; -void rpc_serialize_p(uint8_t fn_index, void * p_priv) { - uint16_t length; - uint8_t * buf; - uint8_t * p; - uintptr_t priv = (uintptr_t) p_priv; - - length = SIG_TYPE_SIZE + FN_INDEX_SIZE + POINTER_SIZE; - - p = buf = rpc_alloc_cb(length); + buf = rpc_alloc_cb(SIG_TYPE_SIZE + FN_INDEX_SIZE + POINTER_SIZE); + p = buf; *p++ = SIG_TYPE_P; *p++ = fn_index; p = serialize_p(p, priv); - _send(buf, length); + _send(buf); } -void rpc_serialize_s_b(uint8_t fn_index, const void * struct_data, uint8_t struct_length, const void * vbuf, uint16_t vbuf_length) { - uint16_t length; - uint8_t * buf; - uint8_t * p; - - length = SIG_TYPE_SIZE + FN_INDEX_SIZE + encoded_structlen(struct_length) + - encoded_buflen(vbuf, vbuf_length); +void rpc_serialize_s_b(uint8_t fn_index, const void *struct_data, + uint8_t struct_length, const void *vbuf, + uint16_t vbuf_length) +{ + uint8_t *buf; + uint8_t *p; - p = buf = rpc_alloc_cb(length); + buf = rpc_alloc_cb(SIG_TYPE_SIZE + FN_INDEX_SIZE + + encoded_structlen(struct_length) + + encoded_buflen(vbuf, vbuf_length)); + p = buf; *p++ = SIG_TYPE_S_B; *p++ = fn_index; p = serialize_struct(p, struct_data, struct_length); p = serialize_buf(p, vbuf, vbuf_length); - _send(buf, length); -} - -void rpc_serialize_b_b_p(uint8_t fn_index, const void * vbuf1, uint16_t vbuf1_length, const void * vbuf2, uint16_t vbuf2_length, void * p_priv) { - uint16_t length; - uint8_t * buf; - uint8_t * p; - uintptr_t priv = (uintptr_t) p_priv; - - length = SIG_TYPE_SIZE + FN_INDEX_SIZE + encoded_buflen(vbuf1, vbuf1_length) + - encoded_buflen(vbuf2, vbuf2_length) + POINTER_SIZE; - - p = buf = rpc_alloc_cb(length); - - *p++ = SIG_TYPE_B_B_P; - *p++ = fn_index; - p = serialize_buf(p, vbuf1, vbuf1_length); - p = serialize_buf(p, vbuf2, vbuf2_length); - p = serialize_p(p, priv); - - _send(buf, length); + _send(buf); } -void rpc_serialize_s_p(uint8_t fn_index, const void * struct_data, uint8_t struct_length, void * p_priv) { - uint16_t length; - uint8_t * buf; - uint8_t * p; - uintptr_t priv = (uintptr_t) p_priv; +void rpc_serialize_s_p(uint8_t fn_index, const void *struct_data, + uint8_t struct_length, void *priv) +{ + uint8_t *buf; + uint8_t *p; - length = SIG_TYPE_SIZE + FN_INDEX_SIZE + encoded_structlen(struct_length) - + POINTER_SIZE; - - p = buf = rpc_alloc_cb(length); + buf = rpc_alloc_cb(SIG_TYPE_SIZE + FN_INDEX_SIZE + + encoded_structlen(struct_length) + POINTER_SIZE); + p = buf; *p++ = SIG_TYPE_S_P; *p++ = fn_index; p = serialize_struct(p, struct_data, struct_length); p = serialize_p(p, priv); - _send(buf, length); + _send(buf); } -void rpc_serialize_s_b_p(uint8_t fn_index, const void * struct_data, uint8_t struct_length, - const void * vbuf, uint16_t vbuf_length, void * p_priv) { - uint16_t length; - uint8_t * buf; - uint8_t * p; - uintptr_t priv = (uintptr_t) p_priv; - - length = SIG_TYPE_SIZE + FN_INDEX_SIZE + encoded_structlen(struct_length) + - encoded_buflen(vbuf, vbuf_length) + POINTER_SIZE; - - p = buf = rpc_alloc_cb(length); - - *p++ = SIG_TYPE_S_B_P; - *p++ = fn_index; - p = serialize_struct(p, struct_data, struct_length); - p = serialize_buf(p, vbuf, vbuf_length); - p = serialize_p(p, priv); - - _send(buf, length); -} - -void rpc_serialize_s_b_b_p(uint8_t fn_index, const void * struct_data, uint8_t struct_length, - const void * vbuf1, uint16_t vbuf1_length, const void * vbuf2, uint16_t vbuf2_length, void * p_priv) { - - uint16_t length; - uint8_t * buf; - uint8_t * p; - uintptr_t priv = (uintptr_t) p_priv; - - length = SIG_TYPE_SIZE + FN_INDEX_SIZE + encoded_structlen(struct_length) + - encoded_buflen(vbuf1, vbuf1_length) + - encoded_buflen(vbuf2, vbuf2_length) + POINTER_SIZE; - - p = buf = rpc_alloc_cb(length); - - *p++ = SIG_TYPE_S_B_B_P; - *p++ = fn_index; - p = serialize_struct(p, struct_data, struct_length); - p = serialize_buf(p, vbuf1, vbuf1_length); - p = serialize_buf(p, vbuf2, vbuf2_length); - p = serialize_p(p, priv); - - _send(buf, length); +void rpc_init(uint32_t version) +{ + uint8_t *buf; + uint8_t *p; + struct { + uint32_t version; + uint32_t ser_hash; + uint32_t des_hash; + } struct_data; + + struct_data.version = version; + struct_data.ser_hash = rpc_serialize_hash(); + struct_data.des_hash = rpc_deserialize_hash(); + buf = rpc_alloc_cb(SIG_TYPE_SIZE + FN_INDEX_SIZE + + encoded_structlen(sizeof(struct_data))); + + p = buf; + *p++ = SIG_TYPE_CONTROL; + *p++ = 0; + p = serialize_struct(p, (uint8_t *)&struct_data, sizeof(struct_data)); + _send(buf); } diff --git a/system/libarc32_arduino101/framework/include/os/os.h b/system/libarc32_arduino101/framework/include/os/os.h index 7f5103d9..6e92b5eb 100644 --- a/system/libarc32_arduino101/framework/include/os/os.h +++ b/system/libarc32_arduino101/framework/include/os/os.h @@ -202,4 +202,11 @@ extern OS_ERR_TYPE mutex_lock (T_MUTEX mutex, int timeout); /** @} */ +struct os_fifo { + T_QUEUE queue; +}; +void fifo_init(struct os_fifo *fifo); +void *fifo_get(struct os_fifo *fifo, int32_t timeout); +void fifo_put(struct os_fifo *fifo, void *data); + #endif diff --git a/system/libarc32_arduino101/framework/src/os/os.c b/system/libarc32_arduino101/framework/src/os/os.c index f9e6faa3..4bf4f0cd 100644 --- a/system/libarc32_arduino101/framework/src/os/os.c +++ b/system/libarc32_arduino101/framework/src/os/os.c @@ -30,52 +30,11 @@ #include "cfw/cfw.h" #include "os/os.h" - -/************************* MEMORY *************************/ - - -#if 0 - -#ifdef TRACK_ALLOCS #include "infra/log.h" -int alloc_count = 0; -#endif +#include "misc/util.h" -void * cfw_alloc(int size, OS_ERR_TYPE * err) { - void * ptr; - unsigned int flags = interrupt_lock(); - ptr = malloc(size+sizeof(void*)); - if (ptr != NULL) { - (*(int*) ptr) = size; -#ifdef TRACK_ALLOCS - alloc_count++; - pr_info(0, "alloc_count - %d", alloc_count); -#endif - interrupt_unlock(flags); - return ptr; - } else - return 0; -} - -void cfw_free(void * ptr, OS_ERR_TYPE * err) { - int flags = interrupt_lock(); -#ifdef TRACK_ALLOCS - alloc_count--; - pr_info(0, "alloc_countf - %d", alloc_count); -#endif - free(ptr); - interrupt_unlock(flags); -} - -void * balloc(uint32_t size, OS_ERR_TYPE *err) { - return cfw_alloc(size, err); -} - -OS_ERR_TYPE bfree(void *ptr) { - cfw_free(ptr, NULL); - return E_OS_OK; -} -#endif +/************************* MEMORY *************************/ +// See the balloc.c /************************* QUEUES *************************/ @@ -85,7 +44,7 @@ typedef struct queue_ { int used; } q_t; -q_t q_pool[10]; +static q_t q_pool[10]; void queue_put(void *queue, void *msg) { q_t * q = (q_t*) queue; @@ -116,15 +75,24 @@ void queue_send_message (T_QUEUE queue, T_QUEUE_MESSAGE message, OS_ERR_TYPE* er T_QUEUE queue_create(uint32_t max_size, OS_ERR_TYPE*err) { int i, found=0; - q_t * q; - for (i=0;i<10; i++) { + q_t * q = NULL; + + for (i = 0; i < ARRAY_SIZE(q_pool); i++) + { q = &q_pool[i]; - if (q->used == 0) { + if (q->used == 0) + { q->used = 1; found = 1; + break; } } - if (!found) return (T_QUEUE)NULL; + + if (!found) + { + return (T_QUEUE)NULL; + } + list_init(&q->lh); q->count = 0; return (T_QUEUE) q; @@ -161,3 +129,23 @@ OS_ERR_TYPE mutex_lock(T_MUTEX mutex, int timeout) { return E_OS_OK; } + +// FIFO +void fifo_init(struct os_fifo *fifo) +{ + if (fifo->queue == NULL) + { + fifo->queue = queue_create (10, NULL); + } +} + +void *fifo_get(struct os_fifo *fifo, int32_t timeout) +{ + return queue_wait(fifo->queue); +} + +void fifo_put(struct os_fifo *fifo, void *data) +{ + queue_put(fifo->queue, data); +} + diff --git a/system/libarc32_arduino101/framework/src/services/ble/conn.c b/system/libarc32_arduino101/framework/src/services/ble/conn.c index c0aa9014..b17c7f07 100644 --- a/system/libarc32_arduino101/framework/src/services/ble/conn.c +++ b/system/libarc32_arduino101/framework/src/services/ble/conn.c @@ -30,19 +30,18 @@ /* #define BT_GATT_DEBUG 1 */ -extern void on_nble_curie_log(char *fmt, ...); extern void __assert_fail(void); #ifdef BT_GATT_DEBUG -#define BT_DBG(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_ERR(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_WARN(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_INFO(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) +#define BT_DBG(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_ERR(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_WARN(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_INFO(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) #define BT_ASSERT(cond) ((cond) ? (void)0 : __assert_fail()) #else #define BT_DBG(fmt, ...) do {} while (0) -#define BT_ERR(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_WARN(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_INFO(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) +#define BT_ERR(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_WARN(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_INFO(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) #define BT_ASSERT(cond) ((cond) ? (void)0 : __assert_fail()) #endif @@ -89,6 +88,23 @@ void notify_le_param_updated(struct bt_conn *conn) } #if defined(CONFIG_BLUETOOTH_SMP) +void bt_conn_identity_resolved(struct bt_conn *conn) +{ + const bt_addr_le_t *rpa; + struct bt_conn_cb *cb; + + if (conn->role == BT_HCI_ROLE_MASTER) { + rpa = &conn->le.resp_addr; + } else { + rpa = &conn->le.init_addr; + } + + for (cb = callback_list; cb; cb = cb->_next) { + if (cb->identity_resolved) { + cb->identity_resolved(conn, rpa, &conn->le.dst); + } + } +} void bt_conn_security_changed(struct bt_conn *conn) { @@ -311,6 +327,7 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state) /* Actions needed for entering the new state */ switch (conn->state) { case BT_CONN_CONNECTED: + atomic_clear_bit(conn->flags, BT_CONN_DIR_ADV_CONNECT); bt_l2cap_connected(conn); notify_connected(conn); break; @@ -326,6 +343,9 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state) } else if (old_state == BT_CONN_CONNECT) { /* conn->err will be set in this case */ notify_connected(conn); + } else if (old_state == BT_CONN_CONNECT_SCAN && conn->err) { + /* this indicate LE Create Connection failed */ + notify_connected(conn); } /* Release the reference we took for the very first @@ -403,7 +423,7 @@ struct bt_conn *bt_conn_lookup_state_le(const bt_addr_le_t *peer, continue; } - if (bt_addr_le_cmp(peer, BT_ADDR_LE_ANY) && + if (peer && bt_addr_le_cmp(peer, BT_ADDR_LE_ANY) && bt_addr_le_cmp(peer, &conns[i].le.dst)) { continue; } @@ -416,6 +436,24 @@ struct bt_conn *bt_conn_lookup_state_le(const bt_addr_le_t *peer, return NULL; } +void bt_conn_disconnect_all(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(conns); i++) { + struct bt_conn *conn = &conns[i]; + + if (!atomic_get(&conn->ref)) { + continue; + } + + if (conn->state == BT_CONN_CONNECTED) { + bt_conn_disconnect(conn, + BT_HCI_ERR_REMOTE_USER_TERM_CONN); + } + } +} + struct bt_conn *bt_conn_ref(struct bt_conn *conn) { atomic_inc(&conn->ref); @@ -441,19 +479,11 @@ int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info) switch (conn->type) { case BT_CONN_TYPE_LE: if (conn->role == BT_HCI_ROLE_MASTER) { -#if 0 info->le.src = &conn->le.init_addr; info->le.dst = &conn->le.resp_addr; -#else - info->le.dst = &conn->le.dst; -#endif } else { -#if 0 info->le.src = &conn->le.resp_addr; info->le.dst = &conn->le.init_addr; -#else - info->le.src = &conn->le.dst; -#endif } info->le.interval = conn->le.interval; info->le.latency = conn->le.latency; @@ -472,11 +502,11 @@ int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info) static int bt_hci_disconnect(struct bt_conn *conn, uint8_t reason) { - struct nble_gap_disconnect_req_params ble_gap_disconnect; + struct nble_gap_disconnect_req params; - ble_gap_disconnect.conn_handle = conn->handle; - ble_gap_disconnect.reason = reason; - nble_gap_disconnect_req(&ble_gap_disconnect); + params.conn_handle = conn->handle; + params.reason = reason; + nble_gap_disconnect_req(¶ms); bt_conn_set_state(conn, BT_CONN_DISCONNECT); return 0; @@ -488,9 +518,9 @@ static int bt_hci_connect_le_cancel(struct bt_conn *conn) return 0; } -void on_nble_gap_cancel_connect_rsp(const struct nble_response *params) +void on_nble_gap_cancel_connect_rsp(const struct nble_common_rsp *par) { - struct bt_conn *conn = params->user_data; + struct bt_conn *conn = par->user_data; conn->err = BT_HCI_ERR_INSUFFICIENT_RESOURCES; bt_conn_set_state(conn, BT_CONN_DISCONNECTED); @@ -513,9 +543,15 @@ int bt_conn_disconnect(struct bt_conn *conn, uint8_t reason) case BT_CONN_CONNECT_SCAN: conn->err = BT_HCI_ERR_INSUFFICIENT_RESOURCES; bt_conn_set_state(conn, BT_CONN_DISCONNECTED); - /* scan update not yet implemented */ + bt_le_scan_update(false); return 0; case BT_CONN_CONNECT: + /* Check if directed advertising was initiated */ + if (atomic_test_and_clear_bit(conn->flags, BT_CONN_DIR_ADV_CONNECT)) { + conn->err = BT_HCI_ERR_REMOTE_USER_TERM_CONN; + bt_conn_set_state(conn, BT_CONN_DISCONNECTED); + return bt_le_adv_stop(); + } return bt_hci_connect_le_cancel(conn); case BT_CONN_CONNECTED: return bt_hci_disconnect(conn, reason); @@ -527,56 +563,52 @@ int bt_conn_disconnect(struct bt_conn *conn, uint8_t reason) } } -static bool valid_adv_params(const struct nble_gap_adv_params *params) +static bool valid_adv_params(const struct bt_le_adv_param *param) { - if (params->type == BT_LE_ADV_DIRECT_IND) { - /* If high duty, ensure interval is 0 */ - if (params->interval_max != 0) - return false; - - if (params->timeout != 0) - return false; - } else if (params->type == BT_LE_ADV_DIRECT_IND_LOW_DUTY) { - if (params->interval_min < 0x20) - return false; - } else { + if (!(param->options & BT_LE_ADV_OPT_CONNECTABLE)) return false; - } - if (params->interval_min > params->interval_max) - return false; + /* In case of high duty cycle, interval is 0 */ + if (param->interval_min == 0) + return true; - if (params->interval_max > 0x4000) + if (param->interval_min > param->interval_max || + param->interval_min < 0x0020 || param->interval_max > 0x4000) { return false; + } return true; } +#if defined(CONFIG_BLUETOOTH_CENTRAL) +int bt_le_set_auto_conn(bt_addr_le_t *addr, + const struct bt_le_conn_param *param) +{ + return -EINVAL; +} +#endif /* CONFIG_BLUETOOTH_CENTRAL */ + struct bt_conn *bt_conn_create_slave_le(const bt_addr_le_t *peer, const struct bt_le_adv_param *param) { struct bt_conn *conn; /* Timeout is handled by application timer */ /* forced to none currently (no whitelist support) */ - struct nble_gap_adv_params params = { + struct nble_gap_set_adv_params_req params = { .interval_max = param->interval_max, .interval_min = param->interval_min, - .type = param->type, + .type = BT_LE_ADV_DIRECT_IND, .timeout = 0, .filter_policy = 0 }; - bt_addr_le_copy(¶ms.peer_bda, peer); - - if (!valid_adv_params(¶ms)) { + if (!valid_adv_params(param)) { return NULL; } - if (param->type == BT_LE_ADV_DIRECT_IND_LOW_DUTY) { - params.type = BT_LE_ADV_DIRECT_IND; - } + bt_addr_le_copy(¶ms.peer_bda, peer); - if (atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) { + if (atomic_test_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING)) { return NULL; } @@ -586,37 +618,20 @@ struct bt_conn *bt_conn_create_slave_le(const bt_addr_le_t *peer, return NULL; } + atomic_set_bit(conn->flags, BT_CONN_DIR_ADV_CONNECT); + bt_conn_set_state(conn, BT_CONN_CONNECT); nble_gap_set_adv_params_req(¶ms); - nble_gap_start_adv_req(); + set_advertise_enable(); + + atomic_set_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING); return conn; } #if defined(CONFIG_BLUETOOTH_CENTRAL) -static int hci_le_create_conn(struct bt_conn *conn) -{ - struct nble_gap_connect_req_params conn_params; - - conn_params.bda = conn->le.dst; - conn_params.conn_params.interval_min = conn->le.interval_min; - conn_params.conn_params.interval_max = conn->le.interval_max; - conn_params.conn_params.slave_latency = conn->le.latency; - conn_params.conn_params.link_sup_to = conn->le.timeout; - - conn_params.scan_params.interval = sys_cpu_to_le16(BT_GAP_SCAN_FAST_INTERVAL); - conn_params.scan_params.window = conn_params.scan_params.interval; - conn_params.scan_params.selective = 0; - conn_params.scan_params.active = 1; - conn_params.scan_params.timeout = 0; - - nble_gap_connect_req(&conn_params, conn); - - return 0; -} - -void on_nble_gap_connect_rsp(const struct nble_response *params) +void on_nble_gap_connect_rsp(const struct nble_common_rsp *params) { struct bt_conn *conn = params->user_data; @@ -632,13 +647,23 @@ struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer, { struct bt_conn *conn; + BT_ERR("%s %d", __FUNCTION__, __LINE__); + BT_ERR("%s %d: min-%d, max-%d, latency-%d, timeout-%d", __FUNCTION__, __LINE__, + param->interval_min, param->interval_max, + param->latency, param->timeout); + if (!bt_le_conn_params_valid(param->interval_min, param->interval_max, param->latency, param->timeout)) { return NULL; } - /* if (atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) */ - /* return NULL; */ + BT_ERR("%s %d", __FUNCTION__, __LINE__); + + if (atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) { + return NULL; + } + + BT_ERR("%s %d", __FUNCTION__, __LINE__); conn = bt_conn_lookup_addr_le(peer); if (conn) { @@ -655,33 +680,26 @@ struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer, } } + BT_ERR("%s %d", __FUNCTION__, __LINE__); + conn = bt_conn_add_le(peer); if (!conn) { return NULL; } -#if 0 - bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN); - bt_le_scan_update(true); -#endif - - bt_addr_le_copy(&conn->le.dst, peer); + BT_ERR("%s %d", __FUNCTION__, __LINE__); bt_conn_set_param_le(conn, param); - /* for the time being, the implementation bypassed the scan procedure */ - if (hci_le_create_conn(conn)) { - goto done; - } + bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN); - bt_conn_set_state(conn, BT_CONN_CONNECT); + bt_le_scan_update(true); -done: return conn; } #else -void on_nble_gap_connect_rsp(const struct nble_response *params) +void on_nble_gap_connect_rsp(const struct nble_common_rsp *params) { } @@ -815,14 +833,14 @@ int bt_conn_auth_passkey_entry(struct bt_conn *conn, unsigned int passkey) return -EINVAL; } -int bt_conn_auth_passkey_confirm(struct bt_conn *conn, bool match) +int bt_conn_auth_passkey_confirm(struct bt_conn *conn) { if (!bt_auth) { return -EINVAL; }; #if defined(CONFIG_BLUETOOTH_SMP) if (conn->type == BT_CONN_TYPE_LE) { - return bt_smp_auth_passkey_confirm(conn, match); + return bt_smp_auth_passkey_confirm(conn); } #endif /* CONFIG_BLUETOOTH_SMP */ @@ -848,24 +866,24 @@ int bt_conn_auth_cancel(struct bt_conn *conn) return -EINVAL; } -int bt_conn_remove_info(const bt_addr_le_t *addr) +int bt_conn_auth_pairing_confirm(struct bt_conn *conn) { - struct bt_conn *conn; - - /* TODO: implement address specific removal */ - if (bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) + if (!bt_auth) { return -EINVAL; + } - do { - conn = bt_conn_lookup_state_le(addr, BT_CONN_CONNECTED); - if (conn) { - bt_conn_unref(conn); - bt_conn_disconnect(conn, - BT_HCI_ERR_REMOTE_USER_TERM_CONN); - } - } while(conn); - - return bt_smp_remove_info(addr); + switch (conn->type) { +#if defined(CONFIG_BLUETOOTH_SMP) + case BT_CONN_TYPE_LE: + return bt_smp_auth_pairing_confirm(conn); +#endif /* CONFIG_BLUETOOTH_SMP */ +#if defined(CONFIG_BLUETOOTH_BREDR) + case BT_CONN_TYPE_BR: + return ssp_confirm_reply(conn); +#endif /* CONFIG_BLUETOOTH_BREDR */ + default: + return -EINVAL; + } } #endif /* CONFIG_BLUETOOTH_SMP || CONFIG_BLUETOOTH_BREDR */ @@ -896,7 +914,7 @@ int bt_conn_init(void) int bt_conn_le_conn_update(struct bt_conn *conn, const struct bt_le_conn_param *param) { - struct nble_gap_connect_update_params ble_gap_connect_update; + struct nble_gap_conn_update_req params; #if 0 struct hci_cp_le_conn_update *conn_update; struct net_buf *buf; @@ -915,13 +933,13 @@ int bt_conn_le_conn_update(struct bt_conn *conn, conn_update->conn_latency = sys_cpu_to_le16(param->latency); conn_update->supervision_timeout = sys_cpu_to_le16(param->timeout); #endif - ble_gap_connect_update.conn_handle = conn->handle; - ble_gap_connect_update.params.interval_min = param->interval_min; - ble_gap_connect_update.params.interval_max = param->interval_max; - ble_gap_connect_update.params.slave_latency = param->latency; - ble_gap_connect_update.params.link_sup_to = param->timeout; + params.conn_handle = conn->handle; + params.params.interval_min = param->interval_min; + params.params.interval_max = param->interval_max; + params.params.slave_latency = param->latency; + params.params.link_sup_to = param->timeout; - nble_gap_conn_update_req(&ble_gap_connect_update); + nble_gap_conn_update_req(¶ms); return 0; } diff --git a/system/libarc32_arduino101/framework/src/services/ble/conn_internal.h b/system/libarc32_arduino101/framework/src/services/ble/conn_internal.h index 04c08839..7846da76 100644 --- a/system/libarc32_arduino101/framework/src/services/ble/conn_internal.h +++ b/system/libarc32_arduino101/framework/src/services/ble/conn_internal.h @@ -25,15 +25,15 @@ typedef enum { /* bt_conn flags: the flags defined here represent connection parameters */ enum { BT_CONN_AUTO_CONNECT, + BT_CONN_DIR_ADV_CONNECT, }; struct bt_conn_le { bt_addr_le_t dst; -#if 0 bt_addr_le_t init_addr; bt_addr_le_t resp_addr; -#endif + uint16_t interval; uint16_t interval_min; uint16_t interval_max; @@ -55,6 +55,7 @@ struct bt_conn { uint16_t handle; uint8_t type; uint8_t role; + atomic_t flags[1]; #if defined(CONFIG_BLUETOOTH_SMP) uint8_t encrypt; @@ -87,6 +88,8 @@ struct bt_conn *bt_conn_add_br(const bt_addr_t *peer); struct bt_conn *bt_conn_lookup_addr_br(const bt_addr_t *peer); #endif +void bt_conn_disconnect_all(void); + /* Look up an existing connection */ struct bt_conn *bt_conn_lookup_handle(uint16_t handle); diff --git a/system/libarc32_arduino101/framework/src/services/ble/dtm.c b/system/libarc32_arduino101/framework/src/services/ble/dtm.c new file mode 100644 index 00000000..04a5afe3 --- /dev/null +++ b/system/libarc32_arduino101/framework/src/services/ble/dtm.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include + +#include +#include "dtm_internal.h" + +extern void __assert_fail(void); +#define BT_ASSERT(cond) ((cond) ? (void)0 : __assert_fail()) + +void on_nble_dtm_rsp(const struct nble_dtm_rsp *rsp) { + struct ble_dtm_rsp ret; + + ret.status = rsp->status; + ret.nb = rsp->nb; + + rsp->func(&ret, rsp->user_data); +} + +int ble_dtm_cmd(struct dtm_cmd_params *params) { + + struct nble_dtm_cmd_req req; + + if (!params || !params->func) { + return -EINVAL; + } + + switch(params->cmd_type) { + case DTM_START_RX: + req.tx_rx_freq = params->rx.freq; + break; + case DTM_START_TX: + req.tx_rx_freq = params->tx.freq; + req.tx_len = params->tx.len; + req.tx_pattern = params->tx.pattern; + break; + case DTM_SET_TXPOWER: + req.pwr_dbm = params->tx_pwr.dbm; + break; + case DTM_START_TX_CARRIER: + req.tx_rx_freq = params->tx.freq; + break; + case DTM_END: + break; + default: + return -EINVAL; + } + + req.cmd_type = params->cmd_type; + req.func = params->func; + req.user_data = params->user_data; + + nble_dtm_cmd_req(&req); + + return 0; +} diff --git a/system/libarc32_arduino101/framework/src/services/ble/gap.c b/system/libarc32_arduino101/framework/src/services/ble/gap.c index 26858281..cd272341 100644 --- a/system/libarc32_arduino101/framework/src/services/ble/gap.c +++ b/system/libarc32_arduino101/framework/src/services/ble/gap.c @@ -20,6 +20,8 @@ #include #include +#include +#include "storage_internal.h" #include "gap_internal.h" #include "conn_internal.h" @@ -31,29 +33,33 @@ /* #define BT_GATT_DEBUG 1 */ -extern void on_nble_curie_log(char *fmt, ...); +#ifndef __weak +#define __weak __attribute__((weak)) +#endif + extern void __assert_fail(void); #ifdef BT_GATT_DEBUG -#define BT_DBG(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_ERR(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_WARN(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_INFO(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) +#define BT_DBG(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_ERR(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_WARN(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_INFO(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) #define BT_ASSERT(cond) ((cond) ? (void)0 : __assert_fail()) #else #define BT_DBG(fmt, ...) do {} while (0) -#define BT_ERR(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_WARN(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_INFO(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) +#define BT_ERR(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_WARN(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_INFO(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) #define BT_ASSERT(cond) ((cond) ? (void)0 : __assert_fail()) #endif static bt_ready_cb_t bt_ready_cb; static bt_le_scan_cb_t *scan_dev_found_cb; static rssi_report_t rssi_report_cb; +static const struct bt_storage *bt_storage; struct bt_dev bt_dev; -static int set_advertise_enable(void) +int set_advertise_enable(void) { #if 0 struct net_buf *buf; @@ -106,24 +112,20 @@ static int set_advertise_disable(void) return 0; } -void ble_gap_get_bonding_info(ble_bond_info_cb_t func, void *user_data, - bool include_bonded_addrs) +void ble_gap_get_bda_info(struct bt_local_addr *addr) { - struct nble_gap_sm_bond_info_param params; - - params.cb = func; - params.user_data = user_data; - params.include_bonded_addrs = include_bonded_addrs; - - nble_gap_sm_bond_info_req(¶ms); + bt_addr_le_copy(&addr->id_addr, &bt_dev.id_addr); +#if defined(CONFIG_BLUETOOTH_PRIVACY) + bt_addr_le_copy(&addr->rpa, &bt_dev.random_addr); +#endif } -void on_nble_gap_start_advertise_rsp(const struct nble_response *params) +void on_nble_gap_start_adv_rsp(const struct nble_common_rsp *par) { - if (params->status == 0) + if (par->status == 0) atomic_set_bit(bt_dev.flags, BT_DEV_ADVERTISING); else - BT_WARN("start advertise failed with %d", params->status); + BT_WARN("start advertise failed with %d", par->status); } void on_nble_gap_disconnect_evt(const struct nble_gap_disconnect_evt *evt) @@ -230,21 +232,27 @@ void on_nble_gap_connect_evt(const struct nble_gap_connect_evt *evt) conn->le.timeout = evt->conn_values.supervision_to; conn->role = evt->role_slave; -#if 0 - src.type = BT_ADDR_LE_PUBLIC; - memcpy(src.val, bt_dev.bdaddr.val, sizeof(bt_dev.bdaddr.val)); - /* use connection address (instead of identity address) as initiator * or responder address */ + if (conn->role == BT_HCI_ROLE_MASTER) { - bt_addr_le_copy(&conn->le.init_addr, &src); - bt_addr_le_copy(&conn->le.resp_addr, &evt->peer_addr); + bt_addr_le_copy(&conn->le.resp_addr, &evt->peer_bda); + + /* init_addr doesn't need updating here since it was + * already set during previous steps. + */ } else { - bt_addr_le_copy(&conn->le.init_addr, &evt->peer_addr); - bt_addr_le_copy(&conn->le.resp_addr, &src); + bt_addr_le_copy(&conn->le.init_addr, &evt->peer_bda); + +#if defined(CONFIG_BLUETOOTH_PRIVACY) + bt_addr_le_copy(&conn->le.resp_addr, &bt_dev.random_addr); +#else + /* id_addr is equal with peer_bda */ + bt_addr_le_copy(&conn->le.resp_addr, &evt->peer_bda); +#endif /* CONFIG_BLUETOOTH_PRIVACY */ } -#endif + bt_conn_set_state(conn, BT_CONN_CONNECTED); /* Note: Connection update removed because Windows interop and BT spec recommendations */ @@ -256,47 +264,6 @@ void on_nble_gap_connect_evt(const struct nble_gap_connect_evt *evt) } -void on_nble_gap_adv_report_evt(const struct nble_gap_adv_report_evt *evt, - const uint8_t *buf, uint8_t len) -{ -#if TODO_IMPLEMENT_CONNECTION - uint8_t num_reports = buf->data[0]; - struct bt_hci_ev_le_advertising_info *info; - - BT_DBG("Adv number of reports %u", num_reports); - - info = net_buf_pull(buf, sizeof(num_reports)); - - while (num_reports--) { - int8_t rssi = info->data[info->length]; - const bt_addr_le_t *addr; - - BT_DBG("%s event %u, len %u, rssi %d dBm", - bt_addr_le_str(&info->addr), - info->evt_type, info->length, rssi); - - addr = find_id_addr(&info->addr); -#endif - - BT_DBG("nble gap: event:%u, len %u", evt->adv_type, len); - - if (scan_dev_found_cb) { - scan_dev_found_cb(&evt->addr, evt->rssi, evt->adv_type, - buf, len); - } -#if TODO_IMPLEMENT_CONNECTION -#if defined(CONFIG_BLUETOOTH_CONN) - check_pending_conn(addr, &info->addr, info->evt_type); -#endif /* CONFIG_BLUETOOTH_CONN */ - /* Get next report iteration by moving pointer to right offset - * in buf according to spec 4.2, Vol 2, Part E, 7.7.65.2. - */ - info = net_buf_pull(buf, sizeof(*info) + info->length + - sizeof(rssi)); - } -#endif -} - void on_nble_gap_conn_update_evt(const struct nble_gap_conn_update_evt *evt) { struct bt_conn *conn; @@ -361,11 +328,12 @@ int bt_conn_update_param_le(struct bt_conn *conn, #endif } -void on_nble_gap_scan_start_stop_rsp(const struct nble_response *rsp) +void on_nble_gap_scan_start_stop_rsp(const struct nble_common_rsp *rsp) { - if (rsp->status) + if (rsp->status) { BT_INFO("scan start/stop failed: %d", rsp->status); - /* TODO: clear scanning bit atomic_clear_bit(bt_dev.flags, BT_DEV_SCANNING) */ + atomic_clear_bit(bt_dev.flags, BT_DEV_SCANNING); + } } static int bt_hci_stop_scanning(void) @@ -405,6 +373,7 @@ static int bt_hci_stop_scanning(void) return err; #endif + atomic_clear_bit(bt_dev.flags, BT_DEV_SCANNING); nble_gap_stop_scan_req(); @@ -412,90 +381,167 @@ static int bt_hci_stop_scanning(void) } #if defined(CONFIG_BLUETOOTH_CENTRAL) -int bt_le_set_auto_conn(bt_addr_le_t *addr, - const struct bt_le_conn_param *param) +static int hci_le_create_conn(struct bt_conn *conn) { - return -EINVAL; -} -#endif /* CONFIG_BLUETOOTH_CENTRAL */ + struct nble_gap_connect_req conn_params; + conn_params.bda = conn->le.dst; + conn_params.conn_params.interval_min = conn->le.interval_min; + conn_params.conn_params.interval_max = conn->le.interval_max; + conn_params.conn_params.slave_latency = conn->le.latency; + conn_params.conn_params.link_sup_to = conn->le.timeout; -static int start_le_scan(uint8_t scan_type, uint16_t interval, uint16_t window, - uint8_t filter_dup) + conn_params.scan_params.interval = BT_GAP_SCAN_FAST_INTERVAL; + conn_params.scan_params.window = conn_params.scan_params.interval; + + nble_gap_connect_req(&conn_params, conn); + + return 0; +} + +static void check_pending_conn(const bt_addr_le_t *id_addr, + const bt_addr_le_t *addr, uint8_t evtype) { - struct nble_gap_scan_params params = { - .interval = interval, - .window = window, - .scan_type = scan_type, - }; + struct bt_conn *conn; -#ifdef NOT_USED_FOR_NOW - struct net_buf *buf, *rsp; - struct bt_hci_cp_le_set_scan_params *set_param; - struct bt_hci_cp_le_set_scan_enable *scan_enable; - int err; + /* No connections are allowed during explicit scanning */ + if (atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) { + return; + } + BT_DBG("%s %d", __FUNCTION__, __LINE__); - buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_SCAN_PARAMS, - sizeof(*set_param)); - if (!buf) { - return -ENOBUFS; + /* Return if event is not connectable */ + if (evtype != BT_LE_ADV_IND && evtype != BT_LE_ADV_DIRECT_IND) { + return; } + BT_DBG("%s %d", __FUNCTION__, __LINE__); - set_param = net_buf_add(buf, sizeof(*set_param)); - memset(set_param, 0, sizeof(*set_param)); - set_param->scan_type = scan_type; + conn = bt_conn_lookup_state_le(id_addr, BT_CONN_CONNECT_SCAN); + if (!conn) { + return; + } + BT_DBG("%s %d", __FUNCTION__, __LINE__); - /* for the rest parameters apply default values according to - * spec 4.2, vol2, part E, 7.8.10 - */ - set_param->interval = sys_cpu_to_le16(interval); - set_param->window = sys_cpu_to_le16(window); - set_param->filter_policy = 0x00; + if (bt_hci_stop_scanning()) { + goto failed; + } - if (scan_type == BT_HCI_LE_SCAN_ACTIVE) { - err = le_set_nrpa(); - if (err) { - net_buf_unref(buf); - return err; - } + BT_DBG("%s %d", __FUNCTION__, __LINE__); - set_param->addr_type = BT_ADDR_LE_RANDOM; - } else { - set_param->addr_type = BT_ADDR_LE_PUBLIC; +#if defined(CONFIG_BLUETOOTH_PRIVACY) + if (le_set_rpa()) { + return; } + conn->le.init_addr.type = BT_ADDR_LE_RANDOM; +#else + bt_addr_le_copy(&conn->le.init_addr, &bt_dev.id_addr); +#endif /* CONFIG_BLUETOOTH_PRIVACY */ - bt_hci_cmd_send(BT_HCI_OP_LE_SET_SCAN_PARAMS, buf); - buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_SCAN_ENABLE, - sizeof(*scan_enable)); - if (!buf) { - return -ENOBUFS; + bt_addr_le_copy(&conn->le.resp_addr, addr); + + BT_DBG("%s %d", __FUNCTION__, __LINE__); + + if (hci_le_create_conn(conn)) { + goto failed; } + BT_DBG("%s %d", __FUNCTION__, __LINE__); - scan_enable = net_buf_add(buf, sizeof(*scan_enable)); - memset(scan_enable, 0, sizeof(*scan_enable)); - scan_enable->filter_dup = filter_dup; - scan_enable->enable = BT_HCI_LE_SCAN_ENABLE; + bt_conn_set_state(conn, BT_CONN_CONNECT); + bt_conn_unref(conn); + return; - err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_SCAN_ENABLE, buf, &rsp); +failed: + conn->err = BT_HCI_ERR_UNSPECIFIED; + bt_conn_set_state(conn, BT_CONN_DISCONNECTED); + bt_conn_unref(conn); + bt_le_scan_update(false); +} +#endif + +void on_nble_gap_adv_report_evt(const struct nble_gap_adv_report_evt *evt, + const uint8_t *buf, uint8_t len) +{ + BT_DBG("nble gap: event:%u, len %u", evt->adv_type, len); + + if (scan_dev_found_cb) { + scan_dev_found_cb(&evt->addr, evt->rssi, evt->adv_type, + buf, len); + } +#if defined(CONFIG_BLUETOOTH_CENTRAL) + check_pending_conn(&evt->addr, &evt->addr, evt->adv_type); +#endif /* CONFIG_BLUETOOTH_CENTRAL */ +} + +static int set_random_address(const bt_addr_t *addr) +{ + struct nble_set_bda_req req = {0}; + + memcpy(&req.bda.a, addr, sizeof(bt_addr_t)); + req.bda.type = BT_ADDR_LE_RANDOM; + req.cb = NULL; + + nble_set_bda_req(&req); + return 0; +} + +static int le_set_nrpa(void) +{ + bt_addr_t nrpa = {{0}}; + + nrpa.val[5] &= 0x3f; + + return set_random_address(&nrpa); +} + +#if defined(CONFIG_BLUETOOTH_PRIVACY) +int le_set_rpa(void) +{ + bt_addr_t rpa = {0}; + + /* Set the two most significant bits to 01 (indicating an RPA) */ + rpa.val[5] &= 0x3f; + rpa.val[5] |= 0x40; + + return set_random_address(&rpa); +} +#endif + +static int start_le_scan(uint8_t scan_type, uint16_t interval, uint16_t window, + uint8_t filter_dup) +{ + struct nble_gap_start_scan_req params; + int err; + +#if defined(CONFIG_BLUETOOTH_PRIVACY) + err = le_set_rpa(); if (err) { return err; } - /* Update scan state in case of success (0) status */ - err = rsp->data[0]; - if (!err) { - atomic_set_bit(bt_dev.flags, BT_DEV_SCANNING); +#else + if (scan_type == BT_HCI_LE_SCAN_ACTIVE) { + /* only set NRPA if there is no advertising ongoing */ + if (!atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) { + err = le_set_nrpa(); + if (err) { + return err; + } + } } - - net_buf_unref(rsp); #endif + params.scan_params.interval = interval; + params.scan_params.window = window; + params.scan_params.scan_type = scan_type; + params.scan_params.use_whitelist = 0; + + atomic_set_bit(bt_dev.flags, BT_DEV_SCANNING); + nble_gap_start_scan_req(¶ms); return 0; } -#if NOT_USED_FOR_NOW /* Used to determine whether to start scan and which scan type should be used */ int bt_le_scan_update(bool fast_scan) { @@ -538,7 +584,59 @@ int bt_le_scan_update(bool fast_scan) return 0; #endif /* CONFIG_BLUETOOTH_CENTRAL */ } -#endif + +static void update_le_oob_local(const bt_addr_le_t *addr) +{ + if (bt_addr_le_is_identity(addr)) { + bt_addr_le_copy(&bt_dev.id_addr, addr); + } else if (bt_addr_le_is_rpa(addr)) { + bt_addr_le_copy(&bt_dev.random_addr, addr); + } +} + +static void nble_get_bda_cb_init(const bt_addr_le_t *bda, void *user_data) +{ + update_le_oob_local(bda); +} + +static int common_init(void) +{ + struct nble_get_bda_req req; + + req.cb = nble_get_bda_cb_init; + req.user_data =NULL; + + /* read nble identity address */ + nble_get_bda_req(&req); + return 0; +} + +static int hci_init(void) +{ + if (bt_storage) { + int ret; + struct nble_set_bda_req params; + + ret = bt_storage->read(NULL, BT_STORAGE_ID_ADDR, ¶ms.bda, + sizeof(params.bda)); + + if (!ret) { + params.cb = NULL; + params.user_data = NULL; + + nble_set_bda_req(¶ms); + /* nble_get_bda_req() returns the set address but this + * ensures that bt_le_oob_get_local() reads a valid + * address independent of nble async response speed */ + update_le_oob_local(¶ms.bda); + return 0; + } + /* in no provisioned bda available -> use nble one */ + } + BT_DBG("no id addr provisioned"); + + return common_init(); +} static int bt_init(void) { @@ -553,9 +651,9 @@ static int bt_init(void) BT_ERR("HCI driver open failed (%d)", err); return err; } - - err = hci_init(); #endif + err = hci_init(); + if (!err) { err = bt_conn_init(); @@ -572,20 +670,28 @@ static int bt_init(void) return err; } -void on_nble_up(void) +void version_at_init_cb(const struct nble_version *ver) { - BT_DBG("%s", __FUNCTION__); if (bt_ready_cb) bt_ready_cb(bt_init()); } -extern void on_nble_curie_init(void); +void rpc_init_cb(uint32_t version, bool compatible) +{ + /* Retrieve the Nordic version */ + ble_gap_get_version(version_at_init_cb); +} + +__weak +void nble_curie_unreset_hook(void) +{ +} int bt_enable(bt_ready_cb_t cb) { bt_ready_cb = cb; - on_nble_curie_init(); + nble_curie_unreset_hook(); if (!cb) { return bt_init(); @@ -597,35 +703,27 @@ int bt_enable(bt_ready_cb_t cb) static bool valid_adv_param(const struct bt_le_adv_param *param) { - switch (param->type) { - case BT_LE_ADV_IND: - case BT_LE_ADV_SCAN_IND: - case BT_LE_ADV_NONCONN_IND: - break; - default: - return false; - } - -#if 0 - /* checks done in Nordic */ - switch (param->addr_type) { - case BT_LE_ADV_ADDR_IDENTITY: - case BT_LE_ADV_ADDR_NRPA: - break; - default: - return false; + if (!(param->options & BT_LE_ADV_OPT_CONNECTABLE)) { + /* + * BT Core 4.2 [Vol 2, Part E, 7.8.5] + * The Advertising_Interval_Min and Advertising_Interval_Max + * shall not be set to less than 0x00A0 (100 ms) if the + * Advertising_Type is set to ADV_SCAN_IND or ADV_NONCONN_IND. + */ + if (param->interval_min < 0x00a0) { + return false; + } } if (param->interval_min > param->interval_max || param->interval_min < 0x0020 || param->interval_max > 0x4000) { return false; } -#endif return true; } -static int set_ad(struct bt_eir_data *p_ad_data, +static int set_ad(struct nble_eir_data *p_ad_data, const struct bt_data *ad, size_t ad_len) { int i; @@ -652,15 +750,13 @@ int bt_le_adv_start(const struct bt_le_adv_param *param, const struct bt_data *sd, size_t sd_len) { int err; - struct nble_gap_adv_params set_param = {0}; - struct nble_gap_ad_data_params data; + struct nble_gap_set_adv_params_req set_param = {0}; + struct nble_gap_set_adv_data_req data = {{0}, {0}}; if (!valid_adv_param(param)) { return -EINVAL; } - memset(&data, 0, sizeof(data)); - if (atomic_test_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING)) { return -EALREADY; } @@ -675,10 +771,15 @@ int bt_le_adv_start(const struct bt_le_adv_param *param, } /* - * Don't bother with scan response if the advertising type isn't - * a scannable one. + * We need to set SCAN_RSP when enabling advertising type that allows + * for Scan Requests. + * + * If sd was not provided but we enable connectable undirected + * advertising sd needs to be cleared from values set by previous calls. + * Clearing sd is done by calling set_ad() with NULL data and zero len. + * So following condition check is unusual but correct. */ - if (param->type == BT_LE_ADV_IND || param->type == BT_LE_ADV_SCAN_IND) { + if (sd || (param->options & BT_LE_ADV_OPT_CONNECTABLE)) { err = set_ad(&data.sd, sd, sd_len); if (err) { return err; @@ -692,23 +793,29 @@ int bt_le_adv_start(const struct bt_le_adv_param *param, set_param.filter_policy = 0; set_param.interval_max = param->interval_max; set_param.interval_min = param->interval_min; - set_param.type = param->type; + + if (param->options & BT_LE_ADV_OPT_CONNECTABLE) { + set_param.type = BT_LE_ADV_IND; + } else { + if (sd) { + set_param.type = BT_LE_ADV_SCAN_IND; + } else { + set_param.type = BT_LE_ADV_NONCONN_IND; + } + } + nble_gap_set_adv_params_req(&set_param); -#if 0 - if (param->addr_type == BT_LE_ADV_ADDR_NRPA) { - err = le_set_nrpa(); - if (err) { - net_buf_unref(buf); +#if defined(CONFIG_BLUETOOTH_PRIVACY) + if (set_param.type == BT_LE_ADV_IND) { + err = le_set_rpa(); + if (err) return err; - } - - set_param->own_addr_type = BT_ADDR_LE_RANDOM; } else { - set_param->own_addr_type = BT_ADDR_LE_PUBLIC; + err = le_set_nrpa(); + if (err) + return err; } - - bt_hci_cmd_send(BT_HCI_OP_LE_SET_ADV_PARAMETERS, buf); #endif err = set_advertise_enable(); @@ -721,13 +828,16 @@ int bt_le_adv_start(const struct bt_le_adv_param *param, return 0; } -void on_nble_gap_dir_adv_timeout_evt(const struct nble_gap_dir_adv_timeout_evt *p_evt) +void on_nble_gap_dir_adv_timeout_evt(const struct nble_gap_dir_adv_timeout_evt *evt) { struct bt_conn *conn = bt_conn_lookup_state_le(BT_ADDR_LE_ANY, BT_CONN_CONNECT); if (conn) { atomic_clear_bit(bt_dev.flags, BT_DEV_ADVERTISING); - conn->err = p_evt->error; + if (atomic_test_and_clear_bit(conn->flags, BT_CONN_DIR_ADV_CONNECT)) { + atomic_clear_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING); + } + conn->err = evt->error; bt_conn_set_state(conn, BT_CONN_DISCONNECTED); bt_conn_unref(conn); } @@ -787,7 +897,7 @@ int bt_le_scan_start(const struct bt_le_scan_param *param, bt_le_scan_cb_t cb) if (!valid_le_scan_param(param)) { return -EINVAL; } -#if NOT_USED_FOR_NOW + /* Return if active scan is already enabled */ if (atomic_test_and_set_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) { return -EALREADY; @@ -800,16 +910,13 @@ int bt_le_scan_start(const struct bt_le_scan_param *param, bt_le_scan_cb_t cb) return err; } } -#endif err = start_le_scan(param->type, param->interval, param->window, param->filter_dup); if (err) { -#if NOT_USED_FOR_NOW atomic_clear_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN); -#endif return err; } @@ -820,86 +927,246 @@ int bt_le_scan_start(const struct bt_le_scan_param *param, bt_le_scan_cb_t cb) int bt_le_scan_stop(void) { -#if NOT_USED_FOR_NOW /* Return if active scanning is already disabled */ if (!atomic_test_and_clear_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) { return -EALREADY; } -#endif + scan_dev_found_cb = NULL; -#if NOT_USED_FOR_NOW return bt_le_scan_update(false); -#else - return bt_hci_stop_scanning(); -#endif } /* Temporary RSSI patch for UAS: RPC need definition if UAS not compiled */ -__attribute__((weak)) +__weak void on_nble_uas_bucket_change(const struct nble_uas_bucket_change *p_params) { } -void ble_gap_set_rssi_report(struct nble_rssi_report_params *params, +void ble_gap_set_rssi_report(struct ble_rssi_report_params *par, struct bt_conn *conn, rssi_report_resp_t resp_cb, rssi_report_t evt_cb) { + struct nble_gap_set_rssi_report_req req; rssi_report_cb = evt_cb; - params->conn_handle = conn->handle; + req.conn_handle = conn->handle; + req.op = par->op; + req.channel = par->channel; + req.delta_dBm = par->delta_dBm; + req.min_count = par->min_count; - nble_gap_set_rssi_report_req(params, resp_cb); + nble_gap_set_rssi_report_req(&req, resp_cb); } -void on_nble_gap_set_rssi_report_rsp(const struct nble_response *params) +void on_nble_gap_set_rssi_report_rsp(const struct nble_common_rsp *rsp) { - rssi_report_resp_t resp_cb = params->user_data; + rssi_report_resp_t resp_cb = rsp->user_data; if (resp_cb) - resp_cb(params->status); + resp_cb(rsp->status); } -void on_nble_gap_rssi_evt(const struct nble_gap_rssi_evt *event) +void on_nble_gap_rssi_evt(const struct nble_gap_rssi_evt *evt) { if (rssi_report_cb) - rssi_report_cb(event->rssi_data); + rssi_report_cb(evt->rssi_data); } void ble_gap_set_tx_power(int8_t tx_power) { - struct nble_gap_tx_power_params params = { + struct nble_gap_set_tx_power_req params = { .tx_power = tx_power, }; - nble_gap_tx_power_req(¶ms); + nble_gap_set_tx_power_req(¶ms); } -void on_nble_gap_tx_power_rsp(const struct nble_response *params) +void on_nble_gap_tx_power_rsp(const struct nble_common_rsp *rsp) { } void ble_gap_get_version(ble_get_version_cb_t func) { - struct nble_gap_get_version_param params; + nble_get_version_req(func); +} + +void on_nble_get_version_rsp(const struct nble_get_version_rsp *rsp) +{ + ble_get_version_cb_t cb = rsp->cb; - params.cb = func; + if (cb) { + cb(&rsp->ver); + } +} - nble_get_version_req(¶ms); +void on_nble_set_bda_rsp(const struct nble_set_bda_rsp *rsp) +{ + update_le_oob_local(&rsp->bda); + + if (rsp->cb) { + rsp->cb(rsp->status, rsp->user_data, &rsp->bda); + } } -void on_nble_get_version_rsp(const struct nble_version_response *par) +void on_nble_get_bda_rsp(const struct nble_get_bda_rsp *rsp) { - struct nble_gap_get_version_param param = par->params; - ble_get_version_cb_t cb = param.cb; + if (rsp->cb) { + rsp->cb(&rsp->bda, rsp->user_data); + } +} - if (cb) { - cb(&par->ver); +__weak +void on_nble_uart_test_evt(const struct nble_uart_test_evt *evt, + const uint8_t *data, uint8_t len) +{ +} + +int bt_le_oob_get_local(struct bt_le_oob *oob) +{ +#if defined(CONFIG_BLUETOOTH_PRIVACY) + bt_addr_le_copy(&oob->addr, &bt_dev.random_addr); +#else + bt_addr_le_copy(&oob->addr, &bt_dev.id_addr); +#endif /* CONFIG_BLUETOOTH_PRIVACY */ + + return 0; +} + +void on_nble_gap_rpa_update_evt(const struct nble_gap_rpa_update_evt *evt) +{ +#if defined(CONFIG_BLUETOOTH_PRIVACY) + /* Update the RPA address */ + bt_addr_le_copy(&bt_dev.random_addr, &evt->addr); +#endif /* CONFIG_BLUETOOTH_PRIVACY */ +} + +/* storage interface */ +void bt_storage_register(const struct bt_storage *storage) +{ + bt_storage = storage; +} + +void on_nble_storage_read_evt(const struct nble_storage_read_evt *evt) +{ + struct nble_storage_read_rsp_req req; + int len; + + req.status = -ENOTSUP; + req.addr = evt->addr; + req.key = evt->key; + + switch (evt->key) { + case BT_STORAGE_ID_ADDR: + len = sizeof(bt_addr_le_t); + break; + + case BT_STORAGE_ADDRESSES: + len = sizeof(bt_addr_le_t) * evt->max_num_keys; + break; + + case BT_STORAGE_SLAVE_LTK: + case BT_STORAGE_LTK: + len = sizeof(struct bt_storage_ltk); + break; + + case BT_STORAGE_IRK: + len = 16; /* irk[16] */ + break; + + default: + len = 64; /* P256 key */ + break; + } + + BT_DBG("nble_storage_rd_evt(key:0x%x) len:%d", evt->key, len); + + if (bt_storage) { + uint8_t data[len]; + + req.status = bt_storage->read(&evt->addr, evt->key, data, len); + + if (req.status < 0) { + BT_DBG("storage rd failed ret:%d", req.status); + len = 0; + } else { + if (evt->key != BT_STORAGE_ADDRESSES) { + BT_ASSERT(req.status == len); + } + + len = req.status; + req.status = 0; + } + + nble_storage_read_rsp_req(&req, data, len); + } else { + BT_DBG("No storage driver!"); + nble_storage_read_rsp_req(&req, NULL, 0); } } +void on_nble_storage_write_evt(const struct nble_storage_write_evt *evt, + const uint8_t *data, uint16_t len) +{ + int ret; + + if (!bt_storage) { + BT_DBG("No storage driver!"); + return; + } + + ret = bt_storage->write(&evt->addr, evt->key, data, len); + if (0 > ret) { + BT_ERR("storage write failed ret:%d", ret); + } + BT_DBG("storage wr(key:0x%x len:%d)", evt->key, len); +} + +int bt_storage_clear(bt_addr_le_t *addr) +{ +#if defined(CONFIG_BLUETOOTH_SMP) + struct nble_sm_clear_bonds_req params; + + memset(¶ms, 0, sizeof(params)); +#endif + if (addr) { + struct bt_conn *conn; + + conn = bt_conn_lookup_addr_le(addr); + if (conn) { + bt_conn_disconnect(conn, + BT_HCI_ERR_REMOTE_USER_TERM_CONN); + bt_conn_unref(conn); + } + +#if defined(CONFIG_BLUETOOTH_SMP) + bt_addr_le_copy(¶ms.addr, addr); + nble_sm_clear_bonds_req(¶ms); +#endif + + if (bt_storage) { + return bt_storage->clear(addr); + } + + return 0; + } + + bt_conn_disconnect_all(); + +#if defined(CONFIG_BLUETOOTH_SMP) + /* BT_ADDR_LE_ANY clears all */ + nble_sm_clear_bonds_req(¶ms); +#endif + + if (bt_storage) { + return bt_storage->clear(NULL); + } + + return 0; +} + void bt_le_set_device_name(char *device_name, int len) { - struct nble_gap_service_write_params gap_service_params; + struct nble_gap_service_req gap_service_params; if (len > 20) len = 20; memset(&gap_service_params, 0, sizeof(gap_service_params)); @@ -907,13 +1174,13 @@ void bt_le_set_device_name(char *device_name, int len) gap_service_params.name.len = len; gap_service_params.name.sec_mode = 0x11;// GAP_SEC_LEVEL_1 | GAP_SEC_MODE_1; memcpy(gap_service_params.name.name_array, device_name, len); - nble_gap_service_write_req(&gap_service_params); + nble_gap_service_req(&gap_service_params); } void bt_le_set_mac_address(bt_addr_le_t bda) { // Update the MAC addr - struct nble_set_bda_params params; + struct nble_set_bda_req params; params.cb = NULL; params.user_data = NULL; params.bda = bda; @@ -921,3 +1188,19 @@ void bt_le_set_mac_address(bt_addr_le_t bda) nble_set_bda_req(¶ms); } +void on_nble_common_rsp(const struct nble_common_rsp *rsp) +{ + if (rsp->status) { + BT_ERR("Last request failed, error %d", rsp->status); + return; + } + + BT_DBG("status %d", rsp->status); +} + +void on_nble_gap_set_tx_power_rsp(const struct nble_common_rsp *rsp) +{ + /* stub */ +} + + diff --git a/system/libarc32_arduino101/framework/src/services/ble/gatt.c b/system/libarc32_arduino101/framework/src/services/ble/gatt.c index fe5ce8e0..ac3d45f4 100644 --- a/system/libarc32_arduino101/framework/src/services/ble/gatt.c +++ b/system/libarc32_arduino101/framework/src/services/ble/gatt.c @@ -25,22 +25,23 @@ #include "gatt_internal.h" #include "hci_core.h" #include "conn_internal.h" +#include "gap_internal.h" /* #define BT_GATT_DEBUG 1 */ - -extern void on_nble_curie_log(char *fmt, ...); +#include "os/os.h" extern void __assert_fail(void); +#define TICKS_NONE 0 #ifdef BT_GATT_DEBUG -#define BT_DBG(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_ERR(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_WARN(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_INFO(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) +#define BT_DBG(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_ERR(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_WARN(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_INFO(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) #define BT_ASSERT(cond) ((cond) ? (void)0 : __assert_fail()) #else #define BT_DBG(fmt, ...) do {} while (0) -#define BT_ERR(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_WARN(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_INFO(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) +#define BT_ERR(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_WARN(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_INFO(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) #define BT_ASSERT(cond) ((cond) ? (void)0 : __assert_fail()) #endif @@ -51,12 +52,16 @@ struct ble_gatt_service { uint16_t attr_count; /* Number of attributes in the array */ }; -struct ble_gatts_flush_all { - struct bt_conn *conn; - int status; - uint8_t flag; +struct prep_data { + void *nano_fifo_data; + const struct bt_gatt_attr *attr; + uint16_t offset; + uint8_t len; + uint8_t *buf; }; +static struct os_fifo prep_queue; + static struct ble_gatt_service db[CONFIG_BT_GATT_BLE_MAX_SERVICES]; static uint8_t db_cnt; @@ -83,9 +88,8 @@ static uint8_t bt_gatt_uuid_memcpy(uint8_t *buf, /* Store the UUID data */ if (uuid->type == BT_UUID_TYPE_16) { uint16_t le16; - - memcpy(&le16, &BT_UUID_16(uuid)->val, sizeof(le16)); - le16 = sys_cpu_to_le16(le16); + + le16 = sys_cpu_to_le16(BT_UUID_16(uuid)->val); memcpy(ptr, &le16, sizeof(le16)); ptr += sizeof(le16); } else { @@ -142,7 +146,7 @@ static int attr_read(struct bt_gatt_attr *attr, uint8_t *data, size_t len) int bt_gatt_register(struct bt_gatt_attr *attrs, size_t count) { size_t attr_table_size, i; - struct nble_gatt_register_req param; + struct nble_gatts_register_req param; /* TODO: Replace the following with net_buf */ uint8_t attr_table[N_BLE_BUF_SIZE]; @@ -161,7 +165,7 @@ int bt_gatt_register(struct bt_gatt_attr *attrs, size_t count) for (i = 0; i < count; i++) { struct bt_gatt_attr *attr = &attrs[i]; - struct ble_gatt_attr *att; + struct nble_gatts_attr *att; int data_size; if (attr_table_size + sizeof(*att) > sizeof(attr_table)) { @@ -169,6 +173,7 @@ int bt_gatt_register(struct bt_gatt_attr *attrs, size_t count) } att = (void *)&attr_table[attr_table_size]; + att->attr = attr; att->perm = attr->perm; /* Read attribute data */ @@ -189,11 +194,11 @@ int bt_gatt_register(struct bt_gatt_attr *attrs, size_t count) attr_table_size += (sizeof(*att) + att->data_size + 3) & ~3; } - nble_gatt_register_req(¶m, attr_table, attr_table_size); + nble_gatts_register_req(¶m, attr_table, attr_table_size); return 0; } -void on_nble_gatt_register_rsp(const struct nble_gatt_register_rsp *rsp, +void on_nble_gatts_register_rsp(const struct nble_gatts_register_rsp *rsp, const struct nble_gatt_attr_handles *handles, uint8_t len) { @@ -209,12 +214,10 @@ void on_nble_gatt_register_rsp(const struct nble_gatt_register_rsp *rsp, for (i = 0; i < rsp->attr_count; i++) { if (handles[i].handle != 0) { - uint16_t le16; - memcpy(&le16, &BT_UUID_16(rsp->attr_base[i].uuid)->val, sizeof(le16)); BT_DBG("gatt: i %d, h %d, type %d, u16 0x%x", i, handles[i].handle, rsp->attr_base[i].uuid->type, - le16); + BT_UUID_16(rsp->attr_base[i].uuid)->val); } } } @@ -248,10 +251,7 @@ ssize_t bt_gatt_attr_read_service(struct bt_conn *conn, struct bt_uuid *uuid = attr->user_data; if (uuid->type == BT_UUID_TYPE_16) { - uint16_t uuid16; - - memcpy(&uuid16, &BT_UUID_16(uuid)->val, sizeof(uuid16)); - uuid16 = sys_cpu_to_le16(uuid16); + uint16_t uuid16 = sys_cpu_to_le16(BT_UUID_16(uuid)->val); return bt_gatt_attr_read(conn, attr, buf, len, offset, &uuid16, 2); @@ -261,36 +261,20 @@ ssize_t bt_gatt_attr_read_service(struct bt_conn *conn, BT_UUID_128(uuid)->val, 16); } -struct gatt_incl { - uint16_t start_handle; - uint16_t end_handle; - uint16_t uuid16; -} __packed; - ssize_t bt_gatt_attr_read_included(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct bt_gatt_include *incl = attr->user_data; - struct gatt_incl pdu; - uint8_t value_len; + struct bt_gatt_attr *incl = attr->user_data; - pdu.start_handle = sys_cpu_to_le16(incl->start_handle); - pdu.end_handle = sys_cpu_to_le16(incl->end_handle); - value_len = sizeof(pdu.start_handle) + sizeof(pdu.end_handle); - - /* - * Core 4.2, Vol 3, Part G, 3.2, - * The Service UUID shall only be present when the UUID is a 16-bit - * Bluetooth UUID. - */ - if (incl->uuid->type == BT_UUID_TYPE_16) { - memcpy(&pdu.uuid16, &BT_UUID_16(incl->uuid)->val, sizeof(pdu.uuid16)); - pdu.uuid16 = sys_cpu_to_le16(pdu.uuid16); - value_len += sizeof(pdu.uuid16); + /* nble gatt register case reading user_data. */ + if (!conn) { + return bt_gatt_attr_read(conn, attr, buf, len, offset, &incl, + sizeof(incl)); } - return bt_gatt_attr_read(conn, attr, buf, len, offset, &pdu, value_len); + /* nble handles gattc reads internally */ + return -EINVAL; } struct gatt_chrc { @@ -332,8 +316,7 @@ ssize_t bt_gatt_attr_read_chrc(struct bt_conn *conn, value_len = sizeof(pdu.properties) + sizeof(pdu.value_handle); if (chrc->uuid->type == BT_UUID_TYPE_16) { - memcpy(&pdu.uuid16, &BT_UUID_16(chrc->uuid)->val, sizeof(pdu.uuid16)); - pdu.uuid16 = sys_cpu_to_le16(pdu.uuid16); + pdu.uuid16 = sys_cpu_to_le16(BT_UUID_16(chrc->uuid)->val); value_len += 2; } else { memcpy(pdu.uuid, BT_UUID_128(chrc->uuid)->val, 16); @@ -464,26 +447,20 @@ static bool is_bonded(const bt_addr_le_t *addr) ssize_t bt_gatt_attr_write_ccc(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, - uint16_t len, uint16_t offset) + uint16_t len, uint16_t offset, uint8_t flags) { struct _bt_gatt_ccc *ccc = attr->user_data; const uint16_t *data = buf; size_t i; - //BT_DBG("%s", __FUNCTION__); - if (offset > sizeof(*data)) { return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); } - //BT_DBG("%s1", __FUNCTION__); - if (offset + len > sizeof(*data)) { return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); } - //BT_DBG("%s2", __FUNCTION__); - for (i = 0; i < ccc->cfg_len; i++) { /* Check for existing configuration */ if (!bt_addr_le_cmp(&ccc->cfg[i].peer, &conn->le.dst)) { @@ -491,8 +468,6 @@ ssize_t bt_gatt_attr_write_ccc(struct bt_conn *conn, } } - //BT_DBG("%s3", __FUNCTION__); - if (i == ccc->cfg_len) { for (i = 0; i < ccc->cfg_len; i++) { /* Check for unused configuration */ @@ -512,12 +487,9 @@ ssize_t bt_gatt_attr_write_ccc(struct bt_conn *conn, } } - //BT_DBG("%s len-%p", __FUNCTION__, ccc); - ccc->cfg[i].value = sys_le16_to_cpu(*data); - //BT_DBG("%s 5len-%d", __FUNCTION__, len); - //BT_DBG("handle 0x%04x value %u", attr->handle, *data); + BT_DBG("handle 0x%04x value %u", attr->handle, *data); /* Update cfg if don't match */ if (ccc->value != *data) { @@ -571,33 +543,33 @@ static int att_notify(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *data, size_t len, bt_gatt_notify_sent_func_t cb) { - struct nble_gatt_send_notif_params notif; + struct nble_gatts_notify_req req; - notif.conn_handle = conn->handle; - notif.params.attr = attr; - notif.params.offset = 0; - notif.cback = cb; + req.params.conn_handle = conn->handle; + req.params.attr = attr; + req.params.offset = 0; + req.cback = cb; - nble_gatt_send_notif_req(¬if, data, len); + nble_gatts_notify_req(&req, data, len); return 0; } -void on_nble_gatts_send_notif_rsp(const struct nble_gatt_notif_rsp *rsp) +void on_nble_gatts_notify_tx_evt(const struct nble_gatts_notify_tx_evt *evt) { struct bt_conn *conn; - conn = bt_conn_lookup_handle(rsp->conn_handle); + conn = bt_conn_lookup_handle(evt->conn_handle); if (conn) { - if (rsp->cback) { - rsp->cback(conn, rsp->attr, rsp->status); + if (evt->cback) { + evt->cback(conn, evt->attr, (uint8_t)evt->status); } bt_conn_unref(conn); } } -void on_nble_gatts_send_ind_rsp(const struct nble_gatt_ind_rsp *rsp) +void on_nble_gatts_indicate_rsp(const struct nble_gatts_indicate_rsp *rsp) { struct bt_conn *conn; @@ -614,14 +586,14 @@ void on_nble_gatts_send_ind_rsp(const struct nble_gatt_ind_rsp *rsp) static int att_indicate(struct bt_conn *conn, struct bt_gatt_indicate_params *params) { - struct nble_gatt_send_ind_params ind; + struct nble_gatts_indicate_req req; - ind.conn_handle = conn->handle; - ind.cback = params->func; - ind.params.attr = params->attr; - ind.params.offset = 0; + req.params.conn_handle = conn->handle; + req.params.attr = params->attr; + req.params.offset = 0; + req.cback = params->func; - nble_gatt_send_ind_req(&ind, params->data, params->len); + nble_gatts_indicate_req(&req, params->data, params->len); return 0; } @@ -664,7 +636,12 @@ static uint8_t notify_cb(const struct bt_gatt_attr *attr, void *user_data) } conn = bt_conn_lookup_addr_le(&ccc->cfg[i].peer); - if (!conn || conn->state != BT_CONN_CONNECTED) {//Bug here + if (!conn) { + continue; + } + + if (conn->state != BT_CONN_CONNECTED) { + bt_conn_unref(conn); continue; } @@ -804,6 +781,11 @@ static uint8_t disconnected_cb(const struct bt_gatt_attr *attr, void *user_data) bt_conn_unref(tmp); } + } else { + /* Clear value if not paired */ + if (!ccc->cfg[i].valid) + memset(&ccc->cfg[i].value, 0, + sizeof(ccc->cfg[i].value)); } } @@ -819,98 +801,126 @@ static uint8_t disconnected_cb(const struct bt_gatt_attr *attr, void *user_data) return BT_GATT_ITER_CONTINUE; } -void on_nble_gatts_write_evt(const struct nble_gatt_wr_evt *evt, +static ssize_t on_prep_write(const struct nble_gatts_write_evt *evt, + const uint8_t *buf, uint8_t buflen) +{ + const struct bt_gatt_attr *attr = evt->attr; + struct bt_conn *conn = bt_conn_lookup_handle(evt->conn_handle); + ssize_t status; + + struct prep_data *data; + data = nble_curie_alloc_hook(sizeof (struct prep_data)); + + /* Assert if memory allocation failed */ + BT_ASSERT(data); + + data->attr = attr; + data->offset = evt->offset; + data->len = buflen; + + data->buf = nble_curie_alloc_hook(buflen); + + /* Assert if memory allocation failed */ + BT_ASSERT(data->buf); + + memcpy(data->buf, buf, buflen); + + if (!(attr->perm & BT_GATT_PERM_PREPARE_WRITE)) { + return BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED); + } + + /* Write attribute value to check if device is authorized */ + status = attr->write(conn, attr, buf, buflen, evt->offset, + BT_GATT_WRITE_FLAG_PREPARE); + + /* Store data in the queue */ + fifo_put(&prep_queue, data); + + if (conn) + bt_conn_unref(conn); + + return status; +} + +void on_nble_gatts_write_evt(const struct nble_gatts_write_evt *evt, const uint8_t *buf, uint8_t buflen) { const struct bt_gatt_attr *attr = evt->attr; struct bt_conn *conn = bt_conn_lookup_handle(evt->conn_handle); - struct nble_gatts_wr_reply_params reply_data; + struct nble_gatts_write_reply_req req; - //BT_DBG("write_evt %p", attr); + BT_DBG("write_evt %p", attr); - /* Check for write support and flush support in case of prepare */ - if (!attr->write || - ((evt->flag & NBLE_GATT_WR_FLAG_PREP) && !attr->flush)) { - reply_data.status = BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED); + /* Check for write support */ + if (!attr->write) { + req.status = BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED); goto reply; } - //BT_DBG("%s", __FUNCTION__); - reply_data.status = attr->write(conn, attr, buf, buflen, evt->offset); - if (reply_data.status < 0) { - - //BT_DBG("%s1-1", __FUNCTION__); + /* Check for prepare writes */ + if (evt->flag & NBLE_GATT_WR_FLAG_PREP) { + req.status = on_prep_write(evt, buf, buflen); goto reply; } - //BT_DBG("%s1", __FUNCTION__); + req.status = attr->write(conn, attr, buf, buflen, evt->offset, 0); + if (req.status < 0) { + goto reply; + } /* Return an error if not all data has been written */ - if (reply_data.status != buflen) { - reply_data.status = BT_GATT_ERR(BT_ATT_ERR_UNLIKELY); + if (req.status != buflen) { + req.status = BT_GATT_ERR(BT_ATT_ERR_UNLIKELY); goto reply; } - //BT_DBG("%s2", __FUNCTION__); - - if (attr->flush && !(evt->flag & NBLE_GATT_WR_FLAG_PREP)) - reply_data.status = attr->flush(conn, attr, BT_GATT_FLUSH_SYNC); - - //BT_DBG("%s3", __FUNCTION__); - reply: - //BT_DBG("%s4", __FUNCTION__); if (evt->flag & NBLE_GATT_WR_FLAG_REPLY) { - reply_data.conn_handle = evt->conn_handle; + req.conn_handle = evt->conn_handle; + req.offset = evt->offset; - nble_gatts_wr_reply_req(&reply_data); + nble_gatts_write_reply_req(&req, buf, buflen); } if (conn) bt_conn_unref(conn); } -static uint8_t flush_all(const struct bt_gatt_attr *attr, void *user_data) +void on_nble_gatts_write_exec_evt(const struct nble_gatts_write_exec_evt *evt) { - struct ble_gatts_flush_all *flush_data = user_data; - - if (attr->flush) { - int status = attr->flush(flush_data->conn, attr, flush_data->flag); - - if (status < 0 && flush_data->status == 0) - flush_data->status = status; - } + struct bt_conn *conn = bt_conn_lookup_handle(evt->conn_handle); + const struct bt_gatt_attr *attr; + struct nble_gatts_write_reply_req req; + struct prep_data *data; - return BT_GATT_ITER_CONTINUE; -} + req.conn_handle = evt->conn_handle; + req.status = 0; -void on_nble_gatts_write_exec_evt(const struct nble_gatt_wr_exec_evt *evt) -{ BT_DBG("write_exec_evt"); - struct ble_gatts_flush_all flush_data = { - .conn = bt_conn_lookup_handle(evt->conn_handle), - .flag = evt->flag, - .status = 0, - }; + while ((data = fifo_get(&prep_queue, TICKS_NONE))) { + attr = data->attr; - bt_gatt_foreach_attr(0x0001, 0xFFFF, flush_all, &flush_data); + /* If an error occurred just discard the data */ + if (req.status >= 0) + req.status = attr->write(conn, attr, data->buf, data->len, + data->offset, 0); - struct nble_gatts_wr_reply_params reply_data = { - .conn_handle = evt->conn_handle, - .status = flush_data.status, - }; - nble_gatts_wr_reply_req(&reply_data); + nble_curie_free_hook(data->buf); + nble_curie_free_hook(data); + } + + nble_gatts_write_reply_req(&req, NULL, 0); - bt_conn_unref(flush_data.conn); + bt_conn_unref(conn); } -void on_nble_gatts_read_evt(const struct nble_gatt_rd_evt *evt) +void on_nble_gatts_read_evt(const struct nble_gatts_read_evt *evt) { - struct nble_gatts_rd_reply_params reply_data; + struct nble_gatts_read_reply_req req; const struct bt_gatt_attr *attr; /* The length of the value sent back in the response is unknown because * of NRF API limitation, so we use the max possible one: ATT_MTU-1 */ @@ -921,7 +931,7 @@ void on_nble_gatts_read_evt(const struct nble_gatt_rd_evt *evt) BT_DBG("read_evt %p", attr); - memset(&reply_data, 0, sizeof(reply_data)); + memset(&req, 0, sizeof(req)); if (attr->read) { struct bt_conn *conn = bt_conn_lookup_handle(evt->conn_handle); @@ -936,38 +946,36 @@ void on_nble_gatts_read_evt(const struct nble_gatt_rd_evt *evt) } /* status >= 0 is considered as success by nble */ - reply_data.status = len; + req.status = len; if (len < 0) { len = 0; } - reply_data.conn_handle = evt->conn_handle; + req.conn_handle = evt->conn_handle; /* offset is needed by nble even in error case */ - reply_data.offset = evt->offset; + req.offset = evt->offset; - nble_gatts_rd_reply_req(&reply_data, data, len); + nble_gatts_read_reply_req(&req, data, len); } #if defined(CONFIG_BLUETOOTH_GATT_CLIENT) -void on_nble_gattc_value_evt(const struct ble_gattc_value_evt *evt, - uint8_t *data, uint8_t length) +void on_nble_gattc_value_evt(const struct nble_gattc_value_evt *evt, + uint8_t *data, uint8_t len) { struct bt_gatt_subscribe_params *params; struct bt_conn *conn; conn = bt_conn_lookup_handle(evt->conn_handle); - //BT_DBG("FUNC %s", __FUNCTION__); - if (conn) { for (params = subscriptions; params; params = params->_next) { if (evt->handle != params->value_handle) { continue; } - if (params->notify(conn, params, data, length) == + if (params->notify(conn, params, data, len) == BT_GATT_ITER_STOP) { bt_gatt_unsubscribe(conn, params); } @@ -1048,7 +1056,6 @@ void on_nble_gattc_discover_rsp(const struct nble_gattc_discover_rsp *rsp, struct bt_gatt_attr *attr = NULL; if (rsp->type == BT_GATT_DISCOVER_PRIMARY) { - //BT_DBG("%s-%d", __FUNCTION__, __LINE__); const struct nble_gattc_primary *gattr = (void *)&data[i * sizeof(*gattr)]; if ((gattr->range.start_handle < params->start_handle) && @@ -1083,8 +1090,9 @@ void on_nble_gattc_discover_rsp(const struct nble_gattc_discover_rsp *rsp, /* Data is not available at this point */ break; } - attr = (&(struct bt_gatt_attr) - BT_GATT_INCLUDE_SERVICE(&inc_value)); + attr = (&(struct bt_gatt_attr) { + .uuid = BT_UUID_GATT_INCLUDE, + .user_data = &inc_value, }); attr->handle = gattr->handle; last_handle = gattr->handle; } else if (rsp->type == BT_GATT_DISCOVER_CHARACTERISTIC) { @@ -1095,10 +1103,6 @@ void on_nble_gattc_discover_rsp(const struct nble_gattc_discover_rsp *rsp, gattr->prop)); attr->handle = gattr->handle; last_handle = gattr->handle; - /* Skip if UUID is set but doesn't match */ - if (params->uuid && bt_uuid_cmp(&gattr->uuid.uuid, params->uuid)) { - continue; - } } else if (rsp->type == BT_GATT_DISCOVER_DESCRIPTOR) { const struct nble_gattc_descriptor *gattr = (void *)&data[i * sizeof(*gattr)]; @@ -1141,7 +1145,7 @@ void on_nble_gattc_discover_rsp(const struct nble_gattc_discover_rsp *rsp, int bt_gatt_discover(struct bt_conn *conn, struct bt_gatt_discover_params *params) { - struct nble_discover_params discover_params; + struct nble_gattc_discover_req req; if (!conn || !params || !params->func || !params->start_handle || !params->end_handle || params->start_handle > params->end_handle) { @@ -1154,15 +1158,15 @@ int bt_gatt_discover(struct bt_conn *conn, BT_DBG("disc: %d", params->start_handle); - memset(&discover_params, 0, sizeof(discover_params)); + memset(&req, 0, sizeof(req)); switch (params->type) { case BT_GATT_DISCOVER_PRIMARY: case BT_GATT_DISCOVER_CHARACTERISTIC: if (params->uuid) { /* Always copy a full 128 bit UUID */ - discover_params.uuid = *BT_UUID_128(params->uuid); - discover_params.flags = DISCOVER_FLAGS_UUID_PRESENT; + req.uuid = *BT_UUID_128(params->uuid); + req.flags = DISCOVER_FLAGS_UUID_PRESENT; } break; @@ -1173,20 +1177,20 @@ int bt_gatt_discover(struct bt_conn *conn, return -EINVAL; } - discover_params.conn_handle = conn->handle; - discover_params.type = params->type; - discover_params.handle_range.start_handle = params->start_handle; - discover_params.handle_range.end_handle = params->end_handle; + req.conn_handle = conn->handle; + req.type = params->type; + req.handle_range.start_handle = params->start_handle; + req.handle_range.end_handle = params->end_handle; - discover_params.user_data = params; + req.user_data = params; - nble_gattc_discover_req(&discover_params); + nble_gattc_discover_req(&req); return 0; } -void on_nble_gattc_read_multiple_rsp(const struct ble_gattc_read_rsp *rsp, - uint8_t *pdu, uint8_t length) +void on_nble_gattc_read_multi_rsp(const struct nble_gattc_read_rsp *rsp, + uint8_t *data, uint8_t len) { struct bt_gatt_read_params *params; struct bt_conn *conn = bt_conn_lookup_handle(rsp->conn_handle); @@ -1203,7 +1207,7 @@ void on_nble_gattc_read_multiple_rsp(const struct ble_gattc_read_rsp *rsp, return; } - params->func(conn, 0, params, pdu, length); + params->func(conn, 0, params, data, len); /* mark read as complete since read multiple is single response */ params->func(conn, 0, params, NULL, 0); @@ -1211,8 +1215,8 @@ void on_nble_gattc_read_multiple_rsp(const struct ble_gattc_read_rsp *rsp, bt_conn_unref(conn); } -void on_nble_gattc_read_rsp(const struct ble_gattc_read_rsp *rsp, - uint8_t *pdu, uint8_t length) +void on_nble_gattc_read_rsp(const struct nble_gattc_read_rsp *rsp, + uint8_t *data, uint8_t len) { struct bt_gatt_read_params *params; struct bt_conn *conn = bt_conn_lookup_handle(rsp->conn_handle); @@ -1227,7 +1231,7 @@ void on_nble_gattc_read_rsp(const struct ble_gattc_read_rsp *rsp, return; } - if (params->func(conn, 0, params, pdu, length) == BT_GATT_ITER_STOP) { + if (params->func(conn, 0, params, data, len) == BT_GATT_ITER_STOP) { bt_conn_unref(conn); return; } @@ -1238,13 +1242,13 @@ void on_nble_gattc_read_rsp(const struct ble_gattc_read_rsp *rsp, * in length, the Read Long Characteristic Value procedure may be used * if the rest of the Characteristic Value is required. */ - if (length < BLE_GATT_MTU_SIZE - 1) { + if (len < BLE_GATT_MTU_SIZE - 1) { params->func(conn, 0, params, NULL, 0); bt_conn_unref(conn); return; } - params->single.offset += length; + params->single.offset += len; /* Continue reading the attribute */ if (bt_gatt_read(conn, params)) { @@ -1256,27 +1260,28 @@ void on_nble_gattc_read_rsp(const struct ble_gattc_read_rsp *rsp, int bt_gatt_read(struct bt_conn *conn, struct bt_gatt_read_params *params) { - struct ble_gattc_read_params single_req; - struct ble_gattc_read_multiple_params mutiple_req; + struct nble_gattc_read_req sreq; + struct nble_gattc_read_multi_req mreq; if (!conn || conn->state != BT_CONN_CONNECTED || !params || params->handle_count == 0 || !params->func) { return -EINVAL; } - single_req.conn_handle = conn->handle; + sreq.conn_handle = conn->handle; if (1 == params->handle_count) { - single_req.handle = params->single.handle; - single_req.offset = params->single.offset; - single_req.user_data = params; + sreq.handle = params->single.handle; + sreq.offset = params->single.offset; + sreq.user_data = params; - nble_gattc_read_req(&single_req); + nble_gattc_read_req(&sreq); } else { - mutiple_req.conn_handle = conn->handle; - mutiple_req.user_data = params; + mreq.conn_handle = conn->handle; + mreq.user_data = params; - nble_gattc_read_multiple_req(&mutiple_req, params->handles, 2 * params->handle_count); + nble_gattc_read_multi_req(&mreq, params->handles, + 2 * params->handle_count); } return 0; } @@ -1287,9 +1292,9 @@ static void on_write_no_rsp_complete(struct bt_conn *conn, uint8_t err, } static void on_write_complete(struct bt_conn *conn, uint8_t err, - const struct bt_gatt_write_params *wr_params) + const struct nble_gattc_write_param *wr_params) { - bt_gatt_write_rsp_func_t func = wr_params->user_data[0]; + bt_gatt_rsp_func_t func = wr_params->user_data[0]; const void *data = wr_params->user_data[1]; BT_ASSERT(func); @@ -1298,9 +1303,9 @@ static void on_write_complete(struct bt_conn *conn, uint8_t err, static int _bt_gatt_write(struct bt_conn *conn, uint16_t handle, bool with_resp, uint16_t offset, const void *data, uint16_t length, - struct bt_gatt_write_params *wr_params) + struct nble_gattc_write_param *wr_params) { - struct ble_gattc_write_params req; + struct nble_gattc_write_req req; req.conn_handle = conn->handle; req.handle = handle; @@ -1313,7 +1318,7 @@ static int _bt_gatt_write(struct bt_conn *conn, uint16_t handle, bool with_resp, return 0; } -void on_nble_gattc_write_rsp(const struct ble_gattc_write_rsp *rsp) +void on_nble_gattc_write_rsp(const struct nble_gattc_write_rsp *rsp) { struct bt_conn *conn = bt_conn_lookup_handle(rsp->conn_handle); @@ -1327,32 +1332,35 @@ void on_nble_gattc_write_rsp(const struct ble_gattc_write_rsp *rsp) bt_conn_unref(conn); } - int bt_gatt_write_without_response(struct bt_conn *conn, uint16_t handle, const void *data, uint16_t length, bool sign) { - return bt_gatt_write(conn, handle, 0, data, length, - on_write_no_rsp_complete); + struct bt_gatt_write_params p; + p.func = on_write_no_rsp_complete; + p.handle = handle; + p.offset = 0; + p.data = data; + p.length = length; + return bt_gatt_write(conn, &p); } -int bt_gatt_write(struct bt_conn *conn, uint16_t handle, uint16_t offset, - const void *data, uint16_t length, - bt_gatt_write_rsp_func_t func) +int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params) { - struct bt_gatt_write_params wr_params; + struct nble_gattc_write_param wr_params; - if (!conn || conn->state != BT_CONN_CONNECTED || !handle || !func) { + if (!conn || conn->state != BT_CONN_CONNECTED || !params->handle || + !params->func) { return -EINVAL; } wr_params.func = on_write_complete; - wr_params.user_data[0] = func; - wr_params.user_data[1] = (void *)data; + wr_params.user_data[0] = params->func; + wr_params.user_data[1] = (void *)params->data; - return _bt_gatt_write(conn, handle, - (func == on_write_no_rsp_complete) + return _bt_gatt_write(conn, params->handle, + (params->func == on_write_no_rsp_complete) ? false : true, - offset, data, length, &wr_params); + params->offset, params->data, params->length, &wr_params); } static void gatt_subscription_add(struct bt_conn *conn, @@ -1366,7 +1374,7 @@ static void gatt_subscription_add(struct bt_conn *conn, } static void att_write_ccc_rsp(struct bt_conn *conn, uint8_t err, - const struct bt_gatt_write_params *wr_params) + const struct nble_gattc_write_param *wr_params) { struct bt_gatt_subscribe_params *params = wr_params->user_data[0]; @@ -1389,7 +1397,7 @@ static int gatt_write_ccc(struct bt_conn *conn, uint16_t handle, uint16_t value, bt_att_func_t func, struct bt_gatt_subscribe_params *params) { - struct bt_gatt_write_params wr_params; + struct nble_gattc_write_param wr_params; wr_params.func = func; wr_params.user_data[0] = params; @@ -1520,26 +1528,26 @@ static void add_subscriptions(struct bt_conn *conn) #else void on_nble_gattc_discover_rsp(const struct nble_gattc_discover_rsp *rsp, - const uint8_t *data, uint8_t data_len) + const uint8_t *data, uint8_t data_len) { } -void on_nble_gattc_write_rsp(const struct ble_gattc_write_rsp *rsp) +void on_nble_gattc_write_rsp(const struct nble_gattc_write_rsp *rsp) { } -void on_nble_gattc_value_evt(const struct ble_gattc_value_evt *evt, - uint8_t *buf, uint8_t buflen) +void on_nble_gattc_value_evt(const struct nble_gattc_value_evt *evt, + uint8_t *buf, uint8_t buflen) { } -void on_nble_gattc_read_rsp(const struct ble_gattc_read_rsp *rsp, - uint8_t *data, uint8_t data_len) +void on_nble_gattc_read_rsp(const struct nble_gattc_read_rsp *rsp, + uint8_t *data, uint8_t data_len) { } -void on_nble_gattc_read_multiple_rsp(const struct ble_gattc_read_rsp *rsp, - uint8_t *data, uint8_t data_len) +void on_nble_gattc_read_multi_rsp(const struct nble_gattc_read_rsp *rsp, + uint8_t *data, uint8_t data_len) { } @@ -1549,6 +1557,8 @@ void bt_gatt_connected(struct bt_conn *conn) { BT_DBG("conn %p", conn); bt_gatt_foreach_attr(0x0001, 0xffff, connected_cb, conn); + fifo_init(&prep_queue); + #if defined(CONFIG_BLUETOOTH_GATT_CLIENT) add_subscriptions(conn); #endif /* CONFIG_BLUETOOTH_GATT_CLIENT */ @@ -1556,9 +1566,17 @@ void bt_gatt_connected(struct bt_conn *conn) void bt_gatt_disconnected(struct bt_conn *conn) { + struct prep_data *data; + BT_DBG("conn %p", conn); - bt_gatt_foreach_attr(0x0001, 0xffff, disconnected_cb, conn); + /* Discard queued buffers */ + while ((data = fifo_get(&prep_queue, TICKS_NONE))) { + nble_curie_free_hook(data->buf); + nble_curie_free_hook(data); + } + + bt_gatt_foreach_attr(0x0001, 0xffff, disconnected_cb, conn); #if defined(CONFIG_BLUETOOTH_GATT_CLIENT) /* If bonded don't remove subscriptions */ if (is_bonded(&conn->le.dst)) { diff --git a/system/libarc32_arduino101/framework/src/services/ble/hci_core.h b/system/libarc32_arduino101/framework/src/services/ble/hci_core.h index dc7374b0..5bb0a58d 100644 --- a/system/libarc32_arduino101/framework/src/services/ble/hci_core.h +++ b/system/libarc32_arduino101/framework/src/services/ble/hci_core.h @@ -16,6 +16,9 @@ /* State tracking for the local Bluetooth controller */ struct bt_dev { + /* Local Identity Address */ + bt_addr_le_t id_addr; + bt_addr_le_t random_addr; atomic_t flags[1]; }; extern struct bt_dev bt_dev; @@ -29,7 +32,7 @@ static inline bool bt_addr_le_is_rpa(const bt_addr_le_t *addr) if (addr->type != BT_ADDR_LE_RANDOM) return false; - if ((addr->val[5] & 0xc0) == 0x40) + if ((addr->a.val[5] & 0xc0) == 0x40) return true; return false; @@ -41,7 +44,7 @@ static inline bool bt_addr_le_is_identity(const bt_addr_le_t *addr) return true; /* Check for Random Static address type */ - if ((addr->val[5] & 0xc0) == 0xc0) + if ((addr->a.val[5] & 0xc0) == 0xc0) return true; return false; diff --git a/system/libarc32_arduino101/framework/src/services/ble/l2cap.c b/system/libarc32_arduino101/framework/src/services/ble/l2cap.c index 488cfd0e..a4c87394 100644 --- a/system/libarc32_arduino101/framework/src/services/ble/l2cap.c +++ b/system/libarc32_arduino101/framework/src/services/ble/l2cap.c @@ -25,19 +25,18 @@ /* #define BT_GATT_DEBUG 1 */ -extern void on_nble_curie_log(char *fmt, ...); extern void __assert_fail(void); #ifdef BT_GATT_DEBUG -#define BT_DBG(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_ERR(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_WARN(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_INFO(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) +#define BT_DBG(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_ERR(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_WARN(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_INFO(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) #define BT_ASSERT(cond) ((cond) ? (void)0 : __assert_fail()) #else #define BT_DBG(fmt, ...) do {} while (0) -#define BT_ERR(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_WARN(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_INFO(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) +#define BT_ERR(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_WARN(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_INFO(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) #define BT_ASSERT(cond) ((cond) ? (void)0 : __assert_fail()) #endif diff --git a/system/libarc32_arduino101/framework/src/services/ble/smp.h b/system/libarc32_arduino101/framework/src/services/ble/smp.h index 4f52c002..7ad3f0b9 100644 --- a/system/libarc32_arduino101/framework/src/services/ble/smp.h +++ b/system/libarc32_arduino101/framework/src/services/ble/smp.h @@ -69,11 +69,10 @@ void bt_smp_pkey_ready(void); int bt_smp_init(void); int bt_smp_auth_passkey_entry(struct bt_conn *conn, unsigned int passkey); -int bt_smp_auth_passkey_confirm(struct bt_conn *conn, bool match); +int bt_smp_auth_passkey_confirm(struct bt_conn *conn); +int bt_smp_auth_pairing_confirm(struct bt_conn *conn); int bt_smp_auth_cancel(struct bt_conn *conn); -int bt_smp_remove_info(const bt_addr_le_t *addr); - #ifdef CONFIG_BLUETOOTH_SMP void bt_smp_connected(struct bt_conn *conn); void bt_smp_disconnected(struct bt_conn *conn); diff --git a/system/libarc32_arduino101/framework/src/services/ble/smp_null.c b/system/libarc32_arduino101/framework/src/services/ble/smp_null.c index cdc3a4d5..025ef33d 100644 --- a/system/libarc32_arduino101/framework/src/services/ble/smp_null.c +++ b/system/libarc32_arduino101/framework/src/services/ble/smp_null.c @@ -27,19 +27,18 @@ /* #define BT_GATT_DEBUG 1 */ -extern void on_nble_curie_log(char *fmt, ...); extern void __assert_fail(void); #ifdef BT_GATT_DEBUG -#define BT_DBG(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_ERR(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_WARN(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_INFO(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) +#define BT_DBG(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_ERR(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_WARN(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_INFO(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) #define BT_ASSERT(cond) ((cond) ? (void)0 : __assert_fail()) #else #define BT_DBG(fmt, ...) do {} while (0) -#define BT_ERR(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_WARN(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) -#define BT_INFO(fmt, ...) on_nble_curie_log(fmt, ##__VA_ARGS__) +#define BT_ERR(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_WARN(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) +#define BT_INFO(fmt, ...) nble_curie_log_hook(fmt, ##__VA_ARGS__) #define BT_ASSERT(cond) ((cond) ? (void)0 : __assert_fail()) #endif @@ -53,66 +52,56 @@ extern void __assert_fail(void); #define NBLE_SMP_AUTH_OPTIONS 0 #define NBLE_SMP_OBB_PRESENT BT_SMP_OOB_NOT_PRESENT -#if NOT_USED_FOR_NOW -int bt_smp_sign_verify(struct bt_conn *conn, struct net_buf *buf) -{ - return -ENOTSUP; -} -int bt_smp_sign(struct bt_conn *conn, struct net_buf *buf) +int bt_smp_init(void) { - return -ENOTSUP; + return 0; } -#endif -void on_nble_gap_sm_bond_info_rsp(const struct nble_gap_sm_bond_info_rsp *rsp, - const bt_addr_le_t *peer_addr, uint16_t len) +void on_nble_sm_bond_info_rsp(const struct nble_sm_bond_info_rsp *par, + const bt_addr_le_t *peer_addr, uint16_t len) { /* stub */ } -void on_nble_gap_sm_passkey_req_evt(const struct nble_gap_sm_passkey_req_evt * p_evt) +void on_nble_sm_passkey_req_evt(const struct nble_sm_passkey_req_evt *evt) { /* stub */ } -void on_nble_gap_sm_passkey_display_evt( - const struct nble_gap_sm_passkey_disp_evt *p_evt) +void on_nble_sm_passkey_disp_evt(const struct nble_sm_passkey_disp_evt *evt) { /* stub */ } -void on_nble_gap_sm_status_evt(const struct nble_gap_sm_status_evt *evt) +void on_nble_sm_status_evt(const struct nble_sm_status_evt *evt) { /* stub */ - BT_INFO("nble_gap_sm_status_evt: %d, gap_status: %d", - evt->evt_type, evt->status); } -int bt_smp_init(void) +void on_nble_sm_common_rsp(const struct nble_sm_common_rsp *rsp) { - struct nble_gap_sm_config_params params = { - .options = NBLE_SMP_AUTH_OPTIONS, - .io_caps = NBLE_SMP_IO_CAPS, - .key_size = BT_SMP_MAX_ENC_KEY_SIZE, - .oob_present = NBLE_SMP_OBB_PRESENT, - }; - - nble_gap_sm_config_req(¶ms); - - return 0; + if (rsp->status) { + BT_WARN("gap sm request failed: %d", rsp->status); + } } -void on_nble_gap_sm_config_rsp(struct nble_gap_sm_config_rsp *p_params) +void on_nble_sm_config_rsp(struct nble_sm_config_rsp *rsp) { - if (p_params->status) { - BT_ERR("sm_config failed: %d", p_params->status); + if (rsp->status) { + BT_ERR("sm_config failed: %d", rsp->status); } } -void on_nble_gap_sm_common_rsp(const struct nble_gap_sm_response *rsp) +void on_nble_sm_pairing_request_evt(const struct nble_sm_pairing_request_evt *evt) { - if (rsp->status) { - BT_WARN("gap sm request failed: %d", rsp->status); - } + /* stub */ + (void)evt; } + +void on_nble_sm_security_request_evt(const struct nble_sm_security_request_evt *evt) +{ + /* stub */ + (void)evt; +} + diff --git a/system/libarc32_arduino101/framework/src/services/ble_service/ble_service.c b/system/libarc32_arduino101/framework/src/services/ble_service/ble_service.c index 07231cb1..64e0b5a6 100644 --- a/system/libarc32_arduino101/framework/src/services/ble_service/ble_service.c +++ b/system/libarc32_arduino101/framework/src/services/ble_service/ble_service.c @@ -51,6 +51,10 @@ #include "rpc.h" #include "util/misc.h" +#include "infra/time.h" + +extern void __assert_fail(void); +#define BT_SERVICE_ASSERT(cond) ((cond) ? (void)0 : __assert_fail()) struct _ble_service_cb _ble_cb = { 0 }; volatile uint8_t ble_inited = false; @@ -84,19 +88,19 @@ static void ble_is_not_enabled_rsp(struct cfw_message *msg, int status) #ifdef CONFIG_TCMD_BLE_DEBUG static void handle_msg_id_ble_dbg(struct cfw_message *msg) { - struct nble_debug_params params; + struct nble_dbg_req params; struct ble_dbg_req_rsp *resp = (void *) cfw_alloc_rsp_msg(msg, MSG_ID_BLE_DBG_RSP, sizeof(*resp)); struct ble_dbg_req_rsp *req = (struct ble_dbg_req_rsp *) msg; params.u0 = req->u0; params.u1 = req->u1; - - nble_gap_dbg_req(¶ms, resp); + params.user_data = (void *)resp; + nble_dbg_req(¶ms); } #endif /* CONFIG_TCMD_BLE_DEBUG */ -void on_nble_gap_dbg_rsp(const struct nble_debug_resp *params) +void on_nble_dbg_rsp(const struct nble_dbg_rsp *params) { #ifdef CONFIG_TCMD_BLE_DEBUG struct ble_dbg_req_rsp *resp = params->user_data; @@ -120,7 +124,9 @@ static void handle_msg_id_ble_rpc_callin(struct message *msg, void *priv) //pr_debug(LOG_MODULE_BLE, "%s-%d", __FUNCTION__, __LINE__); } -static void ble_set_bda_cb(int status, void *user_data) +static void ble_set_bda_cb(int status, + void *user_data, + const bt_addr_le_t *bda) { struct ble_enable_req *req = user_data; @@ -128,13 +134,14 @@ static void ble_set_bda_cb(int status, void *user_data) return; struct ble_enable_rsp *resp = (void *)cfw_alloc_rsp_msg(&req->header, - MSG_ID_BLE_ENABLE_RSP, sizeof(*resp)); + MSG_ID_BLE_ENABLE_RSP, + sizeof(*resp)); resp->status = status; if (status == 0) { resp->enable = 1; - nble_gap_read_bda_req(resp); + //nble_read_bda_req(resp); } else { /* error case */ resp->enable = 0; @@ -143,27 +150,15 @@ static void ble_set_bda_cb(int status, void *user_data) bfree(req); } - -void on_nble_gap_read_bda_rsp(const struct nble_service_read_bda_response *params) -{ - struct cfw_message *rsp = params->user_data; - - if (rsp) { - struct ble_enable_rsp *r = container_of(rsp, struct ble_enable_rsp, header); - r->bd_addr = params->bd; - cfw_send_message(rsp); - } -} - static void handle_ble_enable(struct ble_enable_req *req, - struct _ble_service_cb *p_cb) + struct _ble_service_cb *p_cb) { pr_info(LOG_MODULE_BLE, "ble_enable: state %d", p_cb->ble_state); p_cb->ble_state = BLE_ST_ENABLED; if (req->bda_present) { - struct nble_set_bda_params params; + struct nble_set_bda_req params; params.cb = ble_set_bda_cb; params.user_data = req; @@ -171,14 +166,7 @@ static void handle_ble_enable(struct ble_enable_req *req, nble_set_bda_req(¶ms); } else { - ble_set_bda_cb(0, req); - } -} - -void on_nble_set_bda_rsp(const struct nble_set_bda_rsp *params) -{ - if (params->cb) { - params->cb(params->status, params->user_data); + ble_set_bda_cb(0, req, NULL); } } @@ -257,18 +245,22 @@ static void ble_client_disconnected(conn_handle_t *instance) void ble_bt_rdy(int err) { + BT_SERVICE_ASSERT(err == 0); _ble_cb.ble_state = BLE_ST_DISABLED; ble_inited = true; /* register BLE service */ - if (cfw_register_service(_ble_cb.queue, &ble_service, - ble_service_message_handler, &_ble_cb) == -1) { + if (cfw_register_service(_ble_cb.queue, + &ble_service, + ble_service_message_handler, + &_ble_cb) == -1) { panic(0xb1eb1e); } } void ble_cfw_service_init(int service_id, T_QUEUE queue) { + uint32_t time_stamp_last = 0; _ble_cb.queue = queue; _ble_cb.ble_state = BLE_ST_NOT_READY; @@ -277,23 +269,29 @@ void ble_cfw_service_init(int service_id, T_QUEUE queue) #endif ble_inited = false; - + time_stamp_last = get_uptime_ms(); + bt_enable(ble_bt_rdy); - do{} + do{ + + uint32_t time_stamp_current = get_uptime_ms(); + if (time_stamp_current - time_stamp_last > 3000) + { + nble_driver_hw_reset(); + //pr_warning(LOG_MODULE_BLE, "time_stamp_current %d", time_stamp_current); + + time_stamp_last = time_stamp_current; + } + } while (ble_inited == false); } void nble_log(const struct nble_log_s *param, char *buf, uint8_t buflen) { - pr_info(LOG_MODULE_BLE, buf, param->param0, param->param1, param->param2, param->param3); + pr_info(LOG_MODULE_BLE, + buf, + param->param0, + param->param1, + param->param2); } -void on_nble_common_rsp(const struct nble_response *params) -{ - struct ble_rsp *resp = params->user_data; - - if (!resp) - return; - resp->status = params->status; - cfw_send_message(resp); -} diff --git a/system/libarc32_arduino101/framework/src/services/ble_service/dtm_internal.h b/system/libarc32_arduino101/framework/src/services/ble_service/dtm_internal.h new file mode 100644 index 00000000..1d55a564 --- /dev/null +++ b/system/libarc32_arduino101/framework/src/services/ble_service/dtm_internal.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DTM_INTERNAL_H_ +#define DTM_INTERNAL_H_ + +#include + +struct nble_dtm_cmd_req { + uint8_t cmd_type; + uint8_t tx_rx_freq; + uint8_t tx_len; + uint8_t tx_pattern; + int8_t pwr_dbm; + dtm_rsp_func_t func; + void *user_data; +}; + +void nble_dtm_cmd_req(const struct nble_dtm_cmd_req *req); + +struct nble_dtm_rsp { + int status; + uint16_t nb; + dtm_rsp_func_t func; + void *user_data; +}; + +void on_nble_dtm_rsp(const struct nble_dtm_rsp *rsp); +#endif //DTM_INTERNAL_H_ diff --git a/system/libarc32_arduino101/framework/src/services/ble_service/gap_internal.h b/system/libarc32_arduino101/framework/src/services/ble_service/gap_internal.h index 333ad36e..1add789f 100644 --- a/system/libarc32_arduino101/framework/src/services/ble_service/gap_internal.h +++ b/system/libarc32_arduino101/framework/src/services/ble_service/gap_internal.h @@ -26,24 +26,6 @@ /* Directed advertisement timeout error after 1.28s */ #define ERR_DIRECTED_ADVERTISING_TIMEOUT 0x3C -enum NBLE_GAP_SM_PASSKEY_TYPE { - NBLE_GAP_SM_REJECT = 0, - NBLE_GAP_SM_PK_PASSKEY, - NBLE_GAP_SM_PK_OOB, -}; - -enum NBLE_GAP_SM_EVT { - NBLE_GAP_SM_EVT_START_PAIRING, - NBLE_GAP_SM_EVT_BONDING_COMPLETE, - NBLE_GAP_SM_EVT_LINK_ENCRYPTED, - NBLE_GAP_SM_EVT_LINK_SECURITY_CHANGE, -}; - -enum NBLE_GAP_RSSI_OPS { - NBLE_GAP_RSSI_DISABLE_REPORT = 0, - NBLE_GAP_RSSI_ENABLE_REPORT -}; - enum NBLE_TEST_OPCODES { NBLE_TEST_INIT_DTM = 0x01, NBLE_TEST_START_DTM_RX = 0x1d, @@ -63,30 +45,66 @@ enum NBLE_TEST_OPCODES { #define DTM_HCI_LE_END_IDX (DTM_HCI_STATUS_IDX + 1) -struct nble_response { + +/* bt_dev flags: the flags defined here represent BT controller state */ +enum { + BT_DEV_READY, + + BT_DEV_ADVERTISING, + BT_DEV_KEEP_ADVERTISING, + BT_DEV_SCANNING, + BT_DEV_EXPLICIT_SCAN, + +#if defined(CONFIG_BLUETOOTH_BREDR) + BT_DEV_ISCAN, + BT_DEV_PSCAN, +#endif /* CONFIG_BLUETOOTH_BREDR */ +}; + +struct nble_log_s { + uint32_t param0; + uint32_t param1; + uint32_t param2; +}; + +void nble_log(const struct nble_log_s *par, char *data, uint8_t len); + +struct nble_common_rsp { int status; void *user_data; }; -struct nble_gap_device_name { - /* Security mode for writing device name, @ref BLE_GAP_SEC_MODES */ - uint8_t sec_mode; - /* 0: no authorization, 1: authorization required */ - uint8_t authorization; - /* Device name length (0-248) */ - uint8_t len; - uint8_t name_array[20]; +struct bt_local_addr { + bt_addr_le_t id_addr; +#if defined(CONFIG_BLUETOOTH_PRIVACY) + bt_addr_le_t rpa; +#endif }; -struct nble_gap_connection_values { - /* Connection interval (unit 1.25 ms) */ - uint16_t interval; - /* Connection latency (unit interval) */ - uint16_t latency; - /* Connection supervision timeout (unit 10ms)*/ - uint16_t supervision_to; +void on_nble_common_rsp(const struct nble_common_rsp *rsp); + +void nble_panic_req(void *user_data); + +struct nble_version { + uint8_t version; + uint8_t major; + uint8_t minor; + uint8_t patch; + char version_string[20]; + uint8_t build_hash[4]; + uint8_t hash[4]; +}; + +typedef void (*ble_get_version_cb_t)(const struct nble_version *ver); + +void nble_get_version_req(ble_get_version_cb_t cb); + +struct nble_get_version_rsp { + ble_get_version_cb_t cb; + struct nble_version ver; }; +void on_nble_get_version_rsp(const struct nble_get_version_rsp *rsp); enum NBLE_GAP_SVC_ATTR_TYPE { /* Device Name, UUID 0x2a00 */ @@ -99,7 +117,17 @@ enum NBLE_GAP_SVC_ATTR_TYPE { NBLE_GAP_SVC_ATTR_CAR = 0xa6, }; -struct nble_gap_connection_params { +struct nble_gap_device_name { + /* Security mode for writing device name, see BLE_GAP_SEC_MODES */ + uint8_t sec_mode; + /* 0: no authorization, 1: authorization required */ + uint8_t authorization; + /* Device name length (0-248) */ + uint8_t len; + uint8_t name_array[20]; +}; + +struct nble_conn_param { /* minimal connection interval: range 0x0006 to 0x0c80 (unit 1.25ms) */ uint16_t interval_min; /* maximum connection interval: range 0x0006 to 0x0c80 must be bigger then min! */ @@ -110,90 +138,96 @@ struct nble_gap_connection_params { uint16_t link_sup_to; }; -struct nble_gap_scan_parameters { - /* If 1, perform active scanning (scan requests). */ - uint8_t active; - /* If 1, ignore unknown devices (non whitelisted). */ - uint8_t selective; - /* Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ - uint16_t interval; - /* Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */ - uint16_t window; - /* Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */ - uint16_t timeout; -}; - -struct nble_gap_service_write_params { - /* GAP Characteristics attribute type @ref BLE_GAP_SVC_ATTR_TYPE */ +struct nble_gap_service_req { + /* GAP Characteristics attribute type see NBLE_GAP_SVC_ATTR_TYPE */ uint16_t attr_type; union { struct nble_gap_device_name name; /* Appearance UUID */ uint16_t appearance; /* Preferred Peripheral Connection Parameters */ - struct nble_gap_connection_params conn_params; + struct nble_conn_param ppcp; /* Central Address Resolution support 0: no, 1: yes */ uint8_t car; }; }; -struct nble_service_read_bda_response { - int status; - /* If @ref status ok */ - bt_addr_le_t bd; - void *user_data; -}; - -struct nble_service_write_response { - int status; - /* GAP Characteristics attribute type @ref BLE_GAP_SVC_ATTR_TYPE */ - uint16_t attr_type; - void *user_data; -}; - -struct nble_gap_service_read_params { - /* Type of GAP data characteristic to read @ref BLE_GAP_SVC_ATTR_TYPE */ - uint16_t attr_type; -}; +void nble_gap_service_req(const struct nble_gap_service_req *req); -struct nble_debug_params { +struct nble_dbg_req { uint32_t u0; uint32_t u1; + void *user_data; }; -struct nble_debug_resp { +void nble_dbg_req(const struct nble_dbg_req *req); + +struct nble_dbg_rsp { int status; uint32_t u0; uint32_t u1; void *user_data; }; -typedef void (*nble_set_bda_cb_t)(int status, void *user_data); +void on_nble_dbg_rsp(const struct nble_dbg_rsp *rsp); -struct nble_set_bda_params { - bt_addr_le_t bda; +typedef void (*nble_set_bda_cb_t)(int status, void *user_data, const bt_addr_le_t *bda); + +struct nble_set_bda_req { nble_set_bda_cb_t cb; void *user_data; + bt_addr_le_t bda; }; +void nble_set_bda_req(const struct nble_set_bda_req *req); + struct nble_set_bda_rsp { nble_set_bda_cb_t cb; void *user_data; int status; + bt_addr_le_t bda; +}; + +void on_nble_set_bda_rsp(const struct nble_set_bda_rsp *rsp); + +typedef void (*nble_get_bda_cb_t)(const bt_addr_le_t *bda, void *user_data); + +struct nble_get_bda_req { + nble_get_bda_cb_t cb; + void *user_data; +}; + +void nble_get_bda_req(const struct nble_get_bda_req *req); + +struct nble_get_bda_rsp { + nble_get_bda_cb_t cb; + void *user_data; + bt_addr_le_t bda; }; -struct bt_eir_data { +void on_nble_get_bda_rsp(const struct nble_get_bda_rsp *rsp); + +struct nble_eir_data { uint8_t len; uint8_t data[31]; }; -struct nble_gap_adv_params { +struct nble_gap_set_adv_data_req { + /* Advertisement data, maybe 0 (length) */ + struct nble_eir_data ad; + /* Scan response data, maybe 0 (length) */ + struct nble_eir_data sd; +}; + +void nble_gap_set_adv_data_req(struct nble_gap_set_adv_data_req *req); + +struct nble_gap_set_adv_params_req { uint16_t timeout; /* min interval 0xffff: use default 0x0800 */ uint16_t interval_min; /* max interval 0xffff: use default 0x0800 */ uint16_t interval_max; - /* advertisement types @ref GAP_ADV_TYPES */ + /* advertisement types see GAP_ADV_TYPES */ uint8_t type; /* filter policy to apply with white list */ uint8_t filter_policy; @@ -201,130 +235,63 @@ struct nble_gap_adv_params { bt_addr_le_t peer_bda; }; -struct nble_gap_ad_data_params { - /* Advertisement data, maybe 0 (length) */ - struct bt_eir_data ad; - /* Scan response data, maybe 0 (length) */ - struct bt_eir_data sd; -}; - -struct nble_log_s { - uint8_t param0; - uint8_t param1; - uint8_t param2; - uint8_t param3; -}; - -/* bt_dev flags: the flags defined here represent BT controller state */ -enum { - BT_DEV_READY, - - BT_DEV_ADVERTISING, - BT_DEV_KEEP_ADVERTISING, - BT_DEV_SCANNING, - BT_DEV_EXPLICIT_SCAN, - -#if defined(CONFIG_BLUETOOTH_BREDR) - BT_DEV_ISCAN, - BT_DEV_PSCAN, -#endif /* CONFIG_BLUETOOTH_BREDR */ -}; - -void nble_log(const struct nble_log_s *param, char *buf, uint8_t buflen); - -void on_nble_up(void); - -void nble_gap_service_write_req(const struct nble_gap_service_write_params *params); - -void on_nble_gap_read_bda_rsp(const struct nble_service_read_bda_response *params); - -void nble_gap_dbg_req(const struct nble_debug_params *params, void *user_data); - -void on_nble_gap_dbg_rsp(const struct nble_debug_resp *params); - -void on_nble_set_bda_rsp(const struct nble_set_bda_rsp *params); - -void nble_set_bda_req(const struct nble_set_bda_params *params); - -void nble_gap_set_adv_data_req(struct nble_gap_ad_data_params *ad_data_params); - -void nble_gap_set_adv_params_req(struct nble_gap_adv_params *adv_params); +void nble_gap_set_adv_params_req(struct nble_gap_set_adv_params_req *req); void nble_gap_start_adv_req(void); -void on_nble_gap_start_advertise_rsp(const struct nble_response *params); +void on_nble_gap_start_adv_rsp(const struct nble_common_rsp *rsp); void nble_gap_stop_adv_req(void *user_data); -void nble_gap_read_bda_req(void *priv); - -struct nble_gap_irk_info { - /* Identity Resolving Key (IRK) */ - uint8_t irk[16]; -}; - -void on_nble_common_rsp(const struct nble_response *params); - -struct nble_gap_connect_update_params { +struct nble_gap_conn_update_req { uint16_t conn_handle; - struct nble_gap_connection_params params; + struct nble_conn_param params; }; -void nble_gap_conn_update_req(const struct nble_gap_connect_update_params *params); +void nble_gap_conn_update_req(const struct nble_gap_conn_update_req *req); -void on_nble_gap_conn_update_rsp(const struct nble_response *params); - -struct nble_gap_connect_req_params { - bt_addr_le_t bda; - struct nble_gap_connection_params conn_params; - struct nble_gap_scan_parameters scan_params; -}; +void on_nble_gap_conn_update_rsp(const struct nble_common_rsp *rsp); -struct nble_gap_disconnect_req_params { +struct nble_gap_disconnect_req { uint16_t conn_handle; uint8_t reason; }; -void nble_gap_disconnect_req(const struct nble_gap_disconnect_req_params *params); - -struct nble_gap_sm_config_params { - /* Security options (@ref BLE_GAP_SM_OPTIONS) */ - uint8_t options; - /* I/O Capabilities to allow passkey exchange (@ref BLE_GAP_IO_CAPABILITIES) */ - uint8_t io_caps; - /* Maximum encryption key size (7-16) */ - uint8_t key_size; - uint8_t oob_present; -}; - -void nble_gap_sm_config_req(const struct nble_gap_sm_config_params *params); +void nble_gap_disconnect_req(const struct nble_gap_disconnect_req *req); -struct nble_gap_sm_config_rsp { +struct nble_sm_config_rsp { void *user_data; int status; bool sm_bond_dev_avail; }; -void on_nble_gap_sm_config_rsp(struct nble_gap_sm_config_rsp *params); +void on_nble_sm_config_rsp(struct nble_sm_config_rsp *rsp); - -struct nble_gap_sm_pairing_params { - /* authentication level see @ref BLE_GAP_SM_OPTIONS */ - uint8_t auth_level; +struct nble_sm_pairing_param { + /* authentication level see BLE_GAP_SM_OPTIONS */ + uint8_t auth; + uint8_t io_capabilities; + uint8_t max_key_size; + uint8_t min_key_size; + uint8_t oob_flag; }; -struct nble_gap_sm_security_params { +struct nble_sm_security_req { struct bt_conn *conn; uint16_t conn_handle; /* Local authentication/bonding parameters */ - struct nble_gap_sm_pairing_params params; + struct nble_sm_pairing_param params; }; -void nble_gap_sm_security_req(const struct nble_gap_sm_security_params * - params); +void nble_sm_security_req(const struct nble_sm_security_req *req); -struct nble_gap_sm_passkey { - uint8_t type; +enum NBLE_SM_PASSKEY_TYPE { + NBLE_SM_PK_PASSKEY, + NBLE_SM_PK_OOB, +}; + +struct nble_sm_passkey { + uint8_t type; /* see NBLE_SM_PASSKEY_TYPE */ union { uint32_t passkey; uint8_t oob[16]; @@ -332,42 +299,46 @@ struct nble_gap_sm_passkey { }; }; -struct nble_gap_sm_key_reply_req_params { +struct nble_sm_passkey_reply_req { struct bt_conn *conn; uint16_t conn_handle; - struct nble_gap_sm_passkey params; + struct nble_sm_passkey params; }; -void nble_gap_sm_passkey_reply_req(const struct nble_gap_sm_key_reply_req_params - *params); +void nble_sm_passkey_reply_req(const struct nble_sm_passkey_reply_req *req); -struct nble_gap_sm_clear_bond_req_params { +struct nble_sm_clear_bonds_req { bt_addr_le_t addr; }; -void nble_gap_sm_clear_bonds_req(const struct nble_gap_sm_clear_bond_req_params - *params); +void nble_sm_clear_bonds_req(const struct nble_sm_clear_bonds_req *req); -struct nble_gap_sm_response { +struct nble_sm_common_rsp { int status; struct bt_conn *conn; }; -void on_nble_gap_sm_common_rsp(const struct nble_gap_sm_response *rsp); +void on_nble_sm_common_rsp(const struct nble_sm_common_rsp *rsp); -/** - * Callback for rssi event. - */ -typedef void (*rssi_report_t)(const int8_t *rssi_data); +struct nble_sm_pairing_response_req { + struct bt_conn *conn; + uint16_t conn_handle; + struct nble_sm_pairing_param params; +}; -/** - * Callback for rssi report response. - */ -typedef void (*rssi_report_resp_t)(int status); +void nble_sm_pairing_response_req(const struct nble_sm_pairing_response_req *req); + +struct nble_sm_error_req { + struct bt_conn *conn; + uint16_t conn_handle; + uint8_t reason; +}; -struct nble_rssi_report_params { +void nble_sm_error_req(const struct nble_sm_error_req *req); + +struct nble_gap_set_rssi_report_req { uint16_t conn_handle; - /* RSSI operation @ref NBLE_GAP_RSSI_OPS */ + /* RSSI operation see NBLE_GAP_RSSI_OPS */ uint8_t op; /* Channel for RSSI enabling */ uint8_t channel; @@ -377,122 +348,78 @@ struct nble_rssi_report_params { uint8_t min_count; }; -void ble_gap_set_rssi_report(struct nble_rssi_report_params *params, - struct bt_conn *conn, - rssi_report_resp_t resp_cb, rssi_report_t evt_cb); - -void nble_gap_set_rssi_report_req(const struct nble_rssi_report_params *params, - void *user_data); +void nble_gap_set_rssi_report_req(const struct nble_gap_set_rssi_report_req *req, + void *user_data); -void on_nble_gap_set_rssi_report_rsp(const struct nble_response *params); +void on_nble_gap_set_rssi_report_rsp(const struct nble_common_rsp *rsp); -struct nble_gap_scan_params { +struct nble_scan_param { uint16_t interval; uint16_t window; + /* Unused for the connection request */ uint8_t scan_type; + /* Unused for the connection request */ uint8_t use_whitelist; }; -void nble_gap_start_scan_req(const struct nble_gap_scan_params *params); - -void nble_gap_stop_scan_req(void); - -void on_nble_gap_scan_start_stop_rsp(const struct nble_response *rsp); - -void nble_gap_connect_req(const struct nble_gap_connect_req_params *params, - void *user_data); - -void on_nble_gap_connect_rsp(const struct nble_response *params); +struct nble_gap_start_scan_req { + struct nble_scan_param scan_params; +}; -void nble_gap_cancel_connect_req(void *priv); +void nble_gap_start_scan_req(const struct nble_gap_start_scan_req *req); -void on_nble_gap_cancel_connect_rsp(const struct nble_response *params); +void nble_gap_stop_scan_req(void); -enum BLE_GAP_SET_OPTIONS { - BLE_GAP_SET_CH_MAP = 0, -}; +void on_nble_gap_scan_start_stop_rsp(const struct nble_common_rsp *rsp); -struct nble_gap_channel_map { - /* connection on which to change channel map */ - uint16_t conn_handle; - /* 37 bits are used of the 40 bits (LSB) */ - uint8_t map[5]; +struct nble_gap_connect_req { + bt_addr_le_t bda; + struct nble_conn_param conn_params; + struct nble_scan_param scan_params; }; +void nble_gap_connect_req(const struct nble_gap_connect_req *req, + void *user_data); -struct nble_gap_set_option_params { - /* Option to set @ref BLE_GAP_SET_OPTIONS */ - uint8_t op; - union { - struct nble_gap_channel_map ch_map; - }; -}; +void on_nble_gap_connect_rsp(const struct nble_common_rsp *rsp); -/* - * Generic request op codes. - * This allows to access some non connection related commands like DTM. - */ -enum BLE_GAP_GEN_OPS { - /* Not used now. */ - DUMMY_VALUE = 0, -}; +void nble_gap_cancel_connect_req(void *user_data); -struct nble_gap_gen_cmd_params { - /* @ref BLE_GAP_GEN_OPS */ - uint8_t op_code; -}; +void on_nble_gap_cancel_connect_rsp(const struct nble_common_rsp *rsp); /* Temporary patch: RSSI processing for UAS */ -struct nble_uas_rssi_calibrate { +struct nble_uas_rssi_calibrate_req { float distance; }; -void nble_uas_rssi_calibrate_req(const struct nble_uas_rssi_calibrate *p_struct); +void nble_uas_rssi_calibrate_req(const struct nble_uas_rssi_calibrate_req *req); /* Temporary patch: RSSI processing for UAS */ struct nble_uas_bucket_change { uint8_t distance; }; -void on_nble_uas_bucket_change(const struct nble_uas_bucket_change *p_params); - -struct nble_version { - uint8_t version; - uint8_t major; - uint8_t minor; - uint8_t patch; - char version_string[20]; - uint8_t hash[4]; -}; -typedef void (*ble_get_version_cb_t)(const struct nble_version *ver); +void on_nble_uas_bucket_change(const struct nble_uas_bucket_change *par); -struct nble_gap_get_version_param { - ble_get_version_cb_t cb; -}; - -struct nble_version_response { - struct nble_gap_get_version_param params; - struct nble_version ver; +struct nble_gap_set_tx_power_req { + int8_t tx_power; }; -void nble_get_version_req(const struct nble_gap_get_version_param *params); - -void on_nble_get_version_rsp(const struct nble_version_response *params); +void nble_gap_set_tx_power_req(const struct nble_gap_set_tx_power_req *req); -void nble_gap_dtm_init_req(void *user_data); +void on_nble_gap_set_tx_power_rsp(const struct nble_common_rsp *rsp); -void on_nble_gap_dtm_init_rsp(void *user_data); - -struct nble_gap_tx_power_params { - int8_t tx_power; +struct nble_conn_values { + /* Connection interval (unit 1.25 ms) */ + uint16_t interval; + /* Connection latency (unit interval) */ + uint16_t latency; + /* Connection supervision timeout (unit 10ms)*/ + uint16_t supervision_to; }; -void nble_gap_tx_power_req(const struct nble_gap_tx_power_params *params); - -void on_nble_gap_tx_power_rsp(const struct nble_response *params); - struct nble_gap_connect_evt { uint16_t conn_handle; - struct nble_gap_connection_values conn_values; + struct nble_conn_values conn_values; /* 0 if connected as master, otherwise as slave */ uint8_t role_slave; /* Address of peer device */ @@ -510,7 +437,7 @@ void on_nble_gap_disconnect_evt(const struct nble_gap_disconnect_evt *evt); struct nble_gap_conn_update_evt { uint16_t conn_handle; - struct nble_gap_connection_values conn_values; + struct nble_conn_values conn_values; }; void on_nble_gap_conn_update_evt(const struct nble_gap_conn_update_evt *evt); @@ -522,16 +449,17 @@ struct nble_gap_adv_report_evt { }; void on_nble_gap_adv_report_evt(const struct nble_gap_adv_report_evt *evt, - const uint8_t *buf, uint8_t len); + const uint8_t *data, uint8_t len); struct nble_gap_dir_adv_timeout_evt { uint16_t conn_handle; uint16_t error; }; -void on_nble_gap_dir_adv_timeout_evt(const struct nble_gap_dir_adv_timeout_evt *p_evt); +void on_nble_gap_dir_adv_timeout_evt(const struct nble_gap_dir_adv_timeout_evt *evt); + +#define BLE_GAP_RSSI_EVT_SIZE 32 -#define BLE_GAP_RSSI_EVT_SIZE 32 struct nble_gap_rssi_evt { uint16_t conn_handle; int8_t rssi_data[BLE_GAP_RSSI_EVT_SIZE]; @@ -539,91 +467,164 @@ struct nble_gap_rssi_evt { void on_nble_gap_rssi_evt(const struct nble_gap_rssi_evt *evt); -struct nble_gap_timout_evt { - uint16_t conn_handle; - /* reason for timeout @ref BLE_SVC_GAP_TIMEOUT_REASON */ - int reason; -}; - -struct nble_gap_sm_passkey_req_evt { +struct nble_sm_passkey_req_evt { uint16_t conn_handle; uint8_t key_type; }; -void on_nble_gap_sm_passkey_req_evt(const struct nble_gap_sm_passkey_req_evt *evt); +void on_nble_sm_passkey_req_evt(const struct nble_sm_passkey_req_evt *evt); -struct nble_gap_sm_passkey_disp_evt { +struct nble_sm_passkey_disp_evt { uint16_t conn_handle; uint32_t passkey; + uint8_t passkey_confirm; }; -void on_nble_gap_sm_passkey_display_evt(const struct nble_gap_sm_passkey_disp_evt *evt); +void on_nble_sm_passkey_disp_evt(const struct nble_sm_passkey_disp_evt *evt); + +enum NBLE_SM_STATUS_EVT { + NBLE_SM_STATUS_START_PAIRING, + NBLE_SM_STATUS_BONDING_COMPLETE, + NBLE_SM_STATUS_LINK_ENCRYPTED, + NBLE_SM_STATUS_LINK_SECURITY_CHANGE, +}; struct nble_link_sec { bt_security_t sec_level; uint8_t enc_size; }; -struct nble_gap_sm_status_evt { +struct nble_sm_status_evt { uint16_t conn_handle; - uint8_t evt_type; + uint8_t evt_type; /* see NBLE_SM_STATUS_EVT */ int status; - struct nble_link_sec enc_link_sec; + union { + struct nble_link_sec enc_link_sec; + bt_addr_le_t addr; + }; }; -void on_nble_gap_sm_status_evt(const struct nble_gap_sm_status_evt *evt); +void on_nble_sm_status_evt(const struct nble_sm_status_evt *evt); -void on_nble_set_bda_rsp(const struct nble_set_bda_rsp *params); - -enum BLE_INFO_REQ_TYPES { - BLE_INFO_BONDING = 1, /* Get bonding database related information */ - BLE_INFO_LAST /* Keep last */ +struct nble_sec_param { + uint8_t auth; + uint8_t io_capabilities; + uint8_t min_key_size; + uint8_t max_key_size; }; -struct ble_gap_bonded_dev_info -{ - uint8_t addr_count; /* Count of le_addr in array. */ - uint8_t irk_count; /* IRK count */ - bt_addr_le_t le_addr[]; /* Bonded device address */ +struct nble_sm_pairing_request_evt { + uint16_t conn_handle; + struct nble_sec_param sec_param; }; -struct ble_get_info_rsp { - int status; /* Response status */ - uint8_t info_type; /* Requested information type */ - struct ble_gap_bonded_dev_info info_params; +void on_nble_sm_pairing_request_evt(const struct nble_sm_pairing_request_evt *evt); + +struct nble_sm_security_request_evt { + uint16_t conn_handle; + struct nble_sec_param sec_param; }; -struct nble_gap_sm_bond_info; -typedef void (*ble_bond_info_cb_t)(const struct nble_gap_sm_bond_info *info, - const bt_addr_le_t *addr, uint16_t len, - void *user_data); +void on_nble_sm_security_request_evt(const struct nble_sm_security_request_evt *evt); -struct nble_gap_sm_bond_info_param { +struct nble_sm_bond_info; +typedef void (*ble_bond_info_cb_t)(const struct nble_sm_bond_info *info, + const bt_addr_le_t *addr, uint16_t len, + void *user_data); + +struct nble_sm_bond_info_req { ble_bond_info_cb_t cb; void *user_data; bool include_bonded_addrs; }; -void nble_gap_sm_bond_info_req(const struct nble_gap_sm_bond_info_param *params); +void nble_sm_bond_info_req(const struct nble_sm_bond_info_req *req); -struct nble_gap_sm_bond_info { +struct nble_sm_bond_info { int err; uint8_t addr_count; uint8_t irk_count; }; -struct nble_gap_sm_bond_info_rsp { +struct nble_sm_bond_info_rsp { ble_bond_info_cb_t cb; void *user_data; - struct nble_gap_sm_bond_info info; + struct nble_sm_bond_info info; +}; + +void on_nble_sm_bond_info_rsp(const struct nble_sm_bond_info_rsp *rsp, + const bt_addr_le_t *peer_addr, uint16_t len); + +struct nble_uart_test_req { + /* Test type */ + uint16_t test_type; + /* Number of loops */ + uint16_t nb_loops; + /* The maximum delay */ + uint16_t max_delay; + /* The maximum length */ + uint16_t max_len; }; -void on_nble_gap_sm_bond_info_rsp(const struct nble_gap_sm_bond_info_rsp *rsp, - const bt_addr_le_t *peer_addr, uint16_t len); +void nble_uart_test_req(const struct nble_uart_test_req *req, + const uint8_t *data, uint8_t len); + +struct nble_uart_test_evt { + /* Number of loops executed */ + uint16_t nb_loops; +}; -void ble_gap_get_bonding_info(ble_bond_info_cb_t func, void *user_data, - bool include_bonded_addrs); +void on_nble_uart_test_evt(const struct nble_uart_test_evt *evt, + const uint8_t *data, uint8_t len); + +struct nble_gap_rpa_update_evt { + bt_addr_le_t addr; +}; + +void on_nble_gap_rpa_update_evt(const struct nble_gap_rpa_update_evt *evt); + +/* + * The following functions are NOT RPC functions + */ void ble_gap_get_version(ble_get_version_cb_t func); +void ble_gap_get_bda_info(struct bt_local_addr *addr); + +enum NBLE_GAP_RSSI_OPS { + NBLE_GAP_RSSI_DISABLE_REPORT = 0, + NBLE_GAP_RSSI_ENABLE_REPORT +}; + +typedef void (*rssi_report_t)(const int8_t *rssi_data); + +typedef void (*rssi_report_resp_t)(int status); + +struct ble_rssi_report_params { + /* RSSI operation see NBLE_GAP_RSSI_OPS */ + uint8_t op; + /* Channel for RSSI enabling */ + uint8_t channel; + /* minimum RSSI dBm change to report a new RSSI value */ + uint8_t delta_dBm; + /* number of delta_dBm changes before sending a new RSSI report */ + uint8_t min_count; +}; + +void ble_gap_set_rssi_report(struct ble_rssi_report_params *par, + struct bt_conn *conn, + rssi_report_resp_t resp_cb, rssi_report_t evt_cb); + +/* Hook function to release to BT controller reset */ +void nble_curie_unreset_hook(void); + +/* Hook function to display log from the BT controller */ +void nble_curie_log_hook(char *fmt, ...); + +/* Function to set the RPA address */ +int le_set_rpa(void); + +int bt_le_scan_update(bool fast_scan); + +int set_advertise_enable(void); #endif /* GAP_INTERNAL_H_ */ diff --git a/system/libarc32_arduino101/framework/src/services/ble_service/gatt_internal.h b/system/libarc32_arduino101/framework/src/services/ble_service/gatt_internal.h index 25ac4da8..6185dbf9 100644 --- a/system/libarc32_arduino101/framework/src/services/ble_service/gatt_internal.h +++ b/system/libarc32_arduino101/framework/src/services/ble_service/gatt_internal.h @@ -20,8 +20,6 @@ #include #include -/* Forward declarations */ -struct nble_response; #define BLE_GATT_MTU_SIZE 23 @@ -30,98 +28,154 @@ struct nble_response; * Typically they are required if gatt.h APIs can not be mapped 1:1 onto controller API */ -enum NBLE_GATT_IND_TYPES { - NBLE_GATT_IND_TYPE_NONE = 0, - NBLE_GATT_IND_TYPE_NOTIFICATION, - NBLE_GATT_IND_TYPE_INDICATION, +/* + * GATT Attribute stream structure. + */ +struct nble_gatts_attr { + /* Attribute pointer */ + struct bt_gatt_attr *attr; + /* Attribute permissions */ + uint16_t perm; + /* Attribute variable data size */ + uint16_t data_size; + /* Attribute variable data: always starts with the UUID and data follows */ + uint8_t data[]; }; -struct nble_gatt_register_req { +struct nble_gatts_register_req { /* Base address of the attribute table in the Quark mem space */ struct bt_gatt_attr *attr_base; /* Number of of attributes in this service */ uint8_t attr_count; }; -struct nble_gatt_register_rsp { +void nble_gatts_register_req(const struct nble_gatts_register_req *req, + uint8_t *data, uint16_t len); + +struct nble_gatts_register_rsp { int status; struct bt_gatt_attr *attr_base; /* Number of attributes successfully added */ uint8_t attr_count; }; +struct nble_gatt_attr_handles { + uint16_t handle; +}; + +void on_nble_gatts_register_rsp(const struct nble_gatts_register_rsp *rsp, + const struct nble_gatt_attr_handles *attrs, + uint8_t len); + enum nble_gatt_wr_flag { NBLE_GATT_WR_FLAG_REPLY = 1, NBLE_GATT_WR_FLAG_PREP = 2, }; -struct nble_gatt_wr_evt { +struct nble_gatts_write_evt { struct bt_gatt_attr *attr; uint16_t conn_handle; uint16_t offset; - uint8_t flag; /* Cf. enum nble_gatt_wr_flag */ + /* see nble_gatt_wr_flag */ + uint8_t flag; +}; + +void on_nble_gatts_write_evt(const struct nble_gatts_write_evt *evt, + const uint8_t *data, uint8_t len); + +struct nble_gatts_write_reply_req { + uint16_t conn_handle; + uint16_t offset; + int32_t status; }; -struct nble_gatt_wr_exec_evt { +void nble_gatts_write_reply_req(const struct nble_gatts_write_reply_req *req, + const uint8_t *data, uint8_t len); + +struct nble_gatts_write_exec_evt { uint16_t conn_handle; uint8_t flag; }; -struct nble_gatt_rd_evt { +void on_nble_gatts_write_exec_evt(const struct nble_gatts_write_exec_evt *evt); + +struct nble_gatts_read_evt { struct bt_gatt_attr *attr; uint16_t conn_handle; uint16_t offset; }; -struct nble_gatts_rd_reply_params { +void on_nble_gatts_read_evt(const struct nble_gatts_read_evt *evt); + +struct nble_gatts_read_reply_req { uint16_t conn_handle; uint16_t offset; int32_t status; }; -struct nble_gatts_wr_reply_params { - uint16_t conn_handle; - int32_t status; -}; +void nble_gatts_read_reply_req(const struct nble_gatts_read_reply_req *req, + uint8_t *data, uint16_t len); -struct nble_gatt_notif_ind_params { +struct nble_gatts_value_change_param { const struct bt_gatt_attr *attr; + uint16_t conn_handle; uint16_t offset; }; -struct nble_gatt_send_notif_params { +struct nble_gatts_notify_req { /* Function to be invoked when buffer is freed */ bt_gatt_notify_sent_func_t cback; - uint16_t conn_handle; - struct nble_gatt_notif_ind_params params; + struct nble_gatts_value_change_param params; }; -struct nble_gatt_notif_rsp { +void nble_gatts_notify_req(const struct nble_gatts_notify_req *req, + const uint8_t *data, uint16_t len); + +struct nble_gatts_notify_tx_evt { bt_gatt_notify_sent_func_t cback; - int status; - uint16_t conn_handle; + uint8_t status __attribute__ ((aligned (4))); + uint16_t conn_handle __attribute__ ((aligned (4))); struct bt_gatt_attr *attr; }; -struct nble_gatt_send_ind_params { +void on_nble_gatts_notify_tx_evt(const struct nble_gatts_notify_tx_evt *evt); + +struct nble_gatts_indicate_req { /* Function to be invoked when buffer is freed */ bt_gatt_indicate_func_t cback; - uint16_t conn_handle; - struct nble_gatt_notif_ind_params params; + struct nble_gatts_value_change_param params; }; -struct nble_gatt_ind_rsp { +void nble_gatts_indicate_req(const struct nble_gatts_indicate_req *req, + const uint8_t *data, uint8_t len); + +struct nble_gatts_indicate_rsp { bt_gatt_indicate_func_t cback; - int status; - uint16_t conn_handle; struct bt_gatt_attr *attr; + uint8_t status; + uint16_t conn_handle; }; +void on_nble_gatts_indicate_rsp(const struct nble_gatts_indicate_rsp *rsp); + +#define DISCOVER_FLAGS_UUID_PRESENT 1 + struct nble_gatt_handle_range { uint16_t start_handle; uint16_t end_handle; }; +struct nble_gattc_discover_req { + void *user_data; + struct bt_uuid_128 uuid; + struct nble_gatt_handle_range handle_range; + uint16_t conn_handle; + uint8_t type; + uint8_t flags; +}; + +void nble_gattc_discover_req(const struct nble_gattc_discover_req *req); + struct nble_gattc_primary { uint16_t handle; struct nble_gatt_handle_range range; @@ -147,162 +201,98 @@ struct nble_gattc_descriptor { }; struct nble_gattc_discover_rsp { - int32_t status; + uint8_t status; void *user_data; uint16_t conn_handle; uint8_t type; }; -struct nble_gatts_attribute_rsp { - int32_t status; - struct bt_gatt_attr *attr; - void *user_data; -}; - -void nble_gatts_rd_reply_req(const struct nble_gatts_rd_reply_params *, uint8_t *, uint16_t); - -void nble_gatts_wr_reply_req(const struct nble_gatts_wr_reply_params *p_params); - -void nble_gatt_register_req(const struct nble_gatt_register_req *p_param, - uint8_t *p_buf, - uint16_t len); - -struct nble_gatt_attr_handles { - uint16_t handle; -}; - -void on_nble_gatt_register_rsp(const struct nble_gatt_register_rsp *p_param, - const struct nble_gatt_attr_handles *p_attrs, uint8_t len); - -void on_nble_gatts_write_evt(const struct nble_gatt_wr_evt *p_evt, - const uint8_t *p_buf, uint8_t buflen); - -void on_nble_gatts_write_exec_evt(const struct nble_gatt_wr_exec_evt *evt); - -void on_nble_gatts_read_evt(const struct nble_gatt_rd_evt *p_evt); - -void nble_gatt_send_notif_req(const struct nble_gatt_send_notif_params *p_params, - const uint8_t *p_value, uint16_t length); - -void nble_gatt_send_ind_req(const struct nble_gatt_send_ind_params *p_params, - const uint8_t *p_value, uint8_t length); - -void on_nble_gatts_send_notif_rsp(const struct nble_gatt_notif_rsp *rsp); - -void on_nble_gatts_send_ind_rsp(const struct nble_gatt_ind_rsp *rsp); - -#define DISCOVER_FLAGS_UUID_PRESENT 1 +void on_nble_gattc_discover_rsp(const struct nble_gattc_discover_rsp *rsp, + const uint8_t *data, uint8_t len); -struct nble_discover_params { +struct nble_gattc_read_req { void *user_data; - struct bt_uuid_128 uuid; - struct nble_gatt_handle_range handle_range; uint16_t conn_handle; - uint8_t type; - uint8_t flags; + uint16_t handle; + uint16_t offset; }; -void nble_gattc_discover_req(const struct nble_discover_params *req); - -void on_nble_gattc_discover_rsp(const struct nble_gattc_discover_rsp *rsp, - const uint8_t *data, uint8_t data_len); - -/* - * GATT Attribute stream structure. - * - * This structure is a "compressed" copy of @ref bt_gatt_attr. - * UUID pointer and user_data pointer are used as offset into buffer itself. - * The offset is from the beginning of the buffer. therefore a value of 0 - * means that UUID or user_data is not present. - */ -struct ble_gatt_attr { - /* Attribute permissions */ - uint16_t perm; - /* Attribute variable data size */ - uint16_t data_size; - /* Attribute variable data: always starts with the UUID and data follows */ - uint8_t data[]; -}; +void nble_gattc_read_req(const struct nble_gattc_read_req *req); -struct ble_gattc_read_params { +struct nble_gattc_read_rsp { + uint8_t status; void *user_data; uint16_t conn_handle; uint16_t handle; uint16_t offset; }; -struct ble_gattc_read_multiple_params { - void *user_data; - uint16_t conn_handle; -}; +void on_nble_gattc_read_rsp(const struct nble_gattc_read_rsp *rsp, + uint8_t *data, uint8_t len); -struct ble_gattc_read_rsp { - int status; +struct nble_gattc_read_multi_req { void *user_data; uint16_t conn_handle; - uint16_t handle; - uint16_t offset; }; -/* forward declaration */ -struct bt_gatt_write_params; +void nble_gattc_read_multi_req(const struct nble_gattc_read_multi_req *req, + const uint16_t *handles, uint16_t len); + +void on_nble_gattc_read_multi_rsp(const struct nble_gattc_read_rsp *rsp, + uint8_t *data, uint8_t len); + +struct nble_gattc_write_param; typedef void (*bt_att_func_t)(struct bt_conn *conn, uint8_t err, - const struct bt_gatt_write_params *wr_params); + const struct nble_gattc_write_param *par); -struct bt_gatt_write_params { +struct nble_gattc_write_param { /* Function invoked upon write response */ bt_att_func_t func; /* User specific data */ void *user_data[2]; }; -struct ble_gattc_write_params { +struct nble_gattc_write_req { uint16_t conn_handle; uint16_t handle; uint16_t offset; /* different than 0 if response required */ uint8_t with_resp; - struct bt_gatt_write_params wr_params; + struct nble_gattc_write_param wr_params; }; -struct ble_gattc_write_rsp { +void nble_gattc_write_req(const struct nble_gattc_write_req *req, + const uint8_t *data, uint16_t len); + +struct nble_gattc_write_rsp { + uint8_t status; uint16_t conn_handle; - int status; uint16_t handle; - uint16_t len; - struct bt_gatt_write_params wr_params; + struct nble_gattc_write_param wr_params; }; -void nble_gattc_read_req(const struct ble_gattc_read_params *params); - -void on_nble_gattc_read_rsp(const struct ble_gattc_read_rsp *rsp, - uint8_t *data, uint8_t data_len); - -void nble_gattc_read_multiple_req( - const struct ble_gattc_read_multiple_params *params, - const uint16_t *data, uint16_t data_len); - -void on_nble_gattc_read_multiple_rsp(const struct ble_gattc_read_rsp *rsp, - uint8_t *data, uint8_t data_len); - -void nble_gattc_write_req(const struct ble_gattc_write_params *params, - const uint8_t *buf, uint8_t buflen); - -void on_nble_gattc_write_rsp(const struct ble_gattc_write_rsp *rsp); +void on_nble_gattc_write_rsp(const struct nble_gattc_write_rsp *rsp); void bt_gatt_connected(struct bt_conn *conn); void bt_gatt_disconnected(struct bt_conn *conn); +enum NBLE_GATTC_EVT { + NBLE_GATTC_EVT_NOTIFICATION, + NBLE_GATTC_EVT_INDICATION, +}; -struct ble_gattc_value_evt { - uint16_t conn_handle; +struct nble_gattc_value_evt { int status; + uint16_t conn_handle; uint16_t handle; + /* see NBLE_GATTC_VALUE_EVT */ uint8_t type; }; -void on_nble_gattc_value_evt(const struct ble_gattc_value_evt *evt, - uint8_t *buf, uint8_t buflen); +void on_nble_gattc_value_evt(const struct nble_gattc_value_evt *evt, + uint8_t *data, uint8_t len); +void *nble_curie_alloc_hook(uint32_t size); +void nble_curie_free_hook(void *buffer); #endif /* GATT_INTERNAL_H_ */ diff --git a/system/libarc32_arduino101/framework/src/services/ble_service/nble_driver.c b/system/libarc32_arduino101/framework/src/services/ble_service/nble_driver.c index 4a128f13..97dc6e01 100644 --- a/system/libarc32_arduino101/framework/src/services/ble_service/nble_driver.c +++ b/system/libarc32_arduino101/framework/src/services/ble_service/nble_driver.c @@ -66,7 +66,7 @@ static uint16_t rpc_port_id; static list_head_t m_rpc_tx_q; -extern void on_nble_curie_log(char *fmt, ...) +void nble_curie_log_hook(char *fmt, ...) { va_list args; @@ -75,6 +75,16 @@ extern void on_nble_curie_log(char *fmt, ...) va_end(args); } +void *nble_curie_alloc_hook(uint32_t size) +{ + return balloc(size, NULL); +} + +void nble_curie_free_hook(void *buffer) +{ + bfree(buffer); +} + /* * When we set val to 1 it will wake up the remote (BLE Core), setting it to 0 * will allow remote to sleep. @@ -280,8 +290,13 @@ uint8_t *rpc_alloc_cb(uint16_t length) return p_elt->data; } +void rpc_free_cb(const uint8_t *buf) +{ + // Stub +} + /* called under NON-interrupt context */ -void rpc_transmit_cb(uint8_t *p_buf, uint16_t length) +void rpc_transmit_cb(uint8_t *p_buf) { struct rpc_tx_elt *p_elt; @@ -297,32 +312,27 @@ void rpc_transmit_cb(uint8_t *p_buf, uint16_t length) * other constraints: therefore, this reset might not work everytime, especially after * flashing or debugging. */ -void nble_driver_init(void) +void nble_driver_hw_reset(void) { uint32_t delay_until; - - nble_interface_init(); - /* Setup UART0 for BLE communication, HW flow control required */ - SET_PIN_MODE(18, QRK_PMUX_SEL_MODEA); /* UART0_RXD */ - SET_PIN_MODE(19, QRK_PMUX_SEL_MODEA); /* UART0_TXD */ - SET_PIN_MODE(40, QRK_PMUX_SEL_MODEB); /* UART0_CTS_B */ - SET_PIN_MODE(41, QRK_PMUX_SEL_MODEB); /* UART0_RTS_B */ - - ipc_uart_init(0); - - //while (1) - //{} + /* RESET_PIN depends on the board and the local configuration: check top of file */ gpio_cfg_data_t pin_cfg = { .gpio_type = GPIO_OUTPUT }; + delay_until = get_uptime_32k() + 32768 * 2; // 2ms wait for Nordic chip boot + while (get_uptime_32k() < delay_until); + + ipc_uart_init(0); + soc_gpio_set_config(SOC_GPIO_32, RESET_PIN, &pin_cfg); //soc_gpio_set_config(SOC_GPIO_32_ID, BLE_SW_CLK_PIN, &pin_cfg); /* Reset hold time is 0.2us (normal) or 100us (SWD debug) */ soc_gpio_write(SOC_GPIO_32, RESET_PIN, 0); /* Wait for ~1ms */ - delay_until = get_uptime_32k() + 32768; + delay_until = get_uptime_32k() + 327;//68; /* Open the UART channel for RPC while Nordic is in reset */ + //if (NULL == m_rpc_channel) m_rpc_channel = ipc_uart_channel_open(RPC_CHANNEL, uart_ipc_rpc_cback); while (get_uptime_32k() < delay_until); @@ -336,6 +346,19 @@ void nble_driver_init(void) soc_gpio_set_config(SOC_GPIO_32, RESET_PIN, &pin_cfg); } +void nble_driver_init(void) +{ + + nble_interface_init(); + /* Setup UART0 for BLE communication, HW flow control required */ + SET_PIN_MODE(18, QRK_PMUX_SEL_MODEA); /* UART0_RXD */ + SET_PIN_MODE(19, QRK_PMUX_SEL_MODEA); /* UART0_TXD */ + SET_PIN_MODE(40, QRK_PMUX_SEL_MODEB); /* UART0_CTS_B */ + SET_PIN_MODE(41, QRK_PMUX_SEL_MODEB); /* UART0_RTS_B */ + + nble_driver_hw_reset(); +} + void nble_driver_configure(T_QUEUE queue, void (*handler)(struct message*, void*)) { diff --git a/system/libarc32_arduino101/framework/src/services/ble_service/nble_driver.h b/system/libarc32_arduino101/framework/src/services/ble_service/nble_driver.h index 7ea15b44..b4e8cb74 100644 --- a/system/libarc32_arduino101/framework/src/services/ble_service/nble_driver.h +++ b/system/libarc32_arduino101/framework/src/services/ble_service/nble_driver.h @@ -47,6 +47,7 @@ struct ble_rpc_callin { * mechanism is up and running. */ void nble_driver_init(void); +void nble_driver_hw_reset(void); void nble_driver_configure(T_QUEUE queue, void (*handler)(struct message*, void*)); diff --git a/system/libarc32_arduino101/framework/src/services/ble_service/storage_internal.h b/system/libarc32_arduino101/framework/src/services/ble_service/storage_internal.h new file mode 100644 index 00000000..2fab1b73 --- /dev/null +++ b/system/libarc32_arduino101/framework/src/services/ble_service/storage_internal.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef STORAGE_INTERNAL_H_ +#define STORAGE_INTERNAL_H_ + +struct nble_storage_read_evt { + bt_addr_le_t addr; + /* valid only for BT_STORAGE_ADDRESSES */ + uint8_t max_num_keys; + uint16_t key; +}; + +enum { + NBLE_STORAGE_UPDATE = BIT(0), /* key update */ +}; + +struct nble_storage_write_evt { + uint8_t flags; + bt_addr_le_t addr; + uint16_t key; +}; + +struct nble_storage_read_rsp_req { + int status; /* posix status code */ + bt_addr_le_t addr; + uint16_t key; +}; + +void on_nble_storage_read_evt(const struct nble_storage_read_evt *evt); + +void on_nble_storage_write_evt(const struct nble_storage_write_evt *evt, + const uint8_t *data, uint16_t len); + +void nble_storage_read_rsp_req(const struct nble_storage_read_rsp_req *req, + const uint8_t *data, uint16_t len); + +#endif //STORAGE_INTERNAL_H_ diff --git a/variants/arduino_101/libarc32drv_arduino101.a b/variants/arduino_101/libarc32drv_arduino101.a index db6e5b4591162ed7abd8d50f81b0b7d077847d32..21782aea88921d86011b297d823bf947811e1a8f 100644 GIT binary patch literal 841686 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�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