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