//! //! @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; }
//! This function is the generic control pipe management function. //! This function is used to send and receive control requests over control pipe. //! //! @todo Fix all time-out errors and disconnections in active wait loop. //! //! @param data_pointer void *: Pointer to data to transfer //! //! @return Status_t: Status //! //! @note This function uses the usb_request global structure. Hence, this //! structure should be filled before calling this function. //! Status_t host_transfer_control(void *data_pointer) { int status = CONTROL_GOOD; bool sav_int_sof_enable; bool sav_glob_int_en; uint16_t data_length; uint8_t c; Usb_ack_event(EVT_HOST_SOF); sav_int_sof_enable = Is_host_sof_interrupt_enabled(); Host_enable_sof_interrupt(); // SOF software detection is in interrupt subroutine while (!Is_usb_event(EVT_HOST_SOF)) // Wait 1 SOF { #if defined(Host_wait_action) Host_wait_action(); #endif if (Is_host_emergency_exit()) { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } } Host_configure_pipe_token(P_CONTROL, TOKEN_SETUP); Host_ack_setup_ready(); Host_unfreeze_pipe(P_CONTROL); // Build and send the setup request fields Host_reset_pipe_fifo_access(P_CONTROL); Host_write_pipe_data(P_CONTROL, 8, usb_request.bmRequestType); Host_write_pipe_data(P_CONTROL, 8, usb_request.bRequest); Host_write_pipe_data(P_CONTROL, 16, usb_format_mcu_to_usb_data(16, usb_request.wValue)); Host_write_pipe_data(P_CONTROL, 16, usb_format_mcu_to_usb_data(16, usb_request.wIndex)); Host_write_pipe_data(P_CONTROL, 16, usb_format_mcu_to_usb_data(16, usb_request.wLength)); Host_send_setup(); while (!Is_host_setup_ready()) // Wait for SETUP ack { #if defined(Host_wait_action) Host_wait_action(); #endif if (Is_host_emergency_exit()) { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } if (Is_host_pipe_error(P_CONTROL)) // Any error? { c = Host_error_status(P_CONTROL); Host_ack_all_errors(P_CONTROL); status = c; // Send error status goto host_transfer_control_end; } } // Setup token sent; now send IN or OUT token // Before just wait 1 SOF Usb_ack_event(EVT_HOST_SOF); Host_freeze_pipe(P_CONTROL); data_length = usb_request.wLength; while (!Is_usb_event(EVT_HOST_SOF)) // Wait 1 SOF { #if defined(Host_wait_action) Host_wait_action(); #endif if (Is_host_emergency_exit()) { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } } // IN request management --------------------------------------------- if (usb_request.bmRequestType & 0x80) // Data stage IN (bmRequestType.D7 == 1) { Host_disable_continuous_in_mode(P_CONTROL); Host_configure_pipe_token(P_CONTROL, TOKEN_IN); Host_ack_control_in_received_free(); while (data_length) { Host_unfreeze_pipe(P_CONTROL); private_sof_counter = 0; // Reset the counter in SOF detection subroutine while (!Is_host_control_in_received()) { #if defined(Host_wait_action) Host_wait_action(); #endif if (Is_host_emergency_exit()) { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } if (Is_host_pipe_error(P_CONTROL)) // Any error? { c = Host_error_status(P_CONTROL); Host_ack_all_errors(P_CONTROL); status = c; // Send error status goto host_transfer_control_end; } if (Is_host_stall(P_CONTROL)) { Host_ack_stall(P_CONTROL); status = CONTROL_STALL; goto host_transfer_control_end; } #if TIMEOUT_DELAY_ENABLE == ENABLE if (1000 < host_get_timeout()) // Count 1s { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } #endif } Host_reset_pipe_fifo_access(P_CONTROL); c = Host_get_pipe_size(P_CONTROL) - Host_byte_count(P_CONTROL); data_length = host_read_p_rxpacket(P_CONTROL, data_pointer, data_length, &data_pointer); if (usb_request.incomplete_read || c) data_length = 0; Host_freeze_pipe(P_CONTROL); Host_ack_control_in_received_free(); // 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); 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(); while (!Is_usb_event(EVT_HOST_SOF)) // Wait for next Keep-Alive { if (Is_host_emergency_exit()) { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } } } } // End of IN data stage Host_configure_pipe_token(P_CONTROL, TOKEN_OUT); Host_ack_control_out_ready_send(); Host_unfreeze_pipe(P_CONTROL); #if TIMEOUT_DELAY_ENABLE == ENABLE private_sof_counter = 0; // Reset the counter in SOF detection subroutine #endif while (!Is_host_control_out_ready()) { #if defined(Host_wait_action) Host_wait_action(); #endif if (Is_host_emergency_exit()) { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } if (Is_host_pipe_error(P_CONTROL)) // Any error? { c = Host_error_status(P_CONTROL); Host_ack_all_errors(P_CONTROL); status = c; // Send error status goto host_transfer_control_end; } if (Is_host_stall(P_CONTROL)) { Host_ack_stall(P_CONTROL); status = CONTROL_STALL; goto host_transfer_control_end; } #if TIMEOUT_DELAY_ENABLE == ENABLE if (2000 < host_get_timeout()) // Count 2s { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } #endif } Host_ack_control_out_ready(); } // OUT request management -------------------------------------------- else // Data stage OUT (bmRequestType.D7 == 0) { Host_configure_pipe_token(P_CONTROL, TOKEN_OUT); Host_ack_control_out_ready(); while (data_length) { Host_unfreeze_pipe(P_CONTROL); Host_reset_pipe_fifo_access(P_CONTROL); data_length = host_write_p_txpacket(P_CONTROL, data_pointer, data_length, (const void **)&data_pointer); Host_send_control_out(); while (!Is_host_control_out_ready()) { #if defined(Host_wait_action) Host_wait_action(); #endif if (Is_host_emergency_exit()) { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } if (Is_host_pipe_error(P_CONTROL)) // Any error? { c = Host_error_status(P_CONTROL); Host_ack_all_errors(P_CONTROL); status = c; // Send error status goto host_transfer_control_end; } if (Is_host_stall(P_CONTROL)) { Host_ack_stall(P_CONTROL); status = CONTROL_STALL; goto host_transfer_control_end; } } Host_ack_control_out_ready(); } // End of OUT data stage Host_freeze_pipe(P_CONTROL); Host_configure_pipe_token(P_CONTROL, TOKEN_IN); Host_ack_control_in_received_free(); Host_unfreeze_pipe(P_CONTROL); #if TIMEOUT_DELAY_ENABLE == ENABLE private_sof_counter = 0; // Reset the counter in SOF detection subroutine #endif while (!Is_host_control_in_received()) { #if defined(Host_wait_action) Host_wait_action(); #endif if (Is_host_emergency_exit()) { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } if (Is_host_pipe_error(P_CONTROL)) // Any error? { c = Host_error_status(P_CONTROL); Host_ack_all_errors(P_CONTROL); status = c; // Send error status goto host_transfer_control_end; } if (Is_host_stall(P_CONTROL)) { Host_ack_stall(P_CONTROL); status = CONTROL_STALL; goto host_transfer_control_end; } #if TIMEOUT_DELAY_ENABLE == ENABLE if (2000 < host_get_timeout()) // Count 2s { Host_freeze_pipe(P_CONTROL); Host_reset_pipe(P_CONTROL); status = CONTROL_TIMEOUT; goto host_transfer_control_end; } #endif } Host_ack_control_in_received(); Host_freeze_pipe(P_CONTROL); Host_free_control_in(); } host_transfer_control_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(); } return status; }
//! //! @brief This function sends nb_data bytes pointed to by ptr_buf on the specified pipe. //! //! @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_send_data(uint8_t pipe, uint16_t nb_data, const void *ptr_buf) { Status_t status = PIPE_GOOD; // Frame correctly sent by default bool sav_int_sof_enable; bool sav_glob_int_en; uint8_t nak_timeout; #if NAK_TIMEOUT_ENABLE == ENABLE uint16_t cpt_nak; #endif sav_int_sof_enable = Is_host_sof_interrupt_enabled(); // Save state of enable SOF interrupt Host_enable_sof_interrupt(); Host_configure_pipe_token(pipe, TOKEN_OUT); Host_ack_out_ready(pipe); Host_unfreeze_pipe(pipe); while (nb_data) // While there is something to send... { // Prepare data to be sent Host_reset_pipe_fifo_access(pipe); nb_data = host_write_p_txpacket(pipe, ptr_buf, nb_data, &ptr_buf); private_sof_counter = 0; // Reset the counter in SOF detection subroutine #if NAK_TIMEOUT_ENABLE == ENABLE cpt_nak = 0; #endif nak_timeout = 0; Host_ack_out_ready_send(pipe); while (!Is_host_out_ready(pipe)) { if (Is_host_emergency_exit()) // Async disconnection or role change detected under interrupt { status = PIPE_DELAY_TIMEOUT; Host_reset_pipe(pipe); goto host_send_data_end; } #if TIMEOUT_DELAY_ENABLE == ENABLE if (private_sof_counter >= 250) // Count 250 ms (250 SOF) { private_sof_counter = 0; if (nak_timeout++ >= TIMEOUT_DELAY) // Increment time-out and check for overflow { status = PIPE_DELAY_TIMEOUT; Host_reset_pipe(pipe); goto host_send_data_end; } } #endif if (Is_host_pipe_error(pipe)) // Error management { status = Host_error_status(pipe); Host_ack_all_errors(pipe); goto host_send_data_end; } if (Is_host_stall(pipe)) // STALL management { status = PIPE_STALL; Host_ack_stall(pipe); goto host_send_data_end; } #if NAK_TIMEOUT_ENABLE == ENABLE if (Is_host_nak_received(pipe)) // NAK received { Host_ack_nak_received(pipe); if (cpt_nak++ > NAK_SEND_TIMEOUT) { status = PIPE_NAK_TIMEOUT; Host_reset_pipe(pipe); goto host_send_data_end; } } #endif } // Here OUT sent Host_ack_out_ready(pipe); } while (Host_nb_busy_bank(pipe)); host_send_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; }
//! //! @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); } }
/** * @brief This function receives nb_data pointed with *buf with the pipe number specified * * The nb_data parameter is passed as a U16 pointer, thus the data pointed by this pointer * is updated with the final number of data byte received. * * @param pipe * @param nb_data * @param buf * * @return status */ U8 host_get_data(U8 pipe, U16 *nb_data, U8 *buf) { U8 status=PIPE_GOOD; U8 sav_int_sof_enable; U8 nak_timeout; U16 n,i; U16 cpt_nak; #if (USER_PERIODIC_PIPE==ENABLE) freeze_user_periodic_pipe(); #endif n=*nb_data; *nb_data=0; sav_int_sof_enable=Is_host_sof_interrupt_enabled(); Host_enable_sof_interrupt(); Host_select_pipe(pipe); Host_continuous_in_mode(); Host_set_token_in(); Host_ack_in_received(); while (n) // While missing data... { Host_unfreeze_pipe(); Host_send_in(); private_sof_counter=0; // Reset the counter in SOF detection sub-routine nak_timeout=0; cpt_nak=0; while (!Is_host_in_received()) { if (Is_host_emergency_exit()) // Async disconnection or role change 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) // Timeout management { private_sof_counter=0; // Done in host SOF interrupt if (nak_timeout++>=TIMEOUT_DELAY)// Check for local timeout { status=PIPE_DELAY_TIMEOUT; Host_reset_pipe(pipe); goto host_get_data_end; } } #endif if(Is_host_pipe_error()) // Error management { status = Host_error_status(); Host_ack_all_errors(); goto host_get_data_end; } if(Is_host_stall()) // STALL management { if( Is_host_in_received() ) break; status =PIPE_STALL; Host_reset_pipe(pipe); Host_ack_stall(); goto host_get_data_end; } #if (NAK_TIMEOUT_ENABLE==ENABLE) if(Is_host_nak_received()) //NAK received { Host_ack_nak_received(); if (cpt_nak++>NAK_RECEIVE_TIMEOUT) { status = PIPE_NAK_TIMEOUT; Host_reset_pipe(pipe); goto host_get_data_end; } } #endif } status=PIPE_GOOD; Host_freeze_pipe(); if (Host_byte_counter()<=n) { if ((Host_byte_counter() < n)&&(Host_byte_counter()<Host_get_pipe_length())) { n=0;} else { n-=Host_byte_counter();} (*nb_data)+=Host_byte_counter(); // Update nb of byte received if( NULL != buf ) { for (i=Host_byte_counter();i;i--) { *buf=Host_read_byte(); buf++;} } } else // more bytes received than expected { // TODO error code management *nb_data+=n; if( NULL != buf ) { for (i=n;i;i--) // Byte number limited to the initial request (limit tab over pb) { *buf=Host_read_byte(); buf++; } } n=0; } Host_ack_in_received(); } Host_freeze_pipe(); host_get_data_end: if (sav_int_sof_enable==FALSE) { Host_disable_sof_interrupt(); } #if (USER_PERIODIC_PIPE==ENABLE) unfreeze_user_periodic_pipe(); #endif return ((U8)status); }
/** * @brief This function send nb_data pointed with *buf with the pipe number specified * * @note This function will activate the host sof interrupt to detect timeout. The * interrupt enable sof will be restore. * * @param pipe * @param nb_data * @param buf * * @return status */ U8 host_send_data(U8 pipe, U16 nb_data, U8 *buf) { U8 c; U8 status=PIPE_GOOD; U8 sav_int_sof_enable; U8 nak_timeout; U16 cpt_nak; U8 nb_data_loaded; U8 cpt_err_timeout=0; #if (USER_PERIODIC_PIPE==ENABLE) freeze_user_periodic_pipe(); #endif sav_int_sof_enable=Is_host_sof_interrupt_enabled(); // Save state of enable sof interrupt Host_enable_sof_interrupt(); Host_select_pipe(pipe); Host_set_token_out(); Host_ack_out_sent(); Host_unfreeze_pipe(); while (nb_data != 0) // While there is something to send... { // Prepare data to be sent c = Host_get_pipe_length(); if ( (U16)c > nb_data) { nb_data_loaded = (U8)nb_data; c = nb_data; } else { nb_data_loaded = c; } while (c!=0) // Load Pipe buffer { Host_write_byte(*buf++); c--; } private_sof_counter=0; // Reset the counter in SOF detection sub-routine cpt_nak=0; nak_timeout=0; Host_ack_out_sent(); Host_send_out(); while (!Is_host_out_sent()) { if (Is_host_emergency_exit())// Async disconnection or role change detected under interrupt { status=PIPE_DELAY_TIMEOUT; Host_reset_pipe(pipe); goto host_send_data_end; } #if (TIMEOUT_DELAY_ENABLE==ENABLE) if (private_sof_counter>=250) // Count 250ms (250sof) { private_sof_counter=0; if (nak_timeout++>=TIMEOUT_DELAY) // Inc timeout and check for overflow { status=PIPE_DELAY_TIMEOUT; Host_reset_pipe(pipe); goto host_send_data_end; } } #endif if (Is_host_pipe_error()) // Any error ? { status = Host_error_status(); Host_ack_all_errors(); if(status == PIPE_TIMEOUT) { if(cpt_err_timeout++>100) { goto host_send_data_end; } else { c=0; while(c<2) // wait 2 ms { if (Is_usb_event(EVT_HOST_SOF)) { Usb_ack_event(EVT_HOST_SOF); c++; } if (Is_host_emergency_exit() ) {break;} } Host_unfreeze_pipe(); } } } if (Is_host_stall()) // Stall management { status =PIPE_STALL; Host_ack_stall(); goto host_send_data_end; } #if (NAK_TIMEOUT_ENABLE==ENABLE) if(Is_host_nak_received()) //NAK received { Host_ack_nak_received(); if (cpt_nak++>NAK_SEND_TIMEOUT) { status = PIPE_NAK_TIMEOUT; Host_reset_pipe(pipe); goto host_send_data_end; } } #endif } // Here OUT sent nb_data -= nb_data_loaded; status=PIPE_GOOD; // Frame correctly sent Host_ack_out_sent(); } while(0!=Host_number_of_busy_bank()); host_send_data_end: Host_freeze_pipe(); // Restore sof interrupt enable state if (sav_int_sof_enable==FALSE) {Host_disable_sof_interrupt();} #if (USER_PERIODIC_PIPE==ENABLE) unfreeze_user_periodic_pipe(); #endif // And return... return ((U8)status); }
__interrupt void usb_pipe_interrupt() #endif { U8 pipe_nb; U8 *ptr_buf; void (*fct_handle)(U8 status,U16 nb_byte); U16 n; U8 i; U8 do_call_back=FALSE; pipe_nb_save = Host_get_selected_pipe(); // Important! Save here working pipe number pipe_nb=usb_get_nb_pipe_interrupt(); // work with the correct pipe number that generates the interrupt Host_select_pipe(pipe_nb); // Select this pipe fct_handle=*(it_pipe_str[pipe_nb].handle); // Now try to detect what event generate an interrupt... if (Is_host_pipe_error()) // Any error ? { it_pipe_str[pipe_nb].status = Host_error_status(); it_pipe_str[pipe_nb].enable=DISABLE; Host_stop_pipe_interrupt(pipe_nb); Host_ack_all_errors(); do_call_back=TRUE; goto usb_pipe_interrupt_end; } if (Is_host_stall()) // Stall handshake received ? { it_pipe_str[pipe_nb].status=PIPE_STALL; it_pipe_str[pipe_nb].enable=DISABLE; Host_stop_pipe_interrupt(pipe_nb); do_call_back=TRUE; goto usb_pipe_interrupt_end; } #if (NAK_TIMEOUT_ENABLE==ENABLE) if (Is_host_nak_received()) // NAK ? { Host_ack_nak_received(); // check if number of NAK timeout error occurs (not for interrupt type pipe) if((--it_pipe_str[pipe_nb].nak_timeout==0) && (Host_get_pipe_type()!=TYPE_INTERRUPT)) { it_pipe_str[pipe_nb].status=PIPE_NAK_TIMEOUT; it_pipe_str[pipe_nb].enable=DISABLE; Host_stop_pipe_interrupt(pipe_nb); do_call_back=TRUE; goto usb_pipe_interrupt_end; } } #endif if (Is_host_in_received()) // Pipe IN reception ? { ptr_buf=it_pipe_str[pipe_nb].ptr_buf+it_pipe_str[pipe_nb].nb_byte_processed; // Build pointer to data buffer n=it_pipe_str[pipe_nb].nb_byte_to_process-it_pipe_str[pipe_nb].nb_byte_processed; // Remaining data bytes Host_freeze_pipe(); if (Host_byte_counter()<=n) { if ((Host_byte_counter() < n)&&(Host_byte_counter()<Host_get_pipe_length())) //Received less than remaining, but less than pipe capacity //TODO: error code { n=0; } else { n-=Host_byte_counter(); } it_pipe_str[pipe_nb].nb_byte_processed+=Host_byte_counter(); // Update nb of byte received for (i=Host_byte_counter();i;i--) { *ptr_buf=Host_read_byte(); ptr_buf++;} } else // more bytes received than expected { // TODO error code management it_pipe_str[pipe_nb].nb_byte_processed+=n; for (i=n;i;i--) // Byte number limited to the initial request (limit tab over pb) { *ptr_buf=Host_read_byte(); ptr_buf++;} n=0; } Host_ack_in_received(); if(n>0) //still something to process { Host_unfreeze_pipe(); // Request another IN transfer Host_send_in(); private_sof_counter=0; // Reset the counter in SOF detection sub-routine it_pipe_str[pipe_nb].timeout=0; // Reset timeout it_pipe_str[pipe_nb].nak_timeout=NAK_RECEIVE_TIMEOUT; } else //end of transfer { it_pipe_str[pipe_nb].enable=DISABLE; it_pipe_str[pipe_nb].status=PIPE_GOOD; Host_stop_pipe_interrupt(pipe_nb); do_call_back=TRUE; } } if(Is_host_out_sent()) // Pipe OUT sent ? { Host_ack_out_sent(); it_pipe_str[pipe_nb].nb_byte_processed+=it_pipe_str[pipe_nb].nb_byte_on_going; it_pipe_str[pipe_nb].nb_byte_on_going=0; ptr_buf=it_pipe_str[pipe_nb].ptr_buf+it_pipe_str[pipe_nb].nb_byte_processed; // Build pointer to data buffer n=it_pipe_str[pipe_nb].nb_byte_to_process-it_pipe_str[pipe_nb].nb_byte_processed; // Remaining data bytes if(n>0) // Still data to process... { Host_unfreeze_pipe(); // Prepare data to be sent i = Host_get_pipe_length(); if ( i > n) // Pipe size> remaining data { i = n; n = 0; } else // Pipe size < remaining data { n -= i; } it_pipe_str[pipe_nb].nb_byte_on_going+=i; // Update nb data processed while (i!=0) // Load Pipe buffer { Host_write_byte(*ptr_buf++); i--; } private_sof_counter=0; // Reset the counter in SOF detection sub-routine it_pipe_str[pipe_nb].timeout=0; // Refresh timeout counter it_pipe_str[pipe_nb].nak_timeout=NAK_SEND_TIMEOUT; Host_send_out(); // Send the USB frame } else //n==0 Transfer is finished { it_pipe_str[pipe_nb].enable=DISABLE; // Tranfer end it_pipe_str[pipe_nb].status=PIPE_GOOD; // Status OK Host_stop_pipe_interrupt(pipe_nb); do_call_back=TRUE; } } usb_pipe_interrupt_end: Host_select_pipe(pipe_nb_save); // Restore pipe number !!!! if (is_any_interrupt_pipe_active()==FALSE) // If no more transfer is armed { if (g_sav_int_sof_enable==FALSE) { Host_disable_sof_interrupt(); } } if(do_call_back) // Any callback functions to perform ? { fct_handle(it_pipe_str[pipe_nb].status,it_pipe_str[pipe_nb].nb_byte_processed); } }