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 #include "srvc_battery_int.h"
     25 
     26 #if BLE_INCLUDED == TRUE
     27 
     28 #define BA_MAX_CHAR_NUM          1
     29 #define BA_MAX_ATTR_NUM          (BA_MAX_CHAR_NUM * 5 + 1) /* max 3 descriptors, 1 desclration and 1 value */
     30 
     31 #ifndef BATTER_LEVEL_PROP
     32 #define BATTER_LEVEL_PROP           (GATT_CHAR_PROP_BIT_READ|GATT_CHAR_PROP_BIT_NOTIFY)
     33 #endif
     34 
     35 
     36 #ifndef BATTER_LEVEL_PERM
     37 #define BATTER_LEVEL_PERM           (GATT_PERM_READ)
     38 #endif
     39 
     40 tBATTERY_CB battery_cb;
     41 
     42 
     43 /*******************************************************************************
     44 **   battery_valid_handle_range
     45 **
     46 **   validate a handle to be a DIS attribute handle or not.
     47 *******************************************************************************/
     48 BOOLEAN battery_valid_handle_range(UINT16 handle)
     49 {
     50     UINT8       i = 0;
     51     tBA_INST    *p_inst = &battery_cb.battery_inst[0];
     52 
     53     for (;i < BA_MAX_INT_NUM; i ++, p_inst++)
     54     {
     55         if (handle == p_inst->ba_level_hdl ||
     56             handle == p_inst->clt_cfg_hdl ||
     57             handle == p_inst->rpt_ref_hdl ||
     58             handle == p_inst->pres_fmt_hdl )
     59         {
     60             return TRUE;
     61         }
     62     }
     63     return FALSE;
     64 }
     65 /*******************************************************************************
     66 **   battery_s_write_attr_value
     67 **
     68 **   Process write DIS attribute request.
     69 *******************************************************************************/
     70 UINT8 battery_s_write_attr_value(UINT8 clcb_idx, tGATT_WRITE_REQ * p_value,
     71                                  tGATT_STATUS *p_status)
     72 {
     73     UINT8       *p = p_value->value, i;
     74     UINT16      handle = p_value->handle;
     75     tBA_INST    *p_inst = &battery_cb.battery_inst[0];
     76     tGATT_STATUS    st = GATT_NOT_FOUND;
     77     tBA_WRITE_DATA   cfg;
     78     UINT8       act = SRVC_ACT_RSP;
     79 
     80     for (i = 0; i < BA_MAX_INT_NUM; i ++, p_inst ++)
     81     {
     82         /* read battery level */
     83         if (handle == p_inst->clt_cfg_hdl)
     84         {
     85             memcpy(cfg.remote_bda, srvc_eng_cb.clcb[clcb_idx].bda, BD_ADDR_LEN);
     86             STREAM_TO_UINT16(cfg.clt_cfg, p);
     87 
     88             if (p_inst->p_cback)
     89             {
     90                 p_inst->pending_clcb_idx = clcb_idx;
     91                 p_inst->pending_evt = BA_WRITE_CLT_CFG_REQ;
     92                 p_inst->pending_handle = handle;
     93                 cfg.need_rsp = p_value->need_rsp;
     94                 act = SRVC_ACT_PENDING;
     95 
     96                 (* p_inst->p_cback)(p_inst->app_id, BA_WRITE_CLT_CFG_REQ, &cfg);
     97             }
     98         }
     99         else /* all other handle is not writable */
    100         {
    101             st = GATT_WRITE_NOT_PERMIT;
    102             break;
    103         }
    104     }
    105     *p_status = st;
    106 
    107     return act;
    108 }
    109 /*******************************************************************************
    110 **   BA Attributes Database Server Request callback
    111 *******************************************************************************/
    112 UINT8 battery_s_read_attr_value (UINT8 clcb_idx, UINT16 handle, tGATT_VALUE *p_value, BOOLEAN is_long, tGATT_STATUS* p_status)
    113 {
    114     UINT8       i;
    115     tBA_INST    *p_inst = &battery_cb.battery_inst[0];
    116     tGATT_STATUS    st = GATT_NOT_FOUND;
    117     UINT8       act = SRVC_ACT_RSP;
    118     UNUSED(p_value);
    119 
    120     for (i = 0; i < BA_MAX_INT_NUM; i ++, p_inst ++)
    121     {
    122         /* read battery level */
    123         if (handle == p_inst->ba_level_hdl ||
    124             handle == p_inst->clt_cfg_hdl ||
    125             handle == p_inst->rpt_ref_hdl ||
    126             handle == p_inst->pres_fmt_hdl)
    127             {
    128             if (is_long)
    129                 st = GATT_NOT_LONG;
    130 
    131                 if (p_inst->p_cback)
    132                 {
    133                 if (handle == p_inst->ba_level_hdl) p_inst->pending_evt = BA_READ_LEVEL_REQ;
    134                 if (handle == p_inst->clt_cfg_hdl) p_inst->pending_evt = BA_READ_CLT_CFG_REQ;
    135                 if (handle == p_inst->pres_fmt_hdl) p_inst->pending_evt = BA_READ_PRE_FMT_REQ;
    136                 if (handle == p_inst->rpt_ref_hdl) p_inst->pending_evt = BA_READ_RPT_REF_REQ ;
    137 
    138                     p_inst->pending_clcb_idx = clcb_idx;
    139                     p_inst->pending_handle = handle;
    140                     act = SRVC_ACT_PENDING;
    141 
    142                 (* p_inst->p_cback)(p_inst->app_id, p_inst->pending_evt, NULL);
    143                 }
    144             else /* application is not registered */
    145                 st = GATT_ERR_UNLIKELY;
    146                 break;
    147             }
    148         /* else attribute not found */
    149     }
    150 
    151 
    152     *p_status = st;
    153     return act;
    154 }
    155 
    156 
    157 /*******************************************************************************
    158 **
    159 ** Function         battery_gatt_c_read_ba_req
    160 **
    161 ** Description      Read remote device BA level attribute request.
    162 **
    163 ** Returns          void
    164 **
    165 *******************************************************************************/
    166 BOOLEAN battery_gatt_c_read_ba_req(UINT16 conn_id)
    167 {
    168     UNUSED(conn_id);
    169     return TRUE;
    170 }
    171 
    172 /*******************************************************************************
    173 **
    174 ** Function         battery_c_cmpl_cback
    175 **
    176 ** Description      Client operation complete callback.
    177 **
    178 ** Returns          void
    179 **
    180 *******************************************************************************/
    181 void battery_c_cmpl_cback (tSRVC_CLCB *p_clcb, tGATTC_OPTYPE op,
    182                               tGATT_STATUS status, tGATT_CL_COMPLETE *p_data)
    183 {
    184     UNUSED(p_clcb);
    185     UNUSED(op);
    186     UNUSED(status);
    187     UNUSED(p_data);
    188 }
    189 
    190 
    191 /*******************************************************************************
    192 **
    193 ** Function         Battery_Instantiate
    194 **
    195 ** Description      Instantiate a Battery service
    196 **
    197 *******************************************************************************/
    198 UINT16 Battery_Instantiate (UINT8 app_id, tBA_REG_INFO *p_reg_info)
    199 {
    200     tBT_UUID            uuid = {LEN_UUID_16, {UUID_SERVCLASS_BATTERY}};
    201     UINT16              srvc_hdl;
    202     tGATT_STATUS        status = GATT_ERROR;
    203     tBA_INST            *p_inst;
    204     tGATT_CHAR_PROP     prop = GATT_CHAR_PROP_BIT_READ;
    205 
    206     if (battery_cb.inst_id == BA_MAX_INT_NUM)
    207     {
    208         GATT_TRACE_ERROR("MAX battery service has been reached");
    209         return 0;
    210     }
    211 
    212     p_inst = &battery_cb.battery_inst[battery_cb.inst_id];
    213 
    214     srvc_hdl = GATTS_CreateService (srvc_eng_cb.gatt_if ,
    215                                             &uuid,
    216                                             battery_cb.inst_id ,
    217                                             BA_MAX_ATTR_NUM,
    218                                             p_reg_info->is_pri);
    219 
    220     if (srvc_hdl == 0)
    221     {
    222         GATT_TRACE_ERROR("Can not create service, Battery_Instantiate() failed!");
    223         return 0;
    224     }
    225 
    226     battery_cb.inst_id ++;
    227 
    228     p_inst->app_id  =   app_id;
    229     p_inst->p_cback =   p_reg_info->p_cback;
    230 
    231     /* add battery level
    232     */
    233     uuid.uu.uuid16 = GATT_UUID_BATTERY_LEVEL;
    234 
    235     if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY)
    236         prop |= GATT_CHAR_PROP_BIT_NOTIFY;
    237 
    238     if ((p_inst->ba_level_hdl  = GATTS_AddCharacteristic(srvc_hdl,
    239                                                 &uuid,
    240                                                 BATTER_LEVEL_PERM,
    241                                                 prop)) == 0)
    242     {
    243         GATT_TRACE_ERROR("Can not add Battery Level, Battery_Instantiate() failed!");
    244         status = GATT_ERROR;
    245     }
    246     else
    247     {
    248         if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY)
    249         {
    250             uuid.uu.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG;
    251             p_inst->clt_cfg_hdl  = GATTS_AddCharDescriptor(srvc_hdl,
    252                                                            (GATT_PERM_READ|GATT_PERM_WRITE),
    253                                                            &uuid);
    254             if (p_inst->clt_cfg_hdl == 0)
    255             {
    256                 GATT_TRACE_ERROR("Add battery level client notification FAILED!");
    257             }
    258         }
    259         /* need presentation format descriptor? */
    260         if (p_reg_info->ba_level_descr & BA_LEVEL_PRE_FMT)
    261         {
    262             uuid.uu.uuid16 = GATT_UUID_CHAR_PRESENT_FORMAT;
    263             if ( (p_inst->pres_fmt_hdl = GATTS_AddCharDescriptor(srvc_hdl,
    264                                                                  GATT_PERM_READ,
    265                                                                  &uuid))
    266                                        == 0)
    267             {
    268                 GATT_TRACE_ERROR("Add battery level presentation format descriptor FAILED!");
    269             }
    270 
    271         }
    272         /* need presentation format descriptor? */
    273         if (p_reg_info->ba_level_descr & BA_LEVEL_RPT_REF)
    274         {
    275             uuid.uu.uuid16 = GATT_UUID_RPT_REF_DESCR;
    276             if ( (p_inst->rpt_ref_hdl = GATTS_AddCharDescriptor(srvc_hdl,
    277                                                                 GATT_PERM_READ,
    278                                                                 &uuid))
    279                                        == 0)
    280             {
    281                 GATT_TRACE_ERROR("Add battery level report reference descriptor FAILED!");
    282             }
    283 
    284         }
    285         /* start service
    286         */
    287         status = GATTS_StartService (srvc_eng_cb.gatt_if, srvc_hdl, p_reg_info->transport);
    288     }
    289 
    290     if (status != GATT_SUCCESS)
    291     {
    292         battery_cb.inst_id --;
    293         uuid.uu.uuid16 = UUID_SERVCLASS_BATTERY;
    294         GATTS_DeleteService(srvc_eng_cb.gatt_if, &uuid, battery_cb.inst_id);
    295         srvc_hdl = 0;
    296     }
    297 
    298     return srvc_hdl;
    299 }
    300 /*******************************************************************************
    301 **
    302 ** Function         Battery_Rsp
    303 **
    304 ** Description      Respond to a battery service request
    305 **
    306 *******************************************************************************/
    307 void Battery_Rsp (UINT8 app_id, tGATT_STATUS st, UINT8 event, tBA_RSP_DATA *p_rsp)
    308 {
    309     tBA_INST *p_inst = &battery_cb.battery_inst[0];
    310     tGATTS_RSP  rsp;
    311     UINT8   *pp;
    312 
    313     UINT8   i = 0;
    314     while (i < BA_MAX_INT_NUM)
    315     {
    316         if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0)
    317             break;
    318         i ++;
    319     }
    320 
    321     if (i == BA_MAX_INT_NUM)
    322         return;
    323 
    324     memset(&rsp, 0, sizeof(tGATTS_RSP));
    325 
    326     if (p_inst->pending_evt == event)
    327     {
    328         switch (event)
    329         {
    330         case BA_READ_CLT_CFG_REQ:
    331             rsp.attr_value.handle = p_inst->pending_handle;
    332             rsp.attr_value.len = 2;
    333             pp = rsp.attr_value.value;
    334             UINT16_TO_STREAM(pp, p_rsp->clt_cfg);
    335             srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
    336             break;
    337 
    338         case BA_READ_LEVEL_REQ:
    339             rsp.attr_value.handle = p_inst->pending_handle;
    340             rsp.attr_value.len = 1;
    341             pp = rsp.attr_value.value;
    342             UINT8_TO_STREAM(pp, p_rsp->ba_level);
    343             srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
    344             break;
    345 
    346         case BA_WRITE_CLT_CFG_REQ:
    347             srvc_sr_rsp(p_inst->pending_clcb_idx, st, NULL);
    348             break;
    349 
    350         case BA_READ_RPT_REF_REQ:
    351             rsp.attr_value.handle = p_inst->pending_handle;
    352             rsp.attr_value.len = 2;
    353             pp = rsp.attr_value.value;
    354             UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_id);
    355             UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_type);
    356             srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
    357             break;
    358 
    359         default:
    360             break;
    361         }
    362         p_inst->pending_clcb_idx = 0;
    363         p_inst->pending_evt = 0;
    364         p_inst->pending_handle = 0;
    365     }
    366     return;
    367 }
    368 /*******************************************************************************
    369 **
    370 ** Function         Battery_Notify
    371 **
    372 ** Description      Send battery level notification
    373 **
    374 *******************************************************************************/
    375 void Battery_Notify (UINT8 app_id, BD_ADDR remote_bda, UINT8 battery_level)
    376 {
    377     tBA_INST *p_inst = &battery_cb.battery_inst[0];
    378     UINT8    i = 0;
    379 
    380     while (i < BA_MAX_INT_NUM)
    381     {
    382         if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0)
    383             break;
    384         i ++;
    385     }
    386 
    387     if (i == BA_MAX_INT_NUM || p_inst->clt_cfg_hdl == 0)
    388         return;
    389 
    390     srvc_sr_notify(remote_bda, p_inst->ba_level_hdl, 1, &battery_level);
    391 
    392 }
    393 /*******************************************************************************
    394 **
    395 ** Function         Battery_ReadBatteryLevel
    396 **
    397 ** Description      Read remote device Battery Level information.
    398 **
    399 ** Returns          void
    400 **
    401 *******************************************************************************/
    402 BOOLEAN Battery_ReadBatteryLevel(BD_ADDR peer_bda)
    403 {
    404     UNUSED(peer_bda);
    405     /* to be implemented */
    406     return TRUE;
    407 }
    408 #endif  /* BLE_INCLUDED */
    409