//! 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;
}
Exemplo n.º 3
0
//!
//! @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;
}
Exemplo n.º 4
0
//!
//! @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);
  }
}
Exemplo n.º 5
0
//! 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);
}
Exemplo n.º 6
0
//! 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;
}