/***************************************************************************//**
 * @brief       Handle Endpoint 2 OUT transfer interrupt
 * @note        This function takes no parameters, but it uses the EP2OUT status
 *              variables stored in @ref myUsbDevice.ep2out.
 ******************************************************************************/
void handleUsbOut2Int(void)
{
  uint8_t count;

  USB_Status_TypeDef status;
  bool xferComplete = false;

  USB_SetIndex(2);

  if (USB_EpnOutGetSentStall())
  {
    USB_EpnOutClearSentStall();
  }
  else if (USB_EpnGetOutPacketReady())
  {
    count = USB_EpOutGetCount();

    // If USBD_Read() has not been called, return an error
    if (myUsbDevice.ep2out.state != D_EP_RECEIVING)
    {
      myUsbDevice.ep2out.misc.bits.outPacketPending = true;
      status = USB_STATUS_EP_ERROR;
    }
    // Check for overrun of user buffer
    else if (myUsbDevice.ep2out.remaining < count)
    {
      myUsbDevice.ep2out.state = D_EP_IDLE;
      myUsbDevice.ep2out.misc.bits.outPacketPending = true;
      status = USB_STATUS_EP_RX_BUFFER_OVERRUN;
    }
    else
    {
      USB_ReadFIFO(2, count, myUsbDevice.ep2out.buf);

      myUsbDevice.ep2out.misc.bits.outPacketPending = false;
      myUsbDevice.ep2out.remaining -= count;
      myUsbDevice.ep2out.buf += count;

      if ((myUsbDevice.ep2out.remaining == 0) || (count != SLAB_USB_EP2OUT_MAX_PACKET_SIZE))
      {
        myUsbDevice.ep2out.state = D_EP_IDLE;
        xferComplete = true;
      }

      status = USB_STATUS_OK;
      USB_EpnClearOutPacketReady();
    }
    if (myUsbDevice.ep2out.misc.bits.callback == true)
    {
      if (xferComplete == true)
      {
        myUsbDevice.ep2out.misc.bits.callback = false;
      }

      USBD_XferCompleteCb(EP2OUT, status, count, myUsbDevice.ep2out.remaining);
    }
  }
}
Exemplo n.º 2
0
/***************************************************************************//**
 * @brief       Handles receive data phase on Endpoint 0
 ******************************************************************************/
void handleUsbEp0Rx(void)
{
  uint8_t count;
  USB_Status_TypeDef status;
  bool callback = myUsbDevice.ep0.misc.bits.callback;

  // Get the number of bytes received
  count = USB_Ep0GetCount();

  // If the call to USBD_Read() did not give a large enough buffer to hold this
  // data, set the outPacketPending flag and signal an RX overrun.
  if (myUsbDevice.ep0.remaining < count)
  {
    myUsbDevice.ep0.state = D_EP_IDLE;
    myUsbDevice.ep0.misc.bits.outPacketPending = true;
    status = USB_STATUS_EP_RX_BUFFER_OVERRUN;
  }
  else
  {
    USB_ReadFIFO(0, count, myUsbDevice.ep0.buf);
    myUsbDevice.ep0.buf += count;
    myUsbDevice.ep0.remaining -= count;
    status = USB_STATUS_OK;

    // If the last packet of the transfer is exactly the maximum EP0 packet
    // size, we will must wait to receive a ZLP (zero-length packet) after the
    // last data packet. This signals that the host has completed the transfer.
    // Check for the ZLP packet case here.
    if ((myUsbDevice.ep0.remaining == 0) && (count != USB_EP0_SIZE))
    {
      USB_Ep0SetLastOutPacketReady();
      myUsbDevice.ep0.state = D_EP_IDLE;
      myUsbDevice.ep0.misc.bits.callback = false;
    }
    else
    {
      // Do not call USB_Ep0SetLastOutPacketReady() until we get the ZLP.
      USB_Ep0ServicedOutPacketReady();
    }
  }

  // Make callback if requested
  if (callback == true)
  {
    USBD_XferCompleteCb(EP0, status, count, myUsbDevice.ep0.remaining);
  }
}
/***************************************************************************//**
 * @brief       Handle Endpoint 2 IN transfer interrupt
 * @note        This function takes no parameters, but it uses the EP2IN status
 *              variables stored in @ref myUsbDevice.ep2in.
 ******************************************************************************/
