static vsf_err_t vsfusbd_HID_class_poll(uint8_t iface, struct vsfusbd_device_t *device) { struct vsfusbd_config_t *config = &device->config[device->configuration]; struct vsfusbd_HID_param_t *param = (struct vsfusbd_HID_param_t *)config->iface[iface].protocol_param; struct vsfusbd_HID_report_t *report; uint8_t ep = param->ep_in; struct vsfusbd_transact_t *transact = &device->IN_transact[ep]; struct vsf_buffer_t *buffer = &transact->tbuffer.buffer; if (NULL == param) { return VSFERR_FAIL; } report = ¶m->reports[param->poll_report_idx]; buffer->buffer = report->buffer.buffer; buffer->size = report->buffer.size; transact->callback.callback = NULL; transact->pkt.in.zlp = true; switch (report->type) { case USB_HID_REPORT_TYPE_INPUT: // TODO: process multi-report and idle, need 1 ms systick module if (!vsfusbd_ep_send_nb_isready(device, ep)) { if (vsfusbd_HID_class_update_report(report, ¶m->temp_buffer)) { return VSFERR_FAIL; } transact->tbuffer.buffer = param->temp_buffer; if (vsfusbd_ep_send_nb(device, ep)) { return VSFERR_FAIL; } param->poll_report_idx++; if (param->poll_report_idx >= param->num_of_report) { param->poll_report_idx = 0; } } break; case USB_HID_REPORT_TYPE_OUTPUT: break; default: break; } return VSFERR_NONE; }
static struct vsfsm_state_t * vsfusbd_HID_evt_handler(struct vsfsm_t *sm, vsfsm_evt_t evt) { struct vsfusbd_HID_param_t *param = (struct vsfusbd_HID_param_t *)sm->user_data; struct vsfusbd_device_t *device = param->device; uint8_t i; switch (evt) { case VSFSM_EVT_INIT: if (param->ep_out != 0) { vsfusbd_set_OUT_handler(device, param->ep_out, vsfusbd_HID_OUT_hanlder); device->drv->ep.enable_OUT(param->ep_out); } param->output_state = HID_OUTPUT_STATE_WAIT; param->busy = false; param->num_of_INPUT_report = 0; param->num_of_OUTPUT_report = 0; param->num_of_FEATURE_report = 0; for(i = 0; i < param->num_of_report; i++) { param->reports[i].pos = 0; param->reports[i].idle_cnt = 0; param->reports[i].changed = true; switch (param->reports[i].type) { case USB_HID_REPORT_OUTPUT: param->num_of_OUTPUT_report++; break; case USB_HID_REPORT_INPUT: param->num_of_INPUT_report++; break; case USB_HID_REPORT_FEATURE: param->num_of_FEATURE_report++; break; } } // enable timer param->timer4ms.sm = ¶m->iface->sm; param->timer4ms.evt = VSFUSBD_HID_EVT_TIMER4MS; param->timer4ms.interval = 4; vsftimer_register(¶m->timer4ms); break; case VSFUSBD_HID_EVT_TIMER4MS: { struct vsfusbd_HID_report_t *report; uint8_t i; for (i = 0; i < param->num_of_report; i++) { report = ¶m->reports[i]; if ((report->type == USB_HID_REPORT_TYPE_INPUT) && (report->idle != 0)) { report->idle_cnt++; } } if (param->busy) { break; } } // fall through case VSFUSBD_HID_EVT_INREPORT: { uint8_t ep = param->ep_in; struct vsfusbd_transact_t *transact = &device->IN_transact[ep]; struct vsfusbd_HID_report_t *report; bool busy = false; uint8_t i; for (i = 0; i < param->num_of_report; i++) { report = ¶m->reports[i]; if ((report->type == USB_HID_REPORT_TYPE_INPUT) && (report->changed || ((report->idle != 0) && (report->idle_cnt >= report->idle)))) { report->idle_cnt = 0; transact->tbuffer.buffer = report->buffer; transact->callback.callback = vsfusbd_HID_INREPORT_callback; transact->callback.param = param; vsfusbd_ep_send_nb(device, ep); busy = true; break; } } param->busy = busy; } break; } return NULL; }