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