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 #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 
    119         for (i = 0; i < BA_MAX_INT_NUM; i ++, p_inst ++)
    120         {
    121             /* read battery level */
    122         if (handle == p_inst->ba_level_hdl ||
    123             handle == p_inst->clt_cfg_hdl ||
    124             handle == p_inst->rpt_ref_hdl ||
    125             handle == p_inst->pres_fmt_hdl)
    126             {
    127             if (is_long)
    128                 st = GATT_NOT_LONG;
    129 
    130                 if (p_inst->p_cback)
    131                 {
    132                 if (handle == p_inst->ba_level_hdl) p_inst->pending_evt = BA_READ_LEVEL_REQ;
    133                 if (handle == p_inst->clt_cfg_hdl) p_inst->pending_evt = BA_READ_CLT_CFG_REQ;
    134                 if (handle == p_inst->pres_fmt_hdl) p_inst->pending_evt = BA_READ_PRE_FMT_REQ;
    135                 if (handle == p_inst->rpt_ref_hdl) p_inst->pending_evt = BA_READ_RPT_REF_REQ ;
    136 
    137                     p_inst->pending_clcb_idx = clcb_idx;
    138                     p_inst->pending_handle = handle;
    139                     act = SRVC_ACT_PENDING;
    140 
    141                 (* p_inst->p_cback)(p_inst->app_id, p_inst->pending_evt, NULL);
    142                 }
    143             else /* application is not registered */
    144                 st = GATT_ERR_UNLIKELY;
    145                 break;
    146             }
    147         /* else attribute not found */
    148     }
    149 
    150 
    151     *p_status = st;
    152     return act;
    153 }
    154 
    155 
    156 /*******************************************************************************
    157 **
    158 ** Function         battery_gatt_c_read_ba_req
    159 **
    160 ** Description      Read remote device BA level attribute request.
    161 **
    162 ** Returns          void
    163 **
    164 *******************************************************************************/
    165 BOOLEAN battery_gatt_c_read_ba_req(UINT16 conn_id)
    166 {
    167     return TRUE;
    168 }
    169 
    170 /*******************************************************************************
    171 **
    172 ** Function         battery_c_cmpl_cback
    173 **
    174 ** Description      Client operation complete callback.
    175 **
    176 ** Returns          void
    177 **
    178 *******************************************************************************/
    179 void battery_c_cmpl_cback (tSRVC_CLCB *p_clcb, tGATTC_OPTYPE op,
    180                               tGATT_STATUS status, tGATT_CL_COMPLETE *p_data)
    181 {
    182 }
    183 
    184 
    185 /*******************************************************************************
    186 **
    187 ** Function         Battery_Instantiate
    188 **
    189 ** Description      Instantiate a Battery service
    190 **
    191 *******************************************************************************/
    192 UINT16 Battery_Instantiate (UINT8 app_id, tBA_REG_INFO *p_reg_info)
    193 {
    194     tBT_UUID            uuid = {LEN_UUID_16, {UUID_SERVCLASS_BATTERY}};
    195     UINT16              srvc_hdl;
    196     tGATT_STATUS        status = GATT_ERROR;
    197     tBA_INST            *p_inst;
    198     tGATT_CHAR_PROP     prop = GATT_CHAR_PROP_BIT_READ;
    199 
    200     if (battery_cb.inst_id == BA_MAX_INT_NUM)
    201     {
    202         GATT_TRACE_ERROR0("MAX battery service has been reached");
    203         return 0;
    204     }
    205 
    206     p_inst = &battery_cb.battery_inst[battery_cb.inst_id];
    207 
    208     srvc_hdl = GATTS_CreateService (srvc_eng_cb.gatt_if ,
    209                                             &uuid,
    210                                             battery_cb.inst_id ,
    211                                             BA_MAX_ATTR_NUM,
    212                                             p_reg_info->is_pri);
    213 
    214     if (srvc_hdl == 0)
    215     {
    216         GATT_TRACE_ERROR0("Can not create service, Battery_Instantiate() failed!");
    217         return 0;
    218     }
    219 
    220     battery_cb.inst_id ++;
    221 
    222     p_inst->app_id  =   app_id;
    223     p_inst->p_cback =   p_reg_info->p_cback;
    224 
    225     /* add battery level
    226     */
    227     uuid.uu.uuid16 = GATT_UUID_BATTERY_LEVEL;
    228 
    229     if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY)
    230         prop |= GATT_CHAR_PROP_BIT_NOTIFY;
    231 
    232     if ((p_inst->ba_level_hdl  = GATTS_AddCharacteristic(srvc_hdl,
    233                                                 &uuid,
    234                                                 BATTER_LEVEL_PERM,
    235                                                 prop)) == 0)
    236     {
    237         GATT_TRACE_ERROR0("Can not add Battery Level, Battery_Instantiate() failed!");
    238         status = GATT_ERROR;
    239     }
    240     else
    241     {
    242         if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY)
    243         {
    244             uuid.uu.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG;
    245             p_inst->clt_cfg_hdl  = GATTS_AddCharDescriptor(srvc_hdl,
    246                                                            (GATT_PERM_READ|GATT_PERM_WRITE),
    247                                                            &uuid);
    248             if (p_inst->clt_cfg_hdl == 0)
    249             {
    250                 GATT_TRACE_ERROR0("Add battery level client notification FAILED!");
    251             }
    252         }
    253         /* need presentation format descriptor? */
    254         if (p_reg_info->ba_level_descr & BA_LEVEL_PRE_FMT)
    255         {
    256             uuid.uu.uuid16 = GATT_UUID_CHAR_PRESENT_FORMAT;
    257             if ( (p_inst->pres_fmt_hdl = GATTS_AddCharDescriptor(srvc_hdl,
    258                                                                  GATT_PERM_READ,
    259                                                                  &uuid))
    260                                        == 0)
    261             {
    262                 GATT_TRACE_ERROR0("Add battery level presentation format descriptor FAILED!");
    263             }
    264 
    265         }
    266         /* need presentation format descriptor? */
    267         if (p_reg_info->ba_level_descr & BA_LEVEL_RPT_REF)
    268         {
    269             uuid.uu.uuid16 = GATT_UUID_RPT_REF_DESCR;
    270             if ( (p_inst->rpt_ref_hdl = GATTS_AddCharDescriptor(srvc_hdl,
    271                                                                 GATT_PERM_READ,
    272                                                                 &uuid))
    273                                        == 0)
    274             {
    275                 GATT_TRACE_ERROR0("Add battery level report reference descriptor FAILED!");
    276             }
    277 
    278         }
    279         /* start service
    280         */
    281         status = GATTS_StartService (srvc_eng_cb.gatt_if, srvc_hdl, p_reg_info->transport);
    282     }
    283 
    284     if (status != GATT_SUCCESS)
    285     {
    286         battery_cb.inst_id --;
    287         uuid.uu.uuid16 = UUID_SERVCLASS_BATTERY;
    288         GATTS_DeleteService(srvc_eng_cb.gatt_if, &uuid, battery_cb.inst_id);
    289         srvc_hdl = 0;
    290     }
    291 
    292     return srvc_hdl;
    293 }
    294 /*******************************************************************************
    295 **
    296 ** Function         Battery_Rsp
    297 **
    298 ** Description      Respond to a battery service request
    299 **
    300 *******************************************************************************/
    301 void Battery_Rsp (UINT8 app_id, tGATT_STATUS st, UINT8 event, tBA_RSP_DATA *p_rsp)
    302 {
    303     tBA_INST *p_inst = &battery_cb.battery_inst[0];
    304     tGATTS_RSP  rsp;
    305     UINT8   *pp;
    306 
    307     UINT8   i = 0;
    308     while (i < BA_MAX_INT_NUM)
    309     {
    310         if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0)
    311             break;
    312         i ++;
    313     }
    314 
    315     if (i == BA_MAX_INT_NUM)
    316         return;
    317 
    318     memset(&rsp, 0, sizeof(tGATTS_RSP));
    319 
    320     if (p_inst->pending_evt == event)
    321     {
    322         switch (event)
    323         {
    324         case BA_READ_CLT_CFG_REQ:
    325             rsp.attr_value.handle = p_inst->pending_handle;
    326             rsp.attr_value.len = 2;
    327             pp = rsp.attr_value.value;
    328             UINT16_TO_STREAM(pp, p_rsp->clt_cfg);
    329             srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
    330             break;
    331 
    332         case BA_READ_LEVEL_REQ:
    333             rsp.attr_value.handle = p_inst->pending_handle;
    334             rsp.attr_value.len = 1;
    335             pp = rsp.attr_value.value;
    336             UINT8_TO_STREAM(pp, p_rsp->ba_level);
    337             srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
    338             break;
    339 
    340         case BA_WRITE_CLT_CFG_REQ:
    341             srvc_sr_rsp(p_inst->pending_clcb_idx, st, NULL);
    342             break;
    343 
    344         case BA_READ_RPT_REF_REQ:
    345             rsp.attr_value.handle = p_inst->pending_handle;
    346             rsp.attr_value.len = 2;
    347             pp = rsp.attr_value.value;
    348             UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_id);
    349             UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_type);
    350             srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
    351             break;
    352 
    353         default:
    354             break;
    355         }
    356         p_inst->pending_clcb_idx = 0;
    357         p_inst->pending_evt = 0;
    358         p_inst->pending_handle = 0;
    359     }
    360     return;
    361 }
    362 /*******************************************************************************
    363 **
    364 ** Function         Battery_Notify
    365 **
    366 ** Description      Send battery level notification
    367 **
    368 *******************************************************************************/
    369 void Battery_Notify (UINT8 app_id, BD_ADDR remote_bda, UINT8 battery_level)
    370 {
    371     tBA_INST *p_inst = &battery_cb.battery_inst[0];
    372     UINT8    i = 0;
    373 
    374     while (i < BA_MAX_INT_NUM)
    375     {
    376         if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0)
    377             break;
    378         i ++;
    379     }
    380 
    381     if (i == BA_MAX_INT_NUM || p_inst->clt_cfg_hdl == 0)
    382         return;
    383 
    384     srvc_sr_notify(remote_bda, p_inst->ba_level_hdl, 1, &battery_level);
    385 
    386 }
    387 /*******************************************************************************
    388 **
    389 ** Function         Battery_ReadBatteryLevel
    390 **
    391 ** Description      Read remote device Battery Level information.
    392 **
    393 ** Returns          void
    394 **
    395 *******************************************************************************/
    396 BOOLEAN Battery_ReadBatteryLevel(BD_ADDR peer_bda)
    397 {
    398     /* to be implemented */
    399     return TRUE;
    400 }
    401 #endif  /* BLE_INCLUDED */
    402