1 /****************************************************************************** 2 * 3 * Copyright (C) 1999-2013 Broadcom Corporation 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 19 #include "bt_target.h" 20 #include "bt_utils.h" 21 #include "gatt_api.h" 22 #include "gatt_int.h" 23 #include "srvc_eng_int.h" 24 #include "srvc_battery_int.h" 25 26 #if BLE_INCLUDED == TRUE 27 28 #define BA_MAX_CHAR_NUM 1 29 #define BA_MAX_ATTR_NUM (BA_MAX_CHAR_NUM * 5 + 1) /* max 3 descriptors, 1 desclration and 1 value */ 30 31 #ifndef BATTER_LEVEL_PROP 32 #define BATTER_LEVEL_PROP (GATT_CHAR_PROP_BIT_READ|GATT_CHAR_PROP_BIT_NOTIFY) 33 #endif 34 35 36 #ifndef BATTER_LEVEL_PERM 37 #define BATTER_LEVEL_PERM (GATT_PERM_READ) 38 #endif 39 40 tBATTERY_CB battery_cb; 41 42 43 /******************************************************************************* 44 ** battery_valid_handle_range 45 ** 46 ** validate a handle to be a DIS attribute handle or not. 47 *******************************************************************************/ 48 BOOLEAN battery_valid_handle_range(UINT16 handle) 49 { 50 UINT8 i = 0; 51 tBA_INST *p_inst = &battery_cb.battery_inst[0]; 52 53 for (;i < BA_MAX_INT_NUM; i ++, p_inst++) 54 { 55 if (handle == p_inst->ba_level_hdl || 56 handle == p_inst->clt_cfg_hdl || 57 handle == p_inst->rpt_ref_hdl || 58 handle == p_inst->pres_fmt_hdl ) 59 { 60 return TRUE; 61 } 62 } 63 return FALSE; 64 } 65 /******************************************************************************* 66 ** battery_s_write_attr_value 67 ** 68 ** Process write DIS attribute request. 69 *******************************************************************************/ 70 UINT8 battery_s_write_attr_value(UINT8 clcb_idx, tGATT_WRITE_REQ * p_value, 71 tGATT_STATUS *p_status) 72 { 73 UINT8 *p = p_value->value, i; 74 UINT16 handle = p_value->handle; 75 tBA_INST *p_inst = &battery_cb.battery_inst[0]; 76 tGATT_STATUS st = GATT_NOT_FOUND; 77 tBA_WRITE_DATA cfg; 78 UINT8 act = SRVC_ACT_RSP; 79 80 for (i = 0; i < BA_MAX_INT_NUM; i ++, p_inst ++) 81 { 82 /* read battery level */ 83 if (handle == p_inst->clt_cfg_hdl) 84 { 85 memcpy(cfg.remote_bda, srvc_eng_cb.clcb[clcb_idx].bda, BD_ADDR_LEN); 86 STREAM_TO_UINT16(cfg.clt_cfg, p); 87 88 if (p_inst->p_cback) 89 { 90 p_inst->pending_clcb_idx = clcb_idx; 91 p_inst->pending_evt = BA_WRITE_CLT_CFG_REQ; 92 p_inst->pending_handle = handle; 93 cfg.need_rsp = p_value->need_rsp; 94 act = SRVC_ACT_PENDING; 95 96 (* p_inst->p_cback)(p_inst->app_id, BA_WRITE_CLT_CFG_REQ, &cfg); 97 } 98 } 99 else /* all other handle is not writable */ 100 { 101 st = GATT_WRITE_NOT_PERMIT; 102 break; 103 } 104 } 105 *p_status = st; 106 107 return act; 108 } 109 /******************************************************************************* 110 ** BA Attributes Database Server Request callback 111 *******************************************************************************/ 112 UINT8 battery_s_read_attr_value (UINT8 clcb_idx, UINT16 handle, tGATT_VALUE *p_value, BOOLEAN is_long, tGATT_STATUS* p_status) 113 { 114 UINT8 i; 115 tBA_INST *p_inst = &battery_cb.battery_inst[0]; 116 tGATT_STATUS st = GATT_NOT_FOUND; 117 UINT8 act = SRVC_ACT_RSP; 118 UNUSED(p_value); 119 120 for (i = 0; i < BA_MAX_INT_NUM; i ++, p_inst ++) 121 { 122 /* read battery level */ 123 if (handle == p_inst->ba_level_hdl || 124 handle == p_inst->clt_cfg_hdl || 125 handle == p_inst->rpt_ref_hdl || 126 handle == p_inst->pres_fmt_hdl) 127 { 128 if (is_long) 129 st = GATT_NOT_LONG; 130 131 if (p_inst->p_cback) 132 { 133 if (handle == p_inst->ba_level_hdl) p_inst->pending_evt = BA_READ_LEVEL_REQ; 134 if (handle == p_inst->clt_cfg_hdl) p_inst->pending_evt = BA_READ_CLT_CFG_REQ; 135 if (handle == p_inst->pres_fmt_hdl) p_inst->pending_evt = BA_READ_PRE_FMT_REQ; 136 if (handle == p_inst->rpt_ref_hdl) p_inst->pending_evt = BA_READ_RPT_REF_REQ ; 137 138 p_inst->pending_clcb_idx = clcb_idx; 139 p_inst->pending_handle = handle; 140 act = SRVC_ACT_PENDING; 141 142 (* p_inst->p_cback)(p_inst->app_id, p_inst->pending_evt, NULL); 143 } 144 else /* application is not registered */ 145 st = GATT_ERR_UNLIKELY; 146 break; 147 } 148 /* else attribute not found */ 149 } 150 151 152 *p_status = st; 153 return act; 154 } 155 156 157 /******************************************************************************* 158 ** 159 ** Function battery_gatt_c_read_ba_req 160 ** 161 ** Description Read remote device BA level attribute request. 162 ** 163 ** Returns void 164 ** 165 *******************************************************************************/ 166 BOOLEAN battery_gatt_c_read_ba_req(UINT16 conn_id) 167 { 168 UNUSED(conn_id); 169 return TRUE; 170 } 171 172 /******************************************************************************* 173 ** 174 ** Function battery_c_cmpl_cback 175 ** 176 ** Description Client operation complete callback. 177 ** 178 ** Returns void 179 ** 180 *******************************************************************************/ 181 void battery_c_cmpl_cback (tSRVC_CLCB *p_clcb, tGATTC_OPTYPE op, 182 tGATT_STATUS status, tGATT_CL_COMPLETE *p_data) 183 { 184 UNUSED(p_clcb); 185 UNUSED(op); 186 UNUSED(status); 187 UNUSED(p_data); 188 } 189 190 191 /******************************************************************************* 192 ** 193 ** Function Battery_Instantiate 194 ** 195 ** Description Instantiate a Battery service 196 ** 197 *******************************************************************************/ 198 UINT16 Battery_Instantiate (UINT8 app_id, tBA_REG_INFO *p_reg_info) 199 { 200 tBT_UUID uuid = {LEN_UUID_16, {UUID_SERVCLASS_BATTERY}}; 201 UINT16 srvc_hdl; 202 tGATT_STATUS status = GATT_ERROR; 203 tBA_INST *p_inst; 204 tGATT_CHAR_PROP prop = GATT_CHAR_PROP_BIT_READ; 205 206 if (battery_cb.inst_id == BA_MAX_INT_NUM) 207 { 208 GATT_TRACE_ERROR("MAX battery service has been reached"); 209 return 0; 210 } 211 212 p_inst = &battery_cb.battery_inst[battery_cb.inst_id]; 213 214 srvc_hdl = GATTS_CreateService (srvc_eng_cb.gatt_if , 215 &uuid, 216 battery_cb.inst_id , 217 BA_MAX_ATTR_NUM, 218 p_reg_info->is_pri); 219 220 if (srvc_hdl == 0) 221 { 222 GATT_TRACE_ERROR("Can not create service, Battery_Instantiate() failed!"); 223 return 0; 224 } 225 226 battery_cb.inst_id ++; 227 228 p_inst->app_id = app_id; 229 p_inst->p_cback = p_reg_info->p_cback; 230 231 /* add battery level 232 */ 233 uuid.uu.uuid16 = GATT_UUID_BATTERY_LEVEL; 234 235 if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY) 236 prop |= GATT_CHAR_PROP_BIT_NOTIFY; 237 238 if ((p_inst->ba_level_hdl = GATTS_AddCharacteristic(srvc_hdl, 239 &uuid, 240 BATTER_LEVEL_PERM, 241 prop)) == 0) 242 { 243 GATT_TRACE_ERROR("Can not add Battery Level, Battery_Instantiate() failed!"); 244 status = GATT_ERROR; 245 } 246 else 247 { 248 if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY) 249 { 250 uuid.uu.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG; 251 p_inst->clt_cfg_hdl = GATTS_AddCharDescriptor(srvc_hdl, 252 (GATT_PERM_READ|GATT_PERM_WRITE), 253 &uuid); 254 if (p_inst->clt_cfg_hdl == 0) 255 { 256 GATT_TRACE_ERROR("Add battery level client notification FAILED!"); 257 } 258 } 259 /* need presentation format descriptor? */ 260 if (p_reg_info->ba_level_descr & BA_LEVEL_PRE_FMT) 261 { 262 uuid.uu.uuid16 = GATT_UUID_CHAR_PRESENT_FORMAT; 263 if ( (p_inst->pres_fmt_hdl = GATTS_AddCharDescriptor(srvc_hdl, 264 GATT_PERM_READ, 265 &uuid)) 266 == 0) 267 { 268 GATT_TRACE_ERROR("Add battery level presentation format descriptor FAILED!"); 269 } 270 271 } 272 /* need presentation format descriptor? */ 273 if (p_reg_info->ba_level_descr & BA_LEVEL_RPT_REF) 274 { 275 uuid.uu.uuid16 = GATT_UUID_RPT_REF_DESCR; 276 if ( (p_inst->rpt_ref_hdl = GATTS_AddCharDescriptor(srvc_hdl, 277 GATT_PERM_READ, 278 &uuid)) 279 == 0) 280 { 281 GATT_TRACE_ERROR("Add battery level report reference descriptor FAILED!"); 282 } 283 284 } 285 /* start service 286 */ 287 status = GATTS_StartService (srvc_eng_cb.gatt_if, srvc_hdl, p_reg_info->transport); 288 } 289 290 if (status != GATT_SUCCESS) 291 { 292 battery_cb.inst_id --; 293 uuid.uu.uuid16 = UUID_SERVCLASS_BATTERY; 294 GATTS_DeleteService(srvc_eng_cb.gatt_if, &uuid, battery_cb.inst_id); 295 srvc_hdl = 0; 296 } 297 298 return srvc_hdl; 299 } 300 /******************************************************************************* 301 ** 302 ** Function Battery_Rsp 303 ** 304 ** Description Respond to a battery service request 305 ** 306 *******************************************************************************/ 307 void Battery_Rsp (UINT8 app_id, tGATT_STATUS st, UINT8 event, tBA_RSP_DATA *p_rsp) 308 { 309 tBA_INST *p_inst = &battery_cb.battery_inst[0]; 310 tGATTS_RSP rsp; 311 UINT8 *pp; 312 313 UINT8 i = 0; 314 while (i < BA_MAX_INT_NUM) 315 { 316 if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0) 317 break; 318 i ++; 319 } 320 321 if (i == BA_MAX_INT_NUM) 322 return; 323 324 memset(&rsp, 0, sizeof(tGATTS_RSP)); 325 326 if (p_inst->pending_evt == event) 327 { 328 switch (event) 329 { 330 case BA_READ_CLT_CFG_REQ: 331 rsp.attr_value.handle = p_inst->pending_handle; 332 rsp.attr_value.len = 2; 333 pp = rsp.attr_value.value; 334 UINT16_TO_STREAM(pp, p_rsp->clt_cfg); 335 srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp); 336 break; 337 338 case BA_READ_LEVEL_REQ: 339 rsp.attr_value.handle = p_inst->pending_handle; 340 rsp.attr_value.len = 1; 341 pp = rsp.attr_value.value; 342 UINT8_TO_STREAM(pp, p_rsp->ba_level); 343 srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp); 344 break; 345 346 case BA_WRITE_CLT_CFG_REQ: 347 srvc_sr_rsp(p_inst->pending_clcb_idx, st, NULL); 348 break; 349 350 case BA_READ_RPT_REF_REQ: 351 rsp.attr_value.handle = p_inst->pending_handle; 352 rsp.attr_value.len = 2; 353 pp = rsp.attr_value.value; 354 UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_id); 355 UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_type); 356 srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp); 357 break; 358 359 default: 360 break; 361 } 362 p_inst->pending_clcb_idx = 0; 363 p_inst->pending_evt = 0; 364 p_inst->pending_handle = 0; 365 } 366 return; 367 } 368 /******************************************************************************* 369 ** 370 ** Function Battery_Notify 371 ** 372 ** Description Send battery level notification 373 ** 374 *******************************************************************************/ 375 void Battery_Notify (UINT8 app_id, BD_ADDR remote_bda, UINT8 battery_level) 376 { 377 tBA_INST *p_inst = &battery_cb.battery_inst[0]; 378 UINT8 i = 0; 379 380 while (i < BA_MAX_INT_NUM) 381 { 382 if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0) 383 break; 384 i ++; 385 } 386 387 if (i == BA_MAX_INT_NUM || p_inst->clt_cfg_hdl == 0) 388 return; 389 390 srvc_sr_notify(remote_bda, p_inst->ba_level_hdl, 1, &battery_level); 391 392 } 393 /******************************************************************************* 394 ** 395 ** Function Battery_ReadBatteryLevel 396 ** 397 ** Description Read remote device Battery Level information. 398 ** 399 ** Returns void 400 ** 401 *******************************************************************************/ 402 BOOLEAN Battery_ReadBatteryLevel(BD_ADDR peer_bda) 403 { 404 UNUSED(peer_bda); 405 /* to be implemented */ 406 return TRUE; 407 } 408 #endif /* BLE_INCLUDED */ 409