//! //! @brief This function receives nb_data bytes pointed to by ptr_buf on the specified pipe. //! //! *nb_data is updated with the final number of data bytes received. //! //! @note This function activates the host SOF interrupt to detect time-outs. //! The initial enable state of this interrupt will be restored. //! //! @param pipe //! @param nb_data //! @param ptr_buf //! //! @return Status_t: Pipe status //! Status_t host_get_data(uint8_t pipe, uint16_t *nb_data, void *ptr_buf) { Status_t status = PIPE_GOOD; // Frame correctly received by default bool sav_int_sof_enable; bool sav_glob_int_en; uint8_t nak_timeout; uint16_t n, i; #if NAK_TIMEOUT_ENABLE == ENABLE uint16_t cpt_nak; #endif n = *nb_data; sav_int_sof_enable = Is_host_sof_interrupt_enabled(); Host_enable_sof_interrupt(); Host_enable_continuous_in_mode(pipe); Host_configure_pipe_token(pipe, TOKEN_IN); Host_ack_in_received(pipe); while (n) // While missing data... { Host_free_in(pipe); Host_unfreeze_pipe(pipe); private_sof_counter = 0; // Reset the counter in SOF detection subroutine nak_timeout = 0; #if NAK_TIMEOUT_ENABLE == ENABLE cpt_nak = 0; #endif while (!Is_host_in_received(pipe)) { if (Is_host_emergency_exit()) // Asynchronous disconnection or role exchange detected under interrupt { status = PIPE_DELAY_TIMEOUT; Host_reset_pipe(pipe); goto host_get_data_end; } #if TIMEOUT_DELAY_ENABLE == ENABLE if (private_sof_counter >= 250) // Time-out management { private_sof_counter = 0; // Done in host SOF interrupt if (nak_timeout++ >= TIMEOUT_DELAY) // Check for local time-out { status = PIPE_DELAY_TIMEOUT; Host_reset_pipe(pipe); goto host_get_data_end; } } #endif if (Is_host_pipe_error(pipe)) // Error management { status = Host_error_status(pipe); Host_ack_all_errors(pipe); goto host_get_data_end; } if (Is_host_stall(pipe)) // STALL management { status = PIPE_STALL; Host_reset_pipe(pipe); Host_ack_stall(pipe); goto host_get_data_end; } #if NAK_TIMEOUT_ENABLE == ENABLE if (Is_host_nak_received(pipe)) // NAK received { Host_ack_nak_received(pipe); if (cpt_nak++ > NAK_RECEIVE_TIMEOUT) { status = PIPE_NAK_TIMEOUT; Host_reset_pipe(pipe); goto host_get_data_end; } } #endif } Host_freeze_pipe(pipe); Host_reset_pipe_fifo_access(pipe); i = Host_get_pipe_size(pipe) - Host_byte_count(pipe); if (!ptr_buf) { if (Host_byte_count(pipe) > n) // More bytes received than expected { n = 0; //! @todo Error code management } else // Nb bytes received <= expected { n -= Host_byte_count(pipe); if (i) // Short packet { *nb_data -= n; n = 0; } } } else { n = host_read_p_rxpacket(pipe, ptr_buf, n, &ptr_buf); if (Host_byte_count(pipe)) // More bytes received than expected { //! @todo Error code management } else if (i) // Short packet with nb bytes received <= expected { *nb_data -= n; n = 0; } } Host_ack_in_received(pipe); // In low-speed mode, the USB IP may have not yet sent the ACK at this // point. The USB IP does not support a new start of transaction request // from the firmware if the ACK has not been sent. The only means of making // sure the ACK has been sent is to wait for the next Keep-Alive before // starting a new transaction. if (Is_usb_low_speed_mode()) { Usb_ack_event(EVT_HOST_SOF); sav_int_sof_enable = Is_host_sof_interrupt_enabled(); if ((sav_glob_int_en = cpu_irq_is_enabled())) cpu_irq_disable(); Host_ack_sof(); (void)Is_host_sof_interrupt_enabled(); if (sav_glob_int_en) cpu_irq_enable(); Host_enable_sof_interrupt(); while (!Is_usb_event(EVT_HOST_SOF)) // Wait for next Keep-Alive { if (Is_host_emergency_exit()) { status = PIPE_DELAY_TIMEOUT; Host_reset_pipe(pipe); goto host_get_data_end; } } if (!sav_int_sof_enable) // Restore SOF interrupt enable { if ((sav_glob_int_en = cpu_irq_is_enabled())) cpu_irq_disable(); Host_disable_sof_interrupt(); (void)Is_host_sof_interrupt_enabled(); if (sav_glob_int_en) cpu_irq_enable(); } } } host_get_data_end: Host_freeze_pipe(pipe); // Restore SOF interrupt enable state if (!sav_int_sof_enable) { if ((sav_glob_int_en = cpu_irq_is_enabled())) cpu_irq_disable(); Host_disable_sof_interrupt(); (void)Is_host_sof_interrupt_enabled(); if (sav_glob_int_en) cpu_irq_enable(); } // And return... return status; }
void host_mouse_hid_task(void) #endif { uint8_t i; #ifdef FREERTOS_USED portTickType xLastWakeTime; xLastWakeTime = xTaskGetTickCount(); while (true) { vTaskDelayUntil(&xLastWakeTime, configTSK_USB_HHID_MOUSE_PERIOD); #endif // FREERTOS_USED // First, check the host controller is in full operating mode with the // B-device attached and enumerated if (Is_host_ready()) { // New device connection (executed only once after device connection) if (mouse_hid_new_device_connected) { mouse_hid_new_device_connected = false; // For all supported interfaces for (i = 0; i < Get_nb_supported_interface(); i++) { if(Get_class(i)==HID_CLASS && Get_protocol(i)==MOUSE_PROTOCOL) { host_hid_set_idle(HID_IDLE_DURATION_INDEFINITE, HID_REPORT_ID_ALL, i); host_hid_get_report(HID_REPORT_DESCRIPTOR, 0, i); pipe_mouse_in = Get_ep_pipe(i, 0); Host_enable_continuous_in_mode(pipe_mouse_in); Host_unfreeze_pipe(pipe_mouse_in); mouse_hid_connected=true; break; } } } if( Is_host_mouse_hid_configured() ) { if((Is_host_in_received(pipe_mouse_in)) && (Is_host_stall(pipe_mouse_in)==false) ) { Host_reset_pipe_fifo_access(pipe_mouse_in); usb_report[0]= usb_report[1]= usb_report[2]= usb_report[3]=0; host_read_p_rxpacket(pipe_mouse_in, (void*)usb_report, 4, NULL); Host_ack_in_received(pipe_mouse_in); Host_free_in(pipe_mouse_in); new_x = usb_report[1]; new_y = usb_report[2]; mouse_x += new_x; mouse_y += new_y; if( mouse_x<MOUSE_X_MIN ) mouse_x=MOUSE_X_MIN; else if( mouse_x>MOUSE_X_MAX ) mouse_x=MOUSE_X_MAX; if( mouse_y<MOUSE_Y_MIN ) mouse_y=MOUSE_Y_MIN; else if( mouse_y>MOUSE_Y_MAX ) mouse_y=MOUSE_Y_MAX; mouse_b0=usb_report[0] & 1; mouse_b1=usb_report[0] & 2; mouse_b2=usb_report[0] & 4; disp_led_mouse(); disp_ascii_mouse(); } if(Is_host_nak_received(pipe_mouse_in)) { Host_ack_nak_received(pipe_mouse_in); LED_Off(LED_HOST_MOUSE_B0 ); LED_Off(LED_HOST_MOUSE_B1 ); LED_Off(LED_HOST_MOUSE_B2 ); LED_Off(LED_HOST_MOUSE_B3 ); } } } #ifdef FREERTOS_USED } #endif }
//! //! @brief USB pipe interrupt subroutine //! void usb_pipe_interrupt(uint8_t pipe) { void *ptr_buf; uint16_t n, i; bool callback = false; // Detect which events generate an interrupt... if (Is_host_pipe_error(pipe)) // Error management { it_pipe_str[pipe].status = Host_error_status(pipe); it_pipe_str[pipe].enable = false; Host_reset_pipe(pipe); Host_ack_all_errors(pipe); callback = true; goto usb_pipe_interrupt_end; } if (Is_host_stall(pipe)) // STALL management { it_pipe_str[pipe].status = PIPE_STALL; it_pipe_str[pipe].enable = false; Host_reset_pipe(pipe); callback = true; goto usb_pipe_interrupt_end; } #if NAK_TIMEOUT_ENABLE == ENABLE if (Is_host_nak_received(pipe)) // NAK received { Host_ack_nak_received(pipe); // Check if NAK time-out error occurs (not for interrupt pipes) if (!--it_pipe_str[pipe].nak_timeout && Host_get_pipe_type(pipe) != TYPE_INTERRUPT) { it_pipe_str[pipe].status = PIPE_NAK_TIMEOUT; it_pipe_str[pipe].enable = false; Host_reset_pipe(pipe); callback = true; goto usb_pipe_interrupt_end; } } #endif if (Is_host_in_received(pipe)) // Pipe IN reception? { ptr_buf = (uint8_t *)it_pipe_str[pipe].ptr_buf + it_pipe_str[pipe].nb_byte_processed; // Build pointer to data buffer n = it_pipe_str[pipe].nb_byte_to_process - it_pipe_str[pipe].nb_byte_processed; // Remaining data bytes Host_freeze_pipe(pipe); Host_reset_pipe_fifo_access(pipe); i = Host_get_pipe_size(pipe) - Host_byte_count(pipe); n = host_read_p_rxpacket(pipe, ptr_buf, n, NULL); it_pipe_str[pipe].nb_byte_processed = it_pipe_str[pipe].nb_byte_to_process - n; if (Host_byte_count(pipe)) // More bytes received than expected { //! @todo Error code management } else if (i) // Short packet with nb bytes received <= expected { n = 0; } Host_ack_in_received(pipe); if (n) // Still data to process { Host_free_in(pipe); Host_unfreeze_pipe(pipe); // Request another IN transfer private_sof_counter = 0; // Reset the counter in SOF detection subroutine it_pipe_str[pipe].timeout = 0; // Reset time-out it_pipe_str[pipe].nak_timeout = NAK_RECEIVE_TIMEOUT; } else // End of transfer { it_pipe_str[pipe].enable = false; it_pipe_str[pipe].status = PIPE_GOOD; Host_reset_pipe(pipe); callback = true; } } if (Is_host_out_ready(pipe)) // Pipe OUT sent? { Host_ack_out_ready(pipe); it_pipe_str[pipe].nb_byte_processed += it_pipe_str[pipe].nb_byte_on_going; it_pipe_str[pipe].nb_byte_on_going = 0; ptr_buf = (uint8_t *)it_pipe_str[pipe].ptr_buf + it_pipe_str[pipe].nb_byte_processed; // Build pointer to data buffer n = it_pipe_str[pipe].nb_byte_to_process - it_pipe_str[pipe].nb_byte_processed; // Remaining data bytes if (n) // Still data to process { Host_unfreeze_pipe(pipe); // Prepare data to be sent Host_reset_pipe_fifo_access(pipe); it_pipe_str[pipe].nb_byte_on_going = n - host_write_p_txpacket(pipe, ptr_buf, n, NULL); private_sof_counter = 0; // Reset the counter in SOF detection subroutine it_pipe_str[pipe].timeout = 0; // Refresh time-out counter it_pipe_str[pipe].nak_timeout = NAK_SEND_TIMEOUT; Host_send_out(pipe); // Send the USB frame } else // End of transfer { it_pipe_str[pipe].enable = false; // Transfer end it_pipe_str[pipe].status = PIPE_GOOD; // Status OK Host_reset_pipe(pipe); callback = true; } } usb_pipe_interrupt_end: if (!is_any_interrupt_pipe_active() && !g_sav_int_sof_enable) // If no more transfer is armed { Host_disable_sof_interrupt(); } if (callback) // Any call-back function to perform? { it_pipe_str[pipe].handler(it_pipe_str[pipe].status, it_pipe_str[pipe].nb_byte_processed); } }