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