408 lines
13 KiB
C
408 lines
13 KiB
C
/******************************************************************************
|
|
*
|
|
* Copyright (C) 1999-2013 Broadcom Corporation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at:
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
******************************************************************************/
|
|
|
|
#include "bt_target.h"
|
|
#include "bt_utils.h"
|
|
#include "gatt_api.h"
|
|
#include "gatt_int.h"
|
|
#include "srvc_eng_int.h"
|
|
#include "srvc_battery_int.h"
|
|
|
|
#if BLE_INCLUDED == TRUE
|
|
|
|
#define BA_MAX_CHAR_NUM 1
|
|
#define BA_MAX_ATTR_NUM (BA_MAX_CHAR_NUM * 5 + 1) /* max 3 descriptors, 1 desclration and 1 value */
|
|
|
|
#ifndef BATTER_LEVEL_PROP
|
|
#define BATTER_LEVEL_PROP (GATT_CHAR_PROP_BIT_READ|GATT_CHAR_PROP_BIT_NOTIFY)
|
|
#endif
|
|
|
|
|
|
#ifndef BATTER_LEVEL_PERM
|
|
#define BATTER_LEVEL_PERM (GATT_PERM_READ)
|
|
#endif
|
|
|
|
tBATTERY_CB battery_cb;
|
|
|
|
|
|
/*******************************************************************************
|
|
** battery_valid_handle_range
|
|
**
|
|
** validate a handle to be a DIS attribute handle or not.
|
|
*******************************************************************************/
|
|
BOOLEAN battery_valid_handle_range(UINT16 handle)
|
|
{
|
|
UINT8 i = 0;
|
|
tBA_INST *p_inst = &battery_cb.battery_inst[0];
|
|
|
|
for (;i < BA_MAX_INT_NUM; i ++, p_inst++)
|
|
{
|
|
if (handle == p_inst->ba_level_hdl ||
|
|
handle == p_inst->clt_cfg_hdl ||
|
|
handle == p_inst->rpt_ref_hdl ||
|
|
handle == p_inst->pres_fmt_hdl )
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
/*******************************************************************************
|
|
** battery_s_write_attr_value
|
|
**
|
|
** Process write DIS attribute request.
|
|
*******************************************************************************/
|
|
UINT8 battery_s_write_attr_value(UINT8 clcb_idx, tGATT_WRITE_REQ * p_value,
|
|
tGATT_STATUS *p_status)
|
|
{
|
|
UINT8 *p = p_value->value, i;
|
|
UINT16 handle = p_value->handle;
|
|
tBA_INST *p_inst = &battery_cb.battery_inst[0];
|
|
tGATT_STATUS st = GATT_NOT_FOUND;
|
|
tBA_WRITE_DATA cfg;
|
|
UINT8 act = SRVC_ACT_RSP;
|
|
|
|
for (i = 0; i < BA_MAX_INT_NUM; i ++, p_inst ++)
|
|
{
|
|
/* read battery level */
|
|
if (handle == p_inst->clt_cfg_hdl)
|
|
{
|
|
memcpy(cfg.remote_bda, srvc_eng_cb.clcb[clcb_idx].bda, BD_ADDR_LEN);
|
|
STREAM_TO_UINT16(cfg.clt_cfg, p);
|
|
|
|
if (p_inst->p_cback)
|
|
{
|
|
p_inst->pending_clcb_idx = clcb_idx;
|
|
p_inst->pending_evt = BA_WRITE_CLT_CFG_REQ;
|
|
p_inst->pending_handle = handle;
|
|
cfg.need_rsp = p_value->need_rsp;
|
|
act = SRVC_ACT_PENDING;
|
|
|
|
(* p_inst->p_cback)(p_inst->app_id, BA_WRITE_CLT_CFG_REQ, &cfg);
|
|
}
|
|
}
|
|
else /* all other handle is not writable */
|
|
{
|
|
st = GATT_WRITE_NOT_PERMIT;
|
|
break;
|
|
}
|
|
}
|
|
*p_status = st;
|
|
|
|
return act;
|
|
}
|
|
/*******************************************************************************
|
|
** BA Attributes Database Server Request callback
|
|
*******************************************************************************/
|
|
UINT8 battery_s_read_attr_value (UINT8 clcb_idx, UINT16 handle, tGATT_VALUE *p_value, BOOLEAN is_long, tGATT_STATUS* p_status)
|
|
{
|
|
UINT8 i;
|
|
tBA_INST *p_inst = &battery_cb.battery_inst[0];
|
|
tGATT_STATUS st = GATT_NOT_FOUND;
|
|
UINT8 act = SRVC_ACT_RSP;
|
|
UNUSED(p_value);
|
|
|
|
for (i = 0; i < BA_MAX_INT_NUM; i ++, p_inst ++)
|
|
{
|
|
/* read battery level */
|
|
if (handle == p_inst->ba_level_hdl ||
|
|
handle == p_inst->clt_cfg_hdl ||
|
|
handle == p_inst->rpt_ref_hdl ||
|
|
handle == p_inst->pres_fmt_hdl)
|
|
{
|
|
if (is_long)
|
|
st = GATT_NOT_LONG;
|
|
|
|
if (p_inst->p_cback)
|
|
{
|
|
if (handle == p_inst->ba_level_hdl) p_inst->pending_evt = BA_READ_LEVEL_REQ;
|
|
if (handle == p_inst->clt_cfg_hdl) p_inst->pending_evt = BA_READ_CLT_CFG_REQ;
|
|
if (handle == p_inst->pres_fmt_hdl) p_inst->pending_evt = BA_READ_PRE_FMT_REQ;
|
|
if (handle == p_inst->rpt_ref_hdl) p_inst->pending_evt = BA_READ_RPT_REF_REQ ;
|
|
|
|
p_inst->pending_clcb_idx = clcb_idx;
|
|
p_inst->pending_handle = handle;
|
|
act = SRVC_ACT_PENDING;
|
|
|
|
(* p_inst->p_cback)(p_inst->app_id, p_inst->pending_evt, NULL);
|
|
}
|
|
else /* application is not registered */
|
|
st = GATT_ERR_UNLIKELY;
|
|
break;
|
|
}
|
|
/* else attribute not found */
|
|
}
|
|
|
|
|
|
*p_status = st;
|
|
return act;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function battery_gatt_c_read_ba_req
|
|
**
|
|
** Description Read remote device BA level attribute request.
|
|
**
|
|
** Returns void
|
|
**
|
|
*******************************************************************************/
|
|
BOOLEAN battery_gatt_c_read_ba_req(UINT16 conn_id)
|
|
{
|
|
UNUSED(conn_id);
|
|
return TRUE;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function battery_c_cmpl_cback
|
|
**
|
|
** Description Client operation complete callback.
|
|
**
|
|
** Returns void
|
|
**
|
|
*******************************************************************************/
|
|
void battery_c_cmpl_cback (tSRVC_CLCB *p_clcb, tGATTC_OPTYPE op,
|
|
tGATT_STATUS status, tGATT_CL_COMPLETE *p_data)
|
|
{
|
|
UNUSED(p_clcb);
|
|
UNUSED(op);
|
|
UNUSED(status);
|
|
UNUSED(p_data);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** Function Battery_Instantiate
|
|
**
|
|
** Description Instantiate a Battery service
|
|
**
|
|
*******************************************************************************/
|
|
UINT16 Battery_Instantiate (UINT8 app_id, tBA_REG_INFO *p_reg_info)
|
|
{
|
|
tBT_UUID uuid = {LEN_UUID_16, {UUID_SERVCLASS_BATTERY}};
|
|
UINT16 srvc_hdl;
|
|
tGATT_STATUS status = GATT_ERROR;
|
|
tBA_INST *p_inst;
|
|
tGATT_CHAR_PROP prop = GATT_CHAR_PROP_BIT_READ;
|
|
|
|
if (battery_cb.inst_id >= BA_MAX_INT_NUM)
|
|
{
|
|
GATT_TRACE_ERROR("MAX battery service has been reached");
|
|
return 0;
|
|
}
|
|
|
|
p_inst = &battery_cb.battery_inst[battery_cb.inst_id];
|
|
|
|
srvc_hdl = GATTS_CreateService (srvc_eng_cb.gatt_if ,
|
|
&uuid,
|
|
battery_cb.inst_id ,
|
|
BA_MAX_ATTR_NUM,
|
|
p_reg_info->is_pri);
|
|
|
|
if (srvc_hdl == 0)
|
|
{
|
|
GATT_TRACE_ERROR("Can not create service, Battery_Instantiate() failed!");
|
|
return 0;
|
|
}
|
|
|
|
battery_cb.inst_id ++;
|
|
|
|
p_inst->app_id = app_id;
|
|
p_inst->p_cback = p_reg_info->p_cback;
|
|
|
|
/* add battery level
|
|
*/
|
|
uuid.uu.uuid16 = GATT_UUID_BATTERY_LEVEL;
|
|
|
|
if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY)
|
|
prop |= GATT_CHAR_PROP_BIT_NOTIFY;
|
|
|
|
if ((p_inst->ba_level_hdl = GATTS_AddCharacteristic(srvc_hdl,
|
|
&uuid,
|
|
BATTER_LEVEL_PERM,
|
|
prop)) == 0)
|
|
{
|
|
GATT_TRACE_ERROR("Can not add Battery Level, Battery_Instantiate() failed!");
|
|
status = GATT_ERROR;
|
|
}
|
|
else
|
|
{
|
|
if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY)
|
|
{
|
|
uuid.uu.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG;
|
|
p_inst->clt_cfg_hdl = GATTS_AddCharDescriptor(srvc_hdl,
|
|
(GATT_PERM_READ|GATT_PERM_WRITE),
|
|
&uuid);
|
|
if (p_inst->clt_cfg_hdl == 0)
|
|
{
|
|
GATT_TRACE_ERROR("Add battery level client notification FAILED!");
|
|
}
|
|
}
|
|
/* need presentation format descriptor? */
|
|
if (p_reg_info->ba_level_descr & BA_LEVEL_PRE_FMT)
|
|
{
|
|
uuid.uu.uuid16 = GATT_UUID_CHAR_PRESENT_FORMAT;
|
|
if ( (p_inst->pres_fmt_hdl = GATTS_AddCharDescriptor(srvc_hdl,
|
|
GATT_PERM_READ,
|
|
&uuid))
|
|
== 0)
|
|
{
|
|
GATT_TRACE_ERROR("Add battery level presentation format descriptor FAILED!");
|
|
}
|
|
|
|
}
|
|
/* need presentation format descriptor? */
|
|
if (p_reg_info->ba_level_descr & BA_LEVEL_RPT_REF)
|
|
{
|
|
uuid.uu.uuid16 = GATT_UUID_RPT_REF_DESCR;
|
|
if ( (p_inst->rpt_ref_hdl = GATTS_AddCharDescriptor(srvc_hdl,
|
|
GATT_PERM_READ,
|
|
&uuid))
|
|
== 0)
|
|
{
|
|
GATT_TRACE_ERROR("Add battery level report reference descriptor FAILED!");
|
|
}
|
|
|
|
}
|
|
/* start service
|
|
*/
|
|
status = GATTS_StartService (srvc_eng_cb.gatt_if, srvc_hdl, p_reg_info->transport);
|
|
}
|
|
|
|
if (status != GATT_SUCCESS)
|
|
{
|
|
battery_cb.inst_id --;
|
|
uuid.uu.uuid16 = UUID_SERVCLASS_BATTERY;
|
|
GATTS_DeleteService(srvc_eng_cb.gatt_if, &uuid, battery_cb.inst_id);
|
|
srvc_hdl = 0;
|
|
}
|
|
|
|
return srvc_hdl;
|
|
}
|
|
/*******************************************************************************
|
|
**
|
|
** Function Battery_Rsp
|
|
**
|
|
** Description Respond to a battery service request
|
|
**
|
|
*******************************************************************************/
|
|
void Battery_Rsp (UINT8 app_id, tGATT_STATUS st, UINT8 event, tBA_RSP_DATA *p_rsp)
|
|
{
|
|
tBA_INST *p_inst = &battery_cb.battery_inst[0];
|
|
tGATTS_RSP rsp;
|
|
UINT8 *pp;
|
|
|
|
UINT8 i = 0;
|
|
while (i < BA_MAX_INT_NUM)
|
|
{
|
|
if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0)
|
|
break;
|
|
i ++;
|
|
}
|
|
|
|
if (i == BA_MAX_INT_NUM)
|
|
return;
|
|
|
|
memset(&rsp, 0, sizeof(tGATTS_RSP));
|
|
|
|
if (p_inst->pending_evt == event)
|
|
{
|
|
switch (event)
|
|
{
|
|
case BA_READ_CLT_CFG_REQ:
|
|
rsp.attr_value.handle = p_inst->pending_handle;
|
|
rsp.attr_value.len = 2;
|
|
pp = rsp.attr_value.value;
|
|
UINT16_TO_STREAM(pp, p_rsp->clt_cfg);
|
|
srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
|
|
break;
|
|
|
|
case BA_READ_LEVEL_REQ:
|
|
rsp.attr_value.handle = p_inst->pending_handle;
|
|
rsp.attr_value.len = 1;
|
|
pp = rsp.attr_value.value;
|
|
UINT8_TO_STREAM(pp, p_rsp->ba_level);
|
|
srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
|
|
break;
|
|
|
|
case BA_WRITE_CLT_CFG_REQ:
|
|
srvc_sr_rsp(p_inst->pending_clcb_idx, st, NULL);
|
|
break;
|
|
|
|
case BA_READ_RPT_REF_REQ:
|
|
rsp.attr_value.handle = p_inst->pending_handle;
|
|
rsp.attr_value.len = 2;
|
|
pp = rsp.attr_value.value;
|
|
UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_id);
|
|
UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_type);
|
|
srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
p_inst->pending_clcb_idx = 0;
|
|
p_inst->pending_evt = 0;
|
|
p_inst->pending_handle = 0;
|
|
}
|
|
return;
|
|
}
|
|
/*******************************************************************************
|
|
**
|
|
** Function Battery_Notify
|
|
**
|
|
** Description Send battery level notification
|
|
**
|
|
*******************************************************************************/
|
|
void Battery_Notify (UINT8 app_id, BD_ADDR remote_bda, UINT8 battery_level)
|
|
{
|
|
tBA_INST *p_inst = &battery_cb.battery_inst[0];
|
|
UINT8 i = 0;
|
|
|
|
while (i < BA_MAX_INT_NUM)
|
|
{
|
|
if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0)
|
|
break;
|
|
i ++;
|
|
}
|
|
|
|
if (i == BA_MAX_INT_NUM || p_inst->clt_cfg_hdl == 0)
|
|
return;
|
|
|
|
srvc_sr_notify(remote_bda, p_inst->ba_level_hdl, 1, &battery_level);
|
|
|
|
}
|
|
/*******************************************************************************
|
|
**
|
|
** Function Battery_ReadBatteryLevel
|
|
**
|
|
** Description Read remote device Battery Level information.
|
|
**
|
|
** Returns void
|
|
**
|
|
*******************************************************************************/
|
|
BOOLEAN Battery_ReadBatteryLevel(BD_ADDR peer_bda)
|
|
{
|
|
UNUSED(peer_bda);
|
|
/* to be implemented */
|
|
return TRUE;
|
|
}
|
|
#endif /* BLE_INCLUDED */
|