1 /*
2  * Copyright 2020 HIMSA II K/S - www.himsa.com. Represented by EHIMA -
3  * 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 <algorithm>
21 #include <deque>
22 
23 #include "os/logging/log_adapter.h"
24 #include "stack/gatt/gatt_int.h"
25 #include "types/raw_address.h"
26 
27 #define EATT_MIN_MTU_MPS (64)
28 #define EATT_DEFAULT_MTU (256)
29 #define EATT_MAX_TX_MTU  (1024)
30 #define EATT_ALL_CIDS (0xFFFF)
31 
32 namespace bluetooth {
33 namespace eatt {
34 
35 /* Enums */
36 enum class EattChannelState : uint8_t {
37   EATT_CHANNEL_PENDING = 0x00,
38   EATT_CHANNEL_OPENED,
39   EATT_CHANNEL_RECONFIGURING,
40 };
41 
42 class EattChannel {
43  public:
44   /* Pointer to EattDevice */
45   RawAddress bda_;
46   uint16_t cid_;
47   uint16_t tx_mtu_;
48   uint16_t rx_mtu_;
49   EattChannelState state_;
50 
51   /* Used to keep server commands */
52   tGATT_SR_CMD server_outstanding_cmd_;
53   /* Used to veryfy indication confirmation*/
54   uint16_t indicate_handle_;
55   /* local app confirm to indication timer */
56   alarm_t* ind_ack_timer_;
57   /* indication confirmation timer */
58   alarm_t* ind_confirmation_timer_;
59   /* GATT client command queue */
60   std::deque<tGATT_CMD_Q> cl_cmd_q_;
61 
EattChannel(RawAddress & bda,uint16_t cid,uint16_t tx_mtu,uint16_t rx_mtu)62   EattChannel(RawAddress& bda, uint16_t cid, uint16_t tx_mtu, uint16_t rx_mtu)
63       : bda_(bda),
64         cid_(cid),
65         rx_mtu_(rx_mtu),
66         state_(EattChannelState::EATT_CHANNEL_PENDING),
67         indicate_handle_(0),
68         ind_ack_timer_(NULL),
69         ind_confirmation_timer_(NULL) {
70     cl_cmd_q_ = std::deque<tGATT_CMD_Q>();
71     EattChannelSetTxMTU(tx_mtu);
72   }
73 
~EattChannel()74   ~EattChannel() {
75     if (ind_ack_timer_ != NULL) {
76       alarm_free(ind_ack_timer_);
77     }
78 
79     if (ind_confirmation_timer_ != NULL) {
80       alarm_free(ind_confirmation_timer_);
81     }
82   }
83 
EattChannelSetState(EattChannelState state)84   void EattChannelSetState(EattChannelState state) {
85     if (state_ == EattChannelState::EATT_CHANNEL_PENDING) {
86       if (state == EattChannelState::EATT_CHANNEL_OPENED) {
87         memset(&server_outstanding_cmd_, 0, sizeof(tGATT_SR_CMD));
88         char name[64];
89         sprintf(name, "eatt_ind_ack_timer_%s_cid_0x%04x",
90                 ADDRESS_TO_LOGGABLE_CSTR(bda_), cid_);
91         ind_ack_timer_ = alarm_new(name);
92 
93         sprintf(name, "eatt_ind_conf_timer_%s_cid_0x%04x",
94                 ADDRESS_TO_LOGGABLE_CSTR(bda_), cid_);
95         ind_confirmation_timer_ = alarm_new(name);
96       }
97     }
98     state_ = state;
99   }
100 
EattChannelSetTxMTU(uint16_t tx_mtu)101   void EattChannelSetTxMTU(uint16_t tx_mtu) {
102     this->tx_mtu_ = std::min<uint16_t>(tx_mtu, EATT_MAX_TX_MTU);
103   }
104 };
105 
106 /* Interface class */
107 class EattExtension {
108  public:
109   EattExtension();
110   EattExtension(const EattExtension&) = delete;
111   EattExtension& operator=(const EattExtension&) = delete;
112 
113   virtual ~EattExtension();
114 
GetInstance()115   static EattExtension* GetInstance() {
116     static EattExtension* instance = new EattExtension();
117     return instance;
118   }
119 
120   static void AddFromStorage(const RawAddress& bd_addr);
121 
122   /**
123    * Checks if EATT is supported on peer device.
124    *
125    * @param bd_addr peer device address
126    */
127   virtual bool IsEattSupportedByPeer(const RawAddress& bd_addr);
128 
129   /**
130    * Connect at maximum 5 EATT channels to peer device.
131    *
132    * @param bd_addr peer device address
133    */
134   virtual void Connect(const RawAddress& bd_addr);
135 
136   /**
137    * Disconnect all EATT channels to peer device.
138    *
139    * @param bd_addr peer device address
140    * @param cid remote channel id (EATT_ALL_CIDS for all)
141    */
142   virtual void Disconnect(const RawAddress& bd_addr,
143                           uint16_t cid = EATT_ALL_CIDS);
144 
145   /**
146    * Reconfigure EATT channel for give CID
147    *
148    * @param bd_addr peer device address
149    * @param cid channel id
150    * @param mtu new maximum transmit unit available of local device
151    */
152   virtual void Reconfigure(const RawAddress& bd_addr, uint16_t cid,
153                            uint16_t mtu);
154 
155   /**
156    * Reconfigure all EATT channels to peer device.
157    *
158    * @param bd_addr peer device address
159    * @param mtu new maximum transmit unit available of local device
160    */
161   virtual void ReconfigureAll(const RawAddress& bd_addr, uint16_t mtu);
162 
163   /* Below methods required by GATT implementation */
164 
165   /**
166    * Find EATT channel by cid.
167    *
168    * @param bd_addr peer device address
169    * @param cid channel id
170    *
171    * @return Eatt Channel instance.
172    */
173   virtual EattChannel* FindEattChannelByCid(const RawAddress& bd_addr,
174                                             uint16_t cid);
175 
176   /**
177    * Find EATT channel by transaction id.
178    *
179    * @param bd_addr peer device address
180    * @param trans_id transaction id
181    *
182    * @return pointer to EATT channel.
183    */
184   virtual EattChannel* FindEattChannelByTransId(const RawAddress& bd_addr,
185                                                 uint32_t trans_id);
186 
187   /**
188    * Check if EATT channel on given handle is waiting for a indication
189    * confirmation
190    *
191    * @param bd_addr peer device address
192    * @param indication_handle handle of the pending indication
193    *
194    * @return true if confirmation is pending false otherwise
195    */
196   virtual bool IsIndicationPending(const RawAddress& bd_addr,
197                                    uint16_t indication_handle);
198 
199   /**
200    * Get EATT channel available for indication.
201    *
202    * @param bd_addr peer device address
203    *
204    * @return pointer to EATT channel.
205    */
206   virtual EattChannel* GetChannelAvailableForIndication(
207       const RawAddress& bd_addr);
208 
209   /**
210    * Free Resources.
211    *
212    * (Maybe not needed)
213    * @param bd_addr peer device address
214    *
215    */
216   virtual void FreeGattResources(const RawAddress& bd_addr);
217 
218   /**
219    * Check if there is any EATT channels having some msg in its send queue
220    *
221    * @param bd_addr peer device address
222    *
223    * @return true when there is at least one EATT channel ready to send
224    */
225   virtual bool IsOutstandingMsgInSendQueue(const RawAddress& bd_addr);
226 
227   /**
228    * Get EATT channel ready to send.
229    *
230    * @param bd_addr peer device address
231    *
232    * @return pointer to EATT channel.
233    */
234   virtual EattChannel* GetChannelWithQueuedDataToSend(
235       const RawAddress& bd_addr);
236 
237   /**
238    * Get EATT channel available to send GATT request.
239    *
240    * @param bd_addr peer device address
241    *
242    * @return pointer to EATT channel.
243    */
244   virtual EattChannel* GetChannelAvailableForClientRequest(
245       const RawAddress& bd_addr);
246 
247   /**
248    * Start GATT indication timer per CID.
249    *
250    * @param bd_addr peer device address
251    * @param cid channel id
252    */
253   virtual void StartIndicationConfirmationTimer(const RawAddress& bd_addr,
254                                                 uint16_t cid);
255 
256   /**
257    * Stop GATT indication timer per CID.
258    *
259    * @param bd_addr peer device address
260    * @param cid channel id
261    */
262   virtual void StopIndicationConfirmationTimer(const RawAddress& bd_addr,
263                                                uint16_t cid);
264 
265   /**
266    *  Start application time for incoming indication on given CID
267    *
268    * @param bd_addr peer device address
269    * @param cid channel id
270    */
271   virtual void StartAppIndicationTimer(const RawAddress& bd_addr, uint16_t cid);
272 
273   /**
274    *  Stop application time for incoming indication on given CID
275    *
276    * @param bd_addr peer device address
277    * @param cid channel id
278    */
279   virtual void StopAppIndicationTimer(const RawAddress& bd_addr, uint16_t cid);
280 
281   /**
282    * Starts the EattExtension module
283    */
284   void Start();
285 
286   /**
287    * Stops the EattExtension module
288    */
289   void Stop();
290 
291  private:
292   struct impl;
293   std::unique_ptr<impl> pimpl_;
294 };
295 
296 }  // namespace eatt
297 }  // namespace bluetooth
298