• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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