784 lines
24 KiB
C
784 lines
24 KiB
C
/**
|
|
****************************************************************************************
|
|
*
|
|
* @file prf_ptss.c
|
|
*
|
|
* @brief Profile Testing Service - Server Role Implementation.
|
|
*
|
|
* < If want to modify it, recommend to copy the file to 'user porject'/src >
|
|
****************************************************************************************
|
|
*/
|
|
|
|
#if (PRF_PTSS)
|
|
|
|
/*
|
|
* INCLUDE FILES
|
|
****************************************************************************************
|
|
*/
|
|
|
|
#include "prf.h"
|
|
#include "prf_ptss.h"
|
|
|
|
#if (DBG_PTSS)
|
|
#include "dbg.h"
|
|
#define DEBUG(format, ...) debug("<PTSS>" format "\r\n", ##__VA_ARGS__)
|
|
#else
|
|
#define DEBUG(format, ...)
|
|
#define debugHex(dat, len)
|
|
#endif
|
|
|
|
|
|
/*
|
|
* DEFINITIONS
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/// Version String for Read
|
|
#define PTS_VERS_STR ("Ver:1.25")
|
|
#define PTS_VERS_STR_LEN (sizeof(PTS_VERS_STR) - 1)
|
|
|
|
/// Macro for Client Config value operation
|
|
#define PTS_CLI_CFG_GET(conidx) \
|
|
((ptss_env.cli_cfg >> (conidx*2)) & (PRF_CLI_START_NTF | PRF_CLI_START_IND))
|
|
|
|
#define PTS_CLI_CFG_CLR(conidx) \
|
|
ptss_env.cli_cfg &= ~((PRF_CLI_START_NTF | PRF_CLI_START_IND) << (conidx*2))
|
|
|
|
#define PTS_CLI_CFG_SET(conidx, conf) \
|
|
ptss_env.cli_cfg = (ptss_env.cli_cfg & ~((PRF_CLI_START_NTF | PRF_CLI_START_IND) << (conidx*2))) | ((conf) << (conidx*2))
|
|
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @section ENVIRONMENT DEFINITION
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/// Server Environment Variable
|
|
typedef struct ptss_env_tag
|
|
{
|
|
// Service Start Handle
|
|
uint16_t start_hdl;
|
|
// CCC of peer devices(bits).
|
|
uint16_t cli_cfg;
|
|
} ptss_env_t;
|
|
|
|
/// Global Variable Declarations
|
|
ptss_env_t ptss_env;
|
|
|
|
/// Global state of bonded, changed in gapc
|
|
uint8_t pts_bond;
|
|
|
|
/// Buffer of received data
|
|
static uint16_t recv_len = PTS_DATA_MAX_LEN;
|
|
static uint8_t recv_buf[PTS_DATA_MAX_LEN];
|
|
|
|
/// Buffer of read data
|
|
static uint16_t read_len = PTS_DATA_MAX_LEN;
|
|
static uint8_t read_buf[PTS_DATA_MAX_LEN];
|
|
|
|
/// Buffer of desc data
|
|
static uint16_t desc_len = PTS_DESC_MAX_LEN;
|
|
static uint8_t desc_buf[PTS_DESC_MAX_LEN];
|
|
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @section ATTRIBUTES DEFINITION
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/// Service Attributes Indexes
|
|
enum pts_att_idx
|
|
{
|
|
// Service Declaration, *MUST* Start at 0
|
|
PTS_IDX_SVC,
|
|
|
|
// Attribute No.1: NTF/IND/RD
|
|
PTS_IDX_ATT1_CHAR,
|
|
PTS_IDX_ATT1_VAL,
|
|
PTS_IDX_ATT1_DESC,
|
|
|
|
// Attribute No.2: WR/WC/WS
|
|
PTS_IDX_ATT2_CHAR,
|
|
PTS_IDX_ATT2_VAL,
|
|
|
|
// Attribute No.3: RD
|
|
PTS_IDX_ATT3_CHAR,
|
|
PTS_IDX_ATT3_VAL,
|
|
|
|
// Max Index, *NOTE* Minus 1(Svc Decl) is .nb_att
|
|
PTS_IDX_NB,
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/// *** 0: Test for Normal ***
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define PTS0_SVC_UUID ATT_UUID16(0xFF00)
|
|
|
|
#define PTS0_CHAR_ATT1 ATT_UUID16(0xFF01)
|
|
#define PTS0_CHAR_ATT2 ATT_UUID16(0xFF02)
|
|
#define PTS0_CHAR_ATT3 ATT_UUID16(0xFF03)
|
|
|
|
const att_decl_t pts0_atts[] =
|
|
{
|
|
// No.1 Characteristic Declaration and Value and CCC Descriptor
|
|
ATT_ELMT_DECL_CHAR( PTS_IDX_ATT1_CHAR ),
|
|
ATT_ELMT( PTS_IDX_ATT1_VAL, PTS0_CHAR_ATT1, PROP_NTF|PROP_IND, 0 ),
|
|
ATT_ELMT_DESC_CLI_CHAR_CFG( PTS_IDX_ATT1_DESC ),
|
|
|
|
// No.2 Characteristic Declaration and Value
|
|
ATT_ELMT_DECL_CHAR( PTS_IDX_ATT2_CHAR ),
|
|
ATT_ELMT( PTS_IDX_ATT2_VAL, PTS0_CHAR_ATT2, PROP_WC|PROP_WR|PROP_WS, PTS_DATA_MAX_LEN ),
|
|
|
|
// No.3 Characteristic Declaration and Value
|
|
ATT_ELMT_DECL_CHAR( PTS_IDX_ATT3_CHAR ),
|
|
ATT_ELMT( PTS_IDX_ATT3_VAL, PTS0_CHAR_ATT3, PROP_RD, 0 ),
|
|
};
|
|
|
|
const struct svc_decl pts0_svc_db =
|
|
{
|
|
.uuid = PTS0_SVC_UUID,
|
|
.info = SVC_UUID(16),
|
|
.atts = pts0_atts,
|
|
.nb_att = PTS_IDX_NB - 1,
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/// *** 1: Test for ERROR ***
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define PTS1_SVC_UUID ATT_UUID16(0xFF20)
|
|
|
|
#define PTS1_CHAR_ATT1 ATT_UUID16(0xFF21)
|
|
#define PTS1_CHAR_ATT2 ATT_UUID16(0xFF22)
|
|
#define PTS1_CHAR_ATT3 ATT_UUID16(0xFF23)
|
|
|
|
const att_decl_t pts1_atts[] =
|
|
{
|
|
// No.1 Characteristic Declaration and Value and User Descriptor
|
|
ATT_ELMT_DECL_CHAR( PTS_IDX_ATT1_CHAR ),
|
|
ATT_ELMT( PTS_IDX_ATT1_VAL, PTS1_CHAR_ATT1, PROP_WC|PROP_WR|PROP_RD, PTS_DATA_MAX_LEN ),
|
|
ATT_ELMT( PTS_IDX_ATT1_DESC, ATT_DESC_CHAR_USER_DESCRIPTION, PROP_RD, 0 ),
|
|
|
|
// No.2 Characteristic Declaration and Value
|
|
ATT_ELMT_DECL_CHAR( PTS_IDX_ATT2_CHAR ),
|
|
ATT_ELMT( PTS_IDX_ATT2_VAL, PTS1_CHAR_ATT2, PROP_WC|PROP_WR|PROP_RD, PTS_DATA_MAX_LEN ),
|
|
|
|
// No.3 Characteristic Declaration and Value
|
|
ATT_ELMT_DECL_CHAR( PTS_IDX_ATT3_CHAR ),
|
|
ATT_ELMT( PTS_IDX_ATT3_VAL, PTS1_CHAR_ATT3, PROP_WC|PROP_WR|PROP_RD, PTS_DATA_MAX_LEN ),
|
|
};
|
|
|
|
const struct svc_decl pts1_svc_db =
|
|
{
|
|
.uuid = PTS1_SVC_UUID,
|
|
.info = SVC_UUID(16),
|
|
.atts = pts1_atts,
|
|
.nb_att = PTS_IDX_NB - 1,
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/// *** 2: Test for UUID128 ***
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define PTS_ATT_UUID128(uuid) { 0x16, 0x0A, 0x10, 0x40, 0xD1, 0x9F, 0x4C, 0x6C, \
|
|
0xB4, 0x55, 0xE3, 0xF7, (uuid) & 0xFF, (uuid >> 8) & 0xFF, 0x00, 0x00}
|
|
|
|
const uint8_t PTS2_SVC_UUID[] = PTS_ATT_UUID128(0xFF00);
|
|
|
|
const uint8_t PTS2_CHAR_ATT1[] = PTS_ATT_UUID128(0xFF01);
|
|
const uint8_t PTS2_CHAR_ATT2[] = PTS_ATT_UUID128(0xFF02);
|
|
const uint8_t PTS2_CHAR_ATT3[] = PTS_ATT_UUID128(0xFF03);
|
|
|
|
const att_decl_t pts2_atts[] =
|
|
{
|
|
// No.1 Characteristic Declaration and Value and User Descriptor
|
|
ATT_ELMT_DECL_CHAR( PTS_IDX_ATT1_CHAR ),
|
|
ATT_ELMT128( PTS_IDX_ATT1_VAL, PTS2_CHAR_ATT1, PROP_RD, 0 ),
|
|
ATT_ELMT( PTS_IDX_ATT1_DESC, ATT_DESC_CHAR_USER_DESCRIPTION, PROP_RD|PROP_WR, PTS_DESC_MAX_LEN ),
|
|
|
|
// No.2 Characteristic Declaration and Value
|
|
ATT_ELMT_DECL_CHAR( PTS_IDX_ATT2_CHAR ),
|
|
ATT_ELMT128( PTS_IDX_ATT2_VAL, PTS2_CHAR_ATT2, PROP_WC|PROP_WR|PROP_RD, PTS_DATA_MAX_LEN ),
|
|
|
|
// No.3 Characteristic Declaration and Value
|
|
ATT_ELMT_DECL_CHAR( PTS_IDX_ATT3_CHAR ),
|
|
ATT_ELMT128( PTS_IDX_ATT3_VAL, PTS2_CHAR_ATT3, PROP_RD|PROP_WR, PTS_DATA_MAX_LEN ),
|
|
};
|
|
|
|
const struct svc_decl pts_svc_db2 =
|
|
{
|
|
.uuid128 = PTS2_SVC_UUID,
|
|
.info = SVC_UUID(128),
|
|
.atts = pts2_atts,
|
|
.nb_att = PTS_IDX_NB - 1,
|
|
};
|
|
|
|
|
|
/*
|
|
* FUNCTION DECLARATIONS
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @section SVC FUNCTIONS
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/// Retrieve attribute handle from index (@see pts_att_idx)
|
|
static uint16_t ptss_get_att_handle(uint8_t att_idx)
|
|
{
|
|
ASSERT_ERR(att_idx < PTS_ATT_NB); //svr_idx=0
|
|
|
|
return (att_idx + ptss_env.start_hdl);
|
|
}
|
|
|
|
/// Retrieve attribute index form handle or ATT_INVALID_IDX if nothing found
|
|
static uint8_t ptss_get_att_idx(uint8_t *svr_idx, uint16_t handle)
|
|
{
|
|
uint8_t att_idx = ATT_INVALID_IDX;
|
|
|
|
if ((handle >= ptss_env.start_hdl) && (handle < ptss_env.start_hdl + PTS_IDX_NB))
|
|
{
|
|
att_idx = handle - ptss_env.start_hdl;
|
|
*svr_idx = 0;
|
|
}
|
|
else if ((handle >= ptss_env.start_hdl + PTS_IDX_NB) && (handle < ptss_env.start_hdl + PTS_IDX_NB*2))
|
|
{
|
|
att_idx = handle - (ptss_env.start_hdl + PTS_IDX_NB);
|
|
*svr_idx = 1;
|
|
}
|
|
else if ((handle >= ptss_env.start_hdl + PTS_IDX_NB*2) && (handle < ptss_env.start_hdl + PTS_IDX_NB*3))
|
|
{
|
|
att_idx = handle - (ptss_env.start_hdl + PTS_IDX_NB*2);
|
|
*svr_idx = 2;
|
|
}
|
|
|
|
return (att_idx);
|
|
}
|
|
|
|
/// Handles reception of the attribute info request message.
|
|
static void ptss_att_info_cfm(uint8_t conidx, uint8_t svr_idx, uint8_t att_idx, uint16_t handle)
|
|
{
|
|
uint16_t length = 0;
|
|
uint8_t status = LE_SUCCESS;
|
|
|
|
if (att_idx != ATT_INVALID_IDX)
|
|
{
|
|
if (svr_idx == 1) // PTS1 Error
|
|
{
|
|
// Long Write Error
|
|
if (att_idx == PTS_IDX_ATT1_VAL)
|
|
{
|
|
if ((pts_bond & GAP_AUTH_BOND) == 0)
|
|
status = ATT_ERR_INSUFF_AUTHOR;
|
|
else
|
|
length = PTS_DATA_MAX_LEN;
|
|
}
|
|
else if (att_idx == PTS_IDX_ATT2_VAL)
|
|
{
|
|
if ((pts_bond & GAP_AUTH_MITM) == 0)
|
|
status = ATT_ERR_INSUFF_AUTHEN;
|
|
else
|
|
length = PTS_DATA_MAX_LEN;
|
|
}
|
|
else if (att_idx == PTS_IDX_ATT3_VAL)
|
|
{
|
|
//if (!pts_bond)
|
|
status = ATT_ERR_INSUFF_ENC_KEY_SIZE;
|
|
//else
|
|
// cfm->length = PTS_DATA_MAX_LEN;
|
|
}
|
|
else
|
|
{
|
|
status = ATT_ERR_WRITE_NOT_PERMITTED;
|
|
}
|
|
}
|
|
else if (svr_idx == 2) // PTS2 Normal
|
|
{
|
|
if ((att_idx == PTS_IDX_ATT2_VAL) || (att_idx == PTS_IDX_ATT3_VAL))
|
|
{
|
|
length = PTS_DATA_MAX_LEN;
|
|
}
|
|
else if (att_idx == PTS_IDX_ATT1_DESC)
|
|
{
|
|
length = PTS_DESC_MAX_LEN;
|
|
}
|
|
else
|
|
{
|
|
status = ATT_ERR_WRITE_NOT_PERMITTED;
|
|
}
|
|
}
|
|
else // PTS0 Normal
|
|
{
|
|
if (att_idx == PTS_IDX_ATT2_VAL)
|
|
{
|
|
length = PTS_DATA_MAX_LEN;
|
|
}
|
|
else if (att_idx == PTS_IDX_ATT1_DESC)
|
|
{
|
|
length = sizeof(uint16_t); // CCC attribute
|
|
}
|
|
else
|
|
{
|
|
status = ATT_ERR_WRITE_NOT_PERMITTED;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = PRF_ERR_APP_ERROR;
|
|
}
|
|
|
|
DEBUG(" info_cfm(svr:%d,hdl:0x%x,sta:0x%x,len:%d)", svr_idx, param->handle, status, length);
|
|
|
|
// Send info response
|
|
gatt_info_cfm(conidx, status, handle, length);
|
|
}
|
|
|
|
/// Confirm ATTS_WRITE_REQ
|
|
static void ptss_att_write_cfm(uint8_t conidx, uint8_t svr_idx, uint8_t att_idx, uint16_t handle, const struct atts_write_ind *ind)
|
|
{
|
|
uint8_t status = LE_SUCCESS;
|
|
|
|
if (att_idx != ATT_INVALID_IDX)
|
|
{
|
|
if (svr_idx == 1) // PTS1 Error
|
|
{
|
|
// Write Error
|
|
if (att_idx == PTS_IDX_ATT1_VAL)
|
|
{
|
|
if ((pts_bond & GAP_AUTH_BOND) == 0)
|
|
status = ATT_ERR_INSUFF_AUTHOR;
|
|
}
|
|
else if (att_idx == PTS_IDX_ATT2_VAL)
|
|
{
|
|
if ((pts_bond & GAP_AUTH_MITM) == 0)
|
|
status = ATT_ERR_INSUFF_AUTHEN;
|
|
}
|
|
else if (att_idx == PTS_IDX_ATT3_VAL)
|
|
{
|
|
//if (!pts_bond)
|
|
status = ATT_ERR_INSUFF_ENC_KEY_SIZE;
|
|
}
|
|
else
|
|
{
|
|
status = ATT_ERR_WRITE_NOT_PERMITTED;
|
|
}
|
|
}
|
|
else if (svr_idx == 2) // PTS2 Normal
|
|
{
|
|
if ((att_idx == PTS_IDX_ATT2_VAL) || (att_idx == PTS_IDX_ATT3_VAL))
|
|
{
|
|
// received data to callback
|
|
ptss_cb_recv(conidx, ind->length, ind->value);
|
|
|
|
// Save data to read-back
|
|
if (att_idx == PTS_IDX_ATT2_VAL)
|
|
{
|
|
recv_len = ind->length;
|
|
memcpy(recv_buf, ind->value, ind->length);
|
|
}
|
|
else
|
|
{
|
|
read_len = ind->length;
|
|
memcpy(read_buf, ind->value, ind->length);
|
|
}
|
|
}
|
|
else if (att_idx == PTS_IDX_ATT1_DESC)
|
|
{
|
|
// Save desc to read-back
|
|
desc_len = ind->length;
|
|
memcpy(desc_buf, ind->value, desc_len);
|
|
}
|
|
else
|
|
{
|
|
status = ATT_ERR_WRITE_NOT_PERMITTED;
|
|
}
|
|
}
|
|
else // PTS0 Normal
|
|
{
|
|
if (att_idx == PTS_IDX_ATT2_VAL)
|
|
{
|
|
// received data to callback
|
|
ptss_cb_recv(conidx, ind->length, ind->value);
|
|
}
|
|
else if (att_idx == PTS_IDX_ATT1_DESC)
|
|
{
|
|
// update configuration if value for stop or notification enable
|
|
uint8_t cli_cfg = ind->value[0] & (PRF_CLI_START_NTF | PRF_CLI_START_IND);
|
|
|
|
PTS_CLI_CFG_SET(conidx, cli_cfg);
|
|
|
|
// client conf to callback
|
|
ptss_cb_ccc(conidx, cli_cfg);
|
|
}
|
|
else
|
|
{
|
|
status = PRF_ERR_APP_ERROR;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = PRF_ERR_APP_ERROR;
|
|
}
|
|
|
|
DEBUG(" --write_cfm(svr:%d,hdl:0x%x,sta:0x%x)", svr_idx, handle, status);
|
|
|
|
// Send write conform
|
|
gatt_write_cfm(conidx, status, handle);
|
|
}
|
|
|
|
/// Confirm ATTS_READ_REQ
|
|
static void ptss_att_read_cfm(uint8_t conidx, uint8_t svr_idx, uint8_t att_idx, uint16_t handle)
|
|
{
|
|
uint16_t length = 0;
|
|
uint8_t status = LE_SUCCESS;
|
|
|
|
if (att_idx != ATT_INVALID_IDX)
|
|
{
|
|
if (svr_idx == 1) // PTS1 Error
|
|
{
|
|
// Read Error
|
|
if (att_idx == PTS_IDX_ATT1_VAL)
|
|
{
|
|
if ((pts_bond & GAP_AUTH_BOND) == 0)
|
|
status = ATT_ERR_INSUFF_AUTHOR;
|
|
else
|
|
length = PTS_DATA_MAX_LEN;
|
|
}
|
|
else if (att_idx == PTS_IDX_ATT2_VAL)
|
|
{
|
|
if ((pts_bond & GAP_AUTH_MITM) == 0)
|
|
status = ATT_ERR_INSUFF_AUTHEN;
|
|
else
|
|
length = PTS_DATA_MAX_LEN;
|
|
}
|
|
else if (att_idx == PTS_IDX_ATT3_VAL)
|
|
{
|
|
//if (!pts_bond)
|
|
status = ATT_ERR_INSUFF_ENC_KEY_SIZE;
|
|
//else
|
|
// length = PTS_DATA_MAX_LEN;
|
|
}
|
|
else if (att_idx == PTS_IDX_ATT1_DESC)
|
|
{
|
|
length = 2 * gatt_get_mtu(conidx) - 2;
|
|
}
|
|
else
|
|
{
|
|
status = ATT_ERR_READ_NOT_PERMITTED;
|
|
}
|
|
}
|
|
else if (svr_idx == 2) // PTS2 Normal
|
|
{
|
|
if (att_idx == PTS_IDX_ATT1_VAL)
|
|
{
|
|
length = gatt_get_mtu(conidx);
|
|
|
|
if (length < 512) length--;
|
|
}
|
|
else if (att_idx == PTS_IDX_ATT1_DESC)
|
|
{
|
|
length = desc_len;
|
|
}
|
|
else if (att_idx == PTS_IDX_ATT3_VAL)
|
|
{
|
|
length = read_len;
|
|
}
|
|
else if (att_idx == PTS_IDX_ATT2_VAL)
|
|
{
|
|
length = recv_len;
|
|
}
|
|
else
|
|
{
|
|
status = ATT_ERR_READ_NOT_PERMITTED;
|
|
}
|
|
}
|
|
else // PTS0 Normal
|
|
{
|
|
if (att_idx == PTS_IDX_ATT1_DESC)
|
|
{
|
|
length = sizeof(uint16_t);
|
|
}
|
|
else if (att_idx == PTS_IDX_ATT3_VAL)
|
|
{
|
|
//if (ptss_env.rdv_cb)
|
|
// length = ptss_env.rdv_cb(conidx, NULL);
|
|
length = gatt_get_mtu(conidx);
|
|
|
|
if (length < 512) length--;
|
|
}
|
|
else
|
|
{
|
|
status = ATT_ERR_READ_NOT_PERMITTED;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = PRF_ERR_APP_ERROR;
|
|
}
|
|
|
|
DEBUG(" read_cfm(svr:%d,hdl:0x%x,sta:0x%x,len:%d)", svr_idx, param->handle, status, length);
|
|
|
|
// Send read response
|
|
if (status == LE_SUCCESS)
|
|
{
|
|
if (svr_idx == 2)
|
|
{
|
|
// PTS2 read-back
|
|
if (att_idx == PTS_IDX_ATT2_VAL)
|
|
{
|
|
gatt_read_cfm(conidx, status, handle, recv_len, recv_buf);
|
|
return;
|
|
}
|
|
else if (att_idx == PTS_IDX_ATT3_VAL)
|
|
{
|
|
gatt_read_cfm(conidx, status, handle, read_len, read_buf);
|
|
return;
|
|
}
|
|
else if (att_idx == PTS_IDX_ATT1_DESC)
|
|
{
|
|
gatt_read_cfm(conidx, status, handle, desc_len, desc_buf);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// PTS0 fill data
|
|
if (att_idx == PTS_IDX_ATT1_DESC)
|
|
{
|
|
uint16_t cli_cfg = PTS_CLI_CFG_GET(conidx);
|
|
|
|
gatt_read_cfm(conidx, status, handle, length, (uint8_t *)&cli_cfg);
|
|
return;
|
|
}
|
|
else if (att_idx == PTS_IDX_ATT3_VAL)
|
|
{
|
|
ptss_cb_read(conidx, att_idx, handle);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
gatt_read_cfm(conidx, status, handle, length, NULL);
|
|
}
|
|
|
|
/// Handles reception of the atts request from peer device
|
|
static void ptss_svc_func(uint8_t conidx, uint8_t opcode, uint16_t handle, const void *param)
|
|
{
|
|
uint8_t svr_idx, att_idx;
|
|
|
|
att_idx = ptss_get_att_idx(&svr_idx, handle);
|
|
DEBUG("svc_func(cid:%d,op:0x%x,hdl:0x%x,svr:%d,att:%d)", conidx, opcode, handle, svr_idx, att_idx);
|
|
|
|
switch (opcode)
|
|
{
|
|
case ATTS_READ_REQ:
|
|
{
|
|
ptss_att_read_cfm(conidx, svr_idx, att_idx, handle);
|
|
} break;
|
|
|
|
case ATTS_WRITE_REQ:
|
|
{
|
|
const struct atts_write_ind *ind = param;
|
|
|
|
DEBUG(" write_req(hdl:0x%x,att:%d,wr:0x%x,len:%d)", handle, att_idx, ind->wrcode, ind->length);
|
|
ptss_att_write_cfm(conidx, svr_idx, att_idx, handle, ind);
|
|
} break;
|
|
|
|
case ATTS_INFO_REQ:
|
|
{
|
|
ptss_att_info_cfm(conidx, svr_idx, att_idx, handle);
|
|
} break;
|
|
|
|
case ATTS_CMP_EVT:
|
|
{
|
|
const struct atts_cmp_evt *evt = param;
|
|
|
|
DEBUG(" cmp_evt(op:0x%x,sta:0x%x,seq:%d)", evt->operation, evt->status, evt->seq_num);
|
|
// add 'if' to avoid warning #117-D: "evt" never referenced
|
|
if (evt->operation == GATT_NOTIFY)
|
|
{
|
|
// Notify result
|
|
}
|
|
} break;
|
|
|
|
default:
|
|
{
|
|
// nothing to do
|
|
} break;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @section API FUNCTIONS
|
|
****************************************************************************************
|
|
*/
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Add Service Profile in the DB
|
|
* Customize via pre-define @see PTSS_START_HDL
|
|
*
|
|
* @return Result status, LE_SUCCESS or Error Reason
|
|
****************************************************************************************
|
|
*/
|
|
uint8_t ptss_svc_init(void)
|
|
{
|
|
uint8_t status = LE_SUCCESS;
|
|
uint16_t next_hdl;
|
|
|
|
// Init Environment
|
|
ptss_env.start_hdl = PTS_START_HDL;
|
|
ptss_env.cli_cfg = 0;
|
|
|
|
#if (PTSS_START_HDL)
|
|
*start_hdl = PTSS_START_HDL; // at special handle
|
|
#endif
|
|
|
|
// Create Service in database
|
|
status = attmdb_svc_create(&ptss_env.start_hdl, NULL, &pts0_svc_db, ptss_svc_func);
|
|
|
|
DEBUG("svc_init0(sta:0x%X,shdl:%d)", status, ptss_env.start_hdl);
|
|
if (status != LE_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
next_hdl = ptss_env.start_hdl + PTS_IDX_NB;
|
|
status = attmdb_svc_create(&next_hdl, NULL, &pts1_svc_db, ptss_svc_func);
|
|
|
|
DEBUG("svc_init1(sta:0x%X,shdl:%d)", status, next_hdl);
|
|
if (status != LE_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
next_hdl += PTS_IDX_NB;
|
|
status = attmdb_svc_create(&next_hdl, NULL, &pts_svc_db2, ptss_svc_func);
|
|
if (status != LE_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Enable setting client configuration characteristics
|
|
*
|
|
* @param[in] conidx Connection index
|
|
* @param[in] cli_cfg Client configuration @see prf_cli_conf
|
|
*
|
|
* @return Status of the operation @see prf_err
|
|
****************************************************************************************
|
|
*/
|
|
void ptss_set_ccc(uint8_t conidx, uint8_t cli_cfg)
|
|
{
|
|
//if (gapc_get_conhdl(conidx) != GAP_INVALID_CONHDL)
|
|
{
|
|
// update configuration
|
|
PTS_CLI_CFG_SET(conidx, cli_cfg);
|
|
}
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Transmit data to peer device via NTF or IND
|
|
*
|
|
* @param[in] conidx peer destination connection index
|
|
* @param[in] handle Handle of NTF/IND
|
|
* @param[in] len Length of data
|
|
* @param[in] data pointer of buffer
|
|
*
|
|
* @return Status of the operation @see prf_err
|
|
****************************************************************************************
|
|
*/
|
|
uint8_t ptss_evt_send(uint8_t conidx, uint16_t handle, uint16_t len, const uint8_t* data)
|
|
{
|
|
uint8_t status = PRF_ERR_REQ_DISALLOWED;
|
|
|
|
if (len > 0)
|
|
{
|
|
uint8_t cli_cfg = PTS_CLI_CFG_GET(conidx);
|
|
|
|
if (cli_cfg != PRF_CLI_STOP_NTFIND)
|
|
{
|
|
uint8_t operation = (cli_cfg & PRF_CLI_START_NTF) ? GATT_NOTIFY : GATT_INDICATE;
|
|
|
|
if (handle == 0) ptss_get_att_handle(PTS_IDX_ATT1_VAL);
|
|
|
|
gatt_ntf_send(conidx, handle, len, data);
|
|
|
|
DEBUG("Send(hdl:0x%x,op:0x%x,len:%d)", handle, operation, len);
|
|
status = LE_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
status = PRF_ERR_NTF_DISABLED;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Callback on received data from peer device via WC or WQ (__weak func)
|
|
*
|
|
* @param[in] conidx peer device connection index
|
|
* @param[in] len Length of data
|
|
* @param[in] data pointer of buffer
|
|
****************************************************************************************
|
|
*/
|
|
__weak void ptss_cb_recv(uint8_t conidx, uint16_t len, const uint8_t *data)
|
|
{
|
|
DEBUG("Recv(cid:%d,len:%d)", conidx, len);
|
|
debugHex(data, len);
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Callback to response 'READ' from peer device (__weak func)
|
|
*
|
|
* @param[in] conidx peer device connection index
|
|
* @param[in] attidx SESS attribute index, converted with 'handle'
|
|
* @param[in] handle SESS attribute handle to send read cfm
|
|
*
|
|
* @return Length of value been READ
|
|
****************************************************************************************
|
|
*/
|
|
__weak void ptss_cb_read(uint8_t conidx, uint8_t attidx, uint16_t handle)
|
|
{
|
|
uint16_t length = PTS_VERS_STR_LEN;
|
|
const uint8_t *p_data = (const uint8_t *)PTS_VERS_STR;
|
|
|
|
DEBUG(" read_cfm(att:%d, len:%d)", attidx, length);
|
|
gatt_read_cfm(conidx, LE_SUCCESS, handle, length, p_data);
|
|
}
|
|
|
|
/**
|
|
****************************************************************************************
|
|
* @brief Callback on enabled client config from peer device via WQ (__weak func)
|
|
*
|
|
* @param[in] conidx Connection index
|
|
* @param[in] cli_cfg Client configuration @see prf_cli_conf
|
|
****************************************************************************************
|
|
*/
|
|
__weak void ptss_cb_ccc(uint8_t conidx, uint8_t cli_cfg)
|
|
{
|
|
DEBUG("Enable(cid:%d,cfg:%d)", conidx, cli_cfg);
|
|
}
|
|
|
|
|
|
#endif //PRF_PTSS
|