void CDCNotificationHandler(void) { //Check the DTS I/O pin and if a state change is detected, notify the //USB host by sending a serial state notification element packet. if(UART_DTS == USB_CDC_DSR_ACTIVE_LEVEL) //UART_DTS must be defined to be an I/O pin in the hardware profile to use the DTS feature (ex: "PORTXbits.RXY") { SerialStateBitmap.bits.DSR = 1; } else { SerialStateBitmap.bits.DSR = 0; } //If the state has changed, and the endpoint is available, send a packet to //notify the hUSB host of the change. if((SerialStateBitmap.byte != OldSerialStateBitmap.byte) && (!USBHandleBusy(CDCNotificationInHandle))) { //Copy the updated value into the USB packet buffer to send. SerialStatePacket.SerialState.byte = SerialStateBitmap.byte; //We don't need to write to the other bytes in the SerialStatePacket USB //buffer, since they don't change and will always be the same as our //initialized value. //Send the packet over USB to the host. CDCNotificationInHandle = USBTransferOnePacket(CDC_COMM_EP, IN_TO_HOST, (BYTE*)&SerialStatePacket, sizeof(SERIAL_STATE_NOTIFICATION)); //Save the old value, so we can detect changes later. OldSerialStateBitmap.byte = SerialStateBitmap.byte; } }//void CDCNotificationHandler(void)
/********************************************************************* * Function: void APP_DeviceVendorThroughputTestInitialize(void); * * Overview: Initializes the demo * * PreCondition: Configuration for this app is already set by the USB host. * * Input: None * * Output: None * ********************************************************************/ void APP_DeviceVendorThroughputTestInitialize() { EP1OUTEvenHandle = NULL; EP2OUTEvenHandle = NULL; EP3OUTEvenHandle = NULL; EP1OUTOddHandle = NULL; EP2OUTOddHandle = NULL; EP3OUTOddHandle = NULL; //Now that we are configured, enable the endpoints for use in the demo // and start the initial transfers USBEnableEndpoint(1,USB_OUT_ENABLED|USB_IN_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP); USBEnableEndpoint(2,USB_OUT_ENABLED|USB_IN_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP); USBEnableEndpoint(3,USB_OUT_ENABLED|USB_IN_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP); //Prepare the OUT endpoints to receive the first packets from the host. EP1OUTEvenHandle = USBTransferOnePacket(1, OUT_FROM_HOST,(uint8_t*)&EP1OUTEvenBuffer,64); //First 64-bytes of data sent to EP1 OUT will arrive in the even buffer. EP1OUTOddHandle = USBTransferOnePacket(1, OUT_FROM_HOST,(uint8_t*)&EP1OUTOddBuffer,64); //Second 64-bytes of data sent to EP1 OUT will arrive in the odd buffer. EP1OUTEvenNeedsServicingNext = true; //Used to keep track of which buffer will contain the next sequential data packet. EP2OUTEvenHandle = USBTransferOnePacket(2, OUT_FROM_HOST,(uint8_t*)&EP2OUTEvenBuffer,64); EP2OUTOddHandle = USBTransferOnePacket(2, OUT_FROM_HOST,(uint8_t*)&EP2OUTOddBuffer,64); EP2OUTEvenNeedsServicingNext = true; //Used to keep track of which buffer will contain the next sequential data packet. EP3OUTEvenHandle = USBTransferOnePacket(3, OUT_FROM_HOST,(uint8_t*)&EP3OUTEvenBuffer,64); EP3OUTOddHandle = USBTransferOnePacket(3, OUT_FROM_HOST,(uint8_t*)&EP3OUTOddBuffer,64); EP3OUTEvenNeedsServicingNext = true; //Used to keep track of which buffer will contain the next sequential data packet. }
/********************************************************************* * Function: void APP_DeviceVendorThroughputTestTasks(void); * * Overview: keeps the demo running. * * PreCondition: Demo is initialiized. * * Input: None * * Output: None * ********************************************************************/ void APP_DeviceVendorThroughputTestTasks() { //User Application USB tasks below. //Note: The user application should not begin attempting to read/write over the USB //until after the device has been fully enumerated. After the device is fully //enumerated, the USBDeviceState will be set to "CONFIGURED_STATE". if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) return; //All currently existing Microchip USB microcontroller use a dedicated Direct //Memory Access (DMA) interface allowing the USB module to directly read or //write USB packets into or out of microcontroller SRAM. To receive an "OUT" //packet from the host (in USB terminology, OUT and IN are always from the host's //perspective), the microcontroller firmware needs to "arm" the Buffer //Descriptor Table (BDT) for the endpoint that the data will be received on. //The BDT entry is a small set of special function registers (SFRs) that //control the operation of the DMA transaction (number of bytes to receive, //pointer to where in SRAM the data should be placed, etc.). Depending upon //the USB module configuration, there will be many BDT entries, as each //combination of endpoint number, endpoint direction, and endpoint //"even/odd-ness" (when ping-pong buffering is enabled), needs a dedicated //set of SFRs for controling the DMA behavior when the host tries to read/write //to the respective endpoint. //As the device completes the enumeration process, the USBCBInitEP() function will //get called. In this function, we initialize the user application endpoints (in this //example code, the user application makes use of EP1 OUT, EP2 OUT, EP3 OUT). //The USBTransferOnePacket() function calls in the USBCBInitEP() function initializes an endpoint //and "arms" it so that it can receive a packet of data from the host. Once the endpoint //has been armed, the host can then send data to it (assuming some kind of application software //is running on the host, and the application software tries to send data to the USB device). //If the host sends a packet of data to the endpoint 1 OUT buffer, the hardware of the SIE will //automatically receives it and stores the data at the memory location pointed to when we called //USBTransferOnePacket(). Additionally, the endpoint handle will indicate //that the endpoint is no longer busy. At this point, it is safe for this firmware to begin reading //from the endpoint buffer, and processing the data. In this example, we don't actually do anything //with the data that is received from the host, since this demo is simply meant to show high bandwidth //USB communication. //This demo makes full use of the "ping-pong" buffering features implemented //by the USB module hardware. Ping-pong buffering is like a "DMA FIFO". //It enables up to two transactions to be queued up on a single endpoint. //While the firmware may be processing and using previously received data, //the USB module hardware can be configured to still receive the next packet //of data that may be sent from the host. //As an example in the below code, if the USB host tries to send 273 bytes //to "Endpoint 1 OUT", the following sequence will occur: //1. The first set of bytes (0-63) will arrive in the EP1OUTEvenBuffer[]. //2. The next set of bytes (64-127) will arrive in the EP1OUTOddBuffer[]. //3. Assuming the firmware re-armed the EP1OUTEven BDT, then the next set of // bytes (128-191) will arrive in the EP1OUTEvenBuffer[]. //4. Assuming the firmware re-armed the EP1OUTOdd BDT, then the next set of // bytes (192-255) will arrive in the EP1OUTOddBuffer[]. //5. Assuming the firmware re-armed the EP1OUTEven BDT, then the next set of // bytes (256-272) will arrive in the EP1OUTEvenBuffer[]. This completes // the transfer, as the host has successfully sent 273 bytes total (0-272). //If after successfully completing the above 273 byte transfer, and the host //wants to start another transfer and send another 75 bytes, the following //will occur: //6. Assuming the firmware re-armed the EP1OUTOdd BDT, then bytes (0-63) // will arrive in the EP1OUTOddBuffer[]. //7. Assuming the firmware re-armed the EP1OUTEven BDT, then the next set of // bytes (64-74) will arrive in the EP1OUTEvenBuffer[]. This completes // the transfer, as the host has successfully sent 75 bytes total (0-74). //In the above sequence, if the firmware had not gotten around to re-arming //the EP1OUTEven BDT by step #3, then the EP1 OUT endpoint will continuously //NAK until the firmware eventually does re-arm the EP1OUTEven BDT. This //NAKing will temporarily halt the data flow, but it does not cause data to //be lost. The host will continue to retry sending the data until it is //received successfully, or, the host PC application that is sending the data //aborts the operation. The PC application software can be written to //optionally abort a transfer if it takes too long (or some other event //takes place, such as the user trying to close the application). if(EP1OUTEvenNeedsServicingNext == true) //Check which buffer (even/odd) the next set of data is going to arrive in { if(!USBHandleBusy(EP1OUTEvenHandle)) //Check if the endpoint has received any data from the host. { //If the microcontroller core gets to this point, it means that the host has //successfully sent data to the EP1 OUT endpoint, and the data in the EP1OUTEvenBuffer[] //is currently valid. //Insert code here that would do something useful with the EP1OUTEvenBuffer[] //data, according to the needs of the application. For this high-bandwidth //example application, we don't do anything with the data, as the //objective is to demonstrate maximum data transfer rate only. //Now re-arm the EP1OUTEven BDT entry so that the EP1OUTEvenBuffer[] can //be prepared to receive the "second to next" data packet that the host //sends to EP1 OUT. The very next data packet sent to EP1 OUT will go //into the EP1OUTOdd buffer. However, we still need to re-arm the //EP1OUTEven BDT entry, so that the data packet that arrives after the //one going into the EP1OUTOdd buffer has someplace to go. //The USBTransferOnePacket() function call "arms" the endpoint (and //makes it "busy"). If the endpoint is armed, the SIE will automatically //accept data from the host, if the host tries to send a packet of data //to the endpoint. Once a data packet addressed to this endpoint is //received from the host, the endpoint will no longer be busy, and the //application can read the data which will be sitting in the buffer. EP1OUTEvenHandle = USBTransferOnePacket(1, OUT_FROM_HOST,(uint8_t*)&EP1OUTEvenBuffer,64); EP1OUTEvenNeedsServicingNext = false; } } else //else EP1OUTOdd needs servicing next { if(!USBHandleBusy(EP1OUTOddHandle)) //Check if the endpoint has received any data from the host. { //Insert code here that would do something useful with the data, according to the needs of //the application. //Re-arm the EP1OUTOdd BDT entry so the EP1OUTOddBuffer[] can receive //the second to next data packet sent by the host. EP1OUTOddHandle = USBTransferOnePacket(1, OUT_FROM_HOST,(uint8_t*)&EP1OUTOddBuffer,64); EP1OUTEvenNeedsServicingNext = true; } } if(EP2OUTEvenNeedsServicingNext == true) { if(!USBHandleBusy(EP2OUTEvenHandle)) //Check if the endpoint has received any data from the host. { //Re-arm the OUT endpoint for the next packet: EP2OUTEvenHandle = USBTransferOnePacket(2, OUT_FROM_HOST,(uint8_t*)&EP2OUTEvenBuffer,64); EP2OUTEvenNeedsServicingNext = false; } } else //else EP2OUTOdd needs servicing next { if(!USBHandleBusy(EP2OUTOddHandle)) //Check if the endpoint has received any data from the host. { //Re-arm the OUT endpoint for the next packet: EP2OUTOddHandle = USBTransferOnePacket(2, OUT_FROM_HOST,(uint8_t*)&EP2OUTOddBuffer,64); EP2OUTEvenNeedsServicingNext = true; } } if(EP3OUTEvenNeedsServicingNext == true) { if(!USBHandleBusy(EP3OUTEvenHandle)) //Check if the endpoint has received any data from the host. { //Re-arm the OUT endpoint for the next packet: EP3OUTEvenHandle = USBTransferOnePacket(3, OUT_FROM_HOST,(uint8_t*)&EP3OUTEvenBuffer,64); EP3OUTEvenNeedsServicingNext = false; } } else //else EP3OUTOdd needs servicing next { if(!USBHandleBusy(EP3OUTOddHandle)) //Check if the endpoint has received any data from the host. { //Re-arm the OUT endpoint for the next packet: EP3OUTOddHandle = USBTransferOnePacket(3, OUT_FROM_HOST,(uint8_t*)&EP3OUTOddBuffer,64); EP3OUTEvenNeedsServicingNext = true; } } }