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 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 119 for (i = 0; i < BA_MAX_INT_NUM; i ++, p_inst ++) 120 { 121 /* read battery level */ 122 if (handle == p_inst->ba_level_hdl || 123 handle == p_inst->clt_cfg_hdl || 124 handle == p_inst->rpt_ref_hdl || 125 handle == p_inst->pres_fmt_hdl) 126 { 127 if (is_long) 128 st = GATT_NOT_LONG; 129 130 if (p_inst->p_cback) 131 { 132 if (handle == p_inst->ba_level_hdl) p_inst->pending_evt = BA_READ_LEVEL_REQ; 133 if (handle == p_inst->clt_cfg_hdl) p_inst->pending_evt = BA_READ_CLT_CFG_REQ; 134 if (handle == p_inst->pres_fmt_hdl) p_inst->pending_evt = BA_READ_PRE_FMT_REQ; 135 if (handle == p_inst->rpt_ref_hdl) p_inst->pending_evt = BA_READ_RPT_REF_REQ ; 136 137 p_inst->pending_clcb_idx = clcb_idx; 138 p_inst->pending_handle = handle; 139 act = SRVC_ACT_PENDING; 140 141 (* p_inst->p_cback)(p_inst->app_id, p_inst->pending_evt, NULL); 142 } 143 else /* application is not registered */ 144 st = GATT_ERR_UNLIKELY; 145 break; 146 } 147 /* else attribute not found */ 148 } 149 150 151 *p_status = st; 152 return act; 153 } 154 155 156 /******************************************************************************* 157 ** 158 ** Function battery_gatt_c_read_ba_req 159 ** 160 ** Description Read remote device BA level attribute request. 161 ** 162 ** Returns void 163 ** 164 *******************************************************************************/ 165 BOOLEAN battery_gatt_c_read_ba_req(UINT16 conn_id) 166 { 167 return TRUE; 168 } 169 170 /******************************************************************************* 171 ** 172 ** Function battery_c_cmpl_cback 173 ** 174 ** Description Client operation complete callback. 175 ** 176 ** Returns void 177 ** 178 *******************************************************************************/ 179 void battery_c_cmpl_cback (tSRVC_CLCB *p_clcb, tGATTC_OPTYPE op, 180 tGATT_STATUS status, tGATT_CL_COMPLETE *p_data) 181 { 182 } 183 184 185 /******************************************************************************* 186 ** 187 ** Function Battery_Instantiate 188 ** 189 ** Description Instantiate a Battery service 190 ** 191 *******************************************************************************/ 192 UINT16 Battery_Instantiate (UINT8 app_id, tBA_REG_INFO *p_reg_info) 193 { 194 tBT_UUID uuid = {LEN_UUID_16, {UUID_SERVCLASS_BATTERY}}; 195 UINT16 srvc_hdl; 196 tGATT_STATUS status = GATT_ERROR; 197 tBA_INST *p_inst; 198 tGATT_CHAR_PROP prop = GATT_CHAR_PROP_BIT_READ; 199 200 if (battery_cb.inst_id == BA_MAX_INT_NUM) 201 { 202 GATT_TRACE_ERROR0("MAX battery service has been reached"); 203 return 0; 204 } 205 206 p_inst = &battery_cb.battery_inst[battery_cb.inst_id]; 207 208 srvc_hdl = GATTS_CreateService (srvc_eng_cb.gatt_if , 209 &uuid, 210 battery_cb.inst_id , 211 BA_MAX_ATTR_NUM, 212 p_reg_info->is_pri); 213 214 if (srvc_hdl == 0) 215 { 216 GATT_TRACE_ERROR0("Can not create service, Battery_Instantiate() failed!"); 217 return 0; 218 } 219 220 battery_cb.inst_id ++; 221 222 p_inst->app_id = app_id; 223 p_inst->p_cback = p_reg_info->p_cback; 224 225 /* add battery level 226 */ 227 uuid.uu.uuid16 = GATT_UUID_BATTERY_LEVEL; 228 229 if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY) 230 prop |= GATT_CHAR_PROP_BIT_NOTIFY; 231 232 if ((p_inst->ba_level_hdl = GATTS_AddCharacteristic(srvc_hdl, 233 &uuid, 234 BATTER_LEVEL_PERM, 235 prop)) == 0) 236 { 237 GATT_TRACE_ERROR0("Can not add Battery Level, Battery_Instantiate() failed!"); 238 status = GATT_ERROR; 239 } 240 else 241 { 242 if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY) 243 { 244 uuid.uu.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG; 245 p_inst->clt_cfg_hdl = GATTS_AddCharDescriptor(srvc_hdl, 246 (GATT_PERM_READ|GATT_PERM_WRITE), 247 &uuid); 248 if (p_inst->clt_cfg_hdl == 0) 249 { 250 GATT_TRACE_ERROR0("Add battery level client notification FAILED!"); 251 } 252 } 253 /* need presentation format descriptor? */ 254 if (p_reg_info->ba_level_descr & BA_LEVEL_PRE_FMT) 255 { 256 uuid.uu.uuid16 = GATT_UUID_CHAR_PRESENT_FORMAT; 257 if ( (p_inst->pres_fmt_hdl = GATTS_AddCharDescriptor(srvc_hdl, 258 GATT_PERM_READ, 259 &uuid)) 260 == 0) 261 { 262 GATT_TRACE_ERROR0("Add battery level presentation format descriptor FAILED!"); 263 } 264 265 } 266 /* need presentation format descriptor? */ 267 if (p_reg_info->ba_level_descr & BA_LEVEL_RPT_REF) 268 { 269 uuid.uu.uuid16 = GATT_UUID_RPT_REF_DESCR; 270 if ( (p_inst->rpt_ref_hdl = GATTS_AddCharDescriptor(srvc_hdl, 271 GATT_PERM_READ, 272 &uuid)) 273 == 0) 274 { 275 GATT_TRACE_ERROR0("Add battery level report reference descriptor FAILED!"); 276 } 277 278 } 279 /* start service 280 */ 281 status = GATTS_StartService (srvc_eng_cb.gatt_if, srvc_hdl, p_reg_info->transport); 282 } 283 284 if (status != GATT_SUCCESS) 285 { 286 battery_cb.inst_id --; 287 uuid.uu.uuid16 = UUID_SERVCLASS_BATTERY; 288 GATTS_DeleteService(srvc_eng_cb.gatt_if, &uuid, battery_cb.inst_id); 289 srvc_hdl = 0; 290 } 291 292 return srvc_hdl; 293 } 294 /******************************************************************************* 295 ** 296 ** Function Battery_Rsp 297 ** 298 ** Description Respond to a battery service request 299 ** 300 *******************************************************************************/ 301 void Battery_Rsp (UINT8 app_id, tGATT_STATUS st, UINT8 event, tBA_RSP_DATA *p_rsp) 302 { 303 tBA_INST *p_inst = &battery_cb.battery_inst[0]; 304 tGATTS_RSP rsp; 305 UINT8 *pp; 306 307 UINT8 i = 0; 308 while (i < BA_MAX_INT_NUM) 309 { 310 if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0) 311 break; 312 i ++; 313 } 314 315 if (i == BA_MAX_INT_NUM) 316 return; 317 318 memset(&rsp, 0, sizeof(tGATTS_RSP)); 319 320 if (p_inst->pending_evt == event) 321 { 322 switch (event) 323 { 324 case BA_READ_CLT_CFG_REQ: 325 rsp.attr_value.handle = p_inst->pending_handle; 326 rsp.attr_value.len = 2; 327 pp = rsp.attr_value.value; 328 UINT16_TO_STREAM(pp, p_rsp->clt_cfg); 329 srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp); 330 break; 331 332 case BA_READ_LEVEL_REQ: 333 rsp.attr_value.handle = p_inst->pending_handle; 334 rsp.attr_value.len = 1; 335 pp = rsp.attr_value.value; 336 UINT8_TO_STREAM(pp, p_rsp->ba_level); 337 srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp); 338 break; 339 340 case BA_WRITE_CLT_CFG_REQ: 341 srvc_sr_rsp(p_inst->pending_clcb_idx, st, NULL); 342 break; 343 344 case BA_READ_RPT_REF_REQ: 345 rsp.attr_value.handle = p_inst->pending_handle; 346 rsp.attr_value.len = 2; 347 pp = rsp.attr_value.value; 348 UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_id); 349 UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_type); 350 srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp); 351 break; 352 353 default: 354 break; 355 } 356 p_inst->pending_clcb_idx = 0; 357 p_inst->pending_evt = 0; 358 p_inst->pending_handle = 0; 359 } 360 return; 361 } 362 /******************************************************************************* 363 ** 364 ** Function Battery_Notify 365 ** 366 ** Description Send battery level notification 367 ** 368 *******************************************************************************/ 369 void Battery_Notify (UINT8 app_id, BD_ADDR remote_bda, UINT8 battery_level) 370 { 371 tBA_INST *p_inst = &battery_cb.battery_inst[0]; 372 UINT8 i = 0; 373 374 while (i < BA_MAX_INT_NUM) 375 { 376 if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0) 377 break; 378 i ++; 379 } 380 381 if (i == BA_MAX_INT_NUM || p_inst->clt_cfg_hdl == 0) 382 return; 383 384 srvc_sr_notify(remote_bda, p_inst->ba_level_hdl, 1, &battery_level); 385 386 } 387 /******************************************************************************* 388 ** 389 ** Function Battery_ReadBatteryLevel 390 ** 391 ** Description Read remote device Battery Level information. 392 ** 393 ** Returns void 394 ** 395 *******************************************************************************/ 396 BOOLEAN Battery_ReadBatteryLevel(BD_ADDR peer_bda) 397 { 398 /* to be implemented */ 399 return TRUE; 400 } 401 #endif /* BLE_INCLUDED */ 402