//! 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 takes the stream coming from the selected USB pipe and sends //! it to the DAC driver. Moreover, it ensures that both input and output stream //! keep synchronized by adding or deleting samples. //! //! @param side USB_STREAM_HOST for USB host, USB_STREAM_DEVICE for device. //! @param pipe_in Number of the addressed pipe/endpoint //! @param pFifoCount (return parameter) NULL or pointer to the number of used buffers at this time //! //! @return status: (USB_STREAM_STATUS_OK, USB_STREAM_STATUS_NOT_SYNCHRONIZED, //! USB_STREAM_STATUS_SPEED_UP, USB_STREAM_STATUS_SLOW_DOWN, USB_STREAM_STATUS_BUFFER_OVERFLOW) //! int usb_stream_input(usb_stream_side_t side, uint8_t pipe_in, uint32_t* pFifoCount) { uint16_t fifo_used_cnt; uint16_t byte_count=0; uint32_t i; UnionPtr pswap; UnionPtr buffer; // We comes here since we have received something. Let's increase the internal // activity counter. usb_stream_cnt++; fifo_used_cnt=usb_stream_fifo_get_used_room(); if (pFifoCount) *pFifoCount = fifo_used_cnt; // usb_stream_fifo_get_free_room() if( USB_STREAM_BUFFER_NUMBER-fifo_used_cnt==0 ) { // Fatal error: even with the synchro mechanism acting, we are in a case in which the // buffers are full. usb_stream_context->synchronized = false; usb_stream_context->status = USB_STREAM_ERROR_NOT_SYNCHRONIZED; return usb_stream_context->status; } pswap.s8ptr = buffer.s8ptr = usb_stream_fifo_get_buffer(usb_stream_context->wr_id); #if USB_HOST_FEATURE == true if( side==USB_STREAM_HOST ) { byte_count=Host_byte_count(pipe_in); } #endif #if USB_DEVICE_FEATURE == true if( side==USB_STREAM_DEVICE ) { byte_count=Usb_byte_count(pipe_in); } #endif if( byte_count==0 ) { if( cpu_is_timeout(&broken_stream_timer) ) { usb_stream_context->status = USB_STREAM_ERROR_BROKEN_STREAM; } else { usb_stream_context->status = USB_STREAM_ERROR_NO_DATA; } return usb_stream_context->status; } else { // reset time out detection cpu_set_timeout(cpu_ms_2_cy(BROKEN_STREAM_TIMER, FCPU_HZ), &broken_stream_timer); } #if USB_HOST_FEATURE == true if( side==USB_STREAM_HOST ) { Host_reset_pipe_fifo_access(pipe_in); host_read_p_rxpacket(pipe_in, (void*)buffer.s8ptr, byte_count, NULL); } #endif #if USB_DEVICE_FEATURE == true if( side==USB_STREAM_DEVICE ) { Usb_reset_endpoint_fifo_access(pipe_in); usb_read_ep_rxpacket(pipe_in, (void*)buffer.s8ptr, byte_count, NULL); } #endif usb_stream_context->status = USB_STREAM_ERROR_NONE; if( byte_count > USB_STREAM_REAL_BUFFER_SIZE ) { byte_count = USB_STREAM_REAL_BUFFER_SIZE; usb_stream_context->status = USB_STREAM_ERROR_OVERFLOW; } // Swap samples since they are coming from the USB world. if( usb_stream_context->bits_per_sample==16 ) for( i=0 ; i<byte_count/(16/8) ; i++ ) pswap.s16ptr[i] = swap16(pswap.s16ptr[i]); else if( usb_stream_context->bits_per_sample==32 ) for( i=0 ; i<byte_count/(32/8) ; i++ ) pswap.s32ptr[i] = swap32(pswap.s32ptr[i]); //for( i=0 ; i<byte_count/2 ; i++ ) // printf("0x%04hx ", pswap[i]); //printf("\r\n"); usb_stream_fifo_push(byte_count); fifo_used_cnt++; if( !usb_stream_context->synchronized ) { usb_stream_context->status = USB_STREAM_ERROR_NOT_SYNCHRONIZED; if( fifo_used_cnt>=(USB_STREAM_BUFFER_NUMBER/2) ) { // We have enough buffers to start the playback. void* buffer; uint16_t size; // CS2200 cs2200_freq_clk_out(_32_BITS_RATIO(usb_stream_resync_frequency, CS2200_FREF)); usb_stream_resync_step = PPM(usb_stream_resync_frequency, USB_STREAM_RESYNC_PPM_STEPS); usb_stream_resync_freq_ofst = usb_stream_resync_frequency; usb_stream_resync_ppm_ofst = 0; usb_stream_resync_last_room = fifo_used_cnt; #define TIMER_USB_RESYNC_CORRECTION 320 cpu_set_timeout( cpu_ms_2_cy(TIMER_USB_RESYNC_CORRECTION, FCPU_HZ), &usb_resync_timer ); usb_stream_context->synchronized=true; usb_stream_fifo_get(&buffer, &size); audio_mixer_dacs_output_direct(buffer, size/(usb_stream_context->channel_count*usb_stream_context->bits_per_sample/8)); // Fill also the reload stage of the PDCA. usb_stream_fifo_pull(); usb_stream_fifo_get(&buffer, &size); audio_mixer_dacs_output_direct(buffer, size/(usb_stream_context->channel_count*usb_stream_context->bits_per_sample/8)); } } return usb_stream_context->status; }
//! //! @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; }
//! //! @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); } }
//! host_read_p_rxpacket //! //! This function reads the selected pipe FIFO to the buffer pointed to by //! rxbuf, using as few accesses as possible. //! //! @param p Number of the addressed pipe //! @param rxbuf Address of buffer to write //! @param data_length Number of bytes to read //! @param prxbuf NULL or pointer to the buffer address to update //! //! @return Number of read bytes //! //! @note The selected pipe FIFO may be read in several steps by calling //! host_read_p_rxpacket several times. //! //! @warning Invoke Host_reset_pipe_fifo_access before this function when at //! FIFO beginning whether or not the FIFO is to be read in several steps. //! //! @warning Do not mix calls to this function with calls to indexed macros. //! U32 host_read_p_rxpacket(U8 p, void *rxbuf, U32 data_length, void **prxbuf) { // Use aggregated pointers to have several alignments available for a same address UnionCVPtr p_fifo; UnionPtr rxbuf_cur; #if (!defined __OPTIMIZE_SIZE__) || !__OPTIMIZE_SIZE__ // Auto-generated when GCC's -Os command option is used StructCPtr rxbuf_end; #else UnionCPtr rxbuf_end; #endif // !__OPTIMIZE_SIZE__ // Initialize pointers for copy loops and limit the number of bytes to copy p_fifo.u8ptr = pep_fifo[p].u8ptr; rxbuf_cur.u8ptr = rxbuf; rxbuf_end.u8ptr = rxbuf_cur.u8ptr + min(data_length, Host_byte_count(p)); #if (!defined __OPTIMIZE_SIZE__) || !__OPTIMIZE_SIZE__ // Auto-generated when GCC's -Os command option is used rxbuf_end.u16ptr = (U16 *)Align_down((U32)rxbuf_end.u8ptr, sizeof(U16)); rxbuf_end.u32ptr = (U32 *)Align_down((U32)rxbuf_end.u16ptr, sizeof(U32)); rxbuf_end.u64ptr = (U64 *)Align_down((U32)rxbuf_end.u32ptr, sizeof(U64)); // If all addresses are aligned the same way with respect to 16-bit boundaries if (Get_align((U32)rxbuf_cur.u8ptr, sizeof(U16)) == Get_align((U32)p_fifo.u8ptr, sizeof(U16))) { // If pointer to reception buffer is not 16-bit aligned if (!Test_align((U32)rxbuf_cur.u8ptr, sizeof(U16))) { // Copy 8-bit data to reach 16-bit alignment if (rxbuf_cur.u8ptr < rxbuf_end.u8ptr) { // 8-bit accesses to FIFO data registers do require pointer post-increment *rxbuf_cur.u8ptr++ = *p_fifo.u8ptr++; } } // If all addresses are aligned the same way with respect to 32-bit boundaries if (Get_align((U32)rxbuf_cur.u16ptr, sizeof(U32)) == Get_align((U32)p_fifo.u16ptr, sizeof(U32))) { // If pointer to reception buffer is not 32-bit aligned if (!Test_align((U32)rxbuf_cur.u16ptr, sizeof(U32))) { // Copy 16-bit data to reach 32-bit alignment if (rxbuf_cur.u16ptr < rxbuf_end.u16ptr) { // 16-bit accesses to FIFO data registers do require pointer post-increment *rxbuf_cur.u16ptr++ = *p_fifo.u16ptr++; } } // If pointer to reception buffer is not 64-bit aligned if (!Test_align((U32)rxbuf_cur.u32ptr, sizeof(U64))) { // Copy 32-bit data to reach 64-bit alignment if (rxbuf_cur.u32ptr < rxbuf_end.u32ptr) { // 32-bit accesses to FIFO data registers do not require pointer post-increment *rxbuf_cur.u32ptr++ = *p_fifo.u32ptr; } } // Copy 64-bit-aligned data while (rxbuf_cur.u64ptr < rxbuf_end.u64ptr) { // 64-bit accesses to FIFO data registers do not require pointer post-increment *rxbuf_cur.u64ptr++ = *p_fifo.u64ptr; } // Copy 32-bit-aligned data if (rxbuf_cur.u32ptr < rxbuf_end.u32ptr) { // 32-bit accesses to FIFO data registers do not require pointer post-increment *rxbuf_cur.u32ptr++ = *p_fifo.u32ptr; } } // Copy remaining 16-bit data if some while (rxbuf_cur.u16ptr < rxbuf_end.u16ptr) { // 16-bit accesses to FIFO data registers do require pointer post-increment *rxbuf_cur.u16ptr++ = *p_fifo.u16ptr++; } } #endif // !__OPTIMIZE_SIZE__ // Copy remaining 8-bit data if some while (rxbuf_cur.u8ptr < rxbuf_end.u8ptr) { // 8-bit accesses to FIFO data registers do require pointer post-increment *rxbuf_cur.u8ptr++ = *p_fifo.u8ptr++; } // Save current position in FIFO data register pep_fifo[p].u8ptr = (volatile U8 *)p_fifo.u8ptr; // Return the updated buffer address and the number of copied bytes if (prxbuf) *prxbuf = rxbuf_cur.u8ptr; return (rxbuf_cur.u8ptr - (U8 *)rxbuf); }
//! host_set_p_txpacket //! //! This function fills the selected pipe FIFO with a constant byte, using //! as few accesses as possible. //! //! @param p Number of the addressed pipe //! @param txbyte Byte to fill the pipe with //! @param data_length Number of bytes to write //! //! @return Number of non-written bytes //! //! @note The selected pipe FIFO may be filled in several steps by calling //! host_set_p_txpacket several times. //! //! @warning Invoke Host_reset_pipe_fifo_access before this function when at //! FIFO beginning whether or not the FIFO is to be filled in several steps. //! //! @warning Do not mix calls to this function with calls to indexed macros. //! U32 host_set_p_txpacket(U8 p, U8 txbyte, U32 data_length) { // Use aggregated pointers to have several alignments available for a same address UnionVPtr p_fifo_cur; #if (!defined __OPTIMIZE_SIZE__) || !__OPTIMIZE_SIZE__ // Auto-generated when GCC's -Os command option is used StructCVPtr p_fifo_end; Union64 txval; #else UnionCVPtr p_fifo_end; union { U8 u8[1]; } txval; #endif // !__OPTIMIZE_SIZE__ // Initialize pointers for write loops and limit the number of bytes to write p_fifo_cur.u8ptr = pep_fifo[p].u8ptr; p_fifo_end.u8ptr = p_fifo_cur.u8ptr + min(data_length, Host_get_pipe_size(p) - Host_byte_count(p)); #if (!defined __OPTIMIZE_SIZE__) || !__OPTIMIZE_SIZE__ // Auto-generated when GCC's -Os command option is used p_fifo_end.u16ptr = (U16 *)Align_down((U32)p_fifo_end.u8ptr, sizeof(U16)); p_fifo_end.u32ptr = (U32 *)Align_down((U32)p_fifo_end.u16ptr, sizeof(U32)); p_fifo_end.u64ptr = (U64 *)Align_down((U32)p_fifo_end.u32ptr, sizeof(U64)); #endif // !__OPTIMIZE_SIZE__ txval.u8[0] = txbyte; #if (!defined __OPTIMIZE_SIZE__) || !__OPTIMIZE_SIZE__ // Auto-generated when GCC's -Os command option is used txval.u8[1] = txval.u8[0]; txval.u16[1] = txval.u16[0]; txval.u32[1] = txval.u32[0]; // If pointer to FIFO data register is not 16-bit aligned if (!Test_align((U32)p_fifo_cur.u8ptr, sizeof(U16))) { // Write 8-bit data to reach 16-bit alignment if (p_fifo_cur.u8ptr < p_fifo_end.u8ptr) { *p_fifo_cur.u8ptr++ = txval.u8[0]; } } // If pointer to FIFO data register is not 32-bit aligned if (!Test_align((U32)p_fifo_cur.u16ptr, sizeof(U32))) { // Write 16-bit data to reach 32-bit alignment if (p_fifo_cur.u16ptr < p_fifo_end.u16ptr) { *p_fifo_cur.u16ptr++ = txval.u16[0]; } } // If pointer to FIFO data register is not 64-bit aligned if (!Test_align((U32)p_fifo_cur.u32ptr, sizeof(U64))) { // Write 32-bit data to reach 64-bit alignment if (p_fifo_cur.u32ptr < p_fifo_end.u32ptr) { *p_fifo_cur.u32ptr++ = txval.u32[0]; } } // Write 64-bit-aligned data while (p_fifo_cur.u64ptr < p_fifo_end.u64ptr) { *p_fifo_cur.u64ptr++ = txval.u64; } // Write remaining 32-bit data if some if (p_fifo_cur.u32ptr < p_fifo_end.u32ptr) { *p_fifo_cur.u32ptr++ = txval.u32[0]; } // Write remaining 16-bit data if some if (p_fifo_cur.u16ptr < p_fifo_end.u16ptr) { *p_fifo_cur.u16ptr++ = txval.u16[0]; } // Write remaining 8-bit data if some if (p_fifo_cur.u8ptr < p_fifo_end.u8ptr) { *p_fifo_cur.u8ptr++ = txval.u8[0]; } #else // Write remaining 8-bit data if some while (p_fifo_cur.u8ptr < p_fifo_end.u8ptr) { *p_fifo_cur.u8ptr++ = txval.u8[0]; } #endif // !__OPTIMIZE_SIZE__ // Compute the number of non-written bytes data_length -= p_fifo_cur.u8ptr - pep_fifo[p].u8ptr; // Save current position in FIFO data register pep_fifo[p].u8ptr = p_fifo_cur.u8ptr; // Return the number of non-written bytes return data_length; }