• Home
  • 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 "gatt_api.h"
22  #include "gatt_int.h"
23  #include "srvc_eng_int.h"
24  
25  #if BLE_INCLUDED == TRUE
26  
27  //#if DIS_INCLUDED == TRUE
28  #include "srvc_dis_int.h"
29  //#endif
30  #include "srvc_battery_int.h"
31  
32  #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
33  
34  static void srvc_eng_s_request_cback (UINT16 conn_id, UINT32 trans_id, UINT8 op_code, tGATTS_DATA *p_data);
35  static void srvc_eng_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected,
36                                            tGATT_DISCONN_REASON reason, tBT_TRANSPORT transport);
37  static void srvc_eng_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data);
38  
39  static tGATT_CBACK srvc_gatt_cback =
40  {
41      srvc_eng_connect_cback,
42      srvc_eng_c_cmpl_cback,
43      NULL,
44      NULL,
45      srvc_eng_s_request_cback,
46      NULL,
47      NULL
48  } ;
49  /* type for action functions */
50  typedef void (*tSRVC_ENG_C_CMPL_ACTION)(tSRVC_CLCB *p_clcb, tGATTC_OPTYPE op,
51                                      tGATT_STATUS status, tGATT_CL_COMPLETE *p_data);
52  
53  const tSRVC_ENG_C_CMPL_ACTION srvc_eng_c_cmpl_act[SRVC_ID_MAX] =
54  {
55      dis_c_cmpl_cback,
56  };
57  
58  tSRVC_ENG_CB srvc_eng_cb;
59  
60  /*******************************************************************************
61  **
62  ** Function         srvc_eng_find_conn_id_by_bd_addr
63  **
64  ** Description      The function searches all LCB with macthing bd address
65  **
66  ** Returns          total number of clcb found.
67  **
68  *******************************************************************************/
srvc_eng_find_conn_id_by_bd_addr(BD_ADDR bda)69  UINT16 srvc_eng_find_conn_id_by_bd_addr(BD_ADDR bda)
70  {
71      UINT8 i_clcb;
72      tSRVC_CLCB    *p_clcb = NULL;
73  
74      for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++)
75      {
76          if (p_clcb->in_use && p_clcb->connected && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN))
77          {
78              return p_clcb->conn_id;
79          }
80      }
81  
82      return GATT_INVALID_CONN_ID;
83  }
84  
85  /*******************************************************************************
86  **
87  ** Function         srvc_eng_find_clcb_by_bd_addr
88  **
89  ** Description      The function searches all LCBs with macthing bd address.
90  **
91  ** Returns          Pointer to the found link conenction control block.
92  **
93  *******************************************************************************/
srvc_eng_find_clcb_by_bd_addr(BD_ADDR bda)94  tSRVC_CLCB *srvc_eng_find_clcb_by_bd_addr(BD_ADDR bda)
95  {
96      UINT8 i_clcb;
97      tSRVC_CLCB    *p_clcb = NULL;
98  
99      for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++)
100      {
101          if (p_clcb->in_use && p_clcb->connected && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN))
102          {
103              return p_clcb;
104          }
105      }
106  
107      return NULL;
108  }
109  /*******************************************************************************
110  **
111  ** Function         srvc_eng_find_clcb_by_conn_id
112  **
113  ** Description      The function searches all LCBs with macthing connection ID.
114  **
115  ** Returns          Pointer to the found link conenction control block.
116  **
117  *******************************************************************************/
srvc_eng_find_clcb_by_conn_id(UINT16 conn_id)118  tSRVC_CLCB *srvc_eng_find_clcb_by_conn_id(UINT16 conn_id)
119  {
120      UINT8 i_clcb;
121      tSRVC_CLCB    *p_clcb = NULL;
122  
123      for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++)
124      {
125          if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id)
126          {
127              return p_clcb;
128          }
129      }
130  
131      return NULL;
132  }
133  /*******************************************************************************
134  **
135  ** Function         srvc_eng_find_clcb_by_conn_id
136  **
137  ** Description      The function searches all LCBs with macthing connection ID.
138  **
139  ** Returns          Pointer to the found link conenction control block.
140  **
141  *******************************************************************************/
srvc_eng_find_clcb_idx_by_conn_id(UINT16 conn_id)142  UINT8 srvc_eng_find_clcb_idx_by_conn_id(UINT16 conn_id)
143  {
144      UINT8 i_clcb;
145      tSRVC_CLCB    *p_clcb = NULL;
146  
147      for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++)
148      {
149          if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id)
150          {
151              return i_clcb;
152          }
153      }
154  
155      return SRVC_MAX_APPS;
156  }
157  /*******************************************************************************
158  **
159  ** Function         srvc_eng_clcb_alloc
160  **
161  ** Description      The function allocates a GATT profile  connection link control block
162  **
163  ** Returns           NULL if not found. Otherwise pointer to the connection link block.
164  **
165  *******************************************************************************/
srvc_eng_clcb_alloc(UINT16 conn_id,BD_ADDR bda)166  tSRVC_CLCB *srvc_eng_clcb_alloc (UINT16 conn_id, BD_ADDR bda)
167  {
168      UINT8                   i_clcb = 0;
169      tSRVC_CLCB      *p_clcb = NULL;
170  
171      for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++)
172      {
173          if (!p_clcb->in_use)
174          {
175              p_clcb->in_use      = TRUE;
176              p_clcb->conn_id     = conn_id;
177              p_clcb->connected   = TRUE;
178              memcpy (p_clcb->bda, bda, BD_ADDR_LEN);
179              break;
180          }
181      }
182      return p_clcb;
183  }
184  /*******************************************************************************
185  **
186  ** Function         srvc_eng_clcb_dealloc
187  **
188  ** Description      The function deallocates a GATT profile  connection link control block
189  **
190  ** Returns           True the deallocation is successful
191  **
192  *******************************************************************************/
srvc_eng_clcb_dealloc(UINT16 conn_id)193  BOOLEAN srvc_eng_clcb_dealloc (UINT16 conn_id)
194  {
195      UINT8                   i_clcb = 0;
196      tSRVC_CLCB      *p_clcb = NULL;
197  
198      for (i_clcb = 0, p_clcb= srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS; i_clcb++, p_clcb++)
199      {
200          if (p_clcb->in_use && p_clcb->connected && (p_clcb->conn_id == conn_id))
201          {
202              unsigned j;
203              for (j = 0; j < ARRAY_SIZE(p_clcb->dis_value.data_string); j++)
204                  osi_free(p_clcb->dis_value.data_string[j]);
205  
206              memset(p_clcb, 0, sizeof(tSRVC_CLCB));
207              return TRUE;
208          }
209      }
210      return FALSE;
211  }
212  /*******************************************************************************
213  **   Service Engine Server Attributes Database Read/Read Blob Request process
214  *******************************************************************************/
srvc_eng_process_read_req(UINT8 clcb_idx,tGATT_READ_REQ * p_data,tGATTS_RSP * p_rsp,tGATT_STATUS * p_status)215  UINT8 srvc_eng_process_read_req (UINT8 clcb_idx, tGATT_READ_REQ *p_data, tGATTS_RSP *p_rsp, tGATT_STATUS *p_status)
216  {
217      tGATT_STATUS    status = GATT_NOT_FOUND;
218      UINT8       act = SRVC_ACT_RSP;
219  
220      if (p_data->is_long)
221          p_rsp->attr_value.offset = p_data->offset;
222  
223      p_rsp->attr_value.handle = p_data->handle;
224  
225      if (dis_valid_handle_range(p_data->handle))
226          act = dis_read_attr_value(clcb_idx, p_data->handle, &p_rsp->attr_value, p_data->is_long, p_status);
227  
228      else if (battery_valid_handle_range(p_data->handle))
229          act = battery_s_read_attr_value(clcb_idx, p_data->handle, &p_rsp->attr_value, p_data->is_long, p_status);
230  
231      else
232          *p_status = status;
233      return act;
234  }
235  /*******************************************************************************
236  **   Service Engine Server Attributes Database write Request process
237  *******************************************************************************/
srvc_eng_process_write_req(UINT8 clcb_idx,tGATT_WRITE_REQ * p_data,tGATTS_RSP * p_rsp,tGATT_STATUS * p_status)238  UINT8 srvc_eng_process_write_req (UINT8 clcb_idx, tGATT_WRITE_REQ *p_data, tGATTS_RSP *p_rsp, tGATT_STATUS *p_status)
239  {
240      UINT8       act = SRVC_ACT_RSP;
241      UNUSED(p_rsp);
242  
243      if (dis_valid_handle_range(p_data->handle))
244      {
245          act = dis_write_attr_value(p_data, p_status);
246      }
247      else if (battery_valid_handle_range(p_data->handle))
248      {
249          act = battery_s_write_attr_value(clcb_idx, p_data, p_status);
250      }
251      else
252          *p_status = GATT_NOT_FOUND;
253  
254      return act;
255  }
256  
257  /*******************************************************************************
258  **
259  ** Function         srvc_eng_s_request_cback
260  **
261  ** Description      GATT DIS attribute access request callback.
262  **
263  ** Returns          void.
264  **
265  *******************************************************************************/
srvc_eng_s_request_cback(UINT16 conn_id,UINT32 trans_id,tGATTS_REQ_TYPE type,tGATTS_DATA * p_data)266  static void srvc_eng_s_request_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE type,
267                                          tGATTS_DATA *p_data)
268  {
269      UINT8       status = GATT_INVALID_PDU;
270      tGATTS_RSP  rsp_msg ;
271      UINT8       act = SRVC_ACT_IGNORE;
272      UINT8   clcb_idx = srvc_eng_find_clcb_idx_by_conn_id(conn_id);
273  
274      GATT_TRACE_EVENT("srvc_eng_s_request_cback : recv type (0x%02x)", type);
275  
276      memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
277  
278      srvc_eng_cb.clcb[clcb_idx].trans_id = trans_id;
279  
280      switch (type)
281      {
282          case GATTS_REQ_TYPE_READ:
283              act = srvc_eng_process_read_req(clcb_idx, &p_data->read_req, &rsp_msg, &status);
284              break;
285  
286          case GATTS_REQ_TYPE_WRITE:
287              act = srvc_eng_process_write_req(clcb_idx, &p_data->write_req, &rsp_msg, &status);
288              if (!p_data->write_req.need_rsp)
289                  act = SRVC_ACT_IGNORE;
290              break;
291  
292          case GATTS_REQ_TYPE_WRITE_EXEC:
293              GATT_TRACE_EVENT("Ignore GATT_REQ_EXEC_WRITE/WRITE_CMD" );
294              break;
295  
296          case GATTS_REQ_TYPE_MTU:
297              GATT_TRACE_EVENT("Get MTU exchange new mtu size: %d", p_data->mtu);
298              break;
299  
300          default:
301              GATT_TRACE_EVENT("Unknown/unexpected LE GAP ATT request: 0x%02x", type);
302              break;
303      }
304  
305      srvc_eng_cb.clcb[clcb_idx].trans_id = 0;
306  
307      if (act == SRVC_ACT_RSP)
308          GATTS_SendRsp (conn_id, trans_id, status, &rsp_msg);
309  
310  
311  }
312  
313  
314  /*******************************************************************************
315  **
316  ** Function         srvc_eng_c_cmpl_cback
317  **
318  ** Description      Client operation complete callback.
319  **
320  ** Returns          void
321  **
322  *******************************************************************************/
srvc_eng_c_cmpl_cback(UINT16 conn_id,tGATTC_OPTYPE op,tGATT_STATUS status,tGATT_CL_COMPLETE * p_data)323  static void srvc_eng_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status,
324                                     tGATT_CL_COMPLETE *p_data)
325  {
326      tSRVC_CLCB   *p_clcb = srvc_eng_find_clcb_by_conn_id(conn_id);
327  
328      GATT_TRACE_EVENT ("srvc_eng_c_cmpl_cback() - op_code: 0x%02x  status: 0x%02x ", op, status);
329  
330      if (p_clcb == NULL)
331      {
332          GATT_TRACE_ERROR("srvc_eng_c_cmpl_cback received for unknown connection");
333          return;
334      }
335  
336      if (p_clcb->cur_srvc_id != SRVC_ID_NONE &&
337          p_clcb->cur_srvc_id <= SRVC_ID_MAX)
338          srvc_eng_c_cmpl_act[p_clcb->cur_srvc_id - 1](p_clcb, op, status, p_data);
339  }
340  
341  
342  /*******************************************************************************
343  **
344  ** Function         srvc_eng_connect_cback
345  **
346  ** Description      Gatt profile connection callback.
347  **
348  ** Returns          void
349  **
350  *******************************************************************************/
srvc_eng_connect_cback(tGATT_IF gatt_if,BD_ADDR bda,UINT16 conn_id,BOOLEAN connected,tGATT_DISCONN_REASON reason,tBT_TRANSPORT transport)351  static void srvc_eng_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id,
352                                          BOOLEAN connected, tGATT_DISCONN_REASON reason,  tBT_TRANSPORT transport)
353  {
354      UNUSED(gatt_if);
355      UNUSED (transport);
356  
357      GATT_TRACE_EVENT ("srvc_eng_connect_cback: from %08x%04x connected:%d conn_id=%d reason = 0x%04x",
358                         (bda[0]<<24)+(bda[1]<<16)+(bda[2]<<8)+bda[3],
359                         (bda[4]<<8)+bda[5], connected, conn_id, reason);
360  
361      if (connected)
362      {
363          if (srvc_eng_clcb_alloc(conn_id, bda) == NULL)
364          {
365              GATT_TRACE_ERROR ("srvc_eng_connect_cback: no_resource");
366              return;
367          }
368      }
369      else
370      {
371          srvc_eng_clcb_dealloc(conn_id);
372      }
373  
374  }
375  /*******************************************************************************
376  **
377  ** Function         srvc_eng_c_cmpl_cback
378  **
379  ** Description      Client operation complete callback.
380  **
381  ** Returns          void
382  **
383  *******************************************************************************/
srvc_eng_request_channel(BD_ADDR remote_bda,UINT8 srvc_id)384  BOOLEAN srvc_eng_request_channel (BD_ADDR remote_bda, UINT8 srvc_id )
385  {
386      BOOLEAN set = TRUE;
387      tSRVC_CLCB  *p_clcb = srvc_eng_find_clcb_by_bd_addr(remote_bda);
388  
389      if (p_clcb == NULL)
390          p_clcb = srvc_eng_clcb_alloc(0, remote_bda);
391  
392      if (p_clcb && p_clcb->cur_srvc_id == SRVC_ID_NONE)
393          p_clcb->cur_srvc_id = srvc_id;
394      else
395          set = FALSE;
396  
397      return set;
398  }
399  /*******************************************************************************
400  **
401  ** Function         srvc_eng_release_channel
402  **
403  ** Description      Client operation complete callback.
404  **
405  ** Returns          void
406  **
407  *******************************************************************************/
srvc_eng_release_channel(UINT16 conn_id)408  void srvc_eng_release_channel (UINT16 conn_id)
409  {
410      tSRVC_CLCB *p_clcb =  srvc_eng_find_clcb_by_conn_id(conn_id);
411  
412      if (p_clcb == NULL)
413      {
414          GATT_TRACE_ERROR("%s: invalid connection id %d", __FUNCTION__, conn_id);
415          return;
416      }
417  
418      p_clcb->cur_srvc_id = SRVC_ID_NONE;
419  
420      /* check pending request */
421      GATT_Disconnect(p_clcb->conn_id);
422  }
423  /*******************************************************************************
424  **
425  ** Function         srvc_eng_init
426  **
427  ** Description      Initializa the GATT Service engine.
428  **
429  *******************************************************************************/
srvc_eng_init(void)430  tGATT_STATUS srvc_eng_init (void)
431  {
432      tBT_UUID          app_uuid = {LEN_UUID_16, {UUID_SERVCLASS_DEVICE_INFO}};
433  
434      if (srvc_eng_cb.enabled)
435      {
436          GATT_TRACE_ERROR("DIS already initalized");
437      }
438      else
439      {
440          memset(&srvc_eng_cb, 0, sizeof(tSRVC_ENG_CB));
441  
442          /* Create a GATT profile service */
443          srvc_eng_cb.gatt_if = GATT_Register(&app_uuid, &srvc_gatt_cback);
444          GATT_StartIf(srvc_eng_cb.gatt_if);
445  
446          GATT_TRACE_DEBUG ("Srvc_Init:  gatt_if=%d  ", srvc_eng_cb.gatt_if);
447  
448          srvc_eng_cb.enabled = TRUE;
449  //#if DIS_INCLUDED == TRUE
450          dis_cb.dis_read_uuid_idx = 0xff;
451  //#endif
452      }
453      return GATT_SUCCESS;
454  }
455  
srvc_sr_rsp(UINT8 clcb_idx,tGATT_STATUS st,tGATTS_RSP * p_rsp)456  void srvc_sr_rsp(UINT8 clcb_idx, tGATT_STATUS st, tGATTS_RSP *p_rsp)
457  {
458      if (srvc_eng_cb.clcb[clcb_idx].trans_id != 0)
459      {
460          GATTS_SendRsp(srvc_eng_cb.clcb[clcb_idx].conn_id,
461                    srvc_eng_cb.clcb[clcb_idx].trans_id,
462                    st,
463                    p_rsp);
464  
465          srvc_eng_cb.clcb[clcb_idx].trans_id = 0;
466      }
467  }
srvc_sr_notify(BD_ADDR remote_bda,UINT16 handle,UINT16 len,UINT8 * p_value)468  void srvc_sr_notify(BD_ADDR remote_bda, UINT16 handle, UINT16 len, UINT8 *p_value)
469  {
470      UINT16 conn_id = srvc_eng_find_conn_id_by_bd_addr(remote_bda);
471  
472      if (conn_id != GATT_INVALID_CONN_ID)
473      {
474          GATTS_HandleValueNotification( conn_id, handle, len, p_value);
475      }
476  }
477  
478  #endif
479  
480  
481  
482