bleSDK_expansion_board/ble/prf/prf_hids.c

928 lines
30 KiB
C

/**
****************************************************************************************
*
* @file prf_hids.c
*
* @brief HID Service Profile - Template Source.
*
* < Implementation according to user's application-specific >
****************************************************************************************
*/
#if (PRF_HIDS)
/*
* INCLUDE FILES
****************************************************************************************
*/
#include "prf.h"
#include "hid_desc.h" // application-specific, #include "prf_hids.h"
#if (DBG_HIDS)
#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
****************************************************************************************
*/
/// Support Boot Protocol Mode or Not
#if !defined(HID_BOOT_SUP)
#define HID_BOOT_SUP (0)
#define HID_BOOT_KB (0)
#define HID_BOOT_MOUSE (0)
#endif
/// Support Report Protocol Mode or Not
#if !defined(HID_REPORT_SUP)
#define HID_REPORT_SUP (1)
#define HID_RPT_KB (1)
#define HID_RPT_MEDIA (1)
#define HID_RPT_SYSTEM (1)
#define HID_RPT_MOUSE (1)
#define HID_RPT_PTP (0)
#endif
/// Support Number of HID Connections
#if !defined(HID_CONN_MAX)
#define HID_CONN_MAX (1) // always one, BLE_CONNECTION_MAX
#endif
/// Macro for Client Config value operation
#define HID_RPT_NTF_GET(conidx, ntf_idx) \
((hids_env.conn[conidx].rpt_ntfs >> (ntf_idx)) & PRF_CLI_START_NTF)
#define HID_RPT_NTF_CLR(conidx, ntf_idx) \
hids_env.conn[conidx].rpt_ntfs &= ~(PRF_CLI_START_NTF << (ntf_idx))
#define HID_RPT_NTF_SET(conidx, ntf_idx, conf) \
hids_env.conn[conidx].rpt_ntfs = (hids_env.conn[conidx].rpt_ntfs & ~(PRF_CLI_START_NTF << (ntf_idx))) | ((conf) << (ntf_idx))
/**
****************************************************************************************
* @section ENVIRONMENT DEFINITION
****************************************************************************************
*/
typedef struct hid_conn_tag
{
// Client Config of peer devices, max_bits=RPT_IDX_NB
uint8_t rpt_ntfs;
// keyboard Locks (bit0:num lock, bit1:caps lock, bit2:scroll lock)
uint8_t led_lock;
// Control Point key @see enum hid_ctrl_pt
uint8_t ctrl_pt;
// Boot or Report mode, @see enum hid_proto_mode
uint8_t proto_mode;
} hid_conn_t;
/// HIDS Server Environment Sariable
typedef struct hids_env_tag
{
// Service Start Handle
uint16_t start_hdl;
// Number of notify pkt
uint8_t nb_pkt;
// Connection Info
hid_conn_t conn[HID_CONN_MAX];
} hids_env_t;
/// Global Variable Declarations
__VAR_ENV hids_env_t hids_env;
/**
****************************************************************************************
* @section ATTRIBUTES DEFINITION
****************************************************************************************
*/
/// HID Attributes Index
enum hid_att_idx
{
// Service Declaration, *MUST* Start at 0
HID_IDX_SVC,
// HID Information
HID_IDX_HID_INFO_CHAR,
HID_IDX_HID_INFO_VAL,
// HID Control Point
HID_IDX_HID_CTRL_PT_CHAR,
HID_IDX_HID_CTRL_PT_VAL,
// Report Map
HID_IDX_REPORT_MAP_CHAR, //5
HID_IDX_REPORT_MAP_VAL,
#if (HID_BOOT_SUP)
// Protocol Mode(0-BOOT, 1-REPORT)
HID_IDX_PROTO_MODE_CHAR,
HID_IDX_PROTO_MODE_VAL,
#if (HID_BOOT_KB)
// Boot Keyboard Input Report
HID_IDX_BOOT_KB_IN_RPT_CHAR,
HID_IDX_BOOT_KB_IN_RPT_VAL, //10
HID_IDX_BOOT_KB_IN_RPT_NTF_CFG,
// Boot Keyboard Output Report
HID_IDX_BOOT_KB_OUT_RPT_CHAR,
HID_IDX_BOOT_KB_OUT_RPT_VAL,
#endif //(HID_BOOT_KB)
#if (HID_BOOT_MOUSE)
// Boot Mouse Input Report
HID_IDX_BOOT_MOUSE_IN_RPT_CHAR,
HID_IDX_BOOT_MOUSE_IN_RPT_VAL, //15
HID_IDX_BOOT_MOUSE_IN_RPT_NTF_CFG,
#endif //(HID_BOOT_MOUSE)
#endif //(HID_BOOT_SUP)
#if (HID_REPORT_SUP)
#if (HID_RPT_KB)
// Keyboard Report IN
HID_IDX_KB_IN_RPT_CHAR,
HID_IDX_KB_IN_RPT_VAL,
HID_IDX_KB_IN_RPT_REF,
HID_IDX_KB_IN_RPT_NTF_CFG, //20
// Keyboard Report OUT
HID_IDX_KB_OUT_RPT_CHAR,
HID_IDX_KB_OUT_RPT_VAL,
HID_IDX_KB_OUT_RPT_REF,
#endif //(HID_RPT_KB)
#if (HID_RPT_MEDIA)
// Media IN Report
HID_IDX_MEDIA_IN_RPT_CHAR,
HID_IDX_MEDIA_IN_RPT_VAL, //25
HID_IDX_MEDIA_IN_RPT_REF,
HID_IDX_MEDIA_IN_RPT_NTF_CFG,
#endif //(HID_RPT_MEDIA)
#if (HID_RPT_SYSTEM)
// System IN Report
HID_IDX_SYS_IN_RPT_CHAR,
HID_IDX_SYS_IN_RPT_VAL,
HID_IDX_SYS_IN_RPT_REF, //30
HID_IDX_SYS_IN_RPT_NTF_CFG,
#endif //(HID_RPT_SYSTEM)
#if (HID_RPT_MOUSE)
// Mouse IN Report
HID_IDX_MOUSE_IN_RPT_CHAR,
HID_IDX_MOUSE_IN_RPT_VAL,
HID_IDX_MOUSE_IN_RPT_REF,
HID_IDX_MOUSE_IN_RPT_NTF_CFG, //35
#endif //(HID_RPT_MOUSE)
#if (HID_RPT_PTP)
// TouchPad IN Report
HID_IDX_TP_IN_RPT_CHAR,
HID_IDX_TP_IN_RPT_VAL,
HID_IDX_TP_IN_RPT_REF,
HID_IDX_TP_IN_RPT_NTF_CFG,
// MaxCnt FEAT Report
HID_IDX_MAXCNT_FEAT_RPT_CHAR, //40
HID_IDX_MAXCNT_FEAT_RPT_VAL,
HID_IDX_MAXCNT_FEAT_RPT_REF,
// PTPHQA FEAT Report
HID_IDX_PTPHQA_FEAT_RPT_CHAR,
HID_IDX_PTPHQA_FEAT_RPT_VAL,
HID_IDX_PTPHQA_FEAT_RPT_REF, //45
#endif //(HID_RPT_PTP)
#endif //(HID_REPORT_SUP)
// Max Index, *NOTE* Minus 1(Svc Decl) is .nb_att
HID_IDX_NB,
};
/// Attributes Description
const att_decl_t hid_atts[] =
{
// HID Information Char. Declaration and Value
ATT_ELMT_DECL_CHAR( HID_IDX_HID_INFO_CHAR ),
ATT_ELMT( HID_IDX_HID_INFO_VAL, ATT_CHAR_HID_INFO, PROP_RD, HID_INFO_SIZE ),
// HID Control Point Char. Declaration
ATT_ELMT_DECL_CHAR( HID_IDX_HID_CTRL_PT_CHAR ),
ATT_ELMT( HID_IDX_HID_CTRL_PT_VAL, ATT_CHAR_HID_CTRL_PT, PROP_WC, HID_CTRL_PT_SIZE ),
// Report Map Char. Declaration and Value
ATT_ELMT_DECL_CHAR( HID_IDX_REPORT_MAP_CHAR ),
ATT_ELMT( HID_IDX_REPORT_MAP_VAL, ATT_CHAR_REPORT_MAP, PROP_RD, 0 ),
#if (HID_BOOT_SUP)
// Protocol Mode Char. Declaration and Value
ATT_ELMT_DECL_CHAR( HID_IDX_PROTO_MODE_CHAR ),
ATT_ELMT( HID_IDX_PROTO_MODE_VAL, ATT_CHAR_PROTOCOL_MODE, PROP_RD | PROP_WC, HID_PROTO_MODE_SIZE ),
#if (HID_BOOT_KB)
// Boot Keyboard Input Report Char. Declaration and Value and CCC Descriptor
ATT_ELMT_DECL_CHAR( HID_IDX_BOOT_KB_IN_RPT_CHAR ),
ATT_ELMT( HID_IDX_BOOT_KB_IN_RPT_VAL, ATT_CHAR_BOOT_KB_IN_REPORT, PROP_RD | PROP_NTF, HID_BOOT_REPORT_MAX_LEN ),
ATT_ELMT_DESC_CLI_CHAR_CFG( HID_IDX_BOOT_KB_IN_RPT_NTF_CFG ),
// Boot Keyboard Output Report Char. Declaration and Value
ATT_ELMT_DECL_CHAR( HID_IDX_BOOT_KB_OUT_RPT_CHAR ),
ATT_ELMT( HID_IDX_BOOT_KB_OUT_RPT_VAL, ATT_CHAR_BOOT_KB_OUT_REPORT, PROP_RD | PROP_WR | PROP_WC, HID_BOOT_REPORT_MAX_LEN ),
#endif //(HID_BOOT_KB)
#if (HID_BOOT_MOUSE)
// Boot Mouse Input Report Char. Declaration and Value and CCC Descriptor
ATT_ELMT_DECL_CHAR( HID_IDX_BOOT_MOUSE_IN_RPT_CHAR ),
ATT_ELMT( HID_IDX_BOOT_MOUSE_IN_RPT_VAL, ATT_CHAR_BOOT_MOUSE_IN_REPORT, PROP_RD | PROP_NTF, HID_BOOT_REPORT_MAX_LEN ),
ATT_ELMT_DESC_CLI_CHAR_CFG( HID_IDX_BOOT_MOUSE_IN_RPT_NTF_CFG ),
#endif //(HID_BOOT_MOUSE)
#endif //(HID_BOOT_SUP)
#if (HID_REPORT_SUP)
#if (HID_RPT_KB)
// Keyboard IN Report Char. Declaration and Value, Report Ref. and CCC Descriptor
ATT_ELMT_DECL_CHAR( HID_IDX_KB_IN_RPT_CHAR ),
ATT_ELMT( HID_IDX_KB_IN_RPT_VAL, ATT_CHAR_REPORT, PROP_RD | PROP_NTF, HID_REPORT_MAX_LEN ),
ATT_ELMT_DESC_REPORT_REF( HID_IDX_KB_IN_RPT_REF ),
ATT_ELMT_DESC_CLI_CHAR_CFG( HID_IDX_KB_IN_RPT_NTF_CFG ),
// Keyboard OUT Report Char. Declaration and Value, Report Ref. Descriptor
ATT_ELMT_DECL_CHAR( HID_IDX_KB_OUT_RPT_CHAR ),
// Report Characteristic Value
ATT_ELMT( HID_IDX_KB_OUT_RPT_VAL, ATT_CHAR_REPORT, PROP_RD | PROP_WR | PROP_WC, HID_REPORT_MAX_LEN ),
// Report Characteristic - Report Reference Descriptor
ATT_ELMT_DESC_REPORT_REF( HID_IDX_KB_OUT_RPT_REF ),
#endif //(HID_RPT_KB)
#if (HID_RPT_MEDIA)
// Media IN Report Char. Declaration and Value, Report Ref. and CCC Descriptor
ATT_ELMT_DECL_CHAR( HID_IDX_MEDIA_IN_RPT_CHAR ),
ATT_ELMT( HID_IDX_MEDIA_IN_RPT_VAL, ATT_CHAR_REPORT, PROP_RD | PROP_NTF, HID_REPORT_MAX_LEN ),
ATT_ELMT_DESC_REPORT_REF( HID_IDX_MEDIA_IN_RPT_REF ),
ATT_ELMT_DESC_CLI_CHAR_CFG( HID_IDX_MEDIA_IN_RPT_NTF_CFG ),
#endif //(HID_RPT_MEDIA)
#if (HID_RPT_SYSTEM)
// System IN Report Char. Declaration and Value, Report Ref. and CCC Descriptor
ATT_ELMT_DECL_CHAR( HID_IDX_SYS_IN_RPT_CHAR ),
ATT_ELMT( HID_IDX_SYS_IN_RPT_VAL, ATT_CHAR_REPORT, PROP_RD | PROP_NTF, HID_REPORT_MAX_LEN ),
ATT_ELMT_DESC_REPORT_REF( HID_IDX_SYS_IN_RPT_REF ),
ATT_ELMT_DESC_CLI_CHAR_CFG( HID_IDX_SYS_IN_RPT_NTF_CFG ),
#endif //(HID_RPT_SYSTEM)
#if (HID_RPT_MOUSE)
// Mouse IN Report Char. Declaration and Value, Report Ref. and CCC Descriptor
ATT_ELMT_DECL_CHAR( HID_IDX_MOUSE_IN_RPT_CHAR ),
ATT_ELMT( HID_IDX_MOUSE_IN_RPT_VAL, ATT_CHAR_REPORT, PROP_RD | PROP_NTF, HID_REPORT_MAX_LEN ),
ATT_ELMT_DESC_REPORT_REF( HID_IDX_MOUSE_IN_RPT_REF ),
ATT_ELMT_DESC_CLI_CHAR_CFG( HID_IDX_MOUSE_IN_RPT_NTF_CFG ),
#endif //(HID_RPT_MOUSE)
#if (HID_RPT_PTP)
// TouchPad IN Report Char. Declaration and Value, Report Ref. and CCC Descriptor
ATT_ELMT_DECL_CHAR( HID_IDX_TP_IN_RPT_CHAR ),
ATT_ELMT( HID_IDX_TP_IN_RPT_VAL, ATT_CHAR_REPORT, PROP_RD | PROP_NTF, HID_REPORT_MAX_LEN ),
ATT_ELMT_DESC_REPORT_REF( HID_IDX_TP_IN_RPT_REF ),
ATT_ELMT_DESC_CLI_CHAR_CFG( HID_IDX_TP_IN_RPT_NTF_CFG ),
// Max Count Feature Report Char. Declaration and Value, Report Ref. Descriptor
ATT_ELMT_DECL_CHAR( HID_IDX_MAXCNT_FEAT_RPT_CHAR ),
ATT_ELMT( HID_IDX_MAXCNT_FEAT_RPT_VAL, ATT_CHAR_REPORT, PROP_RD | PROP_WR, HID_REPORT_MAX_LEN ),
ATT_ELMT_DESC_REPORT_REF( HID_IDX_MAXCNT_FEAT_RPT_REF ),
// PTPHQA Feature Report Char. Declaration and Value, Report Ref. Descriptor
ATT_ELMT_DECL_CHAR( HID_IDX_PTPHQA_FEAT_RPT_CHAR ),
ATT_ELMT( HID_IDX_PTPHQA_FEAT_RPT_VAL, ATT_CHAR_REPORT, PROP_RD | PROP_WR, HID_REPORT_MAX_LEN ),
ATT_ELMT_DESC_REPORT_REF( HID_IDX_PTPHQA_FEAT_RPT_REF ),
#endif //(HID_RPT_PTP)
#endif //(HID_REPORT_SUP)
};
/// Service Description
const struct svc_decl hid_svc_db =
{
.uuid = ATT_SVC_HID,
.info = SVC_UUID(16) | SVC_SEC(UNAUTH),
.atts = hid_atts,
.nb_att = HID_IDX_NB - 1,
};
/*
* FUNCTION DECLARATIONS
****************************************************************************************
*/
/**
****************************************************************************************
* @section SVC FUNCTIONS
****************************************************************************************
*/
/// Retrieve attribute index form handle
static uint8_t hids_get_att_idx(uint16_t handle)
{
ASSERT_ERR((handle >= hids_env.start_hdl) && (handle < hids_env.start_hdl + HID_IDX_NB));
return (handle - hids_env.start_hdl);
}
/// Retrieve Report attribute handle from rpt_idx (@see rpt_ntf_idx) or ATT_INVALID_HDL
static uint16_t hids_get_rpt_handle(uint8_t rpt_idx)
{
uint8_t att_idx = 0;
switch (rpt_idx)
{
#if (HID_BOOT_SUP)
#if (HID_BOOT_KB)
case RPT_IDX_BOOT_KB:
{
att_idx = HID_IDX_BOOT_KB_IN_RPT_VAL;
} break;
#endif //(HID_BOOT_KB)
#if (HID_BOOT_MOUSE)
case RPT_IDX_BOOT_MOUSE:
{
att_idx = HID_IDX_BOOT_MOUSE_IN_RPT_VAL;
} break;
#endif //(HID_BOOT_MOUSE)
#endif //(HID_BOOT_SUP)
#if (HID_REPORT_SUP)
#if (HID_RPT_KB)
case RPT_IDX_KB:
{
att_idx = HID_IDX_KB_IN_RPT_VAL;
} break;
#endif //(HID_RPT_KB)
#if (HID_RPT_MEDIA)
case RPT_IDX_MEDIA:
{
att_idx = HID_IDX_MEDIA_IN_RPT_VAL;
} break;
#endif //(HID_RPT_MEDIA)
#if (HID_RPT_SYSTEM)
case RPT_IDX_SYSTEM:
{
att_idx = HID_IDX_SYS_IN_RPT_VAL;
} break;
#endif //(HID_RPT_SYSTEM)
#if (HID_RPT_MOUSE)
case RPT_IDX_MOUSE:
{
att_idx = HID_IDX_MOUSE_IN_RPT_VAL;
} break;
#endif //(HID_RPT_MOUSE)
#if (HID_RPT_PTP)
case RPT_IDX_TP:
{
att_idx = HID_IDX_TP_IN_RPT_VAL;
} break;
#endif //(HID_RPT_PTP)
#endif //(HID_REPORT_SUP)
default:
{
att_idx = 0; // error index
} break;
}
return (att_idx) ? (hids_env.start_hdl + att_idx) : ATT_INVALID_HDL;
}
/// update configuration if value for stop or NTF start
static uint8_t hids_rpt_ntf_cfg(uint8_t conidx, uint8_t rpt_idx, const struct atts_write_ind *ind)
{
uint8_t status = PRF_ERR_APP_ERROR;
if ((!ind->more) && (ind->length == sizeof(uint16_t)))
{
uint16_t cli_cfg = read16p(ind->value);
//if ((cli_cfg == PRF_CLI_STOP_NTFIND) || (cli_cfg == PRF_CLI_START_NTF))
if (cli_cfg <= PRF_CLI_START_NTF)
{
DEBUG(" RPT_NTF_CFG(idx:%d,cfg:%d)", rpt_idx, cli_cfg);
HID_RPT_NTF_SET(conidx, rpt_idx, cli_cfg);
status = LE_SUCCESS;
}
}
return status;
}
/// Confirm ATTS_WRITE_REQ
static void hids_att_write_cfm(uint8_t conidx, uint8_t att_idx, uint16_t handle, const struct atts_write_ind *ind)
{
uint8_t status = LE_SUCCESS;
switch (att_idx)
{
case HID_IDX_HID_CTRL_PT_VAL:
{
ASSERT_ERR(ind->length == HID_CTRL_PT_SIZE);
DEBUG(" HID_CTRL_PT:%d", ind->value[0]);
hids_env.conn[conidx].ctrl_pt = ind->value[0];
} break;
#if (HID_BOOT_SUP)
case HID_IDX_PROTO_MODE_VAL:
{
ASSERT_ERR(ind->length == HID_PROTO_MODE_SIZE);
DEBUG(" PROTO_MODE:%d", ind->value[0]);
hids_env.conn[conidx].proto_mode = ind->value[0];
} break;
#if (HID_BOOT_KB)
case HID_IDX_BOOT_KB_IN_RPT_NTF_CFG:
{
status = hids_rpt_ntf_cfg(conidx, RPT_IDX_BOOT_KB, ind);
} break;
case HID_IDX_BOOT_KB_OUT_RPT_VAL:
{
ASSERT_ERR(ind->length == HID_KB_OUT_RPT_SIZE);
DEBUG(" Led_Lock(b0:num,b1:caps,b2:scroll):0x%02x", ind->value[0]);
hids_env.conn[conidx].led_lock = ind->value[0];
hids_led_lock(ind->value[0]);
} break;
#endif //(HID_BOOT_KB)
#if (HID_BOOT_MOUSE)
case HID_IDX_BOOT_MOUSE_IN_RPT_NTF_CFG:
{
status = hids_rpt_ntf_cfg(conidx, RPT_IDX_BOOT_MOUSE, ind);
} break;
#endif //(HID_BOOT_MOUSE)
#endif //(HID_BOOT_SUP)
#if (HID_REPORT_SUP)
#if (HID_RPT_KB)
case HID_IDX_KB_IN_RPT_NTF_CFG:
{
status = hids_rpt_ntf_cfg(conidx, RPT_IDX_KB, ind);
} break;
case HID_IDX_KB_OUT_RPT_VAL:
{
ASSERT_ERR(ind->length == HID_KB_OUT_RPT_SIZE);
DEBUG(" Led_Lock(b0:num,b1:caps,b2:scroll):0x%02x", ind->value[0]);
hids_env.conn[conidx].led_lock = ind->value[0];
hids_led_lock(ind->value[0]);
} break;
#endif //(HID_RPT_KB)
#if (HID_RPT_MEDIA)
case HID_IDX_MEDIA_IN_RPT_NTF_CFG:
{
status = hids_rpt_ntf_cfg(conidx, RPT_IDX_MEDIA, ind);
} break;
#endif //(HID_RPT_MEDIA)
#if (HID_RPT_SYSTEM)
case HID_IDX_SYS_IN_RPT_NTF_CFG:
{
status = hids_rpt_ntf_cfg(conidx, RPT_IDX_SYSTEM, ind);
} break;
#endif //(HID_RPT_SYSTEM)
#if (HID_RPT_MOUSE)
case HID_IDX_MOUSE_IN_RPT_NTF_CFG:
{
status = hids_rpt_ntf_cfg(conidx, RPT_IDX_MOUSE, ind);
} break;
#endif //(HID_RPT_MOUSE)
#if (HID_RPT_PTP)
case HID_IDX_TP_IN_RPT_NTF_CFG:
{
status = hids_rpt_ntf_cfg(conidx, RPT_IDX_TP, ind);
} break;
case HID_IDX_MAXCNT_FEAT_RPT_VAL:
case HID_IDX_PTPHQA_FEAT_RPT_VAL:
{
// maybe do something
} break;
#endif //(HID_RPT_PTP)
#endif //(HID_REPORT_SUP)
default:
{
status = PRF_ERR_APP_ERROR;
} break;
}
// Send write confirm, if no more data.
if (!ind->more)
gatt_write_cfm(conidx, status, handle);
}
/// Confirm ATTS_READ_REQ
static void hids_att_read_cfm(uint8_t conidx, uint8_t att_idx, uint16_t handle)
{
uint16_t length = 0;
switch (att_idx)
{
case HID_IDX_HID_INFO_VAL:
{
struct hid_info_tag hid_info;
hid_info.bcdHID = HID_INFO_BCDHID;
hid_info.bCountryCode = HID_INFO_BCODE;
hid_info.flags = HID_INFO_FLAGS;
DEBUG(" Read HID_INFO(bcd:0x%04X)", hid_info.bcdHID);
gatt_read_cfm(conidx, LE_SUCCESS, handle, HID_INFO_SIZE, (uint8_t *)&hid_info);
} break;
case HID_IDX_REPORT_MAP_VAL:
{
const uint8_t *report_map = hid_get_report_map(&length);
DEBUG(" Read REPORT_MAP(size:%d)", length);
gatt_read_cfm(conidx, LE_SUCCESS, handle, length, report_map);
} break;
#if (HID_BOOT_SUP)
case HID_IDX_PROTO_MODE_VAL:
{
DEBUG(" Read PROTO_MODE(mode:%d)", hids_env.conn[conidx].proto_mode);
gatt_read_cfm(conidx, LE_SUCCESS, handle, HID_PROTO_MODE_SIZE, &(hids_env.conn[conidx].proto_mode));
} break;
#if (HID_BOOT_KB)
case HID_IDX_BOOT_KB_IN_RPT_VAL:
{
gatt_read_cfm(conidx, LE_SUCCESS, handle, HID_BOOT_KB_RPT_SIZE, NULL); // zero array
} break;
case HID_IDX_BOOT_KB_IN_RPT_NTF_CFG:
{
uint16_t ntf_cfg = HID_RPT_NTF_GET(conidx, RPT_IDX_BOOT_KB);
gatt_read_cfm(conidx, LE_SUCCESS, handle, sizeof(uint16_t), (uint8_t *)&ntf_cfg);
} break;
case HID_IDX_BOOT_KB_OUT_RPT_VAL:
{
gatt_read_cfm(conidx, LE_SUCCESS, handle, HID_KB_OUT_RPT_SIZE, &(hids_env.conn[conidx].led_lock));
} break;
#endif //(HID_BOOT_KB)
#if (HID_BOOT_MOUSE)
case HID_IDX_BOOT_MOUSE_IN_RPT_VAL:
{
gatt_read_cfm(conidx, LE_SUCCESS, handle, HID_BOOT_MOUSE_RPT_SIZE, NULL); // zero array
} break;
case HID_IDX_BOOT_MOUSE_IN_RPT_NTF_CFG:
{
uint16_t ntf_cfg = HID_RPT_NTF_GET(conidx, RPT_IDX_BOOT_MOUSE);
gatt_read_cfm(conidx, LE_SUCCESS, handle, sizeof(uint16_t), (uint8_t *)&ntf_cfg);
} break;
#endif //(HID_BOOT_MOUSE)
#endif //(HID_BOOT_SUP)
#if (HID_REPORT_SUP)
#if (HID_RPT_KB)
case HID_IDX_KB_IN_RPT_VAL:
{
gatt_read_cfm(conidx, LE_SUCCESS, handle, RPT_LEN_KB, NULL); // zero array
} break;
case HID_IDX_KB_IN_RPT_REF:
{
struct hid_report_ref refer;
refer.report_id = RPT_ID_KB;
refer.report_type = HID_REPORT_INPUT;
gatt_read_cfm(conidx, LE_SUCCESS, handle, HID_REPORT_REF_SIZE, (uint8_t *)&refer);
} break;
case HID_IDX_KB_IN_RPT_NTF_CFG:
{
uint16_t ntf_cfg = HID_RPT_NTF_GET(conidx, RPT_IDX_KB);
gatt_read_cfm(conidx, LE_SUCCESS, handle, sizeof(uint16_t), (uint8_t *)&ntf_cfg);
} break;
case HID_IDX_KB_OUT_RPT_VAL:
{
gatt_read_cfm(conidx, LE_SUCCESS, handle, HID_KB_OUT_RPT_SIZE, &(hids_env.conn[conidx].led_lock));
} break;
case HID_IDX_KB_OUT_RPT_REF:
{
struct hid_report_ref refer;
refer.report_id = RPT_ID_KB;
refer.report_type = HID_REPORT_OUTPUT;
gatt_read_cfm(conidx, LE_SUCCESS, handle, HID_REPORT_REF_SIZE, (uint8_t *)&refer);
} break;
#endif //(HID_RPT_KB)
#if (HID_RPT_MEDIA)
case HID_IDX_MEDIA_IN_RPT_VAL:
{
gatt_read_cfm(conidx, LE_SUCCESS, handle, RPT_LEN_MEDIA, NULL); // zero array
} break;
case HID_IDX_MEDIA_IN_RPT_REF:
{
struct hid_report_ref refer;
refer.report_id = RPT_ID_MEDIA;
refer.report_type = HID_REPORT_INPUT;
gatt_read_cfm(conidx, LE_SUCCESS, handle, HID_REPORT_REF_SIZE, (uint8_t *)&refer);
} break;
case HID_IDX_MEDIA_IN_RPT_NTF_CFG:
{
uint16_t ntf_cfg = HID_RPT_NTF_GET(conidx, RPT_IDX_MEDIA);
gatt_read_cfm(conidx, LE_SUCCESS, handle, sizeof(uint16_t), (uint8_t *)&ntf_cfg);
} break;
#endif //(HID_RPT_MEDIA)
#if (HID_RPT_SYSTEM)
case HID_IDX_SYS_IN_RPT_VAL:
{
gatt_read_cfm(conidx, LE_SUCCESS, handle, RPT_LEN_SYSTEM, NULL); // zero array
} break;
case HID_IDX_SYS_IN_RPT_REF:
{
struct hid_report_ref refer;
refer.report_id = RPT_ID_SYSTEM;
refer.report_type = HID_REPORT_INPUT;
gatt_read_cfm(conidx, LE_SUCCESS, handle, HID_REPORT_REF_SIZE, (uint8_t *)&refer);
} break;
case HID_IDX_SYS_IN_RPT_NTF_CFG:
{
uint16_t ntf_cfg = HID_RPT_NTF_GET(conidx, RPT_IDX_SYSTEM);
gatt_read_cfm(conidx, LE_SUCCESS, handle, sizeof(uint16_t), (uint8_t *)&ntf_cfg);
} break;
#endif //(HID_RPT_SYSTEM)
#if (HID_RPT_MOUSE)
case HID_IDX_MOUSE_IN_RPT_VAL:
{
gatt_read_cfm(conidx, LE_SUCCESS, handle, RPT_LEN_MOUSE, NULL); // zero array
} break;
case HID_IDX_MOUSE_IN_RPT_REF:
{
struct hid_report_ref refer;
refer.report_id = RPT_ID_MOUSE;
refer.report_type = HID_REPORT_INPUT;
gatt_read_cfm(conidx, LE_SUCCESS, handle, HID_REPORT_REF_SIZE, (uint8_t *)&refer);
} break;
case HID_IDX_MOUSE_IN_RPT_NTF_CFG:
{
uint16_t ntf_cfg = HID_RPT_NTF_GET(conidx, RPT_IDX_MOUSE);
gatt_read_cfm(conidx, LE_SUCCESS, handle, sizeof(uint16_t), (uint8_t *)&ntf_cfg);
} break;
#endif //(HID_RPT_MOUSE)
#if (HID_RPT_PTP)
case HID_IDX_TP_IN_RPT_VAL:
{
gatt_read_cfm(conidx, LE_SUCCESS, handle, RPT_LEN_TP, NULL); // zero array
} break;
case HID_IDX_TP_IN_RPT_REF:
{
struct hid_report_ref refer;
refer.report_id = RPT_ID_TP;
refer.report_type = HID_REPORT_INPUT;
gatt_read_cfm(conidx, LE_SUCCESS, handle, HID_REPORT_REF_SIZE, (uint8_t *)&refer);
} break;
case HID_IDX_TP_IN_RPT_NTF_CFG:
{
uint16_t ntf_cfg = HID_RPT_NTF_GET(conidx, RPT_IDX_TP);
gatt_read_cfm(conidx, LE_SUCCESS, handle, sizeof(uint16_t), (uint8_t *)&ntf_cfg);
} break;
case HID_IDX_MAXCNT_FEAT_RPT_VAL:
{
uint8_t finger = PTP_MAX_FINGER_CNT;
gatt_read_cfm(conidx, LE_SUCCESS, handle, sizeof(uint8_t), &finger);
} break;
case HID_IDX_MAXCNT_FEAT_RPT_REF:
{
struct hid_report_ref refer;
refer.report_id = RPT_ID_MAXCNT;
refer.report_type = HID_REPORT_FEATURE;
gatt_read_cfm(conidx, LE_SUCCESS, handle, HID_REPORT_REF_SIZE, (uint8_t *)&refer);
} break;
case HID_IDX_PTPHQA_FEAT_RPT_VAL:
{
const uint8_t *ptp_hqa = hid_get_ptphqa_blob(&length);
gatt_read_cfm(conidx, LE_SUCCESS, handle, length, ptp_hqa);
} break;
case HID_IDX_PTPHQA_FEAT_RPT_REF:
{
struct hid_report_ref refer;
refer.report_id = RPT_ID_PTPHQA;
refer.report_type = HID_REPORT_FEATURE;
gatt_read_cfm(conidx, LE_SUCCESS, handle, HID_REPORT_REF_SIZE, (uint8_t *)&refer);
} break;
#endif //(HID_RPT_PTP)
#endif //(HID_REPORT_SUP)
default:
{
// error response
gatt_read_cfm(conidx, PRF_ERR_APP_ERROR, handle, 0, NULL);
} break;
}
}
/// Handles reception of the atts request from peer device
static void hids_svc_func(uint8_t conidx, uint8_t opcode, uint16_t handle, const void *param)
{
uint8_t att_idx = hids_get_att_idx(handle);
ASSERT_ERR(coindx < HID_CONN_MAX);
DEBUG("svc_func(cid:%d,op:0x%x,hdl:0x%x,att:%d)", conidx, opcode, handle, att_idx);
switch (opcode)
{
case ATTS_READ_REQ:
{
hids_att_read_cfm(conidx, 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);
hids_att_write_cfm(conidx, att_idx, handle, ind);
} break;
case ATTS_INFO_REQ:
{
uint16_t length = ATT_MAX_LEN_GET(att_idx, hid_atts);
// Send length-info confirm for prepWR judging.
DEBUG(" info_cfm(hdl:0x%x,att:%d,len:%d)", handle, att_idx, length);
gatt_info_cfm(conidx, LE_SUCCESS, handle, length);
} break;
case ATTS_CMP_EVT:
{
const struct atts_cmp_evt *evt = param;
hids_env.nb_pkt++; // release
DEBUG(" cmp_evt(op:0x%x,sta:0x%x,nb:%d)", evt->operation, evt->status, hids_env.nb_pkt);
// 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 HID Service Profile in the DB
* Customize via pre-define @see HID_START_HDL
*
* @return Result status, LE_SUCCESS or Error Reason
****************************************************************************************
*/
uint8_t hids_prf_init(void)
{
uint8_t status = LE_SUCCESS;
// Init Environment
hids_env.start_hdl = HID_START_HDL;
hids_env.nb_pkt = HID_NB_PKT_MAX;
for (uint8_t conidx = 0; conidx < HID_CONN_MAX; conidx++)
{
hids_env.conn[conidx].rpt_ntfs = RPT_NTF_ALL;
hids_env.conn[conidx].led_lock = 0;
hids_env.conn[conidx].proto_mode = HID_REPORT_PROTOCOL_MODE;
hids_env.conn[conidx].ctrl_pt = HID_CTRL_PT_EXIT_SUSPEND;
}
// Create Service in database
status = attmdb_svc_create(&hids_env.start_hdl, NULL, &hid_svc_db, hids_svc_func);
DEBUG("svc_init(sta:0x%X,shdl:%d,atts:%d)", status, hids_env.start_hdl, HID_IDX_NB-1);
return status;
}
/**
****************************************************************************************
* @brief Show LED Lock of Keyboard Output, User Implement! (__weak func)
*
* @param[in] leds Bits of Led_Lock(b0:num,b1:caps,b2:scroll)
****************************************************************************************
*/
__weak void hids_led_lock(uint8_t leds)
{
// todo LED play...
}
/**
****************************************************************************************
* @brief Enable HID Notification Configurations.
*
* @param[in] conidx Connection index
* @param[in] rpt_ntf Notification Config Bits @see enum rpt_ntf_idx
****************************************************************************************
*/
void hids_set_ccc(uint8_t conidx, uint8_t rpt_ntf)
{
//if (gapc_get_conhdl(conidx) != GAP_INVALID_CONHDL)
{
// update configuration
hids_env.conn[conidx].rpt_ntfs = rpt_ntf;
}
}
/**
****************************************************************************************
* @brief Send HID Report to Host peer.
*
* @param[in] conidx Connection Index
* @param[in] rep_idx Report Index
* @param[in] rep_len Report Length
* @param[in] rep_val Report Value
*
* @return Status of the operation @see prf_err
****************************************************************************************
*/
uint8_t hids_report_send(uint8_t conidx, uint8_t rep_idx, uint16_t rep_len, const uint8_t* rep_val)
{
uint8_t status = PRF_ERR_REQ_DISALLOWED;
if ((rep_len > 0) && (hids_env.nb_pkt > 0))
{
if (HID_RPT_NTF_GET(conidx, rep_idx) == PRF_CLI_START_NTF)
{
uint16_t handle = hids_get_rpt_handle(rep_idx);
if (handle != ATT_INVALID_HDL)
{
hids_env.nb_pkt--; // allocate
DEBUG("hid_ntf_send(len:%d,nb:%d)", rep_len, hids_env.nb_pkt);
debugHex(rep_val, rep_len);
gatt_ntf_send(conidx, handle, rep_len, rep_val);
status = LE_SUCCESS;
}
}
else
{
status = PRF_ERR_NTF_DISABLED;
}
}
return status;
}
#endif //(PRF_HIDS)