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
41 tBATTERY_CB battery_cb;
42
43 /*******************************************************************************
44 * battery_valid_handle_range
45 *
46 * validate a handle to be a DIS attribute handle or not.
47 ******************************************************************************/
battery_valid_handle_range(uint16_t handle)48 bool 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 ******************************************************************************/
battery_s_write_attr_value(uint8_t clcb_idx,tGATT_WRITE_REQ * p_value,tGATT_STATUS * p_status)65 uint8_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 ******************************************************************************/
battery_s_read_attr_value(uint8_t clcb_idx,uint16_t handle,UNUSED_ATTR tGATT_VALUE * p_value,bool is_long,tGATT_STATUS * p_status)102 uint8_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 ******************************************************************************/
battery_gatt_c_read_ba_req(UNUSED_ATTR uint16_t conn_id)151 bool 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 ******************************************************************************/
battery_c_cmpl_cback(UNUSED_ATTR tSRVC_CLCB * p_clcb,UNUSED_ATTR tGATTC_OPTYPE op,UNUSED_ATTR tGATT_STATUS status,UNUSED_ATTR tGATT_CL_COMPLETE * p_data)162 void 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 ******************************************************************************/
Battery_Instantiate(uint8_t app_id,tBA_REG_INFO * p_reg_info)174 uint16_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 ******************************************************************************/
Battery_Rsp(uint8_t app_id,tGATT_STATUS st,uint8_t event,tBA_RSP_DATA * p_rsp)274 void 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 ******************************************************************************/
Battery_Notify(uint8_t app_id,BD_ADDR remote_bda,uint8_t battery_level)337 void 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 ******************************************************************************/
Battery_ReadBatteryLevel(UNUSED_ATTR BD_ADDR peer_bda)359 bool Battery_ReadBatteryLevel(UNUSED_ATTR BD_ADDR peer_bda) {
360 /* to be implemented */
361 return true;
362 }
363