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