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 "os/log.h"
25 #include "src/profiles/csis.rs.h"
26 #include "types/bluetooth/uuid.h"
27 #include "types/raw_address.h"
28 
29 namespace rusty = ::bluetooth::topshim::rust;
30 
31 namespace bluetooth {
32 namespace topshim {
33 namespace rust {
34 namespace internal {
35 
36 static CsisClientIntf* g_csis_if;
37 
to_rust_btcsis_connection_state(csis::ConnectionState state)38 static BtCsisConnectionState to_rust_btcsis_connection_state(csis::ConnectionState state) {
39   switch (state) {
40     case csis::ConnectionState::DISCONNECTED:
41       return BtCsisConnectionState::Disconnected;
42     case csis::ConnectionState::CONNECTING:
43       return BtCsisConnectionState::Connecting;
44     case csis::ConnectionState::CONNECTED:
45       return BtCsisConnectionState::Connected;
46     case csis::ConnectionState::DISCONNECTING:
47       return BtCsisConnectionState::Disconnecting;
48     default:
49       log::assert_that(false, "Unhandled enum value from C++");
50   }
51   return BtCsisConnectionState{};
52 }
53 
to_rust_btcsis_group_lock_status(csis::CsisGroupLockStatus status)54 static BtCsisGroupLockStatus to_rust_btcsis_group_lock_status(csis::CsisGroupLockStatus status) {
55   switch (status) {
56     case csis::CsisGroupLockStatus::SUCCESS:
57       return BtCsisGroupLockStatus::Success;
58     case csis::CsisGroupLockStatus::FAILED_INVALID_GROUP:
59       return BtCsisGroupLockStatus::FailedInvalidGroup;
60     case csis::CsisGroupLockStatus::FAILED_GROUP_EMPTY:
61       return BtCsisGroupLockStatus::FailedGroupEmpty;
62     case csis::CsisGroupLockStatus::FAILED_GROUP_NOT_CONNECTED:
63       return BtCsisGroupLockStatus::FailedGroupNotConnected;
64     case csis::CsisGroupLockStatus::FAILED_LOCKED_BY_OTHER:
65       return BtCsisGroupLockStatus::FailedLockedByOther;
66     case csis::CsisGroupLockStatus::FAILED_OTHER_REASON:
67       return BtCsisGroupLockStatus::FailedOtherReason;
68     case csis::CsisGroupLockStatus::LOCKED_GROUP_MEMBER_LOST:
69       return BtCsisGroupLockStatus::LockedGroupMemberLost;
70     default:
71       log::assert_that(false, "Unhandled enum value from C++");
72   }
73   return BtCsisGroupLockStatus{};
74 }
75 
connection_state_cb(const RawAddress & addr,csis::ConnectionState state)76 static void connection_state_cb(const RawAddress& addr, csis::ConnectionState state) {
77   csis_connection_state_callback(addr, to_rust_btcsis_connection_state(state));
78 }
79 
device_available_cb(const RawAddress & addr,int group_id,int group_size,int rank,const bluetooth::Uuid & uuid)80 static void device_available_cb(
81     const RawAddress& addr, int group_id, int group_size, int rank, const bluetooth::Uuid& uuid) {
82   csis_device_available_callback(addr, group_id, group_size, rank, uuid);
83 }
84 
set_member_available_cb(const RawAddress & addr,int group_id)85 static void set_member_available_cb(const RawAddress& addr, int group_id) {
86   csis_set_member_available_callback(addr, group_id);
87 }
88 
group_lock_changed_cb(int group_id,bool locked,csis::CsisGroupLockStatus status)89 static void group_lock_changed_cb(int group_id, bool locked, csis::CsisGroupLockStatus status) {
90   csis_group_lock_changed_callback(group_id, locked, to_rust_btcsis_group_lock_status(status));
91 }
92 }  // namespace internal
93 
94 class DBusCsisClientCallbacks : public csis::CsisClientCallbacks {
95  public:
GetInstance()96   static csis::CsisClientCallbacks* GetInstance() {
97     static auto instance = new DBusCsisClientCallbacks();
98     return instance;
99   }
100 
DBusCsisClientCallbacks()101   DBusCsisClientCallbacks(){};
102 
OnConnectionState(const RawAddress & addr,csis::ConnectionState state)103   void OnConnectionState(const RawAddress& addr, csis::ConnectionState state) override {
104     log::info("addr={}, state={}", ADDRESS_TO_LOGGABLE_CSTR(addr), static_cast<uint8_t>(state));
105     topshim::rust::internal::connection_state_cb(addr, state);
106   }
107 
OnDeviceAvailable(const RawAddress & addr,int group_id,int group_size,int rank,const bluetooth::Uuid & uuid)108   void OnDeviceAvailable(
109       const RawAddress& addr,
110       int group_id,
111       int group_size,
112       int rank,
113       const bluetooth::Uuid& uuid) override {
114     log::info(
115         "addr={}, group_id={}, group_size={}, rank={}",
116         ADDRESS_TO_LOGGABLE_CSTR(addr),
117         group_id,
118         group_size,
119         rank);
120     topshim::rust::internal::device_available_cb(addr, group_id, group_size, rank, uuid);
121   }
122 
OnSetMemberAvailable(const RawAddress & addr,int group_id)123   void OnSetMemberAvailable(const RawAddress& addr, int group_id) {
124     log::info("addr={}, group_id={}", ADDRESS_TO_LOGGABLE_CSTR(addr), group_id);
125     topshim::rust::internal::set_member_available_cb(addr, group_id);
126   }
127 
OnGroupLockChanged(int group_id,bool locked,csis::CsisGroupLockStatus status)128   void OnGroupLockChanged(int group_id, bool locked, csis::CsisGroupLockStatus status) {
129     topshim::rust::internal::group_lock_changed_cb(group_id, locked, status);
130   }
131 };
132 
GetCsisClientProfile(const unsigned char * btif)133 std::unique_ptr<CsisClientIntf> GetCsisClientProfile(const unsigned char* btif) {
134   if (internal::g_csis_if) std::abort();
135 
136   const bt_interface_t* btif_ = reinterpret_cast<const bt_interface_t*>(btif);
137 
138   auto csis_if = std::make_unique<CsisClientIntf>(
139       const_cast<csis::CsisClientInterface*>(reinterpret_cast<const csis::CsisClientInterface*>(
140           btif_->get_profile_interface("csis_client"))));
141 
142   internal::g_csis_if = csis_if.get();
143 
144   return csis_if;
145 }
146 
init()147 void CsisClientIntf::init(/*CsisClientCallbacks* callbacks*/) {
148   return intf_->Init(DBusCsisClientCallbacks::GetInstance());
149 }
150 
connect(RawAddress addr)151 void CsisClientIntf::connect(RawAddress addr) {
152   return intf_->Connect(addr);
153 }
154 
disconnect(RawAddress addr)155 void CsisClientIntf::disconnect(RawAddress addr) {
156   return intf_->Disconnect(addr);
157 }
158 
lock_group(int group_id,bool lock)159 void CsisClientIntf::lock_group(int group_id, bool lock) {
160   return intf_->LockGroup(group_id, lock);
161 }
162 
remove_device(RawAddress addr)163 void CsisClientIntf::remove_device(RawAddress addr) {
164   return intf_->RemoveDevice(addr);
165 }
166 
cleanup()167 void CsisClientIntf::cleanup() {
168   return intf_->Cleanup();
169 }
170 }  // namespace rust
171 }  // namespace topshim
172 }  // namespace bluetooth
173