void handleUsbIn2Int(void)
{
  uint8_t xferred;
  bool callback;

  USB_SetIndex(2);

  if (USB_EpnInGetSentStall())
  {
    USB_EpnInClearSentStall();
  }
  else if (myUsbDevice.ep2in.state == D_EP_TRANSMITTING)
  {
    xferred = (myUsbDevice.ep2in.remaining > SLAB_USB_EP2IN_MAX_PACKET_SIZE)
              ? SLAB_USB_EP2IN_MAX_PACKET_SIZE : myUsbDevice.ep2in.remaining;
    myUsbDevice.ep2in.remaining -= xferred;
    myUsbDevice.ep2in.buf += xferred;

    callback = myUsbDevice.ep2in.misc.bits.callback;

    // Load more data
    if (myUsbDevice.ep2in.remaining > 0)
    {
      USB_WriteFIFO(2,
                    (myUsbDevice.ep2in.remaining > SLAB_USB_EP2IN_MAX_PACKET_SIZE)
                      ? SLAB_USB_EP2IN_MAX_PACKET_SIZE
                      : myUsbDevice.ep2in.remaining,
                    myUsbDevice.ep2in.buf,
                    true);
    }
    else
    {
      myUsbDevice.ep2in.misc.bits.callback = false;
      myUsbDevice.ep2in.state = D_EP_IDLE;
    }

    if (callback == true)
    {
      USBD_XferCompleteCb(EP2IN, USB_STATUS_OK, xferred, myUsbDevice.ep2in.remaining);
    }

  }
}
/***************************************************************************//**
 * @brief       Handle Endpoint 3 OUT transfer interrupt
 * @details     Endpoint 3 OUT is the only OUT endpoint that supports
 *              isochronous transfers.
 * @note        This function takes no parameters, but it uses the EP3OUT status
 *              variables stored in @ref myUsbDevice.ep3out.
 ******************************************************************************/
void handleUsbOut3Int(void)
{
#if (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC)
  uint16_t nextIdx;
#if (SLAB_USB_EP3OUT_MAX_PACKET_SIZE > 255)
  uint16_t count;
#else
  uint8_t count;
#endif // ( SLAB_USB_EP3OUT_MAX_PACKET_SIZE > 255 )
#else
  uint8_t count;
#endif // ( SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC )

  USB_Status_TypeDef status;
  bool xferComplete = false;

  USB_SetIndex(3);

  if (USB_EpnOutGetSentStall())
  {
    USB_EpnOutClearSentStall();
  }
  else if (USB_EpnGetOutPacketReady())
  {
    count = USB_EpOutGetCount();

    // If USBD_Read() has not been called, return an error
    if (myUsbDevice.ep3out.state != D_EP_RECEIVING)
    {
      myUsbDevice.ep3out.misc.bits.outPacketPending = true;
      status = USB_STATUS_EP_ERROR;
    }
#if  ((SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR))
    // Check for overrun of user buffer
    else if (myUsbDevice.ep3out.remaining < count)
    {
      myUsbDevice.ep3out.state = D_EP_IDLE;
      myUsbDevice.ep3out.misc.bits.outPacketPending = true;
      status = USB_STATUS_EP_RX_BUFFER_OVERRUN;
    }
#endif
    else
    {
#if  ((SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR))
      USB_ReadFIFO(3, count, myUsbDevice.ep3out.buf);

      myUsbDevice.ep3out.remaining -= count;
      myUsbDevice.ep3out.buf += count;

      if ((myUsbDevice.ep3out.remaining == 0) || (count != SLAB_USB_EP3OUT_MAX_PACKET_SIZE))
      {
        myUsbDevice.ep3out.state = D_EP_IDLE;
        xferComplete = true;
      }
#elif (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC)
      nextIdx = count + myUsbDevice.ep3outIsoIdx;

      // In isochronous mode, a circular buffer is used to hold the data
      // If the next index into the circular buffer passes the end of the
      // buffer, make two calls to USB_ReadFIFOIso()
      if (nextIdx > myUsbDevice.ep3out.remaining)
      {
        USB_ReadFIFOIso(3, myUsbDevice.ep3out.remaining - myUsbDevice.ep3outIsoIdx, &myUsbDevice.ep3out.buf[myUsbDevice.ep3outIsoIdx]);
        myUsbDevice.ep3outIsoIdx = nextIdx - myUsbDevice.ep3out.remaining;
        USB_ReadFIFOIso(3, myUsbDevice.ep3outIsoIdx, myUsbDevice.ep3out.buf);
      }
      else
      {
        USB_ReadFIFOIso(3, count, &myUsbDevice.ep3out.buf[myUsbDevice.ep3outIsoIdx]);
        myUsbDevice.ep3outIsoIdx = nextIdx;
      }
#endif // ( ( SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK ) || ( SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR ) )

      myUsbDevice.ep3out.misc.bits.outPacketPending = false;
      status = USB_STATUS_OK;
      USB_EpnClearOutPacketReady();
    }
    if (myUsbDevice.ep3out.misc.bits.callback == true)
    {
      if (xferComplete == true)
      {
        myUsbDevice.ep3out.misc.bits.callback = false;
      }

#if  ((SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR))
      USBD_XferCompleteCb(EP3OUT, status, count, myUsbDevice.ep3out.remaining);
#elif (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC)

      // In Isochronous mode, the meaning of the USBD_XferCompleteCb parameters changes:
      //   xferred is the number of bytes received in the last packet
      //   remaining is the current index into the circular buffer
      USBD_XferCompleteCb(EP3OUT, status, count, myUsbDevice.ep3outIsoIdx);
#endif
    }
  }
}
/***************************************************************************//**
 * @brief       Handle Endpoint 3 IN transfer interrupt
 * @details     Endpoint 3 IN is the only IN endpoint that supports isochronous
 *              transfers.
 * @note        This function takes no parameters, but it uses the EP3IN status
 *              variables stored in @ref myUsbDevice.ep3in.
 ******************************************************************************/
