blob: 21b10aa48764f4fcf45287c7014e469a21f24780 [file] [log] [blame]
/******************************************************************************
*
* 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"
#include "btcore/include/uuid.h"
#include "osi/include/osi.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.
*******************************************************************************/
bool battery_valid_handle_range(uint16_t handle)
{
uint8_t 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_t battery_s_write_attr_value(uint8_t clcb_idx, tGATT_WRITE_REQ * p_value,
tGATT_STATUS *p_status)
{
uint8_t *p = p_value->value, i;
uint16_t handle = p_value->handle;
tBA_INST *p_inst = &battery_cb.battery_inst[0];
tGATT_STATUS st = GATT_NOT_FOUND;
tBA_WRITE_DATA cfg;
uint8_t 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_t battery_s_read_attr_value (uint8_t clcb_idx, uint16_t handle,
UNUSED_ATTR tGATT_VALUE *p_value, bool is_long,
tGATT_STATUS* p_status)
{
uint8_t i;
tBA_INST *p_inst = &battery_cb.battery_inst[0];
tGATT_STATUS st = GATT_NOT_FOUND;
uint8_t act = SRVC_ACT_RSP;
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
**
*******************************************************************************/
bool battery_gatt_c_read_ba_req(UNUSED_ATTR uint16_t conn_id)
{
return true;
}
/*******************************************************************************
**
** Function battery_c_cmpl_cback
**
** Description Client operation complete callback.
**
** Returns void
**
*******************************************************************************/
void battery_c_cmpl_cback (UNUSED_ATTR tSRVC_CLCB *p_clcb, UNUSED_ATTR tGATTC_OPTYPE op,
UNUSED_ATTR tGATT_STATUS status,
UNUSED_ATTR tGATT_CL_COMPLETE *p_data)
{
}
/*******************************************************************************
**
** Function Battery_Instantiate
**
** Description Instantiate a Battery service
**
*******************************************************************************/
uint16_t Battery_Instantiate (uint8_t app_id, tBA_REG_INFO *p_reg_info)
{
uint16_t srvc_hdl = 0;
tGATT_STATUS status = GATT_ERROR;
tBA_INST *p_inst;
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];
btgatt_db_element_t service[BA_MAX_ATTR_NUM] = {};
bt_uuid_t service_uuid;
uuid_128_from_16(&service_uuid, UUID_SERVCLASS_BATTERY);
service[0].type = /* p_reg_info->is_pri */ BTGATT_DB_PRIMARY_SERVICE;
service[0].uuid = service_uuid;
bt_uuid_t char_uuid;
uuid_128_from_16(&char_uuid, GATT_UUID_BATTERY_LEVEL);
service[1].type = BTGATT_DB_CHARACTERISTIC;
service[1].uuid = char_uuid;
service[1].properties = GATT_CHAR_PROP_BIT_READ;
if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY)
service[1].properties |= GATT_CHAR_PROP_BIT_NOTIFY;
int i=2;
if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY) {
bt_uuid_t desc_uuid;
uuid_128_from_16(&desc_uuid, GATT_UUID_CHAR_CLIENT_CONFIG);
service[i].type = BTGATT_DB_DESCRIPTOR;
service[i].uuid = desc_uuid;
service[i].permissions = (GATT_PERM_READ|GATT_PERM_WRITE);
i++;
}
/* need presentation format descriptor? */
if (p_reg_info->ba_level_descr & BA_LEVEL_PRE_FMT) {
bt_uuid_t desc_uuid;
uuid_128_from_16(&desc_uuid, GATT_UUID_CHAR_PRESENT_FORMAT);
service[i].type = BTGATT_DB_DESCRIPTOR;
service[i].uuid = desc_uuid;
service[i].permissions = GATT_PERM_READ;
i++;
}
/* need presentation format descriptor? */
if (p_reg_info->ba_level_descr & BA_LEVEL_RPT_REF) {
bt_uuid_t desc_uuid;
uuid_128_from_16(&desc_uuid, GATT_UUID_RPT_REF_DESCR);
service[i].type = BTGATT_DB_DESCRIPTOR;
service[i].uuid = desc_uuid;
service[i].permissions = GATT_PERM_READ;
i++;
}
GATTS_AddService(srvc_eng_cb.gatt_if, service, i);
if (status != GATT_SUCCESS) {
battery_cb.inst_id --;
GATT_TRACE_ERROR("%s: Failed to add battery servuce!", __func__);
}
battery_cb.inst_id ++;
p_inst->app_id = app_id;
p_inst->p_cback = p_reg_info->p_cback;
srvc_hdl = service[0].attribute_handle;
p_inst->ba_level_hdl = service[1].attribute_handle;
i=2;
if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY) {
p_inst->clt_cfg_hdl = service[i].attribute_handle;
i++;
}
if (p_reg_info->ba_level_descr & BA_LEVEL_PRE_FMT) {
p_inst->pres_fmt_hdl = service[i].attribute_handle;
i++;
}
if (p_reg_info->ba_level_descr & BA_LEVEL_RPT_REF) {
p_inst->rpt_ref_hdl = service[i].attribute_handle;
i++;
}
return srvc_hdl;
}
/*******************************************************************************
**
** Function Battery_Rsp
**
** Description Respond to a battery service request
**
*******************************************************************************/
void Battery_Rsp (uint8_t app_id, tGATT_STATUS st, uint8_t event, tBA_RSP_DATA *p_rsp)
{
tBA_INST *p_inst = &battery_cb.battery_inst[0];
tGATTS_RSP rsp;
uint8_t *pp;
uint8_t 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_t app_id, BD_ADDR remote_bda, uint8_t battery_level)
{
tBA_INST *p_inst = &battery_cb.battery_inst[0];
uint8_t 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
**
*******************************************************************************/
bool Battery_ReadBatteryLevel(UNUSED_ATTR BD_ADDR peer_bda)
{
/* to be implemented */
return true;
}
#endif /* BLE_INCLUDED */