1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "gd/rust/topshim/csis/csis_shim.h"
18 
19 #include <bluetooth/log.h>
20 #include <hardware/bluetooth.h>
21 
22 #include <string>
23 
24 #include "src/profiles/csis.rs.h"
25 #include "types/bluetooth/uuid.h"
26 #include "types/raw_address.h"
27 
28 namespace rusty = ::bluetooth::topshim::rust;
29 
30 namespace bluetooth {
31 namespace topshim {
32 namespace rust {
33 namespace internal {
34 
35 static CsisClientIntf* g_csis_if;
36 
to_rust_btcsis_connection_state(csis::ConnectionState state)37 static BtCsisConnectionState to_rust_btcsis_connection_state(csis::ConnectionState state) {
38   switch (state) {
39     case csis::ConnectionState::DISCONNECTED:
40       return BtCsisConnectionState::Disconnected;
41     case csis::ConnectionState::CONNECTING:
42       return BtCsisConnectionState::Connecting;
43     case csis::ConnectionState::CONNECTED:
44       return BtCsisConnectionState::Connected;
45     case csis::ConnectionState::DISCONNECTING:
46       return BtCsisConnectionState::Disconnecting;
47     default:
48       log::assert_that(false, "Unhandled enum value from C++");
49   }
50   return BtCsisConnectionState{};
51 }
52 
to_rust_btcsis_group_lock_status(csis::CsisGroupLockStatus status)53 static BtCsisGroupLockStatus to_rust_btcsis_group_lock_status(csis::CsisGroupLockStatus status) {
54   switch (status) {
55     case csis::CsisGroupLockStatus::SUCCESS:
56       return BtCsisGroupLockStatus::Success;
57     case csis::CsisGroupLockStatus::FAILED_INVALID_GROUP:
58       return BtCsisGroupLockStatus::FailedInvalidGroup;
59     case csis::CsisGroupLockStatus::FAILED_GROUP_EMPTY:
60       return BtCsisGroupLockStatus::FailedGroupEmpty;
61     case csis::CsisGroupLockStatus::FAILED_GROUP_NOT_CONNECTED:
62       return BtCsisGroupLockStatus::FailedGroupNotConnected;
63     case csis::CsisGroupLockStatus::FAILED_LOCKED_BY_OTHER:
64       return BtCsisGroupLockStatus::FailedLockedByOther;
65     case csis::CsisGroupLockStatus::FAILED_OTHER_REASON:
66       return BtCsisGroupLockStatus::FailedOtherReason;
67     case csis::CsisGroupLockStatus::LOCKED_GROUP_MEMBER_LOST:
68       return BtCsisGroupLockStatus::LockedGroupMemberLost;
69     default:
70       log::assert_that(false, "Unhandled enum value from C++");
71   }
72   return BtCsisGroupLockStatus{};
73 }
74 
connection_state_cb(const RawAddress & addr,csis::ConnectionState state)75 static void connection_state_cb(const RawAddress& addr, csis::ConnectionState state) {
76   csis_connection_state_callback(addr, to_rust_btcsis_connection_state(state));
77 }
78 
device_available_cb(const RawAddress & addr,int group_id,int group_size,int rank,const bluetooth::Uuid & uuid)79 static void device_available_cb(const RawAddress& addr, int group_id, int group_size, int rank,
80                                 const bluetooth::Uuid& uuid) {
81   csis_device_available_callback(addr, group_id, group_size, rank, uuid);
82 }
83 
set_member_available_cb(const RawAddress & addr,int group_id)84 static void set_member_available_cb(const RawAddress& addr, int group_id) {
85   csis_set_member_available_callback(addr, group_id);
86 }
87 
group_lock_changed_cb(int group_id,bool locked,csis::CsisGroupLockStatus status)88 static void group_lock_changed_cb(int group_id, bool locked, csis::CsisGroupLockStatus status) {
89   csis_group_lock_changed_callback(group_id, locked, to_rust_btcsis_group_lock_status(status));
90 }
91 }  // namespace internal
92 
93 class DBusCsisClientCallbacks : public csis::CsisClientCallbacks {
94 public:
GetInstance()95   static csis::CsisClientCallbacks* GetInstance() {
96     static auto instance = new DBusCsisClientCallbacks();
97     return instance;
98   }
99 
DBusCsisClientCallbacks()100   DBusCsisClientCallbacks() {}
101 
OnConnectionState(const RawAddress & addr,csis::ConnectionState state)102   void OnConnectionState(const RawAddress& addr, csis::ConnectionState state) override {
103     log::info("addr={}, state={}", addr, static_cast<uint8_t>(state));
104     topshim::rust::internal::connection_state_cb(addr, state);
105   }
106 
OnDeviceAvailable(const RawAddress & addr,int group_id,int group_size,int rank,const bluetooth::Uuid & uuid)107   void OnDeviceAvailable(const RawAddress& addr, int group_id, int group_size, int rank,
108                          const bluetooth::Uuid& uuid) override {
109     log::info("addr={}, group_id={}, group_size={}, rank={}", addr, group_id, group_size, rank);
110     topshim::rust::internal::device_available_cb(addr, group_id, group_size, rank, uuid);
111   }
112 
OnSetMemberAvailable(const RawAddress & addr,int group_id)113   void OnSetMemberAvailable(const RawAddress& addr, int group_id) {
114     log::info("addr={}, group_id={}", addr, group_id);
115     topshim::rust::internal::set_member_available_cb(addr, group_id);
116   }
117 
OnGroupLockChanged(int group_id,bool locked,csis::CsisGroupLockStatus status)118   void OnGroupLockChanged(int group_id, bool locked, csis::CsisGroupLockStatus status) {
119     topshim::rust::internal::group_lock_changed_cb(group_id, locked, status);
120   }
121 };
122 
GetCsisClientProfile(const unsigned char * btif)123 std::unique_ptr<CsisClientIntf> GetCsisClientProfile(const unsigned char* btif) {
124   if (internal::g_csis_if) {
125     std::abort();
126   }
127 
128   const bt_interface_t* btif_ = reinterpret_cast<const bt_interface_t*>(btif);
129 
130   auto csis_if = std::make_unique<CsisClientIntf>(
131           const_cast<csis::CsisClientInterface*>(reinterpret_cast<const csis::CsisClientInterface*>(
132                   btif_->get_profile_interface("csis_client"))));
133 
134   internal::g_csis_if = csis_if.get();
135 
136   return csis_if;
137 }
138 
init()139 void CsisClientIntf::init(/*CsisClientCallbacks* callbacks*/) {
140   return intf_->Init(DBusCsisClientCallbacks::GetInstance());
141 }
142 
connect(RawAddress addr)143 void CsisClientIntf::connect(RawAddress addr) { return intf_->Connect(addr); }
144 
disconnect(RawAddress addr)145 void CsisClientIntf::disconnect(RawAddress addr) { return intf_->Disconnect(addr); }
146 
lock_group(int group_id,bool lock)147 void CsisClientIntf::lock_group(int group_id, bool lock) {
148   return intf_->LockGroup(group_id, lock);
149 }
150 
remove_device(RawAddress addr)151 void CsisClientIntf::remove_device(RawAddress addr) { return intf_->RemoveDevice(addr); }
152 
cleanup()153 void CsisClientIntf::cleanup() { return intf_->Cleanup(); }
154 }  // namespace rust
155 }  // namespace topshim
156 }  // namespace bluetooth
157