void handleUsbIn3Int(void)
{
#if SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC
  uint16_t xferred, nextIdx;
#else
  uint8_t xferred;
  bool callback;
#endif

  USB_SetIndex(3);

  if (USB_EpnInGetSentStall())
  {
    USB_EpnInClearSentStall();
  }
  else if (myUsbDevice.ep3in.state == D_EP_TRANSMITTING)
  {
#if  ((SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_INTR))
    xferred = (myUsbDevice.ep3in.remaining > SLAB_USB_EP3IN_MAX_PACKET_SIZE)
              ? SLAB_USB_EP3IN_MAX_PACKET_SIZE : myUsbDevice.ep3in.remaining;
    myUsbDevice.ep3in.remaining -= xferred;
    myUsbDevice.ep3in.buf += xferred;
#endif

#if  ((SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_INTR))

    callback = myUsbDevice.ep3in.misc.bits.callback;

#elif (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC)
    if (myUsbDevice.ep3in.misc.bits.callback == true)
    {
      // In Isochronous mode, the meaning of the USBD_XferCompleteCb parameters changes:
      //   xferred is ignored
      //   remaining is the current index into the circular buffer
      //   the return value is the number of bytes to transmit in the next packet
      xferred = USBD_XferCompleteCb(EP3IN, USB_STATUS_OK, 0, myUsbDevice.ep3inIsoIdx);
      if (xferred == 0)
      {
        myUsbDevice.ep3in.misc.bits.inPacketPending = true;
        return;
      }
    }
#endif
    // Load more data
#if  ((SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_INTR))
    if (myUsbDevice.ep3in.remaining > 0)
    {
      USB_WriteFIFO(3,
                    (myUsbDevice.ep3in.remaining > SLAB_USB_EP3IN_MAX_PACKET_SIZE)
                      ? SLAB_USB_EP3IN_MAX_PACKET_SIZE
                      : myUsbDevice.ep3in.remaining,
                    myUsbDevice.ep3in.buf,
                    true);
    }
    else
    {
      myUsbDevice.ep3in.misc.bits.callback = false;
      myUsbDevice.ep3in.state = D_EP_IDLE;
    }

    if (callback == true)
    {
      USBD_XferCompleteCb(EP3IN, USB_STATUS_OK, xferred, myUsbDevice.ep3in.remaining);
    }
#elif (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC)
    nextIdx = xferred + myUsbDevice.ep3inIsoIdx;
    myUsbDevice.ep3in.misc.bits.inPacketPending = false;

    // Check if the next index is past the end of the circular buffer.
    // If so, break the write up into two calls to USB_WriteFIFOIso()
    if (nextIdx > myUsbDevice.ep3in.remaining)
    {
      USB_WriteFIFOIso(3, myUsbDevice.ep3in.remaining - myUsbDevice.ep3inIsoIdx, &myUsbDevice.ep3in.buf[myUsbDevice.ep3inIsoIdx]);
      myUsbDevice.ep3inIsoIdx = nextIdx - myUsbDevice.ep3in.remaining;
      USB_WriteFIFOIso(3, myUsbDevice.ep3inIsoIdx, myUsbDevice.ep3in.buf);
    }
    else
    {
      USB_WriteFIFOIso(3, xferred, &myUsbDevice.ep3in.buf[myUsbDevice.ep3inIsoIdx]);
      myUsbDevice.ep3inIsoIdx = nextIdx;
    }
#endif // ( ( SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_BULK ) || ( SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_INTR ) )
  }
}
Exemplo n.º 6
0
/***************************************************************************//**
 * @brief       Handles transmit data phase on Endpoint 0
 ******************************************************************************/
