/***************************************************************************//** * @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); } } }
/***************************************************************************//** * @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 ) ) } }
/***************************************************************************//** * @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); } }