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