예제 #1
0
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;
}