Index: sources/bluetooth/BluetoothInterface.cpp =================================================================== diff -u -rc447018bc6c50996f402e01f951d40b17a120705 -r1c97eebc80b33b429fa6e9489584ce3bf24f0bbc --- sources/bluetooth/BluetoothInterface.cpp (.../BluetoothInterface.cpp) (revision c447018bc6c50996f402e01f951d40b17a120705) +++ sources/bluetooth/BluetoothInterface.cpp (.../BluetoothInterface.cpp) (revision 1c97eebc80b33b429fa6e9489584ce3bf24f0bbc) @@ -452,9 +452,7 @@ // This indicates the local/host bluetooth have connected passively to the remote device _reconnectionActive = true; - if ( _local->pairingStatus(vAddress) == QBluetoothLocalDevice::Unpaired ) { - requestDevicePairing(vAddress); - } else { + if ( _local->pairingStatus(vAddress) != QBluetoothLocalDevice::Unpaired ) { if ( isDeviceValid() ) { _device->connectToDevice(); } @@ -511,15 +509,8 @@ data.pair = isPaired || isAuthPaired; - if(data.pair){ - // Enable the polling since previously paired device found - _reconnectionActive = true; - - // sets up the bluetooth device info to create the device later for pairing - _temp = QBluetoothDeviceInfo(QBluetoothAddress(data.addr), data.name, QBluetoothDeviceInfo::HealthBloodPressureMonitor); - - // using signal to re-use the slot function of a device selected - emit _BluetoothInterface.didDeviceSelect(data); + if ( data.pair ) { + requestDevicePairing(data); } emit didDeviceChange(data); NOTIFY_SCAN_FOUND @@ -569,21 +560,22 @@ */ void BluetoothInterface::onDeviceSelect(const BluetoothDeviceData &vDevice) { stopScan(); - _temp = QBluetoothDeviceInfo(QBluetoothAddress(vDevice.addr), vDevice.name, QBluetoothDeviceInfo::HealthBloodPressureMonitor); - - requestDevicePairing(QBluetoothAddress(vDevice.addr)); + requestDevicePairing(vDevice); } /*! * \brief BluetoothInterface::requestDevicePairing * \details Request the pairing of the local/host bluetooth with the remote device - * \param vAddress - the address of the remote device + * \param vDevice - The device data */ -void BluetoothInterface::requestDevicePairing(const QBluetoothAddress &vAddress) { +void BluetoothInterface::requestDevicePairing(const BluetoothDeviceData &vDevice) { if ( ! isLocalValid() ) return; NOTIFY_LOCAL_PAIRING - _local->requestPairing(vAddress, QBluetoothLocalDevice::AuthorizedPaired); + + _temp = QBluetoothDeviceInfo(QBluetoothAddress(vDevice.addr), vDevice.name, QBluetoothDeviceInfo::HealthBloodPressureMonitor); + _isPairingKeyWritten = false; + _local->requestPairing(QBluetoothAddress(vDevice.addr), QBluetoothLocalDevice::AuthorizedPaired); } /*! @@ -596,9 +588,8 @@ Q_UNUSED(addr) if( pair == QBluetoothLocalDevice::Paired || pair == QBluetoothLocalDevice::AuthorizedPaired) { connectToDevice(); - } else { - // not handling unpairing case } + // Else is the unpaired completion case } void BluetoothInterface::onAttributeResponse(const DeviceBluetoothPairedQueryResponseData &vData) @@ -644,11 +635,7 @@ NOTIFY_DEVICE_CONNECT _reconnectionActive = false; - if(_local->pairingStatus(_device->remoteAddress()) == QBluetoothLocalDevice::Unpaired) { - requestDevicePairing(_device->remoteAddress()); - } else { - discoverServices(); - } + discoverServices(); } /*! @@ -731,7 +718,6 @@ { interpretBloodPressure(vValue); } - qDebug() << "---------" << vCharacteristic.name() << vValue; } /*! @@ -744,10 +730,43 @@ */ void BluetoothInterface::onServiceCharacteristicRead (const QLowEnergyCharacteristic &vCharacteristic, const QByteArray &vValue) { QLowEnergyService *service = reinterpret_cast(sender()); + NOTIFY_DETAILS_READ + if ( isVendorSpecificService(service) && isDevicePairingCharacteristicUuid(vCharacteristic) ) { + if ( !_isPairingKeyWritten && (vValue.at(0) == _deviceConfirmKeyWriteCodeSuccess ) ) { + // write the key for pairing retention + writeDevicePairingKey(); + _isPairingKeyWritten = true; + } + if(vValue.at(0) == '\x80') { + // No-op key write responded with a success code + } + } } /*! + * \brief BluetoothInterface::isDevicePairingCharacteristicUuid + * \details Indicate whether the characteristic passed is the device pairing characteristic of the vendor specific service + * \return true if the characteristic is the device pairing/bonding characteristic, false otherwise + * \param vCharacteristic - The characteristic object + */ +bool BluetoothInterface::isDevicePairingCharacteristicUuid (const QLowEnergyCharacteristic &vCharacteristic) { + QString characteristicUuid = vCharacteristic.uuid().toString(); + return (characteristicUuid.compare(_devicePairingBondCharacteristicUuid, Qt::CaseInsensitive) == 0); +} + +/*! + * \brief BluetoothInterface::isVendorSpecificService + * \details Indicate whether the service passed has the uuid of a vendor specific service + * \return true if the service is a vendor specific service, false otherwise + * \param vService - The service object + */ +bool BluetoothInterface::isVendorSpecificService (const QLowEnergyService *vService) { + QString serviceUuid = vService->serviceUuid().toString(); + return (serviceUuid.compare(_vendorSpecificServiceUuid, Qt::CaseInsensitive) == 0); +} + +/*! * \brief BluetoothInterface::onServiceCharacteristicWritten * \details This signal handler is called when the value of characteristic is successfully changed to new vValue. * The change must have been triggered by calling writeCharacteristic(). If the write operation is not successful, @@ -759,6 +778,10 @@ */ void BluetoothInterface::onServiceCharacteristicWritten (const QLowEnergyCharacteristic &vCharacteristic, const QByteArray &vValue) { QLowEnergyService *service = reinterpret_cast(sender()); + if ( isVendorSpecificService(service) ) { + service->readCharacteristic(vCharacteristic); + } + NOTIFY_DETAILS_WRITE } @@ -813,6 +836,11 @@ switch (vState) { case QLowEnergyService::ServiceDiscovered : { NOTIFY_SERVICE_DETAILS_DONE + + if ( isVendorSpecificService(service) && !_isPairingKeyWritten) { + enableKeyProgramming(); + } + switch( service->serviceUuid().toUInt32() ) { case QBluetoothUuid::BloodPressure: enableNotify(); @@ -1131,6 +1159,13 @@ */ void BluetoothInterface::makeServices(const QBluetoothUuid &vService) { + // creating QBluetoothUuid object for the vendor service uuid string creates + // an ambiguous object, so doing string compare + if (vService.toString().compare(_vendorSpecificServiceUuid) == 0) { + _serviceVendorSpecific = _device->createServiceObject(vService, this); + initConnectionsService (_serviceVendorSpecific ); + return; + } if (vService == QBluetoothUuid (QBluetoothUuid::DeviceInformation )) { _serviceDeviceInformation = _device->createServiceObject(vService, this); initConnectionsService (_serviceDeviceInformation ); @@ -1161,6 +1196,11 @@ void BluetoothInterface::discoverServicesDetails() { if ( ! isValid() ) return; + + if ( _serviceVendorSpecific ) { + NOTIFY_SERVICE_DETAILS (_serviceVendorSpecific ) + _serviceVendorSpecific ->discoverDetails(); + } if ( _serviceDeviceInformation ) { NOTIFY_SERVICE_DETAILS (_serviceDeviceInformation ) _serviceDeviceInformation ->discoverDetails(); @@ -1188,6 +1228,11 @@ */ void BluetoothInterface::quitServices() { NOTIFY_SERVICE_DONE + + if ( _serviceVendorSpecific ) { + delete _serviceVendorSpecific ; + _serviceVendorSpecific = nullptr; + } if ( _serviceDeviceInformation ) { delete _serviceDeviceInformation ; _serviceDeviceInformation = nullptr; @@ -1209,8 +1254,43 @@ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~ Characteristics // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/*! + * \brief BluetoothInterface::enableKeyProgramming + * \details Write the special key to enable key programming mode for the pairing retention + */ +void BluetoothInterface::enableKeyProgramming() { + if ( ! _serviceVendorSpecific ) { + NOTIFY_SERVICE_INVALID + return; + } + // write the special value to the characteristic to enable key programming mode + const QLowEnergyCharacteristic detailBPMeas = _serviceVendorSpecific->characteristic(QBluetoothUuid(_devicePairingBondCharacteristicUuid)); + if ( detailBPMeas.isValid() ) { + _serviceVendorSpecific->writeCharacteristic(detailBPMeas, QByteArray::fromHex(_enableKeyProgrammingString)); + } +} + /*! + * \brief BluetoothInterface::writeDevicePairingKey + * \details Write the pairing key value to the bonding characteristic of the vendor specific service. + * This allows the device to maintain the pairing state with the remote device without the need to re-pair + * after the initial pairing. The device will be able to reconnect and retrieve measurements without pairing first. + */ +void BluetoothInterface::writeDevicePairingKey() { + if ( ! _serviceVendorSpecific ) { + NOTIFY_SERVICE_INVALID + return; + } + + // set the value of the pairing key on the device + const QLowEnergyCharacteristic detailBPMeas = _serviceVendorSpecific->characteristic(QBluetoothUuid(_devicePairingBondCharacteristicUuid)); + if ( detailBPMeas.isValid() ) { + _serviceVendorSpecific->writeCharacteristic(detailBPMeas, QByteArray::fromHex(_devicePairingKeyString)); + } +} + +/*! * \brief BluetoothInterface::enableNotify * \details Enabling the Blood Pressure measurement notification. * This has to be done to first get the OK on the Bluetooth Cuff device.