Home | History | Annotate | Download | only in srvc
      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 *******************************************************************************/
     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 *******************************************************************************/
     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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 
    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 }
    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