// Assumption: The user has previously called usbComRxAvailable and its return value // was greater than or equal to size. void usbComRxReceive(uint8 XDATA* buffer, uint8 size) { usbReadFifo(CDC_DATA_ENDPOINT, size, buffer); if (USBCNTL == 0) { USBCSOL &= ~USBCSOL_OUTPKT_RDY; // Tell the USB module we are done reading this packet, so it can receive more. } }
void usbPoll() { uint8 usbcif; uint8 usbiif; //uint8 usboif = USBOIF; if (!usbPowerPresent()) { // The VBUS line is low. This usually means that the USB cable has been // disconnected or the computer has been turned off. SLEEP &= ~(1<<7); // Disable the USB module (SLEEP.USB_EN = 0). disableUsbPullup(); usbDeviceState = USB_STATE_DETACHED; usbSuspendMode = 0; return; } if (usbDeviceState == USB_STATE_DETACHED) { enableUsbPullup(); SLEEP |= (1<<7); // Enable the USB module (SLEEP.USB_EN = 1). __asm nop __endasm; // Datasheet doesn't say so, but David suspects we need some NOPs here before writing to USB registers. __asm nop __endasm; __asm nop __endasm; __asm nop __endasm; usbDeviceState = USB_STATE_POWERED; basicUsbInit(); } usbcif = USBCIF; usbiif = USBIIF; if (usbcif & (1<<0)) // Check SUSPENDIF { // The bus has been idle for 3 ms, so we are now in Suspend mode. // It is the user's responsibility to check usbSuspended() and go to sleep (PM1) // if necessary. usbSuspendMode = 1; } if (usbcif & (1<<2)) // check RSTIF, the reset flag { // A USB reset signal has been received. usbDeviceState = USB_STATE_DEFAULT; controlTransferState = CONTROL_TRANSFER_STATE_NONE; basicUsbInit(); } if (usbcif & (1<<1)) // Check RESUMEIF { usbSuspendMode = 0; } if (usbiif & (1<<0)) // Check EP0IF { // Something happened on Endpoint 0, the endpoint for control transfers. uint8 usbcs0; USBINDEX = 0; usbcs0 = USBCS0; usbActivityFlag = 1; if (usbcs0 & (1<<4)) // Check SETUP_END { // A new setup packet has arrived, prematurely ending the previous control transfer. USBCS0 = 0x80; // Clear the SETUP_END bit controlTransferState = CONTROL_TRANSFER_STATE_NONE; } if (usbcs0 & (1<<2)) // Check SENT_STALL { // A STALL packet was sent USBCS0 = 0x00; // Reset endpoint 0. controlTransferState = CONTROL_TRANSFER_STATE_NONE; } if (usbcs0 & (1<<0)) // Check OUTPKT_RDY { // Requirement: Every codepath from here must result in writing a 1 to // bit 6 of USBCS0 to clear the OUTPKT_RDY flag: USBCS0 = (1<<6). if (controlTransferState == CONTROL_TRANSFER_STATE_WRITE) { // A data packet has been received as part of a control write transfer. uint8 bytesReceived = USBCNT0; if (bytesReceived > controlTransferBytesLeft) { bytesReceived = controlTransferBytesLeft; } usbReadFifo(0, bytesReceived, controlTransferPointer); controlTransferPointer += bytesReceived; controlTransferBytesLeft -= bytesReceived; if (controlTransferBytesLeft) { // Arm the endpoint to receive more bytes USBCS0 = (1<<6); // De-asserts the OUTPKT_RDY bit (bit 0). } else { // The host has sent all the data we were expecting. if (usbSetupPacket.requestType != USB_REQUEST_TYPE_STANDARD) // OPT: remove this check { usbCallbackControlWriteHandler(); } USBINDEX = 0; // Just in case USBINDEX was changed above. if (controlTransferState == CONTROL_TRANSFER_STATE_NONE) { // The data received was invalid. USBCS0 = (1<<6) | (1<<3) | (1<<5); // clear OUTPKT_RDY, set DATA_END, SEND_STALL } else { // The data received was valid. USBCS0 = (1<<6) | (1<<3); // clear OUTPKT_RDY, set DATA_END controlTransferState = CONTROL_TRANSFER_STATE_NONE; } } } else if (USBCNT0 == 8) { // A SETUP packet has been received from the computer, starting a new // control transfer. usbReadFifo(0, 8, (uint8 XDATA *)&usbSetupPacket); // Store the data in usbSetupPacket. // Wipe out the information about the last control transfer. controlTransferState = CONTROL_TRANSFER_STATE_NONE; if (usbSetupPacket.requestType == USB_REQUEST_TYPE_STANDARD) { // The request_type field indicates that this is a Standard Device Request // as described in USB2.0 Chapter 9.4 Standard Device Requests. // These requests are handled by the library in the function below. usbStandardDeviceRequestHandler(); } else { // Otherwise, we use this callback so the user can decide how to handle the // setup packet. In this callback, the user can call various helper // functions that set controlTransferState. usbCallbackSetupHandler(); } USBINDEX = 0; // Select EP0 again because the functions above might have changed USBINDEX. // Modify the count so that we don't send more data than the host requested. if(controlTransferBytesLeft > usbSetupPacket.wLength) { controlTransferBytesLeft = usbSetupPacket.wLength; } // Prepare for the first transaction after the SETUP packet. if (controlTransferState == CONTROL_TRANSFER_STATE_NONE) { // This is invalid/unrecognized control transfer, so send a STALL packet. USBCS0 = (1<<6) | (1<<5); // Clears the OUTPKT_RDY flag because we've handled it, and sends a STALL. } else if (controlTransferState == CONTROL_TRANSFER_STATE_WRITE) { if (controlTransferBytesLeft) { // Arm the endpoint to receive the first data packet of a control write transfer. USBCS0 = (1<<6); // De-asserts the OUTPKT_RDY bit. } else { // Acknowledge a control write transfer with no data phase. USBCS0 = (1<<6) | (1<<3) | (1<<1); // De-asserts OUTPKY_RDY, asserts DATA_END, asserts INPKT_RDY. controlTransferState = CONTROL_TRANSFER_STATE_NONE; } } } else { // An OUT packet was received on Endpoint 0, but we are not in the middle of a // control write transfer and it was not the right length to be a setup packet. // This situation is not expected. USBCS0 = (1<<6); // De-asserts the OUTPKT_RDY. } } if (!(usbcs0 & (1<<1)) && (controlTransferState == CONTROL_TRANSFER_STATE_READ)) { // We are doing a control read transfer, and Endpoint 0 is ready to accept another // IN packet to send to the computer. uint8 bytesToSend; if (controlTransferBytesLeft < USB_EP0_PACKET_SIZE) { // Send the last packet (might be an empty packet). usbcs0 = (1<<1)|(1<<3); // INPKT_RDY and DATA_END bytesToSend = controlTransferBytesLeft; controlTransferState = CONTROL_TRANSFER_STATE_NONE; } else { // Send a packet. usbcs0 = (1<<1); // INPKT_RDY bytesToSend = USB_EP0_PACKET_SIZE; } // Arm endpoint 0 to send the next packet. usbWriteFifo(0, bytesToSend, controlTransferPointer); USBCS0 = usbcs0; // Update the control transfer state. controlTransferPointer += bytesToSend; controlTransferBytesLeft -= bytesToSend; } } }