adaptation for bkap
Fork of X_NUCLEO_IDB0XA1 by
Diff: source/BlueNRGGap.cpp
- Branch:
- sync_with_github
- Revision:
- 276:a20f4cad1d61
- Parent:
- 265:46333d70cf81
- Parent:
- 272:4639da7705e1
- Child:
- 278:a5209d8cfd61
--- a/source/BlueNRGGap.cpp Thu Sep 15 10:51:38 2016 +0100 +++ b/source/BlueNRGGap.cpp Thu Sep 15 10:51:40 2016 +0100 @@ -17,7 +17,7 @@ /** ****************************************************************************** - * @file BlueNRGGap.cpp + * @file BlueNRGGap.cpp * @author STMicroelectronics * @brief Implementation of BLE_API Gap Class ****************************************************************************** @@ -44,15 +44,11 @@ #include "Utils.h" #include "debug.h" -//Local Variables -//const char *local_name = NULL; -//uint8_t local_name_length = 0; - /* * Utility to process GAP specific events (e.g., Advertising timeout) */ void BlueNRGGap::Process(void) -{ +{ if(AdvToFlag) { stopAdvertising(); } @@ -61,7 +57,7 @@ /**************************************************************************/ /*! - @brief Sets the advertising parameters and payload for the device. + @brief Sets the advertising parameters and payload for the device. Note: Some data types give error when their adv data is updated using aci_gap_update_adv_data() API @params[in] advData @@ -95,7 +91,7 @@ */ /**************************************************************************/ ble_error_t BlueNRGGap::setAdvertisingData(const GapAdvertisingData &advData, const GapAdvertisingData &scanResponse) -{ +{ PRINTF("BlueNRGGap::setAdvertisingData\n\r"); /* Make sure we don't exceed the advertising payload length */ if (advData.getPayloadLen() > GAP_ADVERTISING_DATA_MAX_PAYLOAD) { @@ -103,18 +99,8 @@ return BLE_ERROR_BUFFER_OVERFLOW; } - // Reset the length of the ADV payload each time - // since we get fields of argument 'advData' iteratively - AdvLen = 0; - /* Make sure we have a payload! */ - if (advData.getPayloadLen() == 0) { - PRINTF("advData.getPayloadLen() == 0\n\r"); - //return BLE_ERROR_PARAM_OUT_OF_RANGE; - local_name_length = 0; - txPowLevSet = 0; - servUuidlength = 0; - } else { + if (advData.getPayloadLen() != 0) { PayloadPtr loadPtr(advData.getPayload(), advData.getPayloadLen()); /* Align the GAP Service Appearance Char value coherently @@ -125,88 +111,17 @@ setAppearance((GapAdvertisingData::Appearance)(deviceAppearance[1]<<8|deviceAppearance[0])); - for(uint8_t index=0; index<loadPtr.getPayloadUnitCount(); index++) { + for(uint8_t index=0; index<loadPtr.getPayloadUnitCount(); index++) { loadPtr.getUnitAtIndex(index); PRINTF("adData[%d].length=%d\n\r", index,(uint8_t)(*loadPtr.getUnitAtIndex(index).getLenPtr())); - PRINTF("adData[%d].AdType=0x%x\n\r", index,(uint8_t)(*loadPtr.getUnitAtIndex(index).getAdTypePtr())); - + PRINTF("adData[%d].AdType=0x%x\n\r", index,(uint8_t)(*loadPtr.getUnitAtIndex(index).getAdTypePtr())); + switch(*loadPtr.getUnitAtIndex(index).getAdTypePtr()) { - case GapAdvertisingData::FLAGS: /* ref *Flags */ - { - PRINTF("Advertising type: FLAGS\n\r"); - //Check if Flags are OK. BlueNRG only supports LE Mode. - uint8_t *flags = loadPtr.getUnitAtIndex(index).getDataPtr(); - if((*flags & GapAdvertisingData::BREDR_NOT_SUPPORTED) != GapAdvertisingData::BREDR_NOT_SUPPORTED) { - PRINTF("BlueNRG does not support BR/EDR Mode"); - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - - break; - } - case GapAdvertisingData::INCOMPLETE_LIST_16BIT_SERVICE_IDS: /**< Incomplete list of 16-bit Service IDs */ - case GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS: /**< Complete list of 16-bit Service IDs */ - case GapAdvertisingData::INCOMPLETE_LIST_128BIT_SERVICE_IDS: /**< Incomplete list of 128-bit Service IDs */ - case GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS: /**< Complete list of 128-bit Service IDs */ + /**< TX Power Level (in dBm) */ + case GapAdvertisingData::TX_POWER_LEVEL: { - PRINTF("Advertising type: INCOMPLETE_LIST SERVICE_IDS/COMPLETE_LIST SERVICE_IDS\n\r"); - - uint8_t buffSize = *loadPtr.getUnitAtIndex(index).getLenPtr()-1; - // The total lenght should include the Data Type Value - if(buffSize>UUID_BUFFER_SIZE-1) { - return BLE_ERROR_INVALID_PARAM; - } - - servUuidlength = buffSize+1; // +1 to include the Data Type Value - servUuidData[0] = (uint8_t)(*loadPtr.getUnitAtIndex(index).getAdTypePtr()); //Data Type Value - - PRINTF("servUuidlength=%d servUuidData[0]=%d buffSize=%d\n\r", servUuidlength, servUuidData[0], buffSize); - // Save the Service UUID list just after the Data Type Value field - memcpy(servUuidData+1, loadPtr.getUnitAtIndex(index).getDataPtr(), buffSize); -#ifdef DEBUG - for(unsigned i=0; i<servUuidlength; i++) { - PRINTF("servUuidData[%d] = 0x%x\n\r", i, servUuidData[i]); - } - - for(unsigned i=0; i<buffSize; i++) { - PRINTF("loadPtr.getUnitAtIndex(index).getDataPtr()[%d] = 0x%x\n\r", - i, loadPtr.getUnitAtIndex(index).getDataPtr()[i]); - } -#endif /* DEBUG */ - break; - } - case GapAdvertisingData::INCOMPLETE_LIST_32BIT_SERVICE_IDS: /**< Incomplete list of 32-bit Service IDs (not relevant for Bluetooth 4.0) */ - { - PRINTF("Advertising type: INCOMPLETE_LIST_32BIT_SERVICE_IDS\n\r"); - return BLE_ERROR_NOT_IMPLEMENTED; - } - case GapAdvertisingData::COMPLETE_LIST_32BIT_SERVICE_IDS: /**< Complete list of 32-bit Service IDs (not relevant for Bluetooth 4.0) */ - { - PRINTF("Advertising type: COMPLETE_LIST_32BIT_SERVICE_IDS\n\r"); - return BLE_ERROR_NOT_IMPLEMENTED; - } - case GapAdvertisingData::SHORTENED_LOCAL_NAME: /**< Shortened Local Name */ - { - break; - } - case GapAdvertisingData::COMPLETE_LOCAL_NAME: /**< Complete Local Name */ - { - PRINTF("Advertising type: COMPLETE_LOCAL_NAME\n\r"); - loadPtr.getUnitAtIndex(index).printDataAsString(); - local_name_length = *loadPtr.getUnitAtIndex(index).getLenPtr()-1; - // The total length should include the Data Type Value - if(local_name_length>ADV_DATA_MAX_SIZE-1) { - return BLE_ERROR_INVALID_PARAM; - } - local_name[0] = (uint8_t)(*loadPtr.getUnitAtIndex(index).getAdTypePtr()); //Data Type Value - memcpy(local_name+1, (uint8_t*)loadPtr.getUnitAtIndex(index).getDataPtr(), local_name_length-1); - PRINTF("Advertising type: COMPLETE_LOCAL_NAME local_name=%s local_name_length=%d\n\r", local_name+1, local_name_length); - - break; - } - case GapAdvertisingData::TX_POWER_LEVEL: /**< TX Power Level (in dBm) */ - { - PRINTF("Advertising type: TX_POWER_LEVEL\n\r"); + PRINTF("Advertising type: TX_POWER_LEVEL\n\r"); int8_t enHighPower = 0; int8_t paLevel = 0; @@ -218,47 +133,11 @@ #endif if(ret == BLE_STATUS_SUCCESS) { aci_hal_set_tx_power_level(enHighPower, paLevel); - txPowLevSet = 1; } break; } - case GapAdvertisingData::DEVICE_ID: /**< Device ID */ - { - break; - } - case GapAdvertisingData::SLAVE_CONNECTION_INTERVAL_RANGE: /**< Slave :Connection Interval Range */ - { - PRINTF("Advertising type: SLAVE_CONNECTION_INTERVAL_RANGE\n\r"); - uint8_t *ptr = loadPtr.getUnitAtIndex(index).getDataPtr(); - slaveConnIntervMin = ptr[0]|ptr[1]<<8; - slaveConnIntervMax = ptr[2]|ptr[3]<<8; - - break; - } - case GapAdvertisingData::SERVICE_DATA: /**< Service Data */ - { - PRINTF("Advertising type: SERVICE_DATA\n\r"); - uint8_t buffSize = *loadPtr.getUnitAtIndex(index).getLenPtr()-1; - PRINTF("Advertising type: SERVICE_DATA (buffSize=%d)\n\r", buffSize); - // the total ADV DATA LEN should include two more bytes: the buffer size byte; and the Service Data Type Value byte - if(buffSize>ADV_DATA_MAX_SIZE-2) { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } -#ifdef DEBUG - for(int i=0; i<buffSize+1; i++) { - PRINTF("Advertising type: SERVICE_DATA loadPtr.getUnitAtIndex(index).getDataPtr()[%d] = 0x%x\n\r", - i, loadPtr.getUnitAtIndex(index).getDataPtr()[i]); - } -#endif - // the total ADV DATA LEN should include two more bytes: the buffer size byte; and the Service Data Type Value byte - AdvData[AdvLen++] = buffSize+1; // the fisrt byte is the data buffer size (type+data) - AdvData[AdvLen++] = AD_TYPE_SERVICE_DATA; - memcpy(&AdvData[AdvLen], loadPtr.getUnitAtIndex(index).getDataPtr(), buffSize); - AdvLen += buffSize; - break; - } - - case GapAdvertisingData::APPEARANCE: /**< Appearance */ + /**< Appearance */ + case GapAdvertisingData::APPEARANCE: { PRINTF("Advertising type: APPEARANCE\n\r"); @@ -273,70 +152,15 @@ break; } - case GapAdvertisingData::ADVERTISING_INTERVAL: /**< Advertising Interval */ - { - printf("Advertising type: ADVERTISING_INTERVAL\n\r"); - uint8_t buffSize = *loadPtr.getUnitAtIndex(index).getLenPtr()-1; - AdvData[AdvLen++] = buffSize+1; // the fisrt byte is the data buffer size (type+data) - AdvData[AdvLen++] = AD_TYPE_ADVERTISING_INTERVAL; - memcpy(&AdvData[AdvLen], loadPtr.getUnitAtIndex(index).getDataPtr(), buffSize); - AdvLen += buffSize; - break; - } - case GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA: /**< Manufacturer Specific Data */ - { - PRINTF("Advertising type: MANUFACTURER_SPECIFIC_DATA\n\r"); - uint8_t buffSize = *loadPtr.getUnitAtIndex(index).getLenPtr()-1; - PRINTF("Advertising type: MANUFACTURER_SPECIFIC_DATA (buffSize=%d)\n\r", buffSize); - // the total ADV DATA LEN should include two more bytes: - // the buffer size byte; - // and the Manufacturer Specific Data Type Value byte - if(buffSize>ADV_DATA_MAX_SIZE-2) { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } -#ifdef DBEUG - for(int i=0; i<buffSize+1; i++) { - PRINTF("Advertising type: MANUFACTURER_SPECIFIC_DATA loadPtr.getUnitAtIndex(index).getDataPtr()[%d] = 0x%x\n\r", - i, loadPtr.getUnitAtIndex(index).getDataPtr()[i]); - } -#endif - // the total ADV DATA LEN should include two more bytes: the buffer size byte; and the Manufacturer Specific Data Type Value byte - AdvData[AdvLen++] = buffSize+1; // the fisrt byte is the data buffer size (type+data) - AdvData[AdvLen++] = AD_TYPE_MANUFACTURER_SPECIFIC_DATA; - memcpy(&AdvData[AdvLen], loadPtr.getUnitAtIndex(index).getDataPtr(), buffSize); - AdvLen += buffSize; - break; - } } // end switch } //end for - //Set the SCAN_RSP Payload - if(scanResponse.getPayloadLen() > 0) { - scan_response_payload = scanResponse.getPayload(); - scan_rsp_length = scanResponse.getPayloadLen(); - } + } - // Update the ADV data if we are already in ADV mode - if(AdvLen > 0 && state.advertising == 1) { - - tBleStatus ret = aci_gap_update_adv_data(AdvLen, AdvData); - if(BLE_STATUS_SUCCESS!=ret) { - PRINTF("error occurred while adding adv data (ret=0x%x)\n", ret); - switch (ret) { - case BLE_STATUS_TIMEOUT: - return BLE_STACK_BUSY; - case ERR_INVALID_HCI_CMD_PARAMS: - case BLE_STATUS_INVALID_PARAMS: - return BLE_ERROR_INVALID_PARAM; - case BLE_STATUS_FAILED: - return BLE_ERROR_PARAM_OUT_OF_RANGE; - default: - return BLE_ERROR_UNSPECIFIED; - } - } - } - } + _advData = advData; + _scanResponse = scanResponse; + return BLE_ERROR_NONE; } @@ -354,40 +178,40 @@ static void advTimeoutCB(void) { Gap::GapState_t state; - + state = BlueNRGGap::getInstance().getState(); if (state.advertising == 1) { - + BlueNRGGap::getInstance().stopAdvertising(); - + } } #else static void advTimeoutCB(void) { Gap::GapState_t state; - + state = BlueNRGGap::getInstance().getState(); if (state.advertising == 1) { - + BlueNRGGap::getInstance().setAdvToFlag(); - + Timeout t = BlueNRGGap::getInstance().getAdvTimeout(); t.detach(); /* disable the callback from the timeout */ } } #endif /* AST_FOR_MBED_OS */ - + /**************************************************************************/ /*! @brief Starts the BLE HW, initialising any services that were added before this function was called. - + @param[in] params Basic advertising details, including the advertising delay, timeout and how the device should be advertised - + @note All services must be added before calling this function! @returns ble_error_t @@ -406,7 +230,7 @@ ble_error_t BlueNRGGap::startAdvertising(const GapAdvertisingParams ¶ms) { tBleStatus ret; - ble_error_t rc; + int err; /* Make sure we support the advertising type */ if (params.getAdvertisingType() == GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) { @@ -475,8 +299,8 @@ params.getAdvertisingType() == GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED) { /* set scan response data */ - PRINTF(" setting scan response data (scan_rsp_length=%u)\n", scan_rsp_length); - ret = hci_le_set_scan_resp_data(scan_rsp_length, scan_response_payload); + PRINTF(" setting scan response data (_scanResponseLen=%u)\n", _scanResponse.getPayloadLen()); + ret = hci_le_set_scan_resp_data(_scanResponse.getPayloadLen(), _scanResponse.getPayload()); if(BLE_STATUS_SUCCESS!=ret) { PRINTF(" error while setting scan response data (ret=0x%x)\n", ret); @@ -491,54 +315,42 @@ hci_le_set_scan_resp_data(0, NULL); } - //advInterval = params.getIntervalInADVUnits(); setAdvParameters(); PRINTF("advInterval=%d advType=%d\n\r", advInterval, params.getAdvertisingType()); - /* Setting discoverable mode */ - ret = aci_gap_set_discoverable(params.getAdvertisingType(), // AdvType - advInterval, // AdvIntervMin - advInterval, // AdvIntervMax - addr_type, // OwnAddrType - advFilterPolicy, // AdvFilterPolicy - local_name_length, // LocalNameLen - (const char*)local_name, // LocalName - servUuidlength, // ServiceUUIDLen - servUuidData, // ServiceUUIDList - slaveConnIntervMin, // SlaveConnIntervMin - slaveConnIntervMax); // SlaveConnIntervMax + err = hci_le_set_advertising_data(_advData.getPayloadLen(), _advData.getPayload()); - - PRINTF("!!!setting discoverable (servUuidlength=0x%x)\n\r", servUuidlength); - if(BLE_STATUS_SUCCESS!=ret) { - PRINTF("error occurred while setting discoverable (ret=0x%x)\n\r", ret); - switch (ret) { - case BLE_STATUS_INVALID_PARAMS: - case ERR_INVALID_HCI_CMD_PARAMS: - return BLE_ERROR_INVALID_PARAM; - case ERR_COMMAND_DISALLOWED: - return BLE_ERROR_OPERATION_NOT_PERMITTED; - case ERR_UNSUPPORTED_FEATURE: - return BLE_ERROR_NOT_IMPLEMENTED; - case BLE_STATUS_TIMEOUT: - return BLE_STACK_BUSY; - default: - return BLE_ERROR_UNSPECIFIED; - } + if (err) { + PRINTF("error while setting the payload\r\n"); + return BLE_ERROR_UNSPECIFIED; } - // Since AD_TYPE_TX_POWER_LEVEL has not been set by application, we delete it - if(!txPowLevSet) { - PRINTF("Deleting TX POW LEV\n"); - aci_gap_delete_ad_type(AD_TYPE_TX_POWER_LEVEL); - txPowLevSet = 0; + tBDAddr dummy_addr = { 0 }; + uint16_t advIntervalMin = advInterval == GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MAX ? advInterval - 1 : advInterval; + uint16_t advIntervalMax = advIntervalMin + 1; + + err = hci_le_set_advertising_parameters( + advIntervalMin, + advIntervalMax, + params.getAdvertisingType(), + addr_type, + 0x00, + dummy_addr, + /* all channels */ 7, + advFilterPolicy + ); + + if (err) { + PRINTF("impossible to set advertising parameters\n\r"); + PRINTF("advInterval min: %u, advInterval max: %u\n\r", advInterval, advInterval + 1); + PRINTF("advType: %u, advFilterPolicy: %u\n\r", params.getAdvertisingType(), advFilterPolicy); + return BLE_ERROR_INVALID_PARAM; } - // Stop Advertising if an error occurs while updating ADV data - rc = updateAdvertisingData(); - if(rc != BLE_ERROR_NONE) { - aci_gap_set_non_discoverable(); - return rc; + err = hci_le_set_advertise_enable(0x01); + if (err) { + PRINTF("impossible to start advertising\n\r"); + return BLE_ERROR_UNSPECIFIED; } state.advertising = 1; @@ -554,76 +366,9 @@ } return BLE_ERROR_NONE; + } -ble_error_t BlueNRGGap::updateAdvertisingData(void) -{ - tBleStatus ret; - - // Before updating the ADV data, delete COMPLETE_LOCAL_NAME field - if(AdvLen > 0) { - if(local_name_length > 0) { - ret = aci_gap_delete_ad_type(AD_TYPE_COMPLETE_LOCAL_NAME); - if (BLE_STATUS_SUCCESS!=ret){ - PRINTF("aci_gap_delete_ad_type failed return=%d\n", ret); - switch (ret) { - case BLE_STATUS_TIMEOUT: - return BLE_STACK_BUSY; - case ERR_COMMAND_DISALLOWED: - return BLE_ERROR_OPERATION_NOT_PERMITTED; - case ERR_INVALID_HCI_CMD_PARAMS: - return BLE_ERROR_INVALID_PARAM; - default: - return BLE_ERROR_UNSPECIFIED; - } - } - } - - // ...and TX_POWER_LEVEL field to make the needed room in ADV payload - if(txPowLevSet) { - ret = aci_gap_delete_ad_type(AD_TYPE_TX_POWER_LEVEL); - if (BLE_STATUS_SUCCESS!=ret){ - PRINTF("aci_gap_delete_ad_type failed return=%d\n", ret); - switch (ret) { - case BLE_STATUS_TIMEOUT: - return BLE_STACK_BUSY; - case ERR_COMMAND_DISALLOWED: - return BLE_ERROR_OPERATION_NOT_PERMITTED; - case ERR_INVALID_HCI_CMD_PARAMS: - return BLE_ERROR_INVALID_PARAM; - default: - return BLE_ERROR_UNSPECIFIED; - } - } - } - - ret = aci_gap_update_adv_data(AdvLen, AdvData); - if(BLE_STATUS_SUCCESS!=ret) { - PRINTF("error occurred while adding adv data (ret=0x%x)\n\r", ret); - switch (ret) { - case BLE_STATUS_TIMEOUT: - return BLE_STACK_BUSY; - case ERR_INVALID_HCI_CMD_PARAMS: - case BLE_STATUS_INVALID_PARAMS: - return BLE_ERROR_INVALID_PARAM; - case BLE_STATUS_FAILED: - return BLE_ERROR_PARAM_OUT_OF_RANGE; - default: - return BLE_ERROR_UNSPECIFIED; - } - } - - } // AdvLen>0 - - if(deviceAppearance != 0) { - uint8_t appearance[] = {3, AD_TYPE_APPEARANCE, deviceAppearance[0], deviceAppearance[1]}; - // just ignore error code while setting appearance - aci_gap_update_adv_data(4, appearance); - } - - return BLE_ERROR_NONE; - -} /**************************************************************************/ /*! @@ -643,28 +388,19 @@ /**************************************************************************/ ble_error_t BlueNRGGap::stopAdvertising(void) { - tBleStatus ret; if(state.advertising == 1) { - //Set non-discoverable to stop advertising - ret = aci_gap_set_non_discoverable(); - - if (BLE_STATUS_SUCCESS!=ret){ - PRINTF("Error in stopping advertisement (ret=0x%x)!!\n\r", ret) ; - switch (ret) { - case ERR_COMMAND_DISALLOWED: - return BLE_ERROR_OPERATION_NOT_PERMITTED; - case BLE_STATUS_TIMEOUT: - return BLE_STACK_BUSY; - default: - return BLE_ERROR_UNSPECIFIED; - } + + int err = hci_le_set_advertise_enable(0); + if (err) { + return BLE_ERROR_OPERATION_NOT_PERMITTED; } + PRINTF("Advertisement stopped!!\n\r") ; //Set GapState_t::advertising state state.advertising = 0; } - + return BLE_ERROR_NONE; } @@ -674,7 +410,7 @@ @param[in] reason Disconnection Reason - + @returns ble_error_t @retval BLE_ERROR_NONE @@ -704,7 +440,7 @@ return BLE_ERROR_UNSPECIFIED; } } - + return BLE_ERROR_NONE; } @@ -714,7 +450,7 @@ @param[in] reason Disconnection Reason - + @returns ble_error_t @retval BLE_ERROR_NONE @@ -735,10 +471,10 @@ /**************************************************************************/ /*! @brief Sets the 16-bit connection handle - + @param[in] conn_handle Connection Handle which is set in the Gap Instance - + @returns void */ /**************************************************************************/ @@ -750,9 +486,9 @@ /**************************************************************************/ /*! @brief Gets the 16-bit connection handle - + @param[in] void - + @returns uint16_t Connection Handle of the Gap Instance */ @@ -769,10 +505,10 @@ @param[in] type Type of Address - + @param[in] address[6] Value of the Address to be set - + @returns ble_error_t @section EXAMPLE @@ -784,26 +520,47 @@ /**************************************************************************/ ble_error_t BlueNRGGap::setAddress(AddressType_t type, const BLEProtocol::AddressBytes_t address) { - tBleStatus ret; - if (type > BLEProtocol::AddressType::RANDOM_PRIVATE_NON_RESOLVABLE) { return BLE_ERROR_PARAM_OUT_OF_RANGE; } - - addr_type = type; - // If Address Type is other than PUBLIC, the given Address is ignored - if(addr_type == BLEProtocol::AddressType::PUBLIC){ - ret = aci_hal_write_config_data(CONFIG_DATA_PUBADDR_OFFSET, - CONFIG_DATA_PUBADDR_LEN, - address); + if(type == BLEProtocol::AddressType::PUBLIC){ + tBleStatus ret = aci_hal_write_config_data( + CONFIG_DATA_PUBADDR_OFFSET, + CONFIG_DATA_PUBADDR_LEN, + address + ); if(ret != BLE_STATUS_SUCCESS) { return BLE_ERROR_OPERATION_NOT_PERMITTED; } + } else if (type == BLEProtocol::AddressType::RANDOM_STATIC) { + // ensure that the random static address is well formed + if ((address[5] & 0xC0) != 0xC0) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + + // thanks to const correctness of the API ... + tBDAddr random_address = { 0 }; + memcpy(random_address, address, sizeof(random_address)); + int err = hci_le_set_random_address(random_address); + if (err) { + return BLE_ERROR_OPERATION_NOT_PERMITTED; + } + + // It is not possible to get the bluetooth address when it is set + // store it locally in class data member + memcpy(bdaddr, address, sizeof(bdaddr)); } else { - return BLE_ERROR_OPERATION_NOT_PERMITTED; + // FIXME random addresses are not supported yet + // BLEProtocol::AddressType::RANDOM_PRIVATE_NON_RESOLVABLE + // BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE + return BLE_ERROR_NOT_IMPLEMENTED; } - + + // if we're here then the address was correctly set + // commit it inside the addr_type + addr_type = type; + isSetAddress = true; return BLE_ERROR_NONE; } @@ -811,7 +568,7 @@ /*! @brief Returns boolean if the address of the device has been set or not - + @returns bool @section EXAMPLE @@ -821,9 +578,9 @@ @endcode */ /**************************************************************************/ -bool BlueNRGGap::getIsSetAddress() +bool BlueNRGGap::getIsSetAddress() { - return isSetAddress; + return isSetAddress; } /**************************************************************************/ @@ -844,24 +601,31 @@ uint8_t bdaddr[BDADDR_SIZE]; uint8_t data_len_out; - if (addr_type == BLEProtocol::AddressType::RANDOM_PRIVATE_NON_RESOLVABLE || - addr_type == BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE) { - return BLE_ERROR_OPERATION_NOT_PERMITTED; - } - - if(typeP != NULL) { - *typeP = addr_type; + // precondition, check that pointers in input are valid + if (typeP == NULL || address == NULL) { + return BLE_ERROR_INVALID_PARAM; } - tBleStatus ret = aci_hal_read_config_data(CONFIG_DATA_RANDOM_ADDRESS_IDB05A1, BDADDR_SIZE, &data_len_out, bdaddr); - if(ret != BLE_STATUS_SUCCESS) { - return BLE_ERROR_UNSPECIFIED; + if (addr_type == BLEProtocol::AddressType::PUBLIC) { + tBleStatus ret = aci_hal_read_config_data(CONFIG_DATA_PUBADDR_OFFSET, BDADDR_SIZE, &data_len_out, bdaddr); + if(ret != BLE_STATUS_SUCCESS || data_len_out != BDADDR_SIZE) { + return BLE_ERROR_UNSPECIFIED; + } + } else if (addr_type == BLEProtocol::AddressType::RANDOM_STATIC) { + // FIXME hci_read_bd_addr and + // aci_hal_read_config_data CONFIG_DATA_RANDOM_ADDRESS_IDB05A1 + // does not work, use the address stored in class data member + memcpy(bdaddr, this->bdaddr, sizeof(bdaddr)); + } else { + // FIXME: should be implemented with privacy features + // BLEProtocol::AddressType::RANDOM_PRIVATE_NON_RESOLVABLE + // BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE + return BLE_ERROR_NOT_IMPLEMENTED; } - if(address != NULL) { - memcpy(address, bdaddr, BDADDR_SIZE); - } - + *typeP = addr_type; + memcpy(address, bdaddr, BDADDR_SIZE); + return BLE_ERROR_NONE; } @@ -878,12 +642,39 @@ @endcode */ /**************************************************************************/ -ble_error_t BlueNRGGap::getPreferredConnectionParams(ConnectionParams_t *params) +ble_error_t BlueNRGGap::getPreferredConnectionParams(ConnectionParams_t *params) { - /* avoid compiler warnings about unused variables */ - (void)params; + static const size_t parameter_size = 2; + + if (!g_preferred_connection_parameters_char_handle) { + return BLE_ERROR_OPERATION_NOT_PERMITTED; + } + + // Peripheral preferred connection parameters are an array of 4 uint16_t + uint8_t parameters_packed[parameter_size * 4]; + uint16_t bytes_read = 0; - return BLE_ERROR_NOT_IMPLEMENTED; + tBleStatus err = aci_gatt_read_handle_value( + g_preferred_connection_parameters_char_handle + BlueNRGGattServer::CHAR_VALUE_HANDLE, + sizeof(parameters_packed), + &bytes_read, + parameters_packed + ); + + PRINTF("getPreferredConnectionParams err=0x%02x (bytes_read=%u)\n\r", err, bytes_read); + + // check that the read succeed and the result have the expected length + if (err || bytes_read != sizeof(parameters_packed)) { + return BLE_ERROR_UNSPECIFIED; + } + + // memcpy field by field + memcpy(¶ms->minConnectionInterval, parameters_packed, parameter_size); + memcpy(¶ms->maxConnectionInterval, ¶meters_packed[parameter_size], parameter_size); + memcpy(¶ms->slaveLatency, ¶meters_packed[2 * parameter_size], parameter_size); + memcpy(¶ms->connectionSupervisionTimeout, ¶meters_packed[3 * parameter_size], parameter_size); + + return BLE_ERROR_NONE; } @@ -900,12 +691,63 @@ @endcode */ /**************************************************************************/ -ble_error_t BlueNRGGap::setPreferredConnectionParams(const ConnectionParams_t *params) +ble_error_t BlueNRGGap::setPreferredConnectionParams(const ConnectionParams_t *params) { - /* avoid compiler warnings about unused variables */ - (void)params; + static const size_t parameter_size = 2; + uint8_t parameters_packed[parameter_size * 4]; + + // ensure that parameters are correct + // see BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part C] + // section 12.3 PERIPHERAL PREFERRED CONNECTION PARAMETERS CHARACTERISTIC + if (((0x0006 > params->minConnectionInterval) || (params->minConnectionInterval > 0x0C80)) && + params->minConnectionInterval != 0xFFFF) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + + if (((params->minConnectionInterval > params->maxConnectionInterval) || (params->maxConnectionInterval > 0x0C80)) && + params->maxConnectionInterval != 0xFFFF) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + + if (params->slaveLatency > 0x01F3) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + + if (((0x000A > params->connectionSupervisionTimeout) || (params->connectionSupervisionTimeout > 0x0C80)) && + params->connectionSupervisionTimeout != 0xFFFF) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } - return BLE_ERROR_NOT_IMPLEMENTED; + // copy the parameters inside the byte array + memcpy(parameters_packed, ¶ms->minConnectionInterval, parameter_size); + memcpy(¶meters_packed[parameter_size], ¶ms->maxConnectionInterval, parameter_size); + memcpy(¶meters_packed[2 * parameter_size], ¶ms->slaveLatency, parameter_size); + memcpy(¶meters_packed[3 * parameter_size], ¶ms->connectionSupervisionTimeout, parameter_size); + + tBleStatus err = aci_gatt_update_char_value( + g_gap_service_handle, + g_preferred_connection_parameters_char_handle, + /* offset */ 0, + sizeof(parameters_packed), + parameters_packed + ); + + if (err) { + PRINTF("setPreferredConnectionParams failed (err=0x%x)!!\n\r", err) ; + switch (err) { + case BLE_STATUS_INVALID_HANDLE: + case BLE_STATUS_INVALID_PARAMETER: + return BLE_ERROR_INVALID_PARAM; + case BLE_STATUS_INSUFFICIENT_RESOURCES: + return BLE_ERROR_NO_MEM; + case BLE_STATUS_TIMEOUT: + return BLE_STACK_BUSY; + default: + return BLE_ERROR_UNSPECIFIED; + } + } + + return BLE_ERROR_NONE; } /**************************************************************************/ @@ -923,16 +765,43 @@ /**************************************************************************/ ble_error_t BlueNRGGap::updateConnectionParams(Handle_t handle, const ConnectionParams_t *params) { - /* avoid compiler warnings about unused variables */ - (void) handle; - (void)params; + tBleStatus ret = BLE_STATUS_SUCCESS; + + if(gapRole == Gap::CENTRAL) { + ret = aci_gap_start_connection_update(handle, + params->minConnectionInterval, + params->maxConnectionInterval, + params->slaveLatency, + params->connectionSupervisionTimeout, + CONN_L1, CONN_L2); + } else { + ret = aci_l2cap_connection_parameter_update_request(handle, + params->minConnectionInterval, + params->maxConnectionInterval, + params->slaveLatency, + params->connectionSupervisionTimeout); + } + + if (BLE_STATUS_SUCCESS != ret){ + PRINTF("updateConnectionParams failed (ret=0x%x)!!\n\r", ret) ; + switch (ret) { + case ERR_INVALID_HCI_CMD_PARAMS: + case BLE_STATUS_INVALID_PARAMETER: + return BLE_ERROR_INVALID_PARAM; + case ERR_COMMAND_DISALLOWED: + case BLE_STATUS_NOT_ALLOWED: + return BLE_ERROR_OPERATION_NOT_PERMITTED; + default: + return BLE_ERROR_UNSPECIFIED; + } + } return BLE_ERROR_NONE; } /**************************************************************************/ /*! - @brief Sets the Device Name Characteristic + @brief Sets the Device Name Characteristic @param[in] deviceName pointer to device name to be set @@ -949,11 +818,11 @@ @endcode */ /**************************************************************************/ -ble_error_t BlueNRGGap::setDeviceName(const uint8_t *deviceName) +ble_error_t BlueNRGGap::setDeviceName(const uint8_t *deviceName) { tBleStatus ret; - uint8_t nameLen = 0; - + uint8_t nameLen = 0; + nameLen = strlen((const char*)deviceName); PRINTF("DeviceName Size=%d\n\r", nameLen); @@ -983,13 +852,13 @@ /**************************************************************************/ /*! - @brief Gets the Device Name Characteristic + @brief Gets the Device Name Characteristic @param[in] deviceName - pointer to device name + pointer to device name @param[in] lengthP - pointer to device name length + pointer to device name length @returns ble_error_t @@ -1021,10 +890,10 @@ /**************************************************************************/ /*! - @brief Sets the Device Appearance Characteristic + @brief Sets the Device Appearance Characteristic @param[in] appearance - device appearance + device appearance @returns ble_error_t @@ -1043,9 +912,9 @@ tBleStatus ret; uint8_t deviceAppearance[2]; - STORE_LE_16(deviceAppearance, appearance); + STORE_LE_16(deviceAppearance, appearance); PRINTF("setAppearance= 0x%x 0x%x\n\r", deviceAppearance[1], deviceAppearance[0]); - + ret = aci_gatt_update_char_value(g_gap_service_handle, g_appearance_char_handle, 0, 2, (uint8_t *)deviceAppearance); @@ -1072,7 +941,7 @@ @brief Gets the Device Appearance Characteristic @param[in] appearance - pointer to device appearance value + pointer to device appearance value @returns ble_error_t @@ -1161,7 +1030,7 @@ default: type = GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED; } - + PRINTF("data_length=%d adv peerAddr[%02x %02x %02x %02x %02x %02x] \r\n", *data_length, addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]); if(!_connecting) { @@ -1170,7 +1039,7 @@ PRINTF("!!!After processAdvertisementReport\n\r"); } break; - + case DISCOVERY_COMPLETE: // The discovery is complete. If this is due to a stop scanning (i.e., the device // we are interested in has been found) and a connection has been requested @@ -1199,7 +1068,7 @@ ble_error_t BlueNRGGap::startRadioScan(const GapScanningParams &scanningParams) { - + tBleStatus ret = BLE_STATUS_SUCCESS; // Stop ADV before scanning @@ -1256,13 +1125,13 @@ PRINTF("stopScan\n\r"); ret = aci_gap_terminate_gap_procedure(GAP_OBSERVATION_PROC); - + if (ret != BLE_STATUS_SUCCESS) { PRINTF("GAP Terminate Gap Procedure failed(ret=0x%x)\n", ret); - return BLE_ERROR_UNSPECIFIED; + return BLE_ERROR_UNSPECIFIED; } else { PRINTF("Discovery Procedure Terminated\n"); - return BLE_ERROR_NONE; + return BLE_ERROR_NONE; } } @@ -1276,7 +1145,7 @@ ble_error_t BlueNRGGap::setTxPower(int8_t txPower) { tBleStatus ret; - + int8_t enHighPower = 0; int8_t paLevel = 0; @@ -1285,7 +1154,7 @@ return BLE_ERROR_PARAM_OUT_OF_RANGE; } - PRINTF("enHighPower=%d, paLevel=%d\n\r", enHighPower, paLevel); + PRINTF("enHighPower=%d, paLevel=%d\n\r", enHighPower, paLevel); ret = aci_hal_set_tx_power_level(enHighPower, paLevel); if(ret!=BLE_STATUS_SUCCESS) { return BLE_ERROR_PARAM_OUT_OF_RANGE; @@ -1298,7 +1167,7 @@ /*! @brief get permitted Tx power values @param[in] values pointer to pointer to permitted power values - @param[in] num number of values + @param[in] num number of values */ /**************************************************************************/ void BlueNRGGap::getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP) { @@ -1324,6 +1193,8 @@ if(state.connected == 1) { advIntMS = (conn_min_interval*1.25)-GUARD_INT; advInterval = _advParams.MSEC_TO_ADVERTISEMENT_DURATION_UNITS(advIntMS); + + PRINTF("conn_min_interval is equal to %u\r\n", conn_min_interval); } else { advInterval = _advParams.getIntervalInADVUnits(); } @@ -1391,8 +1262,8 @@ setConnectionParameters(); /* - Scan_Interval, Scan_Window, Peer_Address_Type, Peer_Address, Own_Address_Type, Conn_Interval_Min, - Conn_Interval_Max, Conn_Latency, Supervision_Timeout, Conn_Len_Min, Conn_Len_Max + Scan_Interval, Scan_Window, Peer_Address_Type, Peer_Address, Own_Address_Type, Conn_Interval_Min, + Conn_Interval_Max, Conn_Latency, Supervision_Timeout, Conn_Len_Min, Conn_Len_Max */ ret = aci_gap_create_connection(scanInterval, scanWindow, @@ -1403,7 +1274,7 @@ SUPERV_TIMEOUT, CONN_L1, CONN_L1); //_connecting = false; - + if (ret != BLE_STATUS_SUCCESS) { PRINTF("Error while starting connection (ret=0x%02X).\n\r", ret); return BLE_ERROR_UNSPECIFIED; @@ -1421,7 +1292,12 @@ { /* avoid compiler warnings about unused variables */ (void)connectionParams; - (void)scanParams; + + setScanParams(scanParams->getInterval(), + scanParams->getWindow(), + scanParams->getTimeout(), + scanParams->getActiveScanning() + ); // Save the peer address for(int i=0; i<BDADDR_SIZE; i++) { @@ -1437,7 +1313,7 @@ PRINTF("Calling createConnection from connect()\n\r"); return createConnection(); } - + return BLE_ERROR_NONE; } @@ -1528,14 +1404,19 @@ /* Clear derived class members */ m_connectionHandle = BLE_CONN_HANDLE_INVALID; - memset(deviceAppearance, 0, sizeof(deviceAppearance)); - memset(local_name, 0, LOCAL_NAME_MAX_SIZE); - memset(local_name, 0, UUID_BUFFER_SIZE); - memset(AdvData, 0, ADV_DATA_MAX_SIZE); - /* Set the whitelist policy filter modes to IGNORE_WHITELIST */ advertisingPolicyMode = Gap::ADV_POLICY_IGNORE_WHITELIST; scanningPolicyMode = Gap::SCAN_POLICY_IGNORE_WHITELIST; return BLE_ERROR_NONE; } + +void BlueNRGGap::setConnectionInterval(uint16_t interval) { + conn_min_interval = interval; + conn_max_interval = interval; +} + +void BlueNRGGap::setGapRole(Role_t role) +{ + gapRole = role; +}