384 lines
13 KiB
C
384 lines
13 KiB
C
/**
|
|
****************************************************************************************
|
|
* @addtogroup PRF_UTILS
|
|
* @{
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
* INCLUDE FILES
|
|
****************************************************************************************
|
|
*/
|
|
#include "rwip_config.h"
|
|
#if (BLE_PROFILES)
|
|
#if (BLE_SERVER_PRF || BLE_CLIENT_PRF)
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include "ke_task.h"
|
|
#include "attm.h"
|
|
#include "gattc_task.h"
|
|
#include "prf_utils.h"
|
|
#include "gap.h"
|
|
#include "gapc.h"
|
|
|
|
#include "ke_mem.h"
|
|
#include "co_utils.h"
|
|
#include "co_error.h"
|
|
|
|
#endif /* (BLE_SERVER_PRF || BLE_CLIENT_PRF) */
|
|
|
|
/*
|
|
* LOCAL FUNCTIONS DEFINITIONS
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
* EXPORTED FUNCTIONS DEFINITIONS
|
|
****************************************************************************************
|
|
*/
|
|
|
|
#if (BLE_BATT_SERVER)
|
|
void prf_pack_char_pres_fmt(uint8_t *packed_val, const struct prf_char_pres_fmt* char_pres_fmt)
|
|
{
|
|
*packed_val = char_pres_fmt->format;
|
|
*(packed_val + 1) = char_pres_fmt->exponent;
|
|
co_write16p(packed_val + 2, char_pres_fmt->unit);
|
|
*(packed_val + 4) = char_pres_fmt->name_space;
|
|
co_write16p(packed_val + 5, char_pres_fmt->description);
|
|
}
|
|
#endif // (BLE_BATT_SERVER)
|
|
|
|
#if (BLE_BATT_CLIENT)
|
|
void prf_unpack_char_pres_fmt(const uint8_t *packed_val, struct prf_char_pres_fmt* char_pres_fmt)
|
|
{
|
|
|
|
char_pres_fmt->format = *packed_val;
|
|
char_pres_fmt->exponent = *(packed_val + 1);
|
|
char_pres_fmt->unit = co_read16p(packed_val + 2);
|
|
char_pres_fmt->name_space = *(packed_val + 4);
|
|
char_pres_fmt->description = co_read16p(packed_val + 5);
|
|
}
|
|
#endif // (BLE_BATT_CLIENT)
|
|
|
|
|
|
#if (BLE_CLIENT_PRF)
|
|
void prf_read_char_send(prf_env_t *prf_env, uint8_t conidx,
|
|
uint16_t shdl, uint16_t ehdl, uint16_t valhdl)
|
|
{
|
|
struct gattc_read_cmd * req = KE_MSG_ALLOC(GATTC_READ_CMD, KE_BUILD_ID(TASK_GATTC, conidx),
|
|
prf_src_task_get(prf_env, conidx), gattc_read_cmd);
|
|
//request type
|
|
req->operation = GATTC_READ;
|
|
req->nb = 1;
|
|
req->req.simple.offset = 0;
|
|
req->req.simple.length = 0;
|
|
req->req.simple.handle = valhdl;
|
|
|
|
//send request to GATT
|
|
ke_msg_send(req);
|
|
}
|
|
|
|
void prf_register_atthdl2gatt(prf_env_t *prf_env, uint8_t conidx, struct prf_svc *svc)
|
|
{
|
|
if(svc->shdl != ATT_INVALID_HANDLE)
|
|
{
|
|
//register profile task in gatt for indication/notifications
|
|
struct gattc_reg_to_peer_evt_cmd * reg = KE_MSG_ALLOC(GATTC_REG_TO_PEER_EVT_CMD,
|
|
KE_BUILD_ID(TASK_GATTC, conidx), prf_src_task_get(prf_env, conidx),
|
|
gattc_reg_to_peer_evt_cmd);
|
|
|
|
reg->operation = GATTC_REGISTER;
|
|
reg->start_hdl = svc->shdl;
|
|
reg->end_hdl = svc->ehdl;
|
|
|
|
ke_msg_send(reg);
|
|
}
|
|
}
|
|
|
|
void prf_unregister_atthdl2gatt(prf_env_t *prf_env, uint8_t conidx, struct prf_svc *svc)
|
|
{
|
|
if(svc->shdl != ATT_INVALID_HANDLE)
|
|
{
|
|
//un register profile task in gatt for indication/notifications
|
|
struct gattc_reg_to_peer_evt_cmd * reg = KE_MSG_ALLOC(GATTC_REG_TO_PEER_EVT_CMD,
|
|
KE_BUILD_ID(TASK_GATTC, conidx), prf_src_task_get(prf_env, conidx),
|
|
gattc_reg_to_peer_evt_cmd);
|
|
|
|
reg->operation = GATTC_UNREGISTER;
|
|
reg->start_hdl = svc->shdl;
|
|
reg->end_hdl = svc->ehdl;
|
|
|
|
ke_msg_send(reg);
|
|
}
|
|
}
|
|
|
|
|
|
void prf_disc_svc_send(prf_env_t *prf_env, uint8_t conidx, uint16_t uuid)
|
|
{
|
|
//send GATT discover primary services by UUID request
|
|
struct gattc_sdp_svc_disc_cmd * svc_req = KE_MSG_ALLOC_DYN(GATTC_SDP_SVC_DISC_CMD,
|
|
KE_BUILD_ID(TASK_GATTC, conidx), prf_src_task_get(prf_env, conidx),
|
|
gattc_sdp_svc_disc_cmd, ATT_UUID_16_LEN);
|
|
|
|
//gatt request type: by UUID
|
|
svc_req->operation = GATTC_SDP_DISC_SVC;
|
|
//start handle;
|
|
svc_req->start_hdl = ATT_1ST_REQ_START_HDL;
|
|
//end handle
|
|
svc_req->end_hdl = ATT_1ST_REQ_END_HDL;
|
|
|
|
// UUID search
|
|
svc_req->uuid_len = ATT_UUID_16_LEN;
|
|
|
|
//set the first two bytes to the value array, LSB to MSB:Health Thermometer Service UUID first
|
|
co_write16p(&(svc_req->uuid[0]), uuid);
|
|
|
|
//send the message to GATT, which will send back the response when it gets it
|
|
ke_msg_send(svc_req);
|
|
}
|
|
|
|
|
|
|
|
void prf_gatt_write(prf_env_t *prf_env, uint8_t conidx,
|
|
uint16_t handle, uint8_t* value, uint16_t length, uint8_t operation)
|
|
{
|
|
if(handle != ATT_INVALID_HANDLE)
|
|
{
|
|
struct gattc_write_cmd *wr_char = KE_MSG_ALLOC_DYN(GATTC_WRITE_CMD,
|
|
KE_BUILD_ID(TASK_GATTC, conidx), prf_src_task_get(prf_env, conidx),
|
|
gattc_write_cmd, length);
|
|
|
|
// Offset
|
|
wr_char->offset = 0x0000;
|
|
// cursor always 0
|
|
wr_char->cursor = 0x0000;
|
|
// Write Type
|
|
wr_char->operation = operation;
|
|
// Characteristic Value attribute handle
|
|
wr_char->handle = handle;
|
|
// Value Length
|
|
wr_char->length = length;
|
|
// Auto Execute
|
|
wr_char->auto_execute = true;
|
|
// Value
|
|
memcpy(&wr_char->value[0], value, length);
|
|
|
|
// Send the message
|
|
ke_msg_send(wr_char);
|
|
}
|
|
}
|
|
|
|
void prf_gatt_write_ntf_ind(prf_env_t *prf_env, uint8_t conidx, uint16_t handle, uint16_t ntf_ind_cfg)
|
|
{
|
|
uint8_t value[2];
|
|
|
|
// put value in air format
|
|
co_write16p((&value[0]), ntf_ind_cfg);
|
|
// write value over GATT
|
|
prf_gatt_write(prf_env, conidx, handle, value, 2, GATTC_WRITE);
|
|
}
|
|
|
|
uint8_t prf_check_svc_char_validity(uint8_t nb_chars,
|
|
const struct prf_char_inf* chars,
|
|
const struct prf_char_def* chars_req)
|
|
{
|
|
uint8_t status = GAP_ERR_NO_ERROR;
|
|
uint8_t i;
|
|
|
|
for(i = 0; ((i < nb_chars) && (status == GAP_ERR_NO_ERROR)); i++)
|
|
{
|
|
if (chars[i].char_hdl == ATT_INVALID_HANDLE)
|
|
{
|
|
//If Characteristic is not present, check requirements
|
|
if (chars_req[i].req_flag == ATT_MANDATORY)
|
|
{
|
|
status = PRF_ERR_STOP_DISC_CHAR_MISSING;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//If Characteristic is present, check properties
|
|
if((chars[i].prop & chars_req[i].prop_mand) != chars_req[i].prop_mand)
|
|
{
|
|
status = PRF_ERR_STOP_DISC_WRONG_CHAR_PROP;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (status);
|
|
}
|
|
|
|
|
|
uint8_t prf_check_svc_char_desc_validity(uint8_t descs_size,
|
|
const struct prf_char_desc_inf* descs,
|
|
const struct prf_char_desc_def* descs_req,
|
|
const struct prf_char_inf* chars)
|
|
{
|
|
uint8_t status = GAP_ERR_NO_ERROR;
|
|
uint8_t i;
|
|
|
|
for(i = 0; ((i < descs_size) && (status == GAP_ERR_NO_ERROR)) ; i++)
|
|
{
|
|
if (descs[i].desc_hdl == ATT_INVALID_HANDLE)
|
|
{
|
|
//If Descriptor is missing, check if it is mandatory
|
|
if (descs_req[i].req_flag == ATT_MANDATORY)
|
|
{
|
|
//Check if Char is present
|
|
if (chars[descs_req[i].char_code].char_hdl != ATT_INVALID_HANDLE)
|
|
{
|
|
//Char. is present and descriptor not, error
|
|
status = PRF_ERR_STOP_DISC_CHAR_MISSING;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (status);
|
|
}
|
|
|
|
void prf_extract_svc_info(const struct gattc_sdp_svc_ind* param,
|
|
uint8_t nb_chars, const struct prf_char_def* chars_req, struct prf_char_inf* chars,
|
|
uint8_t nb_descs, const struct prf_char_desc_def* descs_req, struct prf_char_desc_inf* descs)
|
|
{
|
|
//Counters
|
|
uint8_t svc_char;
|
|
uint8_t svc_desc;
|
|
uint8_t fnd_att;
|
|
|
|
for (fnd_att=0; fnd_att< (param->end_hdl - param->start_hdl); fnd_att++)
|
|
{
|
|
if(param->info[fnd_att].att_type == GATTC_SDP_ATT_CHAR)
|
|
{
|
|
uint16_t char_hdl = param->start_hdl+ 1 + fnd_att;
|
|
uint16_t val_hdl = param->info[fnd_att].att_char.handle;
|
|
uint8_t val_prop = param->info[fnd_att].att_char.prop;
|
|
uint8_t char_idx = fnd_att;
|
|
|
|
// check that value handle is in a valid range
|
|
if((val_hdl <= param->end_hdl) && (val_hdl > (param->start_hdl + fnd_att)))
|
|
{
|
|
// retrieve value index
|
|
uint8_t val_idx = (val_hdl - param->start_hdl - 1);
|
|
|
|
//Look over requested characteristics
|
|
for (svc_char=0; svc_char<nb_chars ; svc_char++)
|
|
{
|
|
// check if attribute is valid
|
|
if((chars[svc_char].char_hdl == ATT_INVALID_HDL)
|
|
&& attm_uuid16_comp((uint8_t*)param->info[val_idx].att.uuid,
|
|
param->info[val_idx].att.uuid_len, chars_req[svc_char].uuid))
|
|
{
|
|
//Save properties and handles
|
|
chars[svc_char].char_hdl = char_hdl;
|
|
chars[svc_char].val_hdl = val_hdl;
|
|
chars[svc_char].prop = val_prop;
|
|
|
|
// find end of characteristic handle and discover descriptors
|
|
do
|
|
{
|
|
fnd_att++;
|
|
|
|
// found a descriptor
|
|
if(param->info[fnd_att].att_type == GATTC_SDP_ATT_DESC)
|
|
{
|
|
//Retrieve characteristic descriptor handle using UUID
|
|
for(svc_desc = 0; svc_desc<nb_descs; svc_desc++)
|
|
{
|
|
// check if it's expected descriptor
|
|
if ((descs[svc_desc].desc_hdl == ATT_INVALID_HANDLE)
|
|
&& (descs_req[svc_desc].char_code == svc_char)
|
|
&& (attm_uuid16_comp((uint8_t*)param->info[fnd_att].att.uuid,
|
|
param->info[fnd_att].att.uuid_len, descs_req[svc_desc].uuid)))
|
|
{
|
|
descs[svc_desc].desc_hdl = param->start_hdl + 1 + fnd_att;
|
|
// search for next descriptor
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} while(((param->start_hdl+ 1 + fnd_att) <= param->end_hdl)
|
|
&& (param->info[fnd_att].att_type != GATTC_SDP_ATT_CHAR)
|
|
&& (param->info[fnd_att].att_type != GATTC_SDP_INC_SVC));
|
|
|
|
// return to previous valid value
|
|
fnd_att--;
|
|
// previous handle was end of the characteristic
|
|
chars[svc_char].char_ehdl_off = fnd_att - char_idx;
|
|
|
|
// search next characteristic
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#endif //(BLE_CLIENT_PRF)
|
|
|
|
#if (BLE_CLIENT_PRF || BLE_TIP_SERVER || BLE_AN_SERVER || BLE_PAS_SERVER)
|
|
|
|
void prf_client_att_info_rsp(prf_env_t *prf_env, uint8_t conidx, uint16_t msg_id,
|
|
uint8_t status, struct gattc_read_ind const* read_ind)
|
|
{
|
|
// retrieve value length
|
|
uint16_t length = 0;
|
|
if(status == GAP_ERR_NO_ERROR)
|
|
{
|
|
length = read_ind->length;
|
|
}
|
|
|
|
// prepare response
|
|
struct prf_att_info *rsp = KE_MSG_ALLOC_DYN(msg_id,
|
|
prf_dst_task_get(prf_env, conidx), prf_src_task_get(prf_env, conidx),
|
|
prf_att_info, length);
|
|
|
|
rsp->status = status;
|
|
rsp->handle = ATT_INVALID_HDL;
|
|
rsp->length = length;
|
|
|
|
// set value array
|
|
if (read_ind != NULL)
|
|
{
|
|
rsp->handle = read_ind->handle;
|
|
memcpy(&(rsp->value[0]), &(read_ind->value[0]), length);
|
|
}
|
|
|
|
ke_msg_send(rsp);
|
|
}
|
|
#endif //(BLE_CLIENT_PRF || BLE_TIP_SERVER || BLE_AN_SERVER || BLE_PAS_SERVER)
|
|
|
|
|
|
#if ((BLE_SERVER_PRF || BLE_CLIENT_PRF))
|
|
|
|
uint8_t prf_pack_date_time(uint8_t *packed_date, const struct prf_date_time* date_time)
|
|
{
|
|
co_write16p(packed_date, date_time->year);
|
|
*(packed_date + 2) = date_time->month;
|
|
*(packed_date + 3) = date_time->day;
|
|
*(packed_date + 4) = date_time->hour;
|
|
*(packed_date + 5) = date_time->min;
|
|
*(packed_date + 6) = date_time->sec;
|
|
|
|
return 7;
|
|
}
|
|
uint8_t prf_unpack_date_time(uint8_t *packed_date, struct prf_date_time* date_time)
|
|
{
|
|
date_time->year = co_read16p(&(packed_date[0]));
|
|
date_time->month = packed_date[2];
|
|
date_time->day = packed_date[3];
|
|
date_time->hour = packed_date[4];
|
|
date_time->min = packed_date[5];
|
|
date_time->sec = packed_date[6];
|
|
|
|
return 7;
|
|
}
|
|
|
|
|
|
#endif /* ((BLE_SERVER_PRF || BLE_CLIENT_PRF)) */
|
|
#endif // (BLE_PROFILES)
|
|
/// @} PRF_UTILS
|
|
|