bleSDK_expansion_board/ble/prf/prf_diss.c

413 lines
12 KiB
C
Raw Permalink Normal View History

/**
****************************************************************************************
*
* @file prf_diss.c
*
* @brief Device Information Service(DIS) - Server Role Implementation.
*
* < If want to modify it, recommend to copy the file to 'user porject'/src >
****************************************************************************************
*/
#if (PRF_DISS)
/*
* INCLUDE FILES
****************************************************************************************
*/
#include "prf.h"
#include "prf_diss.h"
#if (DBG_DISS)
#include "dbg.h"
#define DEBUG(format, ...) debug("<%s,%d>" format "\r\n", __MODULE__, __LINE__, ##__VA_ARGS__)
#else
#define DEBUG(format, ...)
#define debugHex(dat, len)
#endif
/*
* DEFINITIONS
****************************************************************************************
*/
/// Manufacturer Name Value
#define INFO_MANUF_NAME ("BLE5x")
#define INFO_MANUF_NAME_LEN (sizeof(INFO_MANUF_NAME)-1)
/// Model Number String Value
#define INFO_MODEL_NB_STR ("BLE5.2")
#define INFO_MODEL_NB_STR_LEN (sizeof(INFO_MODEL_NB_STR)-1)
/// Serial Number
#define INFO_SERIAL_NB_STR ("11.0.2-LE")
#define INFO_SERIAL_NB_STR_LEN (sizeof(INFO_SERIAL_NB_STR)-1)
/// Firmware Revision
#define INFO_FW_REV_STR ("11.0.2")
#define INFO_FW_REV_STR_LEN (sizeof(INFO_FW_REV_STR)-1)
/// System ID Value - LSB -> MSB, Length=8(DIS_SYS_ID_LEN)
#define INFO_SYS_ID ("\x12\x34\x56\xFF\xFE\x9A\xBC\xDE")
#define INFO_SYS_ID_LEN (sizeof(INFO_SYS_ID)-1)
/// Hardware Revision String
#define INFO_HW_REV_STR ("1.0.0")
#define INFO_HW_REV_STR_LEN (sizeof(INFO_HW_REV_STR)-1)
/// Software Revision String
#define INFO_SW_REV_STR ("1.0.0")
#define INFO_SW_REV_STR_LEN (sizeof(INFO_SW_REV_STR)-1)
/// IEEE Certif, Length>=6(DIS_IEEE_CERTIF_MIN_LEN)
#define INFO_IEEE ("\xFF\xEE\xDD\xCC\xBB\xAA")
#define INFO_IEEE_LEN (sizeof(INFO_IEEE)-1)
/**
* PNP ID Value - LSB -> MSB, Length=7(DIS_PNP_ID_LEN)
* Vendor ID Source : 0x02 (USB Implementer<EFBFBD><EFBFBD>s Forum assigned Vendor ID value)
* Vendor ID : 0x045E (Microsoft Corp)
* Product ID : 0x0040
* Product Version : 0x0300
*/
#define INFO_PNP_ID ("\x02\x5E\x04\x40\x00\x00\x03")
#define INFO_PNP_ID_LEN (sizeof(INFO_PNP_ID)-1)
/**
****************************************************************************************
* @section ENVIRONMENT DEFINITION
****************************************************************************************
*/
/// DIS Server Environment Variable
typedef struct diss_env_tag
{
// Service Start Handle
uint16_t start_hdl;
// Supported features @see enum dis_features
uint16_t features;
} diss_env_t;
/// Global Variable Declarations
__VAR_ENV diss_env_t diss_env;
/**
****************************************************************************************
* @section ATTRIBUTES DEFINITION
****************************************************************************************
*/
/// DIS Attributes Index, keep up with @see enum dis_values
enum dis_att_idx
{
// Service Declaration, *MUST* Start at 0
DIS_IDX_SVC,
// Manufacturer Name String Char.
DIS_IDX_MANUF_NAME_CHAR,
DIS_IDX_MANUF_NAME_VAL,
// Model Number String Char.
DIS_IDX_MODEL_NB_STR_CHAR,
DIS_IDX_MODEL_NB_STR_VAL,
// Serial Number String Char.
DIS_IDX_SERIAL_NB_STR_CHAR,
DIS_IDX_SERIAL_NB_STR_VAL,
// Hardware Revision String Char.
DIS_IDX_HW_REV_STR_CHAR,
DIS_IDX_HW_REV_STR_VAL,
// Firmware Revision String Char.
DIS_IDX_FW_REV_STR_CHAR,
DIS_IDX_FW_REV_STR_VAL,
// Software Revision String Char.
DIS_IDX_SW_REV_STR_CHAR,
DIS_IDX_SW_REV_STR_VAL,
// System Identifier Char.
DIS_IDX_SYS_ID_CHAR,
DIS_IDX_SYS_ID_VAL,
// IEEE Certificate Char.
DIS_IDX_IEEE_CHAR,
DIS_IDX_IEEE_VAL,
// PnP ID Char.
DIS_IDX_PNP_ID_CHAR,
DIS_IDX_PNP_ID_VAL,
// Max Index, *NOTE* Minus 1(Svc Decl) is .nb_att
DIS_IDX_NB,
};
/// Attributes Description
const att_decl_t dis_atts[] =
{
// Manufacturer Name Char. Declaration and Value
ATT_ELMT_DECL_CHAR( DIS_IDX_MANUF_NAME_CHAR ),
ATT_ELMT( DIS_IDX_MANUF_NAME_VAL, ATT_CHAR_MANUF_NAME, PROP_RD, DIS_VAL_MAX_LEN ),
// Model Number String Char. Declaration and Value
ATT_ELMT_DECL_CHAR( DIS_IDX_MODEL_NB_STR_CHAR ),
ATT_ELMT( DIS_IDX_MODEL_NB_STR_VAL, ATT_CHAR_MODEL_NB, PROP_RD, DIS_VAL_MAX_LEN ),
// Serial Number String Char. Declaration and Value
ATT_ELMT_DECL_CHAR( DIS_IDX_SERIAL_NB_STR_CHAR ),
ATT_ELMT( DIS_IDX_SERIAL_NB_STR_VAL, ATT_CHAR_SERIAL_NB, PROP_RD, DIS_VAL_MAX_LEN ),
// Hardware Revision String Char. Declaration and Value
ATT_ELMT_DECL_CHAR( DIS_IDX_HW_REV_STR_CHAR ),
ATT_ELMT( DIS_IDX_HW_REV_STR_VAL, ATT_CHAR_HW_REV, PROP_RD, DIS_VAL_MAX_LEN ),
// Firmware Revision String Char. Declaration and Value
ATT_ELMT_DECL_CHAR( DIS_IDX_FW_REV_STR_CHAR ),
ATT_ELMT( DIS_IDX_FW_REV_STR_VAL, ATT_CHAR_FW_REV, PROP_RD, DIS_VAL_MAX_LEN ),
// Software Revision String Char. Declaration and Value
ATT_ELMT_DECL_CHAR( DIS_IDX_SW_REV_STR_CHAR ),
ATT_ELMT( DIS_IDX_SW_REV_STR_VAL, ATT_CHAR_SW_REV, PROP_RD, DIS_VAL_MAX_LEN ),
// System ID Char. Declaration and Value
ATT_ELMT_DECL_CHAR( DIS_IDX_SYS_ID_CHAR ),
ATT_ELMT( DIS_IDX_SYS_ID_VAL, ATT_CHAR_SYS_ID, PROP_RD, DIS_SYS_ID_LEN ),
// IEEE 11073-20601 Regulatory Certification Data List Char. Declaration and Value
ATT_ELMT_DECL_CHAR( DIS_IDX_IEEE_CHAR ),
ATT_ELMT( DIS_IDX_IEEE_VAL, ATT_CHAR_IEEE_CERTIF, PROP_RD, DIS_SYS_ID_LEN ),
// PnP ID Char. Declaration and Value
ATT_ELMT_DECL_CHAR( DIS_IDX_PNP_ID_CHAR ),
ATT_ELMT( DIS_IDX_PNP_ID_VAL, ATT_CHAR_PNP_ID, PROP_RD, DIS_PNP_ID_LEN ),
};
/// Service Description
const struct svc_decl dis_svc_db =
{
{.uuid = ATT_SVC_DEVICE_INFO},
.info = SVC_UUID(16),
.atts = dis_atts,
.nb_att = DIS_IDX_NB - 1,
};
/*
* FUNCTION DECLARATIONS
****************************************************************************************
*/
/**
****************************************************************************************
* @section SVC FUNCTIONS
****************************************************************************************
*/
/// Retrieve value index from attribute handle
static uint8_t diss_get_val_idx(uint16_t handle)
{
// handle start from first characteristic value handle
uint16_t cur_hdl = diss_env.start_hdl + 2;
for (uint8_t idx = 0; idx < DIS_CHAR_MAX; idx++)
{
if (((diss_env.features >> idx) & 1) == 1)
{
// check if value handle correspond to requested handle
if (cur_hdl == handle)
{
return idx;
}
cur_hdl += 2;
}
}
return DIS_CHAR_MAX;
}
/// Handles reception of the read request from peer device
static void diss_svc_func(uint8_t conidx, uint8_t opcode, uint16_t handle, const void *param)
{
uint8_t val_idx = diss_get_val_idx(handle);
DEBUG("svc_func(cid:%d,op:0x%x,hdl:0x%x,att:%d)", conidx, opcode, handle, val_idx);
if (opcode == ATTS_READ_REQ)
{
// Check Characteristic Code
if (val_idx < DIS_CHAR_MAX)
{
uint16_t length;
const uint8_t *value = diss_value_get(val_idx, &length);
if (value != NULL)
{
// Send value to peer device.
gatt_read_cfm(conidx, LE_SUCCESS, handle, length, value);
return;
}
}
// application error, value cannot be retrieved
gatt_read_cfm(conidx, PRF_ERR_APP_ERROR, handle, 0, NULL);
}
}
/**
****************************************************************************************
* @section API FUNCTIONS
****************************************************************************************
*/
/**
****************************************************************************************
* @brief Add Device Information Profile in the DB.
* Customize via pre-define @see DIS_START_HDL @see DIS_FEATURES
*
* @return Result status, LE_SUCCESS or Error Reason
****************************************************************************************
*/
uint8_t diss_svc_init(void)
{
uint8_t status = LE_SUCCESS;
uint32_t cfg_att = 0;
// Init Environment
diss_env.start_hdl = DIS_START_HDL;
diss_env.features = DIS_FEATURES;
// Compute Attributes supported
for (uint8_t i = 0; i < DIS_CHAR_MAX; i++)
{
if (((diss_env.features >> i) & 1) == 1)
{
cfg_att |= (3 << (i*2 + 1)); // 3:CHAR + VAL
}
}
// Create Service in database
status = attmdb_svc_create(&diss_env.start_hdl, (uint8_t *)&cfg_att, &dis_svc_db, diss_svc_func);
DEBUG("svc_init(sta:0x%X,shdl:%d,feat:0x%X,cfg:0x%X)",
status, diss_env.start_hdl, diss_env.features, cfg_att);
return status;
}
/**
****************************************************************************************
* @brief Get value for attribute read (__weak func)
*
* @param[in] val_idx Index of Value to set @see enum dis_values
* @param[out] p_len Value Length
*
* @return Value data pointer
****************************************************************************************
*/
__weak const uint8_t *diss_value_get(uint8_t val_idx, uint16_t *p_len)
{
uint16_t length = 0;
const uint8_t *p_data = NULL;
// Retrieve value information
switch (val_idx)
{
#if DIS_FEAT_SUP(MANUF_NAME)
case DIS_MANUF_NAME_CHAR:
{
length = INFO_MANUF_NAME_LEN;
p_data = (const uint8_t *)INFO_MANUF_NAME;
} break;
#endif
#if DIS_FEAT_SUP(MODEL_NB_STR)
case DIS_MODEL_NB_STR_CHAR:
{
length = INFO_MODEL_NB_STR_LEN;
p_data = (const uint8_t *)INFO_MODEL_NB_STR;
} break;
#endif
#if DIS_FEAT_SUP(SERIAL_NB_STR)
case DIS_SERIAL_NB_STR_CHAR:
{
length = INFO_SERIAL_NB_STR_LEN;
p_data = (const uint8_t *)INFO_SERIAL_NB_STR;
} break;
#endif
#if DIS_FEAT_SUP(HW_REV_STR)
case DIS_HW_REV_STR_CHAR:
{
length = INFO_HW_REV_STR_LEN;
p_data = (const uint8_t *)INFO_HW_REV_STR;
} break;
#endif
#if DIS_FEAT_SUP(FW_REV_STR)
case DIS_FW_REV_STR_CHAR:
{
length = INFO_FW_REV_STR_LEN;
p_data = (const uint8_t *)INFO_FW_REV_STR;
} break;
#endif
#if DIS_FEAT_SUP(SW_REV_STR)
case DIS_SW_REV_STR_CHAR:
{
length = INFO_SW_REV_STR_LEN;
p_data = (const uint8_t *)INFO_SW_REV_STR;
} break;
#endif
#if DIS_FEAT_SUP(SYS_ID)
case DIS_SYS_ID_CHAR:
{
// Check if length matches particular requirements
if (INFO_SYS_ID_LEN == DIS_SYS_ID_LEN)
{
length = INFO_SYS_ID_LEN;
p_data = (const uint8_t *)INFO_SYS_ID;
}
} break;
#endif
#if DIS_FEAT_SUP(IEEE)
case DIS_IEEE_CHAR:
{
// Check if length matches particular requirements
if (INFO_IEEE_LEN >= DIS_IEEE_CERTIF_MIN_LEN)
{
length = INFO_IEEE_LEN;
p_data = (const uint8_t *)INFO_IEEE;
}
} break;
#endif
#if DIS_FEAT_SUP(PNP_ID)
case DIS_PNP_ID_CHAR:
{
// Check if length matches particular requirements
if (INFO_PNP_ID_LEN == DIS_PNP_ID_LEN)
{
length = INFO_PNP_ID_LEN;
p_data = (const uint8_t *)INFO_PNP_ID;
}
} break;
#endif
default:
break;
}
// Check value length not exceed MAX_LEN
if (length > DIS_VAL_MAX_LEN)
{
length = DIS_VAL_MAX_LEN;
}
DEBUG("value_get(req:%d,len:%d)", val_idx, length);
*p_len = length;
return p_data;
}
#endif //(PRF_DISS)