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                 if (p_clcb->dis_value.data_string[j]) {
    205                     GKI_freebuf(p_clcb->dis_value.data_string[j]);
    206                 }
    207             }
    208             memset(p_clcb, 0, sizeof(tSRVC_CLCB));
    209             return TRUE;
    210         }
    211     }
    212     return FALSE;
    213 }
    214 /*******************************************************************************
    215 **   Service Engine Server Attributes Database Read/Read Blob Request process
    216 *******************************************************************************/
    217 UINT8 srvc_eng_process_read_req (UINT8 clcb_idx, tGATT_READ_REQ *p_data, tGATTS_RSP *p_rsp, tGATT_STATUS *p_status)
    218 {
    219     tGATT_STATUS    status = GATT_NOT_FOUND;
    220     UINT8       act = SRVC_ACT_RSP;
    221 
    222     if (p_data->is_long)
    223         p_rsp->attr_value.offset = p_data->offset;
    224 
    225     p_rsp->attr_value.handle = p_data->handle;
    226 
    227     if (dis_valid_handle_range(p_data->handle))
    228         act = dis_read_attr_value(clcb_idx, p_data->handle, &p_rsp->attr_value, p_data->is_long, p_status);
    229 
    230     else if (battery_valid_handle_range(p_data->handle))
    231         act = battery_s_read_attr_value(clcb_idx, p_data->handle, &p_rsp->attr_value, p_data->is_long, p_status);
    232 
    233     else
    234         *p_status = status;
    235     return act;
    236 }
    237 /*******************************************************************************
    238 **   Service Engine Server Attributes Database write Request process
    239 *******************************************************************************/
    240 UINT8 srvc_eng_process_write_req (UINT8 clcb_idx, tGATT_WRITE_REQ *p_data, tGATTS_RSP *p_rsp, tGATT_STATUS *p_status)
    241 {
    242     UINT8       act = SRVC_ACT_RSP;
    243     UNUSED(p_rsp);
    244 
    245     if (dis_valid_handle_range(p_data->handle))
    246     {
    247         act = dis_write_attr_value(p_data, p_status);
    248     }
    249     else if (battery_valid_handle_range(p_data->handle))
    250     {
    251         act = battery_s_write_attr_value(clcb_idx, p_data, p_status);
    252     }
    253     else
    254         *p_status = GATT_NOT_FOUND;
    255 
    256     return act;
    257 }
    258 
    259 /*******************************************************************************
    260 **
    261 ** Function         srvc_eng_s_request_cback
    262 **
    263 ** Description      GATT DIS attribute access request callback.
    264 **
    265 ** Returns          void.
    266 **
    267 *******************************************************************************/
    268 static void srvc_eng_s_request_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE type,
    269                                         tGATTS_DATA *p_data)
    270 {
    271     UINT8       status = GATT_INVALID_PDU;
    272     tGATTS_RSP  rsp_msg ;
    273     UINT8       act = SRVC_ACT_IGNORE;
    274     UINT8   clcb_idx = srvc_eng_find_clcb_idx_by_conn_id(conn_id);
    275 
    276     GATT_TRACE_EVENT("srvc_eng_s_request_cback : recv type (0x%02x)", type);
    277 
    278     memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
    279 
    280     srvc_eng_cb.clcb[clcb_idx].trans_id = trans_id;
    281 
    282     switch (type)
    283     {
    284         case GATTS_REQ_TYPE_READ:
    285             act = srvc_eng_process_read_req(clcb_idx, &p_data->read_req, &rsp_msg, &status);
    286             break;
    287 
    288         case GATTS_REQ_TYPE_WRITE:
    289             act = srvc_eng_process_write_req(clcb_idx, &p_data->write_req, &rsp_msg, &status);
    290             if (!p_data->write_req.need_rsp)
    291                 act = SRVC_ACT_IGNORE;
    292             break;
    293 
    294         case GATTS_REQ_TYPE_WRITE_EXEC:
    295             GATT_TRACE_EVENT("Ignore GATT_REQ_EXEC_WRITE/WRITE_CMD" );
    296             break;
    297 
    298         case GATTS_REQ_TYPE_MTU:
    299             GATT_TRACE_EVENT("Get MTU exchange new mtu size: %d", p_data->mtu);
    300             break;
    301 
    302         default:
    303             GATT_TRACE_EVENT("Unknown/unexpected LE GAP ATT request: 0x%02x", type);
    304             break;
    305     }
    306 
    307     srvc_eng_cb.clcb[clcb_idx].trans_id = 0;
    308 
    309     if (act == SRVC_ACT_RSP)
    310         GATTS_SendRsp (conn_id, trans_id, status, &rsp_msg);
    311 
    312 
    313 }
    314 
    315 
    316 /*******************************************************************************
    317 **
    318 ** Function         srvc_eng_c_cmpl_cback
    319 **
    320 ** Description      Client operation complete callback.
    321 **
    322 ** Returns          void
    323 **
    324 *******************************************************************************/
    325 static void srvc_eng_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status,
    326                                    tGATT_CL_COMPLETE *p_data)
    327 {
    328     tSRVC_CLCB   *p_clcb = srvc_eng_find_clcb_by_conn_id(conn_id);
    329 
    330     GATT_TRACE_EVENT ("srvc_eng_c_cmpl_cback() - op_code: 0x%02x  status: 0x%02x ", op, status);
    331 
    332     if (p_clcb == NULL)
    333     {
    334         GATT_TRACE_ERROR("srvc_eng_c_cmpl_cback received for unknown connection");
    335         return;
    336     }
    337 
    338     if (p_clcb->cur_srvc_id != SRVC_ID_NONE &&
    339         p_clcb->cur_srvc_id <= SRVC_ID_MAX)
    340         srvc_eng_c_cmpl_act[p_clcb->cur_srvc_id - 1](p_clcb, op, status, p_data);
    341 }
    342 
    343 
    344 /*******************************************************************************
    345 **
    346 ** Function         srvc_eng_connect_cback
    347 **
    348 ** Description      Gatt profile connection callback.
    349 **
    350 ** Returns          void
    351 **
    352 *******************************************************************************/
    353 static void srvc_eng_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id,
    354                                         BOOLEAN connected, tGATT_DISCONN_REASON reason,  tBT_TRANSPORT transport)
    355 {
    356     UNUSED(gatt_if);
    357     UNUSED (transport);
    358 
    359     GATT_TRACE_EVENT ("srvc_eng_connect_cback: from %08x%04x connected:%d conn_id=%d reason = 0x%04x",
    360                        (bda[0]<<24)+(bda[1]<<16)+(bda[2]<<8)+bda[3],
    361                        (bda[4]<<8)+bda[5], connected, conn_id, reason);
    362 
    363     if (connected)
    364     {
    365         if (srvc_eng_clcb_alloc(conn_id, bda) == NULL)
    366         {
    367             GATT_TRACE_ERROR ("srvc_eng_connect_cback: no_resource");
    368             return;
    369         }
    370     }
    371     else
    372     {
    373         srvc_eng_clcb_dealloc(conn_id);
    374     }
    375 
    376 }
    377 /*******************************************************************************
    378 **
    379 ** Function         srvc_eng_c_cmpl_cback
    380 **
    381 ** Description      Client operation complete callback.
    382 **
    383 ** Returns          void
    384 **
    385 *******************************************************************************/
    386 BOOLEAN srvc_eng_request_channel (BD_ADDR remote_bda, UINT8 srvc_id )
    387 {
    388     BOOLEAN set = TRUE;
    389     tSRVC_CLCB  *p_clcb = srvc_eng_find_clcb_by_bd_addr(remote_bda);
    390 
    391     if (p_clcb == NULL)
    392         p_clcb = srvc_eng_clcb_alloc(0, remote_bda);
    393 
    394     if (p_clcb && p_clcb->cur_srvc_id == SRVC_ID_NONE)
    395         p_clcb->cur_srvc_id = srvc_id;
    396     else
    397         set = FALSE;
    398 
    399     return set;
    400 }
    401 /*******************************************************************************
    402 **
    403 ** Function         srvc_eng_release_channel
    404 **
    405 ** Description      Client operation complete callback.
    406 **
    407 ** Returns          void
    408 **
    409 *******************************************************************************/
    410 void srvc_eng_release_channel (UINT16 conn_id)
    411 {
    412     tSRVC_CLCB *p_clcb =  srvc_eng_find_clcb_by_conn_id(conn_id);
    413 
    414     if (p_clcb == NULL)
    415     {
    416         GATT_TRACE_ERROR("%s: invalid connection id %d", __FUNCTION__, conn_id);
    417         return;
    418     }
    419 
    420     p_clcb->cur_srvc_id = SRVC_ID_NONE;
    421 
    422     /* check pending request */
    423     GATT_Disconnect(p_clcb->conn_id);
    424 }
    425 /*******************************************************************************
    426 **
    427 ** Function         srvc_eng_init
    428 **
    429 ** Description      Initializa the GATT Service engine.
    430 **
    431 *******************************************************************************/
    432 tGATT_STATUS srvc_eng_init (void)
    433 {
    434     tBT_UUID          app_uuid = {LEN_UUID_16, {UUID_SERVCLASS_DEVICE_INFO}};
    435 
    436     if (srvc_eng_cb.enabled)
    437     {
    438         GATT_TRACE_ERROR("DIS already initalized");
    439     }
    440     else
    441     {
    442         memset(&srvc_eng_cb, 0, sizeof(tDIS_CB));
    443 
    444         /* Create a GATT profile service */
    445         srvc_eng_cb.gatt_if = GATT_Register(&app_uuid, &srvc_gatt_cback);
    446         GATT_StartIf(srvc_eng_cb.gatt_if);
    447 
    448         GATT_TRACE_DEBUG ("Srvc_Init:  gatt_if=%d  ", srvc_eng_cb.gatt_if);
    449 
    450         srvc_eng_cb.enabled = TRUE;
    451 //#if DIS_INCLUDED == TRUE
    452         dis_cb.dis_read_uuid_idx = 0xff;
    453 //#endif
    454     }
    455     return GATT_SUCCESS;
    456 }
    457 
    458 void srvc_sr_rsp(UINT8 clcb_idx, tGATT_STATUS st, tGATTS_RSP *p_rsp)
    459 {
    460     if (srvc_eng_cb.clcb[clcb_idx].trans_id != 0)
    461     {
    462         GATTS_SendRsp(srvc_eng_cb.clcb[clcb_idx].conn_id,
    463                   srvc_eng_cb.clcb[clcb_idx].trans_id,
    464                   st,
    465                   p_rsp);
    466 
    467         srvc_eng_cb.clcb[clcb_idx].trans_id = 0;
    468     }
    469 }
    470 void srvc_sr_notify(BD_ADDR remote_bda, UINT16 handle, UINT16 len, UINT8 *p_value)
    471 {
    472     UINT16 conn_id = srvc_eng_find_conn_id_by_bd_addr(remote_bda);
    473 
    474     if (conn_id != GATT_INVALID_CONN_ID)
    475     {
    476         GATTS_HandleValueNotification( conn_id, handle, len, p_value);
    477     }
    478 }
    479 
    480 #endif
    481 
    482 
    483 
    484