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