• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 HIMSA II K/S - www.himsa.com.
3  * Represented by EHIMA - www.ehima.com
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #pragma once
19 
20 #include <cstdint>
21 #include <unordered_set>
22 #include <vector>
23 
24 #include "bta/include/bta_gatt_api.h"
25 #include "bta/vc/types.h"
26 #include "include/hardware/bt_vc.h"
27 #include "types/raw_address.h"
28 
29 namespace bluetooth {
30 namespace vc {
31 namespace internal {
32 
33 class VolumeControlDevice {
34  public:
35   RawAddress address;
36   /* This is true only during first connection to profile, until we store the
37    * device
38    */
39   bool first_connection;
40 
41   /* we are making active attempt to connect to this device, 'direct connect'.
42    * This is true only during initial phase of first connection. */
43   bool connecting_actively;
44 
45   bool service_changed_rcvd;
46 
47   uint8_t volume;
48   uint8_t change_counter;
49   bool mute;
50   uint8_t flags;
51 
52   uint16_t connection_id;
53 
54   /* Volume Control Service */
55   uint16_t volume_state_handle;
56   uint16_t volume_state_ccc_handle;
57   uint16_t volume_control_point_handle;
58   uint16_t volume_flags_handle;
59   uint16_t volume_flags_ccc_handle;
60 
61   bool device_ready; /* Set when device read server status and registgered for
62                         notifications */
63 
VolumeControlDevice(const RawAddress & address,bool first_connection)64   VolumeControlDevice(const RawAddress& address, bool first_connection)
65       : address(address),
66         first_connection(first_connection),
67         connecting_actively(first_connection),
68         service_changed_rcvd(false),
69         volume(0),
70         change_counter(0),
71         mute(false),
72         flags(0),
73         connection_id(GATT_INVALID_CONN_ID),
74         volume_state_handle(0),
75         volume_state_ccc_handle(0),
76         volume_control_point_handle(0),
77         volume_flags_handle(0),
78         volume_flags_ccc_handle(0),
79         device_ready(false) {}
80 
81   ~VolumeControlDevice() = default;
82 
ToString()83   inline std::string ToString() { return address.ToString(); }
84 
DebugDump(int fd)85   void DebugDump(int fd) { dprintf(fd, "%s\n", this->ToString().c_str()); }
86 
IsConnected()87   bool IsConnected() { return connection_id != GATT_INVALID_CONN_ID; }
88 
89   void Disconnect(tGATT_IF gatt_if);
90 
91   bool UpdateHandles(void);
92 
93   void ResetHandles(void);
94 
HasHandles(void)95   bool HasHandles(void) { return GATT_HANDLE_IS_VALID(volume_state_handle); }
96 
97   void ControlPointOperation(uint8_t opcode, const std::vector<uint8_t>* arg,
98                              GATT_WRITE_OP_CB cb, void* cb_data);
99   bool IsEncryptionEnabled();
100 
101   bool EnableEncryption(tBTM_SEC_CALLBACK* callback);
102 
103   bool EnqueueInitialRequests(tGATT_IF gatt_if, GATT_READ_OP_CB chrc_read_cb,
104                               GATT_WRITE_OP_CB cccd_write_cb);
105   void EnqueueRemainingRequests(tGATT_IF gatt_if, GATT_READ_OP_CB chrc_read_cb,
106                                 GATT_WRITE_OP_CB cccd_write_cb);
107   bool VerifyReady(uint16_t handle);
108 
109  private:
110   /*
111    * This is used to track the pending GATT operation handles. Once the list is
112    * empty the device is assumed ready and connected. We are doing it because we
113    * want to make sure all the required characteristics and descritors are
114    * available on server side.
115    */
116   std::unordered_set<uint16_t> handles_pending;
117 
118   uint16_t find_ccc_handle(uint16_t chrc_handle);
119   bool set_volume_control_service_handles(const gatt::Service& service);
120   bool subscribe_for_notifications(tGATT_IF gatt_if, uint16_t handle,
121                                    uint16_t ccc_handle, GATT_WRITE_OP_CB cb);
122 };
123 
124 class VolumeControlDevices {
125  public:
Add(const RawAddress & address,bool first_connection)126   void Add(const RawAddress& address, bool first_connection) {
127     if (FindByAddress(address) != nullptr) return;
128 
129     devices_.emplace_back(address, first_connection);
130   }
131 
Remove(const RawAddress & address)132   void Remove(const RawAddress& address) {
133     for (auto it = devices_.begin(); it != devices_.end(); it++) {
134       if (it->address == address) {
135         it = devices_.erase(it);
136         break;
137       }
138     }
139   }
140 
FindByAddress(const RawAddress & address)141   VolumeControlDevice* FindByAddress(const RawAddress& address) {
142     auto iter = std::find_if(devices_.begin(), devices_.end(),
143                              [&address](const VolumeControlDevice& device) {
144                                return device.address == address;
145                              });
146 
147     return (iter == devices_.end()) ? nullptr : &(*iter);
148   }
149 
FindByConnId(uint16_t connection_id)150   VolumeControlDevice* FindByConnId(uint16_t connection_id) {
151     auto iter =
152         std::find_if(devices_.begin(), devices_.end(),
153                      [&connection_id](const VolumeControlDevice& device) {
154                        return device.connection_id == connection_id;
155                      });
156 
157     return (iter == devices_.end()) ? nullptr : &(*iter);
158   }
159 
Size()160   size_t Size() { return (devices_.size()); }
161 
Clear()162   void Clear() { devices_.clear(); }
163 
DebugDump(int fd)164   void DebugDump(int fd) {
165     for (auto& device : devices_) {
166       device.DebugDump(fd);
167     }
168   }
169 
Disconnect(tGATT_IF gatt_if)170   void Disconnect(tGATT_IF gatt_if) {
171     for (auto& device : devices_) {
172       device.Disconnect(gatt_if);
173     }
174   }
175 
ControlPointOperation(std::vector<RawAddress> & devices,uint8_t opcode,const std::vector<uint8_t> * arg,GATT_WRITE_OP_CB cb,void * cb_data)176   void ControlPointOperation(std::vector<RawAddress>& devices, uint8_t opcode,
177                              const std::vector<uint8_t>* arg,
178                              GATT_WRITE_OP_CB cb, void* cb_data) {
179     for (auto& addr : devices) {
180       VolumeControlDevice* device = FindByAddress(addr);
181       if (device && device->IsConnected())
182         device->ControlPointOperation(opcode, arg, cb, cb_data);
183     }
184   }
185 
186  private:
187   std::vector<VolumeControlDevice> devices_;
188 };
189 
190 }  // namespace internal
191 }  // namespace vc
192 }  // namespace bluetooth
193