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 *******************************************************************************/
battery_valid_handle_range(UINT16 handle)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 *******************************************************************************/
battery_s_write_attr_value(UINT8 clcb_idx,tGATT_WRITE_REQ * p_value,tGATT_STATUS * p_status)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 *******************************************************************************/
battery_s_read_attr_value(UINT8 clcb_idx,UINT16 handle,tGATT_VALUE * p_value,BOOLEAN is_long,tGATT_STATUS * p_status)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 *******************************************************************************/
battery_gatt_c_read_ba_req(UINT16 conn_id)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 *******************************************************************************/
battery_c_cmpl_cback(tSRVC_CLCB * p_clcb,tGATTC_OPTYPE op,tGATT_STATUS status,tGATT_CL_COMPLETE * p_data)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 *******************************************************************************/
Battery_Instantiate(UINT8 app_id,tBA_REG_INFO * p_reg_info)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 *******************************************************************************/
Battery_Rsp(UINT8 app_id,tGATT_STATUS st,UINT8 event,tBA_RSP_DATA * p_rsp)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 *******************************************************************************/
Battery_Notify(UINT8 app_id,BD_ADDR remote_bda,UINT8 battery_level)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 *******************************************************************************/
Battery_ReadBatteryLevel(BD_ADDR peer_bda)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