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 { ...@@ -29,6 +29,12 @@ class MockRemoteCharacteristic : public RemoteCharacteristic {
std::move(cb).Run(SetRegisterNotification(enable)); 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 SetNotification(bool enable, StatusCallback cb) override {}
void ReadAuth(bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req, void ReadAuth(bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
ReadCallback callback) override {} ReadCallback callback) override {}
......
...@@ -38,13 +38,21 @@ class RemoteCharacteristic ...@@ -38,13 +38,21 @@ class RemoteCharacteristic
const bluetooth_v2_shlib::Uuid& uuid) = 0; const bluetooth_v2_shlib::Uuid& uuid) = 0;
// Register or deregister from a notification. Calls |SetNotification| and // 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; virtual void SetRegisterNotification(bool enable, StatusCallback cb) = 0;
// Enable notifications for this characteristic. Client must still write to // Enable notifications for this characteristic. Client must still write to
// the CCCD seperately (or use |SetRegisterNotification| instead). // the CCCD seperately (or use |SetRegisterNotification| instead).
virtual void SetNotification(bool enable, StatusCallback cb) = 0; 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 // Read the characteristic with |auth_req|. When completed, |callback| will be
// called. // called.
virtual void ReadAuth(bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req, virtual void ReadAuth(bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
......
...@@ -33,12 +33,26 @@ namespace chromecast { ...@@ -33,12 +33,26 @@ namespace chromecast {
namespace bluetooth { namespace bluetooth {
namespace { 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>( return std::vector<uint8_t>(
std::begin(bluetooth::RemoteDescriptor::kEnableNotificationValue), std::begin(bluetooth::RemoteDescriptor::kEnableNotificationValue),
std::end(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>( return std::vector<uint8_t>(
std::begin(bluetooth::RemoteDescriptor::kDisableNotificationValue), std::begin(bluetooth::RemoteDescriptor::kDisableNotificationValue),
std::end(bluetooth::RemoteDescriptor::kDisableNotificationValue)); std::end(bluetooth::RemoteDescriptor::kDisableNotificationValue));
...@@ -46,15 +60,19 @@ std::vector<uint8_t> GetDescriptorNotificationValue(bool enable) { ...@@ -46,15 +60,19 @@ std::vector<uint8_t> GetDescriptorNotificationValue(bool enable) {
bool CharacteristicHasNotify( bool CharacteristicHasNotify(
const bluetooth_v2_shlib::Gatt::Characteristic* characteristic) { 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 & return characteristic->properties &
bluetooth_v2_shlib::Gatt::PROPERTY_NOTIFY || bluetooth_v2_shlib::Gatt::PROPERTY_INDICATE;
characteristic->properties &
bluetooth_v2_shlib::Gatt::PROPERTY_INDICATE;
} }
std::unique_ptr<bluetooth_v2_shlib::Gatt::Descriptor> MaybeCreateFakeCccd( std::unique_ptr<bluetooth_v2_shlib::Gatt::Descriptor> MaybeCreateFakeCccd(
const bluetooth_v2_shlib::Gatt::Characteristic* characteristic) { const bluetooth_v2_shlib::Gatt::Characteristic* characteristic) {
if (!CharacteristicHasNotify(characteristic)) { if (!CharacteristicHasNotify(characteristic) &&
!CharacteristicHasIndication(characteristic)) {
return nullptr; return nullptr;
} }
...@@ -134,16 +152,69 @@ void RemoteCharacteristicImpl::SetRegisterNotification(bool enable, ...@@ -134,16 +152,69 @@ void RemoteCharacteristicImpl::SetRegisterNotification(bool enable,
StatusCallback cb) { StatusCallback cb) {
MAKE_SURE_IO_THREAD(SetRegisterNotification, enable, MAKE_SURE_IO_THREAD(SetRegisterNotification, enable,
BindToCurrentSequence(std::move(cb))); 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_) { if (!gatt_client_manager_) {
LOG(ERROR) << __func__ << " failed: Destroyed"; LOG(ERROR) << __func__ << " failed: Destroyed";
EXEC_CB_AND_RET(cb, false); 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__ LOG(ERROR) << __func__
<< " failed: Characteristic doesn't support notifications"; << " failed: Characteristic doesn't support notification or "
"indication";
EXEC_CB_AND_RET(cb, false); 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) { if (notification_enabled_ == enable) {
EXEC_CB_AND_RET(cb, true); EXEC_CB_AND_RET(cb, true);
...@@ -164,28 +235,14 @@ void RemoteCharacteristicImpl::SetRegisterNotification(bool enable, ...@@ -164,28 +235,14 @@ void RemoteCharacteristicImpl::SetRegisterNotification(bool enable,
} }
auto it = uuid_to_descriptor_.find(RemoteDescriptor::kCccdUuid); 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. // 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, it->second->WriteAuth(bluetooth_v2_shlib::Gatt::Client::AUTH_REQ_NONE,
GetDescriptorNotificationValue(enable), std::move(cb)); write_val, 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);
} }
void RemoteCharacteristicImpl::ReadAuth( void RemoteCharacteristicImpl::ReadAuth(
......
...@@ -30,6 +30,8 @@ class RemoteCharacteristicImpl : public RemoteCharacteristic { ...@@ -30,6 +30,8 @@ class RemoteCharacteristicImpl : public RemoteCharacteristic {
const bluetooth_v2_shlib::Uuid& uuid) override; const bluetooth_v2_shlib::Uuid& uuid) override;
void SetRegisterNotification(bool enable, StatusCallback cb) override; void SetRegisterNotification(bool enable, StatusCallback cb) override;
void SetNotification(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, void ReadAuth(bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
ReadCallback callback) override; ReadCallback callback) override;
void Read(ReadCallback callback) override; void Read(ReadCallback callback) override;
...@@ -65,6 +67,12 @@ class RemoteCharacteristicImpl : public RemoteCharacteristic { ...@@ -65,6 +67,12 @@ class RemoteCharacteristicImpl : public RemoteCharacteristic {
std::map<bluetooth_v2_shlib::Uuid, scoped_refptr<RemoteDescriptor>> std::map<bluetooth_v2_shlib::Uuid, scoped_refptr<RemoteDescriptor>>
CreateDescriptorMap(); 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. // Weak reference to avoid refcount loop.
RemoteDeviceImpl* const device_; RemoteDeviceImpl* const device_;
base::WeakPtr<GattClientManagerImpl> gatt_client_manager_; base::WeakPtr<GattClientManagerImpl> gatt_client_manager_;
......
...@@ -10,6 +10,8 @@ namespace bluetooth { ...@@ -10,6 +10,8 @@ namespace bluetooth {
// static // static
constexpr uint8_t RemoteDescriptor::kEnableNotificationValue[]; constexpr uint8_t RemoteDescriptor::kEnableNotificationValue[];
// static // static
constexpr uint8_t RemoteDescriptor::kEnableIndicationValue[];
// static
constexpr uint8_t RemoteDescriptor::kDisableNotificationValue[]; constexpr uint8_t RemoteDescriptor::kDisableNotificationValue[];
// static // static
const bluetooth_v2_shlib::Uuid RemoteDescriptor::kCccdUuid = { const bluetooth_v2_shlib::Uuid RemoteDescriptor::kCccdUuid = {
......
...@@ -25,6 +25,7 @@ class RemoteDescriptor; ...@@ -25,6 +25,7 @@ class RemoteDescriptor;
class RemoteDescriptor : public base::RefCountedThreadSafe<RemoteDescriptor> { class RemoteDescriptor : public base::RefCountedThreadSafe<RemoteDescriptor> {
public: public:
static constexpr uint8_t kEnableNotificationValue[] = {0x01, 0x00}; static constexpr uint8_t kEnableNotificationValue[] = {0x01, 0x00};
static constexpr uint8_t kEnableIndicationValue[] = {0x02, 0x00};
static constexpr uint8_t kDisableNotificationValue[] = {0x00, 0x00}; static constexpr uint8_t kDisableNotificationValue[] = {0x00, 0x00};
static const bluetooth_v2_shlib::Uuid kCccdUuid; 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