Commit 61ebeaff authored by Wai Hon Law's avatar Wai Hon Law Committed by Commit Bot

[Chromecast][BLE] Support indication

Create a new API for subscribing to notification or indication smartly
based on the availability of both options.

Note that notification has higher priority over indication.

Bug: internal 118329438
Change-Id: I610477424e2e0a2877e41c3bfd4dd1493e02f8f7
Reviewed-on: https://chromium-review.googlesource.com/c/1352492Reviewed-by: default avatarLuke Halliwell <halliwell@chromium.org>
Commit-Queue: Wai Hon Law <whhone@google.com>
Cr-Commit-Position: refs/heads/master@{#611401}
parent 88843ebb
......@@ -29,6 +29,12 @@ class MockRemoteCharacteristic : public RemoteCharacteristic {
std::move(cb).Run(SetRegisterNotification(enable));
}
MOCK_METHOD1(SetRegisterNotificationOrIndication, bool(bool));
void SetRegisterNotificationOrIndication(bool enable,
StatusCallback cb) override {
std::move(cb).Run(SetRegisterNotificationOrIndication(enable));
}
void SetNotification(bool enable, StatusCallback cb) override {}
void ReadAuth(bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
ReadCallback callback) override {}
......
......@@ -38,13 +38,21 @@ class RemoteCharacteristic
const bluetooth_v2_shlib::Uuid& uuid) = 0;
// Register or deregister from a notification. Calls |SetNotification| and
// writes the cccd.
// writes the CCCD. For indication support, see method
// |SetRegisterNotificationOrIndication|.
virtual void SetRegisterNotification(bool enable, StatusCallback cb) = 0;
// Enable notifications for this characteristic. Client must still write to
// the CCCD seperately (or use |SetRegisterNotification| instead).
virtual void SetNotification(bool enable, StatusCallback cb) = 0;
// If notification is supported, then register or deregister notification.
// If indication is supported, then register or deregister indication.
// Note that notification has higher priority over indication.
// Calls |SetNotification| and writes the CCCD.
virtual void SetRegisterNotificationOrIndication(bool enable,
StatusCallback cb) = 0;
// Read the characteristic with |auth_req|. When completed, |callback| will be
// called.
virtual void ReadAuth(bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
......
......@@ -33,12 +33,26 @@ namespace chromecast {
namespace bluetooth {
namespace {
std::vector<uint8_t> GetDescriptorNotificationValue(bool enable) {
if (enable) {
std::vector<uint8_t> GetDescriptorNotificationValue(bool notification_enable) {
if (notification_enable) {
return std::vector<uint8_t>(
std::begin(bluetooth::RemoteDescriptor::kEnableNotificationValue),
std::end(bluetooth::RemoteDescriptor::kEnableNotificationValue));
}
return std::vector<uint8_t>(
std::begin(bluetooth::RemoteDescriptor::kDisableNotificationValue),
std::end(bluetooth::RemoteDescriptor::kDisableNotificationValue));
}
std::vector<uint8_t> GetDescriptorIndicationValue(bool indication_enable) {
if (indication_enable) {
return std::vector<uint8_t>(
std::begin(bluetooth::RemoteDescriptor::kEnableIndicationValue),
std::end(bluetooth::RemoteDescriptor::kEnableIndicationValue));
}
return std::vector<uint8_t>(
std::begin(bluetooth::RemoteDescriptor::kDisableNotificationValue),
std::end(bluetooth::RemoteDescriptor::kDisableNotificationValue));
......@@ -46,15 +60,19 @@ std::vector<uint8_t> GetDescriptorNotificationValue(bool enable) {
bool CharacteristicHasNotify(
const bluetooth_v2_shlib::Gatt::Characteristic* characteristic) {
return characteristic->properties & bluetooth_v2_shlib::Gatt::PROPERTY_NOTIFY;
}
bool CharacteristicHasIndication(
const bluetooth_v2_shlib::Gatt::Characteristic* characteristic) {
return characteristic->properties &
bluetooth_v2_shlib::Gatt::PROPERTY_NOTIFY ||
characteristic->properties &
bluetooth_v2_shlib::Gatt::PROPERTY_INDICATE;
bluetooth_v2_shlib::Gatt::PROPERTY_INDICATE;
}
std::unique_ptr<bluetooth_v2_shlib::Gatt::Descriptor> MaybeCreateFakeCccd(
const bluetooth_v2_shlib::Gatt::Characteristic* characteristic) {
if (!CharacteristicHasNotify(characteristic)) {
if (!CharacteristicHasNotify(characteristic) &&
!CharacteristicHasIndication(characteristic)) {
return nullptr;
}
......@@ -134,16 +152,69 @@ void RemoteCharacteristicImpl::SetRegisterNotification(bool enable,
StatusCallback cb) {
MAKE_SURE_IO_THREAD(SetRegisterNotification, enable,
BindToCurrentSequence(std::move(cb)));
SetRegisterNotificationOrIndicationInternal(false, enable, std::move(cb));
}
void RemoteCharacteristicImpl::SetNotification(bool enable, StatusCallback cb) {
MAKE_SURE_IO_THREAD(SetNotification, enable,
BindToCurrentSequence(std::move(cb)));
if (!gatt_client_manager_) {
LOG(ERROR) << __func__ << " failed: Destroyed";
EXEC_CB_AND_RET(cb, false);
}
if (!gatt_client_manager_->gatt_client()->SetCharacteristicNotification(
device_->addr(), *characteristic_, enable)) {
LOG(ERROR) << "Set characteristic notification failed";
EXEC_CB_AND_RET(cb, false);
}
if (!CharacteristicHasNotify(characteristic_)) {
notification_enabled_ = enable;
EXEC_CB_AND_RET(cb, true);
}
void RemoteCharacteristicImpl::SetRegisterNotificationOrIndication(
bool enable,
RemoteCharacteristic::StatusCallback cb) {
MAKE_SURE_IO_THREAD(SetRegisterNotificationOrIndication, enable,
BindToCurrentSequence(std::move(cb)));
if (CharacteristicHasNotify(characteristic_)) {
SetRegisterNotificationOrIndicationInternal(false, enable, std::move(cb));
} else if (CharacteristicHasIndication(characteristic_)) {
SetRegisterNotificationOrIndicationInternal(true, enable, std::move(cb));
} else {
LOG(ERROR) << __func__
<< " failed: Characteristic doesn't support notifications";
<< " failed: Characteristic doesn't support notification or "
"indication";
EXEC_CB_AND_RET(cb, false);
}
}
void RemoteCharacteristicImpl::SetRegisterNotificationOrIndicationInternal(
bool indication,
bool enable,
RemoteCharacteristic::StatusCallback cb) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
if (!gatt_client_manager_) {
LOG(ERROR) << __func__ << " failed: Destroyed";
EXEC_CB_AND_RET(cb, false);
}
if (indication) {
if (!CharacteristicHasIndication(characteristic_)) {
LOG(ERROR) << __func__
<< " failed: Characteristic doesn't support indication";
EXEC_CB_AND_RET(cb, false);
}
} else {
if (!CharacteristicHasNotify(characteristic_)) {
LOG(ERROR) << __func__
<< " failed: Characteristic doesn't support notifications";
EXEC_CB_AND_RET(cb, false);
}
}
if (notification_enabled_ == enable) {
EXEC_CB_AND_RET(cb, true);
......@@ -164,28 +235,14 @@ void RemoteCharacteristicImpl::SetRegisterNotification(bool enable,
}
auto it = uuid_to_descriptor_.find(RemoteDescriptor::kCccdUuid);
DCHECK(it != uuid_to_descriptor_.end());
// CCCD must exist. |fake_cccd_| should have been created if it doesn't exist.
DCHECK(it != uuid_to_descriptor_.end());
std::vector<uint8_t> write_val = indication
? GetDescriptorIndicationValue(enable)
: GetDescriptorNotificationValue(enable);
it->second->WriteAuth(bluetooth_v2_shlib::Gatt::Client::AUTH_REQ_NONE,
GetDescriptorNotificationValue(enable), std::move(cb));
}
void RemoteCharacteristicImpl::SetNotification(bool enable, StatusCallback cb) {
MAKE_SURE_IO_THREAD(SetNotification, enable,
BindToCurrentSequence(std::move(cb)));
if (!gatt_client_manager_) {
LOG(ERROR) << __func__ << " failed: Destroyed";
EXEC_CB_AND_RET(cb, false);
}
if (!gatt_client_manager_->gatt_client()->SetCharacteristicNotification(
device_->addr(), *characteristic_, enable)) {
LOG(ERROR) << "Set characteristic notification failed";
EXEC_CB_AND_RET(cb, false);
}
notification_enabled_ = enable;
EXEC_CB_AND_RET(cb, true);
write_val, std::move(cb));
}
void RemoteCharacteristicImpl::ReadAuth(
......
......@@ -30,6 +30,8 @@ class RemoteCharacteristicImpl : public RemoteCharacteristic {
const bluetooth_v2_shlib::Uuid& uuid) override;
void SetRegisterNotification(bool enable, StatusCallback cb) override;
void SetNotification(bool enable, StatusCallback cb) override;
void SetRegisterNotificationOrIndication(bool enable,
StatusCallback cb) override;
void ReadAuth(bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
ReadCallback callback) override;
void Read(ReadCallback callback) override;
......@@ -65,6 +67,12 @@ class RemoteCharacteristicImpl : public RemoteCharacteristic {
std::map<bluetooth_v2_shlib::Uuid, scoped_refptr<RemoteDescriptor>>
CreateDescriptorMap();
// If |indication| is true, register or deregister indication.
// If |indication| is false, register or deregister notification.
void SetRegisterNotificationOrIndicationInternal(bool indication,
bool enable,
StatusCallback cb);
// Weak reference to avoid refcount loop.
RemoteDeviceImpl* const device_;
base::WeakPtr<GattClientManagerImpl> gatt_client_manager_;
......
......@@ -10,6 +10,8 @@ namespace bluetooth {
// static
constexpr uint8_t RemoteDescriptor::kEnableNotificationValue[];
// static
constexpr uint8_t RemoteDescriptor::kEnableIndicationValue[];
// static
constexpr uint8_t RemoteDescriptor::kDisableNotificationValue[];
// static
const bluetooth_v2_shlib::Uuid RemoteDescriptor::kCccdUuid = {
......
......@@ -25,6 +25,7 @@ class RemoteDescriptor;
class RemoteDescriptor : public base::RefCountedThreadSafe<RemoteDescriptor> {
public:
static constexpr uint8_t kEnableNotificationValue[] = {0x01, 0x00};
static constexpr uint8_t kEnableIndicationValue[] = {0x02, 0x00};
static constexpr uint8_t kDisableNotificationValue[] = {0x00, 0x00};
static const bluetooth_v2_shlib::Uuid kCccdUuid;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment