/******************************************************************** * Function: void USBCBSendResume(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: The USB specifications allow some types of USB * peripheral devices to wake up a host PC (such * as if it is in a low power suspend to RAM state). * This can be a very useful feature in some * USB applications, such as an Infrared remote * control receiver. If a user presses the "power" * button on a remote control, it is nice that the * IR receiver can detect this signalling, and then * send a USB "command" to the PC to wake up. * * The USBCBSendResume() "callback" function is used * to send this special USB signalling which wakes * up the PC. This function may be called by * application firmware to wake up the PC. This * function will only be able to wake up the host if * all of the below are true: * * 1. The USB driver used on the host PC supports * the remote wakeup capability. * 2. The USB configuration descriptor indicates * the device is remote wakeup capable in the * bmAttributes field. * 3. The USB host PC is currently sleeping, * and has previously sent your device a SET * FEATURE setup packet which "armed" the * remote wakeup capability. * * If the host has not armed the device to perform remote wakeup, * then this function will return without actually performing a * remote wakeup sequence. This is the required behavior, * as a USB device that has not been armed to perform remote * wakeup must not drive remote wakeup signalling onto the bus; * doing so will cause USB compliance testing failure. * * This callback should send a RESUME signal that * has the period of 1-15ms. * * Note: This function does nothing and returns quickly, if the USB * bus and host are not in a suspended condition, or are * otherwise not in a remote wakeup ready state. Therefore, it * is safe to optionally call this function regularly, ex: * anytime application stimulus occurs, as the function will * have no effect, until the bus really is in a state ready * to accept remote wakeup. * * When this function executes, it may perform clock switching, * depending upon the application specific code in * USBCBWakeFromSuspend(). This is needed, since the USB * bus will no longer be suspended by the time this function * returns. Therefore, the USB module will need to be ready * to receive traffic from the host. * * The modifiable section in this routine may be changed * to meet the application needs. Current implementation * temporary blocks other functions from executing for a * period of ~3-15 ms depending on the core frequency. * * According to USB 2.0 specification section 7.1.7.7, * "The remote wakeup device must hold the resume signaling * for at least 1 ms but for no more than 15 ms." * The idea here is to use a delay counter loop, using a * common value that would work over a wide range of core * frequencies. * That value selected is 1800. See table below: * ========================================================== * Core Freq(MHz) MIP RESUME Signal Period (ms) * ========================================================== * 48 12 1.05 * 4 1 12.6 * ========================================================== * * These timing could be incorrect when using code * optimization or extended instruction mode, * or when having other interrupts enabled. * Make sure to verify using the MPLAB SIM's Stopwatch * and verify the actual signal on an oscilloscope. *******************************************************************/ void USBCBSendResume(void) { static WORD delay_count; // First verify that the host has armed us to perform remote wakeup. // It does this by sending a SET_FEATURE request to enable remote wakeup, // usually just before the host goes to standby mode (note: it will only // send this SET_FEATURE request if the configuration descriptor declares // the device as remote wakeup capable, AND, if the feature is enabled // on the host (ex: on Windows based hosts, in the device manager // properties page for the USB device, power management tab, the // "Allow this device to bring the computer out of standby." checkbox // should be checked). if (USBGetRemoteWakeupStatus() == TRUE) { // Verify that the USB bus is in fact suspended, before we send // remote wakeup signalling. if (USBIsBusSuspended() == TRUE) { USBMaskInterrupts(); // Clock switch to settings consistent with normal USB operation. USBCBWakeFromSuspend(); USBSuspendControl = 0; USBBusIsSuspended = FALSE; // So we don't execute this code again, // until a new suspend condition is detected. // Section 7.1.7.7 of the USB 2.0 specifications indicates a USB // device must continuously see 5ms+ of idle on the bus, before it sends // remote wakeup signalling. One way to be certain that this parameter // gets met, is to add a 2ms+ blocking delay here (2ms plus at // least 3ms from bus idle to USBIsBusSuspended() == TRUE, yeilds // 5ms+ total delay since start of idle). delay_count = 3600U; do { delay_count--; } while(delay_count); // Now drive the resume K-state signalling onto the USB bus. USBResumeControl = 1; // Start RESUME signaling delay_count = 1800U; // Set RESUME line for 1-13 ms do { delay_count--; } while(delay_count); USBResumeControl = 0; // Finished driving resume signalling USBUnmaskInterrupts(); } } }
void USBCBSendResume(void) { static WORD delay_count; if(USBGetRemoteWakeupStatus() == TRUE) { // Verify that the USB bus is in fact suspended, before we send // remote wakeup signalling. if(USBIsBusSuspended() == TRUE) { USBMaskInterrupts(); // Clock switch to settings consistent with normal USB operation. // USBCBWakeFromSuspend(); USBSuspendControl = 0; USBBusIsSuspended = FALSE; // So we don't execute this code again, // until a new suspend condition is // detected. // Section 7.1.7.7 of the USB 2.0 specifications indicates a USB // device must continuously see 5ms+ of idle on the bus, before it // sends remote wakeup signalling. One way to be certain that this // parameter gets met, is to add a 2ms+ blocking delay here // (2ms plus at least 3ms from bus idle to // USBIsBusSuspended() == TRUE, yeilds 5ms+ total delay since start // of idle). delay_count = 3600U; do { delay_count--; }while(delay_count); //Now drive the resume K-state signalling onto the USB bus. USBResumeControl = 1; // Start RESUME signaling delay_count = 1800U; // Set RESUME line for 1-13 ms do { delay_count--; }while(delay_count); USBResumeControl = 0; //Finished driving resume signalling USBUnmaskInterrupts(); } } }
// Send resume call-back void USBCBSendResume(void) { static WORD delay_count; // Verify that the host has armed us to perform remote wakeup. if(USBGetRemoteWakeupStatus() == FLAG_TRUE) { // Verify that the USB bus is suspended (before we send remote wakeup signalling). if(USBIsBusSuspended() == FLAG_TRUE) { USBMaskInterrupts(); // Bring the clock speed up to normal running state USBCBWakeFromSuspend(); USBSuspendControl = 0; USBBusIsSuspended = FLAG_FALSE; // Section 7.1.7.7 of the USB 2.0 specifications indicates a USB // device must continuously see 5ms+ of idle on the bus, before it sends // remote wakeup signalling. One way to be certain that this parameter // gets met, is to add a 2ms+ blocking delay here (2ms plus at // least 3ms from bus idle to USBIsBusSuspended() == FLAG_TRUE, yeilds // 5ms+ total delay since start of idle). delay_count = 3600U; do { delay_count--; } while(delay_count); // Start RESUME signaling for 1-13 ms USBResumeControl = 1; delay_count = 1800U; do { delay_count--; } while(delay_count); USBResumeControl = 0; USBUnmaskInterrupts(); } } }
void CDCTxService(void) { BYTE byte_to_send; BYTE i; USBMaskInterrupts(); CDCNotificationHandler(); if(USBHandleBusy(CDCDataInHandle)) { USBUnmaskInterrupts(); return; } /* * Completing stage is necessary while [ mCDCUSartTxIsBusy()==1 ]. * By having this stage, user can always check cdc_trf_state, * and not having to call mCDCUsartTxIsBusy() directly. */ if(cdc_trf_state == CDC_TX_COMPLETING) cdc_trf_state = CDC_TX_READY; /* * If CDC_TX_READY state, nothing to do, just return. */ if(cdc_trf_state == CDC_TX_READY) { USBUnmaskInterrupts(); return; } /* * If CDC_TX_BUSY_ZLP state, send zero length packet */ if(cdc_trf_state == CDC_TX_BUSY_ZLP) { CDCDataInHandle = USBTxOnePacket(CDC_DATA_EP,NULL,0); //CDC_DATA_BD_IN.CNT = 0; cdc_trf_state = CDC_TX_COMPLETING; } else if(cdc_trf_state == CDC_TX_BUSY) { /* * First, have to figure out how many byte of data to send. */ if(cdc_tx_len > sizeof(cdc_data_tx)) byte_to_send = sizeof(cdc_data_tx); else byte_to_send = cdc_tx_len; /* * Subtract the number of bytes just about to be sent from the total. */ cdc_tx_len = cdc_tx_len - byte_to_send; pCDCDst.bRam = (BYTE*)&cdc_data_tx; // Set destination pointer i = byte_to_send; if(cdc_mem_type == USB_EP0_ROM) // Determine type of memory source { while(i) { *pCDCDst.bRam = *pCDCSrc.bRom; pCDCDst.bRam++; pCDCSrc.bRom++; i--; }//end while(byte_to_send) } else // _RAM { while(i) { *pCDCDst.bRam = *pCDCSrc.bRam; pCDCDst.bRam++; pCDCSrc.bRam++; i--; }//end while(byte_to_send._word) }//end if(cdc_mem_type...) /* * Lastly, determine if a zero length packet state is necessary. * See explanation in USB Specification 2.0: Section 5.8.3 */ if(cdc_tx_len == 0) { if(byte_to_send == CDC_DATA_IN_EP_SIZE) cdc_trf_state = CDC_TX_BUSY_ZLP; else cdc_trf_state = CDC_TX_COMPLETING; }//end if(cdc_tx_len...) CDCDataInHandle = USBTxOnePacket(CDC_DATA_EP,(BYTE*)&cdc_data_tx,byte_to_send); }//end if(cdc_tx_sate == CDC_TX_BUSY) USBUnmaskInterrupts(); }//end CDCTxService
void USBCCIDBulkInService(void) { WORD byte_to_send; BYTE i; USBMaskInterrupts(); if(USBHandleBusy(usbCcidBulkInHandle)) { USBUnmaskInterrupts(); return; } if(usbCcidBulkInTrfState == USB_CCID_BULK_IN_COMPLETING) usbCcidBulkInTrfState = USB_CCID_BULK_IN_READY; /* * If USB_CCID_BULK_IN_READY state, nothing to do, just return. */ if(usbCcidBulkInTrfState == USB_CCID_BULK_IN_READY) { USBUnmaskInterrupts(); return; } /* * If USB_CCID_BULK_IN_BUSY_ZLP state, send zero length packet */ if(usbCcidBulkInTrfState == USB_CCID_BULK_IN_BUSY_ZLP) { usbCcidBulkInHandle = USBTxOnePacket(USB_EP_BULK_IN,NULL,0); usbCcidBulkInTrfState = USB_CCID_BULK_IN_COMPLETING; } else if(usbCcidBulkInTrfState == USB_CCID_BULK_IN_BUSY) { /* * First, have to figure out how many byte of data to send. */ if(usbCcidBulkInLen > sizeof(usbCcidBulkInEndpoint)) byte_to_send = sizeof(usbCcidBulkInEndpoint); else byte_to_send = usbCcidBulkInLen; /* * Subtract the number of bytes just about to be sent from the total. */ usbCcidBulkInLen = usbCcidBulkInLen - byte_to_send; pCCIDDst.bRam = (BYTE*)usbCcidBulkInEndpoint; // Set destination pointer i = byte_to_send; while(i) { *pCCIDDst.bRam = *pCCIDSrc.bRam; pCCIDDst.bRam++; pCCIDSrc.bRam++; i--; }//end while(byte_to_send._word) /* * Lastly, determine if a zero length packet state is necessary. * See explanation in USB Specification 2.0: Section 5.8.3 */ if(usbCcidBulkInLen == 0) { if(byte_to_send == USB_EP_SIZE) usbCcidBulkInTrfState = USB_CCID_BULK_IN_BUSY_ZLP; else usbCcidBulkInTrfState = USB_CCID_BULK_IN_COMPLETING; }//end if(usbCcidBulkInLen...) usbCcidBulkInHandle = USBTxOnePacket(USB_EP_BULK_IN,(BYTE*)usbCcidBulkInEndpoint,byte_to_send); }//end if(cdc_tx_sate == USB_CCID_BULK_IN_BUSY) USBUnmaskInterrupts(); }//end USBCCIDBulkInService