| /****************************************************************************** |
| * |
| * 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 */ |