| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #pragma once |
| |
| #include <zircon/types.h> |
| |
| #include <ddk/device.h> |
| #include <ddk/driver.h> |
| #include <ddk/protocol/bt-gatt-svc.h> |
| |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/async/cpp/task.h> |
| #include <lib/async/dispatcher.h> |
| |
| #include "garnet/drivers/bluetooth/lib/gatt/gatt.h" |
| |
| #include "lib/fxl/macros.h" |
| |
| namespace bthost { |
| |
| // This class is responsible for bridging remote GATT services to the DDK so |
| // GATT services can be implimented as drivers (eg HID over GATT as HIDBUS |
| // device) |
| class GattRemoteServiceDevice final { |
| public: |
| GattRemoteServiceDevice(zx_device_t* parent_device, |
| const std::string& peer_id, |
| fbl::RefPtr<btlib::gatt::RemoteService> service); |
| |
| ~GattRemoteServiceDevice(); |
| |
| zx_status_t Bind(); |
| |
| private: |
| static bt_gatt_svc_ops_t proto_ops_; |
| |
| // Protocol trampolines. |
| static void DdkUnbind(void* ctx) { |
| static_cast<GattRemoteServiceDevice*>(ctx)->Unbind(); |
| } |
| |
| static void DdkRelease(void* ctx) { |
| static_cast<GattRemoteServiceDevice*>(ctx)->Release(); |
| } |
| |
| static zx_status_t OpConnect(void* ctx, void* cookie, |
| bt_gatt_connect_cb connect_cb) { |
| return static_cast<GattRemoteServiceDevice*>(ctx)->Connect(cookie, |
| connect_cb); |
| } |
| |
| static void OpStop(void* ctx) { |
| static_cast<GattRemoteServiceDevice*>(ctx)->Stop(); |
| } |
| |
| static zx_status_t OpReadCharacteristic( |
| void* ctx, bt_gatt_id_t id, void* cookie, |
| bt_gatt_read_characteristic_cb read_cb) { |
| return static_cast<GattRemoteServiceDevice*>(ctx)->ReadCharacteristic( |
| id, cookie, read_cb); |
| } |
| |
| static zx_status_t OpReadLongCharacteristic( |
| void* ctx, bt_gatt_id_t id, void* cookie, uint16_t offset, |
| size_t max_bytes, bt_gatt_read_characteristic_cb read_cb) { |
| return static_cast<GattRemoteServiceDevice*>(ctx)->ReadLongCharacteristic( |
| id, cookie, offset, max_bytes, read_cb); |
| } |
| |
| static zx_status_t OpWriteCharacteristic(void* ctx, bt_gatt_id_t id, |
| void* cookie, const uint8_t* buf, |
| size_t len, |
| bt_gatt_status_cb status_cb) { |
| return static_cast<GattRemoteServiceDevice*>(ctx)->WriteCharacteristic( |
| id, cookie, buf, len, status_cb); |
| } |
| |
| static zx_status_t OpEnableNotifications( |
| void* ctx, bt_gatt_id_t id, void* cookie, bt_gatt_status_cb status_cb, |
| bt_gatt_notification_value_cb value_cb) { |
| return static_cast<GattRemoteServiceDevice*>(ctx)->EnableNotifications( |
| id, cookie, status_cb, value_cb); |
| } |
| |
| // DDK device ops. |
| void Unbind(); |
| void Release(); |
| |
| // bt-gatt-svc ops. |
| zx_status_t Connect(void* cookie, bt_gatt_connect_cb connect_cb); |
| void Stop(); |
| zx_status_t ReadCharacteristic(bt_gatt_id_t id, void* cookie, |
| bt_gatt_read_characteristic_cb read_cb); |
| |
| zx_status_t ReadLongCharacteristic(bt_gatt_id_t id, void* cookie, |
| uint16_t offset, size_t max_bytes, |
| bt_gatt_read_characteristic_cb read_cb); |
| zx_status_t WriteCharacteristic(bt_gatt_id_t id, void* cookie, |
| const uint8_t* buff, size_t len, |
| bt_gatt_status_cb write_cb); |
| zx_status_t EnableNotifications(bt_gatt_id_t id, void* cookie, |
| bt_gatt_status_cb status_cb, |
| bt_gatt_notification_value_cb value_cb); |
| |
| // All device protocol messages are dispatched on this loop to not block the |
| // gatt or host thread. |
| async::Loop loop_; |
| |
| zx_device_t* parent_device_; // The BT Host device |
| zx_device_t* dev_; // The child we are creating. |
| |
| const std::string& peer_id_; |
| fbl::RefPtr<btlib::gatt::RemoteService> service_; |
| |
| // The base DDK device ops. |
| zx_protocol_device_t dev_proto_ = {}; |
| |
| FXL_DISALLOW_COPY_AND_ASSIGN(GattRemoteServiceDevice); |
| }; |
| |
| } // namespace bthost |