Serial_::operator bool() { bool result = false; if(USBDevice.configured() && (_cdcLineState & CONTROL_LINE_STATE_DTR) && !USB_IsSendQFull(CDC_TX) // && !USB_IsStalled(CDC_TX) ) { result = true; } // We add a short delay before returning to fix a bug observed by Federico // where the port is configured (_cdcLineState != 0) but not quite opened. // delay(10); if(!result) { if(!USBDevice.configured()) { #ifdef DEBUG_CODE error_printP(F("USB device not configured")); #endif // DEBUG_CODE } else if(!(_cdcLineState & CONTROL_LINE_STATE_DTR)) { #ifdef DEBUG_CODE error_printP(F("DTR is off")); #endif // DEBUG_CODE } else if(USB_IsSendQFull(CDC_TX)) { #ifdef DEBUG_CODE error_printP(F("Send Queue FULL")); #endif // DEBUG_CODE } // else if(USB_IsStalled(CDC_TX)) // { //#ifdef DEBUG_CODE // error_printP(F("USB is stalled")); //#endif // DEBUG_CODE // } } return result; }
bool WEAK CDC_Setup(Setup& setup) { u8 r = setup.bRequest; u8 requestType = setup.bmRequestType; if(REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType) { if (CDC_GET_LINE_CODING == r) { error_printP(F("Get Line Coding")); #if 1 USB_SendControl(0,(void*)&_usbLineInfo, sizeof(_usbLineInfo)/*7*/); #endif // 0 return true; } } else if(REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) { if(CDC_SET_LINE_CODING == r) { error_printP_(F("CDC_SET_LINE_CODING")); // setup packet is followed by data? memcpy((void *)&_usbLineInfo, (char *)&(setup) + sizeof(Setup), sizeof(_usbLineInfo)); error_printP_(F(" rate:")); error_printL_(_usbLineInfo.dwDTERate); error_printP_(F(" fmt:")); error_printL_(_usbLineInfo.bCharFormat); error_printP_(F(" par:")); error_printL_(_usbLineInfo.bParityType); error_printP_(F(" bit:")); error_printL(_usbLineInfo.bDataBits); USB_SendControl(0, NULL, 0); // send a ZLP _cdcLineState = CONTROL_LINE_STATE_DTR; // for now... assume "this" // now set up the ACM interrupt info in '_cdcSerialState' and send it back _cdcSerialState = SERIAL_STATE_TX_CARRIER_DSR; // to tell host "I have data" (always) return true; } else if(CDC_SET_CONTROL_LINE_STATE == r) { error_printP_(F("Set Control Line State: ")); error_printL(setup.wValueL); _cdcLineState = setup.wValueL; // NOTE: this next part is for the 'caterina' CDC bootloader, arduino/bootloaders/caterina/Caterina.c // it has some "special" code in it, like using 0x0800 in RAM as an address for a 'key' (7777H) // to indicate it was soft-booted. XMEGA has better ways of handling this, like a CPU flag that // indicates "I was soft-booted" as one example, and a 'WDT' timeout flag on top of that. // auto-reset into the bootloader is triggered when the port, already // open at 1200 bps, is closed. this is the signal to start the watchdog // with a relatively long period so it can finish housekeeping tasks // like servicing endpoints before the sketch ends if (1200 == _usbLineInfo.dwDTERate) { // We check DTR state to determine if host port is open (bit 0 of _cdcLineState). if ((_cdcLineState & 0x01) == 0) { // This section of code is support for the 'caterina' bootloader, which allows USB flashing (apparently) // // *(uint16_t *)0x0800 = 0x7777; note that on XMEGA this is a VERY bad thing // wdt_enable(WDTO_120MS); // // on the atmega, address 800H is the start of the final 256-byte page in RAM space for 2k RAM // // atmega328(p) RAM goes from 0x100 through 0x8ff - see datasheet for atmega 328 [etc.] section 8.3 // 32U4 RAM goes through 0xaff - see datasheet for U4 processors, section 5.2 // 8/16/32U2 RAM goes through 4FFH so this won't even work - see datasheet for U2 processors, section 7.2 // basically it's a 'hack' and needs to be re-evaluated // TODO: would it be safe to enable interrupts, NOT return from this function, // and simply wait until the appropriate time has elapsed? Or, as is // handled in the section below, this 'wait period' is canceled // TODO: if I use a function that's part of the USB driver to trigger a soft boot, I can detect // that a soft boot has taken place using the bits in the 'RESET' status register. If all // I have to do is detect this, it's not a problem, and I won't need "magic memory locations" // TODO: timeout-based reboot } else { // Most OSs do some intermediate steps when configuring ports and DTR can // twiggle more than once before stabilizing. // To avoid spurious resets we set the watchdog to 250ms and eventually // cancel if DTR goes back high. // This section of code is support for the 'caterina' bootloader, which allows USB flashing (apparently) // // TODO: reset whatever boot timeout I did // wdt_disable(); // wdt_reset(); // *(uint16_t *)0x0800 = 0x0; note that on XMEGA this is a VERY bad thing } } USB_SendControl(0, NULL, 0); // send a ZLP return true; } } // unrecognized request - report it error_printP_(F("CDC request: type=")); error_printL_(requestType); error_printP_(F(" request=")); error_printL(r); return false; }