static void handleUsbEp0Tx(void)
{
  uint8_t count, count_snapshot, i;
  bool callback = myUsbDevice.ep0.misc.bits.callback;

  // The number of bytes to send in the next packet must be less than or equal
  // to the maximum EP0 packet size.
  count = (myUsbDevice.ep0.remaining >= USB_EP0_SIZE) ?
           USB_EP0_SIZE : myUsbDevice.ep0.remaining;

  // Save the packet size for future use.
  count_snapshot = count;

  // Strings can use the USB_STRING_DESCRIPTOR_UTF16LE_PACKED type to pack
  // UTF16LE data without the zero's between each character.
  // If the current string is of type USB_STRING_DESCRIPTOR_UTF16LE_PACKED,
  // unpacket it by inserting a zero between each character in the string.
  if (myUsbDevice.ep0String.encoding.type == USB_STRING_DESCRIPTOR_UTF16LE_PACKED)
  {
    // If ep0String.encoding.init is true, this is the beginning of the string.
    // The first two bytes of the string are the bLength and bDescriptorType
    // fields. These are no packed like the reset of the string, so write them
    // to the FIFO and set ep0String.encoding.init to false.
    if (myUsbDevice.ep0String.encoding.init == true)
    {
      USB_WriteFIFO(0, 2, myUsbDevice.ep0.buf, false);
      myUsbDevice.ep0.buf += 2;
      count -= 2;
      myUsbDevice.ep0String.encoding.init = false;
    }

    // Insert a 0x00 between each character of the string.
    for (i = 0; i < count / 2; i++)
    {
      USB_WriteFIFO(0, 1, myUsbDevice.ep0.buf, false);
      myUsbDevice.ep0.buf++;
      USB_WriteFIFO(0, 1, &txZero, false);
    }
  }
  // For any data other than USB_STRING_DESCRIPTOR_UTF16LE_PACKED, just send the
  // data normally.
  else
  {
    USB_WriteFIFO(0, count, myUsbDevice.ep0.buf, false);
    myUsbDevice.ep0.buf += count;
  }

  myUsbDevice.ep0.misc.bits.inPacketPending = false;
  myUsbDevice.ep0.remaining -= count_snapshot;

  // If the last packet of the transfer is exactly the maximum EP0 packet size,
  // we will have to send a ZLP (zero-length packet) after the last data packet
  // to signal to the host that the transfer is complete.
  // Check for the ZLP packet case here.
  if ((myUsbDevice.ep0.remaining == 0) && (count_snapshot != USB_EP0_SIZE))
  {
    USB_Ep0SetLastInPacketReady();
    myUsbDevice.ep0.state = D_EP_IDLE;
    myUsbDevice.ep0String.c = USB_STRING_DESCRIPTOR_UTF16LE;
    myUsbDevice.ep0.misc.c = 0;
  }
  else
  {
    // Do not call USB_Ep0SetLastInPacketReady() because we still need to send
    // the ZLP.
    USB_Ep0SetInPacketReady();
  }
  // Make callback if requested
  if (callback == true)
  {
    USBD_XferCompleteCb(EP0, USB_STATUS_OK, count_snapshot, myUsbDevice.ep0.remaining);
  }
}