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