/** **************************************************************************************** * @addtogroup HOGPDTASK * @{ **************************************************************************************** */ /* * INCLUDE FILES **************************************************************************************** */ #include "rwip_config.h" #if (BLE_HID_DEVICE) #include "gap.h" #include "gattc_task.h" //HID Over GATT Profile Device Role Functions #include "hogpd.h" #include "hogpd_task.h" #include "prf_utils.h" #include "co_utils.h" /* * DEFINES **************************************************************************************** */ /* * GLOBAL VARIABLE DEFINITIONS **************************************************************************************** */ /** **************************************************************************************** * @brief Handles reception of the @ref HOGPD_ENABLE_REQ message. * The handler enables the HID Over GATT Profile Device Role. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ __STATIC int hogpd_enable_req_handler(ke_msg_id_t const msgid, struct hogpd_enable_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // Counter for HIDS instance uint8_t svc_idx; uint8_t status = GAP_ERR_NO_ERROR; struct hogpd_env_tag* hogpd_env = PRF_ENV_GET(HOGPD, hogpd); ASSERT_ERR(hogpd_env!=NULL); // Check provided values and check if connection exists if((param->conidx > BLE_CONNECTION_MAX) || (gapc_get_conhdl(param->conidx) == GAP_INVALID_CONHDL)) { // an error occurs, trigg it. status = (param->conidx > BLE_CONNECTION_MAX) ? GAP_ERR_INVALID_PARAM : PRF_ERR_REQ_DISALLOWED; } else { for (svc_idx = 0; svc_idx < hogpd_env->hids_nb; svc_idx++) { // Retrieve notification configuration hogpd_env->svcs[svc_idx].ntf_cfg[param->conidx] = param->ntf_cfg[svc_idx]; } } // Send back response struct hogpd_enable_rsp* rsp = KE_MSG_ALLOC(HOGPD_ENABLE_RSP, src_id, dest_id, hogpd_enable_rsp); rsp->conidx = param->conidx; rsp->status = status; ke_msg_send(rsp); return (KE_MSG_CONSUMED); } /** **************************************************************************************** * @brief Handles reception of the @ref HOGPD_REPORT_UPD_REQ message. * * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ __STATIC int hogpd_report_upd_req_handler(ke_msg_id_t const msgid, struct hogpd_report_upd_req const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { int msg_status = KE_MSG_CONSUMED; uint8_t state = ke_state_get(dest_id); // check that task is in idle state if((state & HOGPD_REQ_BUSY) == HOGPD_IDLE) { // Status uint8_t status = PRF_ERR_INVALID_PARAM; // Check provided values and check if connection exists if((param->conidx > BLE_CONNECTION_MAX) || (gapc_get_conhdl(param->conidx) == GAP_INVALID_CONHDL)) { status = (param->conidx > BLE_CONNECTION_MAX) ? GAP_ERR_INVALID_PARAM : PRF_ERR_REQ_DISALLOWED; } else { status = hogpd_ntf_send(param->conidx, &(param->report)); } // an error occurs inform application if (status != GAP_ERR_NO_ERROR) { // send report update response struct hogpd_report_upd_rsp *rsp = KE_MSG_ALLOC(HOGPD_REPORT_UPD_RSP, src_id, dest_id, hogpd_report_upd_rsp); rsp->conidx = param->conidx; rsp->status = status; ke_msg_send(rsp); } // go in a busy state else { ke_state_set(dest_id, state | HOGPD_REQ_BUSY); } } // else process it later else { msg_status = KE_MSG_SAVED; } return (msg_status); } /** **************************************************************************************** * @brief Handles reception of the @ref HOGPD_REPORT_CFM message. * * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ __STATIC int hogpd_report_cfm_handler(ke_msg_id_t const msgid, struct hogpd_report_cfm const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { uint8_t state = ke_state_get(dest_id); // check that an operation is ongoing if((state & HOGPD_OP_BUSY) == HOGPD_OP_BUSY) { uint16_t handle = ATT_INVALID_HANDLE; uint8_t status = PRF_APP_ERROR; struct hogpd_env_tag* hogpd_env = PRF_ENV_GET(HOGPD, hogpd); // check received status if(param->status != GAP_ERR_NO_ERROR) { status = param->status; } // perform operation sanity check else if((param->operation == hogpd_env->op.operation) && (param->conidx == hogpd_env->op.conidx)) { // retrieve attribute index. uint8_t att_idx = 0; switch(param->report.type) { case HOGPD_REPORT: { att_idx = HOGPD_IDX_REPORT_VAL; }break; case HOGPD_REPORT_MAP: { att_idx = HOGPD_IDX_REPORT_MAP_VAL; }break; case HOGPD_BOOT_KEYBOARD_INPUT_REPORT: { att_idx = HOGPD_IDX_BOOT_KB_IN_REPORT_VAL; }break; case HOGPD_BOOT_KEYBOARD_OUTPUT_REPORT: { att_idx = HOGPD_IDX_BOOT_KB_OUT_REPORT_VAL; }break; case HOGPD_BOOT_MOUSE_INPUT_REPORT: { att_idx = HOGPD_IDX_BOOT_MOUSE_IN_REPORT_VAL; }break; default: /* Nothing to do */ break; } // retrieve handle handle = hogpd_get_att_handle(hogpd_env, param->report.hid_idx, att_idx, param->report.idx); // check if answer correspond to expected one if(handle == hogpd_env->op.handle) { status = GAP_ERR_NO_ERROR; } } // read operation if(hogpd_env->op.operation == HOGPD_OP_REPORT_READ) { uint16_t length = (status == GAP_ERR_NO_ERROR) ? param->report.length : 0; //Send read response struct gattc_read_cfm * rd_cfm = KE_MSG_ALLOC_DYN(GATTC_READ_CFM, KE_BUILD_ID(TASK_GATTC, hogpd_env->op.conidx), dest_id, gattc_read_cfm, length); rd_cfm->handle = hogpd_env->op.handle; rd_cfm->status = status; rd_cfm->length = length; if(status == GAP_ERR_NO_ERROR) { memcpy(rd_cfm->value, param->report.value, length); } ke_msg_send(rd_cfm); } // write operation else { //Send write response struct gattc_write_cfm * wr_cfm = KE_MSG_ALLOC(GATTC_WRITE_CFM, KE_BUILD_ID(TASK_GATTC, hogpd_env->op.conidx), dest_id, gattc_write_cfm); wr_cfm->handle = hogpd_env->op.handle; wr_cfm->status = status; ke_msg_send(wr_cfm); } // cleanup environment hogpd_env->op.operation = HOGPD_OP_NO; hogpd_env->op.handle = ATT_INVALID_HDL; hogpd_env->op.conidx = 0xFF; // go back in idle state ke_state_set(dest_id, state & ~HOGPD_OP_BUSY); } return (KE_MSG_CONSUMED); } /** **************************************************************************************** * @brief Handles reception of the @ref HOGPD_PROTO_MODE_CFM message. * * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ __STATIC int hogpd_proto_mode_cfm_handler(ke_msg_id_t const msgid, struct hogpd_proto_mode_cfm const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { uint8_t state = ke_state_get(dest_id); // check that an operation is ongoing if((state & HOGPD_OP_BUSY) == HOGPD_OP_BUSY) { uint16_t handle = ATT_INVALID_HANDLE; uint8_t status = PRF_APP_ERROR; struct hogpd_env_tag* hogpd_env = PRF_ENV_GET(HOGPD, hogpd); // check received status if(param->status != GAP_ERR_NO_ERROR) { status = param->status; } // perform operation sanity check else if((hogpd_env->op.operation == HOGPD_OP_PROT_UPDATE) && (param->conidx == hogpd_env->op.conidx)) { // retrieve handle handle = hogpd_get_att_handle(hogpd_env, param->hid_idx, HOGPD_IDX_PROTO_MODE_VAL, 0); // check if answer correspond to expected one if(handle == hogpd_env->op.handle) { status = GAP_ERR_NO_ERROR; hogpd_env->svcs[param->hid_idx].proto_mode = param->proto_mode; } } // read operation/something failed if(hogpd_env->op.operation == HOGPD_OP_REPORT_READ) { //Send read response struct gattc_read_cfm * rd_cfm = KE_MSG_ALLOC(GATTC_READ_CFM, KE_BUILD_ID(TASK_GATTC, hogpd_env->op.conidx), dest_id, gattc_read_cfm); rd_cfm->handle = hogpd_env->op.handle; rd_cfm->status = status; ke_msg_send(rd_cfm); } // write operation else { //Send write response struct gattc_write_cfm * wr_cfm = KE_MSG_ALLOC(GATTC_WRITE_CFM, KE_BUILD_ID(TASK_GATTC, hogpd_env->op.conidx), dest_id, gattc_write_cfm); wr_cfm->handle = hogpd_env->op.handle; wr_cfm->status = status; ke_msg_send(wr_cfm); } // cleanup environment hogpd_env->op.operation = HOGPD_OP_NO; hogpd_env->op.handle = ATT_INVALID_HDL; hogpd_env->op.conidx = 0xFF; // go back in idle state ke_state_set(dest_id, state & ~HOGPD_OP_BUSY); } return (KE_MSG_CONSUMED); } /** **************************************************************************************** * @brief Handles reception of the @ref GATTC_ATT_INFO_REQ_IND message. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ __STATIC int gattc_att_info_req_ind_handler(ke_msg_id_t const msgid, struct gattc_att_info_req_ind const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { uint8_t hid_idx, att_idx, report_idx; struct gattc_att_info_cfm * cfm; struct hogpd_env_tag* hogpd_env = PRF_ENV_GET(HOGPD, hogpd); // retrieve attribute requested uint8_t status = hogpd_get_att_idx(hogpd_env, param->handle, &hid_idx, &att_idx, &report_idx); //Send write response cfm = KE_MSG_ALLOC(GATTC_ATT_INFO_CFM, src_id, dest_id, gattc_att_info_cfm); cfm->handle = param->handle; if(status == GAP_ERR_NO_ERROR) { // check which attribute is requested by peer device switch(att_idx) { case HOGPD_IDX_BOOT_KB_IN_REPORT_VAL: case HOGPD_IDX_BOOT_KB_OUT_REPORT_VAL: case HOGPD_IDX_BOOT_MOUSE_IN_REPORT_VAL: case HOGPD_IDX_REPORT_VAL: { cfm->length = 0; }break; // Notification configuration case HOGPD_IDX_BOOT_KB_IN_REPORT_NTF_CFG: case HOGPD_IDX_BOOT_MOUSE_IN_REPORT_NTF_CFG: case HOGPD_IDX_REPORT_NTF_CFG: { cfm->length = 2; }break; default: { cfm->length = 0; status = ATT_ERR_WRITE_NOT_PERMITTED; } break; } } cfm->status = status; ke_msg_send(cfm); return (KE_MSG_CONSUMED); } /** **************************************************************************************** * @brief Handles reception of the @ref GATTC_WRITE_REQ_IND message. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ __STATIC int gattc_write_req_ind_handler(ke_msg_id_t const msgid, struct gattc_write_req_ind const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { int msg_status = KE_MSG_CONSUMED; uint8_t state = ke_state_get(dest_id); // check that task is in idle state if((state & HOGPD_OP_BUSY) == HOGPD_IDLE) { uint8_t hid_idx, att_idx, report_idx; // used to know if gatt_write confirmation should be sent immediately uint8_t conidx = KE_IDX_GET(src_id); struct hogpd_env_tag* hogpd_env = PRF_ENV_GET(HOGPD, hogpd); // retrieve attribute requested uint8_t status = hogpd_get_att_idx(hogpd_env, param->handle, &hid_idx, &att_idx, &report_idx); // prepare operation info hogpd_env->op.conidx = conidx; hogpd_env->op.operation = HOGPD_OP_NO; hogpd_env->op.handle = param->handle; if(status == GAP_ERR_NO_ERROR) { // check which attribute is requested by peer device switch(att_idx) { // Control point value updated case HOGPD_IDX_HID_CTNL_PT_VAL: { // send control point indication struct hogpd_ctnl_pt_ind *cp_ind = KE_MSG_ALLOC(HOGPD_CTNL_PT_IND, prf_dst_task_get(&(hogpd_env->prf_env), conidx), dest_id, hogpd_ctnl_pt_ind); cp_ind->conidx = conidx; cp_ind->hid_idx = hid_idx; cp_ind->hid_ctnl_pt = param->value[0]; ke_msg_send(cp_ind); }break; // Modification of protocol mode requested case HOGPD_IDX_PROTO_MODE_VAL: { // send control point indication struct hogpd_proto_mode_req_ind *prot_ind = KE_MSG_ALLOC(HOGPD_PROTO_MODE_REQ_IND, prf_dst_task_get(&(hogpd_env->prf_env), conidx), dest_id, hogpd_proto_mode_req_ind); prot_ind->conidx = conidx; prot_ind->operation = HOGPD_OP_PROT_UPDATE; prot_ind->hid_idx = hid_idx; prot_ind->proto_mode = param->value[0]; ke_msg_send(prot_ind); hogpd_env->op.operation = HOGPD_OP_PROT_UPDATE; }break; // Modification of report value requested case HOGPD_IDX_BOOT_KB_IN_REPORT_VAL: case HOGPD_IDX_BOOT_KB_OUT_REPORT_VAL: case HOGPD_IDX_BOOT_MOUSE_IN_REPORT_VAL: case HOGPD_IDX_REPORT_VAL: { // send report indication struct hogpd_report_req_ind *report_ind = KE_MSG_ALLOC_DYN(HOGPD_REPORT_REQ_IND, prf_dst_task_get(&(hogpd_env->prf_env), conidx), dest_id, hogpd_report_req_ind, param->length); report_ind->conidx = conidx; report_ind->operation = HOGPD_OP_REPORT_WRITE; report_ind->report.length = param->length; report_ind->report.hid_idx = hid_idx; report_ind->report.idx = report_idx; memcpy(report_ind->report.value, param->value, param->length); // retrieve report type switch(att_idx) { // An Input Report case HOGPD_IDX_BOOT_KB_IN_REPORT_VAL: { report_ind->report.type = HOGPD_BOOT_KEYBOARD_INPUT_REPORT; }break; // Boot Keyboard input report case HOGPD_IDX_BOOT_KB_OUT_REPORT_VAL: { report_ind->report.type = HOGPD_BOOT_KEYBOARD_OUTPUT_REPORT; }break; // Boot Mouse input report case HOGPD_IDX_BOOT_MOUSE_IN_REPORT_VAL: { report_ind->report.type = HOGPD_BOOT_MOUSE_INPUT_REPORT; }break; // Normal report case HOGPD_IDX_REPORT_VAL: { report_ind->report.type = HOGPD_REPORT; }break; default: { ASSERT_ERR(0); }break; } ke_msg_send(report_ind); hogpd_env->op.operation = HOGPD_OP_REPORT_WRITE; }break; // Notification configuration update case HOGPD_IDX_BOOT_KB_IN_REPORT_NTF_CFG: case HOGPD_IDX_BOOT_MOUSE_IN_REPORT_NTF_CFG: case HOGPD_IDX_REPORT_NTF_CFG: { uint16_t ntf_cfg = co_read16p(param->value); status = hogpd_ntf_cfg_ind_send(conidx, hid_idx, att_idx, report_idx, ntf_cfg); }break; default: { status = PRF_APP_ERROR; } break; } } // check if peer operation is over if(hogpd_env->op.operation == HOGPD_OP_NO) { //Send write response struct gattc_write_cfm * cfm = KE_MSG_ALLOC(GATTC_WRITE_CFM, src_id, dest_id, gattc_write_cfm); cfm->handle = param->handle; cfm->status = status; ke_msg_send(cfm); } else { // go into operation busy state ke_state_set(dest_id, state | HOGPD_OP_BUSY); } } // else process it later else { msg_status = KE_MSG_SAVED; } return (msg_status); } /** **************************************************************************************** * @brief Handles reception of the @ref GATTC_READ_REQ_IND message. * @param[in] msgid Id of the message received (probably unused). * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance (probably unused). * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ __STATIC int gattc_read_req_ind_handler(ke_msg_id_t const msgid, struct gattc_read_req_ind const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { int msg_status = KE_MSG_CONSUMED; uint8_t state = ke_state_get(dest_id); // check that task is in idle state if((state & HOGPD_OP_BUSY) == HOGPD_IDLE) { uint8_t hid_idx, att_idx, report_idx; bool finished = true; uint8_t report_type = 0; uint16_t value = 0; uint16_t length = 0; struct hogpd_env_tag* hogpd_env = PRF_ENV_GET(HOGPD, hogpd); // used to know if gatt_write confirmation should be sent immediately uint8_t conidx = KE_IDX_GET(src_id); // retrieve attribute requested uint8_t status = hogpd_get_att_idx(hogpd_env, param->handle, &hid_idx, &att_idx, &report_idx); if(status == GAP_ERR_NO_ERROR) { // check which attribute is requested by peer device switch(att_idx) { // ------------ READ report value requested case HOGPD_IDX_BOOT_KB_IN_REPORT_VAL: { report_type = HOGPD_BOOT_KEYBOARD_INPUT_REPORT; finished = false; }break; case HOGPD_IDX_BOOT_KB_OUT_REPORT_VAL: { report_type = HOGPD_BOOT_KEYBOARD_OUTPUT_REPORT; finished = false; }break; case HOGPD_IDX_BOOT_MOUSE_IN_REPORT_VAL: { report_type = HOGPD_BOOT_MOUSE_INPUT_REPORT; finished = false; }break; case HOGPD_IDX_REPORT_VAL: { report_type = HOGPD_REPORT; finished = false; }break; case HOGPD_IDX_REPORT_MAP_VAL: { report_type = HOGPD_REPORT_MAP; finished = false; }break; // ------------ READ active protocol mode case HOGPD_IDX_PROTO_MODE_VAL: { value = hogpd_env->svcs[hid_idx].proto_mode; length = sizeof(uint8_t); }break; // ------------ READ Notification configuration case HOGPD_IDX_BOOT_KB_IN_REPORT_NTF_CFG: { value = ((hogpd_env->svcs[hid_idx].ntf_cfg[conidx] & HOGPD_CFG_KEYBOARD) != 0) ? PRF_CLI_START_NTF : PRF_CLI_STOP_NTFIND; length = sizeof(uint16_t); }break; case HOGPD_IDX_BOOT_MOUSE_IN_REPORT_NTF_CFG: { value = ((hogpd_env->svcs[hid_idx].ntf_cfg[conidx] & HOGPD_CFG_MOUSE) != 0) ? PRF_CLI_START_NTF : PRF_CLI_STOP_NTFIND; length = sizeof(uint16_t); }break; case HOGPD_IDX_REPORT_NTF_CFG: { value = ((hogpd_env->svcs[hid_idx].ntf_cfg[conidx] & (HOGPD_CFG_REPORT_NTF_EN << report_idx)) != 0) ? PRF_CLI_START_NTF : PRF_CLI_STOP_NTFIND; length = sizeof(uint16_t); }break; default: { status = PRF_APP_ERROR; } break; } } // check if peer operation is over if(finished) { //Send write response struct gattc_read_cfm * cfm = KE_MSG_ALLOC_DYN(GATTC_READ_CFM, src_id, dest_id, gattc_read_cfm, length); cfm->handle = param->handle; cfm->status = status; cfm->length = length; memcpy(cfm->value, &value, length); ke_msg_send(cfm); } else { // send report indication struct hogpd_report_req_ind *report_ind = KE_MSG_ALLOC(HOGPD_REPORT_REQ_IND, prf_dst_task_get(&(hogpd_env->prf_env), conidx), dest_id, hogpd_report_req_ind); report_ind->conidx = conidx; report_ind->operation = HOGPD_OP_REPORT_READ; report_ind->report.length = 0; report_ind->report.hid_idx = hid_idx; report_ind->report.type = report_type; report_ind->report.idx = report_idx; ke_msg_send(report_ind); hogpd_env->op.conidx = conidx; hogpd_env->op.operation = HOGPD_OP_REPORT_READ; hogpd_env->op.handle = param->handle; // go into operation busy state ke_state_set(dest_id, state | HOGPD_OP_BUSY); } } // else process it later else { msg_status = KE_MSG_SAVED; } return (msg_status); } /** **************************************************************************************** * @brief Handles @ref GATT_NOTIFY_CMP_EVT message meaning that Report notification * has been correctly sent to peer device (but not confirmed by peer device). * * @param[in] msgid Id of the message received. * @param[in] param Pointer to the parameters of the message. * @param[in] dest_id ID of the receiving task instance * @param[in] src_id ID of the sending task instance. * @return If the message was consumed or not. **************************************************************************************** */ __STATIC int gattc_cmp_evt_handler(ke_msg_id_t const msgid, struct gattc_cmp_evt const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { if(param->operation == GATTC_NOTIFY) { uint8_t conidx = KE_IDX_GET(src_id); struct hogpd_env_tag* hogpd_env = PRF_ENV_GET(HOGPD, hogpd); // send report update response struct hogpd_report_upd_rsp *rsp = KE_MSG_ALLOC(HOGPD_REPORT_UPD_RSP, prf_dst_task_get(&(hogpd_env->prf_env), conidx), dest_id, hogpd_report_upd_rsp); rsp->conidx = conidx; rsp->status = param->status; ke_msg_send(rsp); // go back in to idle mode ke_state_set(dest_id, ke_state_get(dest_id) & ~HOGPD_REQ_BUSY); } // else ignore the message return (KE_MSG_CONSUMED); } /* * GLOBAL VARIABLE DEFINITIONS **************************************************************************************** */ /// Default State handlers definition KE_MSG_HANDLER_TAB(hogpd) { { HOGPD_ENABLE_REQ, (ke_msg_func_t) hogpd_enable_req_handler }, { HOGPD_REPORT_UPD_REQ, (ke_msg_func_t) hogpd_report_upd_req_handler }, { HOGPD_REPORT_CFM, (ke_msg_func_t) hogpd_report_cfm_handler }, { HOGPD_PROTO_MODE_CFM, (ke_msg_func_t) hogpd_proto_mode_cfm_handler }, { GATTC_ATT_INFO_REQ_IND, (ke_msg_func_t) gattc_att_info_req_ind_handler }, { GATTC_WRITE_REQ_IND, (ke_msg_func_t) gattc_write_req_ind_handler }, { GATTC_READ_REQ_IND, (ke_msg_func_t) gattc_read_req_ind_handler }, { GATTC_CMP_EVT, (ke_msg_func_t) gattc_cmp_evt_handler }, }; void hogpd_task_init(struct ke_task_desc *task_desc) { // Get the address of the environment struct hogpd_env_tag *hogpd_env = PRF_ENV_GET(HOGPD, hogpd); task_desc->msg_handler_tab = hogpd_msg_handler_tab; task_desc->msg_cnt = ARRAY_LEN(hogpd_msg_handler_tab); task_desc->state = hogpd_env->state; task_desc->idx_max = HOGPD_IDX_MAX; } #endif /* #if (BLE_HID_DEVICE) */ /// @} HOGPDTASK