• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //  Copyright 2015 Google, Inc.
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 "service/low_energy_client.h"
18 
19 #include <base/logging.h>
20 
21 #include "service/adapter.h"
22 #include "service/logging_helpers.h"
23 #include "stack/include/bt_types.h"
24 #include "stack/include/hcidefs.h"
25 #include "types/bt_transport.h"
26 
27 using std::lock_guard;
28 using std::mutex;
29 
30 constexpr int kPhyLe1MbMask = 1;
31 
32 namespace bluetooth {
33 
34 // LowEnergyClient implementation
35 // ========================================================
36 
LowEnergyClient(Adapter & adapter,const Uuid & uuid,int client_id)37 LowEnergyClient::LowEnergyClient(Adapter& adapter, const Uuid& uuid,
38                                  int client_id)
39     : adapter_(adapter),
40       app_identifier_(uuid),
41       client_id_(client_id),
42       delegate_(nullptr) {}
43 
~LowEnergyClient()44 LowEnergyClient::~LowEnergyClient() {
45   // Automatically unregister the client.
46   VLOG(1) << "LowEnergyClient unregistering client: " << client_id_;
47 
48   // Unregister as observer so we no longer receive any callbacks.
49   hal::BluetoothGattInterface::Get()->RemoveClientObserver(this);
50 
51   hal::BluetoothGattInterface::Get()
52       ->GetClientHALInterface()
53       ->unregister_client(client_id_);
54 }
55 
Connect(const std::string & address,bool is_direct)56 bool LowEnergyClient::Connect(const std::string& address, bool is_direct) {
57   VLOG(2) << __func__ << "Address: " << address << " is_direct: " << is_direct;
58 
59   RawAddress bda;
60   RawAddress::FromString(address, bda);
61 
62   bt_status_t status =
63       hal::BluetoothGattInterface::Get()->GetClientHALInterface()->connect(
64           client_id_, bda, is_direct, BT_TRANSPORT_LE, false, kPhyLe1MbMask);
65   if (status != BT_STATUS_SUCCESS) {
66     LOG(ERROR) << "HAL call to connect failed";
67     return false;
68   }
69 
70   return true;
71 }
72 
Disconnect(const std::string & address)73 bool LowEnergyClient::Disconnect(const std::string& address) {
74   VLOG(2) << __func__ << "Address: " << address;
75 
76   RawAddress bda;
77   RawAddress::FromString(address, bda);
78 
79   std::map<const RawAddress, int>::iterator conn_id;
80   {
81     lock_guard<mutex> lock(connection_fields_lock_);
82     conn_id = connection_ids_.find(bda);
83     if (conn_id == connection_ids_.end()) {
84       LOG(WARNING) << "Can't disconnect, no existing connection to " << address;
85       return false;
86     }
87   }
88 
89   bt_status_t status =
90       hal::BluetoothGattInterface::Get()->GetClientHALInterface()->disconnect(
91           client_id_, bda, conn_id->second);
92   if (status != BT_STATUS_SUCCESS) {
93     LOG(ERROR) << "HAL call to disconnect failed";
94     return false;
95   }
96 
97   return true;
98 }
99 
SetMtu(const std::string & address,int mtu)100 bool LowEnergyClient::SetMtu(const std::string& address, int mtu) {
101   VLOG(2) << __func__ << "Address: " << address << " MTU: " << mtu;
102 
103   RawAddress bda;
104   RawAddress::FromString(address, bda);
105 
106   std::map<const RawAddress, int>::iterator conn_id;
107   {
108     lock_guard<mutex> lock(connection_fields_lock_);
109     conn_id = connection_ids_.find(bda);
110     if (conn_id == connection_ids_.end()) {
111       LOG(WARNING) << "Can't set MTU, no existing connection to " << address;
112       return false;
113     }
114   }
115 
116   bt_status_t status = hal::BluetoothGattInterface::Get()
117                            ->GetClientHALInterface()
118                            ->configure_mtu(conn_id->second, mtu);
119   if (status != BT_STATUS_SUCCESS) {
120     LOG(ERROR) << "HAL call to set MTU failed";
121     return false;
122   }
123 
124   return true;
125 }
126 
SetDelegate(Delegate * delegate)127 void LowEnergyClient::SetDelegate(Delegate* delegate) {
128   lock_guard<mutex> lock(delegate_mutex_);
129   delegate_ = delegate;
130 }
131 
GetAppIdentifier() const132 const Uuid& LowEnergyClient::GetAppIdentifier() const {
133   return app_identifier_;
134 }
135 
GetInstanceId() const136 int LowEnergyClient::GetInstanceId() const { return client_id_; }
137 
ConnectCallback(hal::BluetoothGattInterface * gatt_iface,int conn_id,int status,int client_id,const RawAddress & bda)138 void LowEnergyClient::ConnectCallback(hal::BluetoothGattInterface* gatt_iface,
139                                       int conn_id, int status, int client_id,
140                                       const RawAddress& bda) {
141   if (client_id != client_id_) return;
142 
143   VLOG(1) << __func__ << "client_id: " << client_id << " status: " << status;
144 
145   {
146     lock_guard<mutex> lock(connection_fields_lock_);
147     auto success = connection_ids_.emplace(bda, conn_id);
148     if (!success.second) {
149       LOG(ERROR) << __func__ << " Insertion into connection_ids_ failed!";
150     }
151   }
152 
153   if (delegate_)
154     delegate_->OnConnectionState(this, status, BtAddrString(&bda).c_str(),
155                                  true);
156 }
157 
DisconnectCallback(hal::BluetoothGattInterface * gatt_iface,int conn_id,int status,int client_id,const RawAddress & bda)158 void LowEnergyClient::DisconnectCallback(
159     hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
160     int client_id, const RawAddress& bda) {
161   if (client_id != client_id_) return;
162 
163   VLOG(1) << __func__ << " client_id: " << client_id << " status: " << status;
164   {
165     lock_guard<mutex> lock(connection_fields_lock_);
166     if (!connection_ids_.erase(bda)) {
167       LOG(ERROR) << __func__ << " Erasing from connection_ids_ failed!";
168     }
169   }
170 
171   if (delegate_)
172     delegate_->OnConnectionState(this, status, BtAddrString(&bda).c_str(),
173                                  false);
174 }
175 
MtuChangedCallback(hal::BluetoothGattInterface * gatt_iface,int conn_id,int status,int mtu)176 void LowEnergyClient::MtuChangedCallback(
177     hal::BluetoothGattInterface* gatt_iface, int conn_id, int status, int mtu) {
178   VLOG(1) << __func__ << " conn_id: " << conn_id << " status: " << status
179           << " mtu: " << mtu;
180 
181   const RawAddress* bda = nullptr;
182   {
183     lock_guard<mutex> lock(connection_fields_lock_);
184     for (auto& connection : connection_ids_) {
185       if (connection.second == conn_id) {
186         bda = &connection.first;
187         break;
188       }
189     }
190   }
191 
192   if (!bda) return;
193 
194   std::string addr = BtAddrString(bda);
195   if (delegate_) delegate_->OnMtuChanged(this, status, addr.c_str(), mtu);
196 }
197 
198 // LowEnergyClientFactory implementation
199 // ========================================================
200 
LowEnergyClientFactory(Adapter & adapter)201 LowEnergyClientFactory::LowEnergyClientFactory(Adapter& adapter)
202     : adapter_(adapter) {
203   hal::BluetoothGattInterface::Get()->AddClientObserver(this);
204 }
205 
~LowEnergyClientFactory()206 LowEnergyClientFactory::~LowEnergyClientFactory() {
207   hal::BluetoothGattInterface::Get()->RemoveClientObserver(this);
208 }
209 
RegisterInstance(const Uuid & uuid,const RegisterCallback & callback)210 bool LowEnergyClientFactory::RegisterInstance(
211     const Uuid& uuid, const RegisterCallback& callback) {
212   VLOG(1) << __func__ << " - Uuid: " << uuid.ToString();
213   lock_guard<mutex> lock(pending_calls_lock_);
214 
215   if (pending_calls_.find(uuid) != pending_calls_.end()) {
216     LOG(ERROR) << "Low-Energy client with given Uuid already registered - "
217                << "Uuid: " << uuid.ToString();
218     return false;
219   }
220 
221   const btgatt_client_interface_t* hal_iface =
222       hal::BluetoothGattInterface::Get()->GetClientHALInterface();
223 
224   if (hal_iface->register_client(uuid, false) != BT_STATUS_SUCCESS)
225     return false;
226 
227   pending_calls_[uuid] = callback;
228 
229   return true;
230 }
231 
RegisterClientCallback(hal::BluetoothGattInterface * gatt_iface,int status,int client_id,const bluetooth::Uuid & app_uuid)232 void LowEnergyClientFactory::RegisterClientCallback(
233     hal::BluetoothGattInterface* gatt_iface, int status, int client_id,
234     const bluetooth::Uuid& app_uuid) {
235   Uuid uuid(app_uuid);
236 
237   VLOG(1) << __func__ << " - Uuid: " << uuid.ToString();
238   lock_guard<mutex> lock(pending_calls_lock_);
239 
240   auto iter = pending_calls_.find(uuid);
241   if (iter == pending_calls_.end()) {
242     VLOG(1) << "Ignoring callback for unknown app_id: " << uuid.ToString();
243     return;
244   }
245 
246   // No need to construct a client if the call wasn't successful.
247   std::unique_ptr<LowEnergyClient> client;
248   BLEStatus result = BLE_STATUS_FAILURE;
249   if (status == BT_STATUS_SUCCESS) {
250     client.reset(new LowEnergyClient(adapter_, uuid, client_id));
251 
252     gatt_iface->AddClientObserver(client.get());
253 
254     result = BLE_STATUS_SUCCESS;
255   }
256 
257   // Notify the result via the result callback.
258   iter->second(result, uuid, std::move(client));
259 
260   pending_calls_.erase(iter);
261 }
262 
263 }  // namespace bluetooth
264