You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
363 lines
11 KiB
363 lines
11 KiB
/****************************************************************************** |
|
* |
|
* 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 "btcore/include/uuid.h" |
|
#include "gatt_api.h" |
|
#include "gatt_int.h" |
|
#include "osi/include/osi.h" |
|
#include "srvc_battery_int.h" |
|
#include "srvc_eng_int.h" |
|
|
|
#define BA_MAX_CHAR_NUM 1 |
|
|
|
/* max 3 descriptors, 1 desclration and 1 value */ |
|
#define BA_MAX_ATTR_NUM (BA_MAX_CHAR_NUM * 5 + 1) |
|
|
|
#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) { |
|
cfg.remote_bda = srvc_eng_cb.clcb[clcb_idx].bda; |
|
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) { |
|
LOG(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--; |
|
LOG(ERROR) << __func__ << " Failed to add battery servuce!"; |
|
} |
|
|
|
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, const RawAddress& 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(const RawAddress&) { |
|
/* to be implemented */ |
|
return true; |
|
}
|
|
|