Go Down

Topic: [Solved] SerialUSB - checking if connection is (still) present (Read 419 times) previous topic - next topic

rotunnoz

Mar 28, 2019, 01:07 am Last Edit: Apr 05, 2019, 05:57 pm by rotunnoz Reason: Found a solution to the problem. (see answer #3)
I'm using a modified Due to control the timing of a USB camera, which sends images to C++ software on a PC.

The Due is connected to the PC by its native USB port (the programming port isn't present in the modified design) and I'm using the SerialUSB class to communicate to the C++ application on the PC.

I'm trying to come up with a way to automatically detect when the connection to the PC is lost, on the Due program, in the hopes that I can act on it somehow to help restore that connection. I did some research but documentation on the SerialUSB class seems hard to come by. I know the only way to do that when using regular Serial communication is by periodically sending a "heartbeat" message, but I imagine SerialUSB would work differently since it's actually USB.

I have an Atmel ICE debugger hooked up to the JTAG headers and by stepping through the code, I can see that:

Code: [Select]
if (SerialUSB)

Returns false until a connection is established to the PC (my application or any serial monitor), after which point it always returns true, even after the connection ceases. I was also looking through the available methods in the SerialUSB class but none of them seemed relevant to what I'm trying to do.

Input and ideas would be greatly appreciated!

ard_newbie

#1
Mar 28, 2019, 06:30 am Last Edit: Mar 28, 2019, 06:31 am by ard_newbie
When the DUE is connected to a PC thru the Native USB Port, the DUE is a USB Device and an internal counter is incremented (UOTGHS_DEVFNUM) each 125 us. If you unplug the Native USB, the USB Device STALLS and the internal counter stops incrementing. When the connection resumes, the internal counter increments again.

The code below lights up an LED when the DUE, as a USB Device, STALLS, and turns OFF the LED when the counter increments again. However, the counter increments even if a correct COM port is not selected (the electrical connection suffices).

Code: [Select]

void setup() {
  SerialUSB.begin(250000);
  while (!SerialUSB);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {

  static uint32_t Oldmillis;
  static uint32_t OldCount, Count;

  if (millis() - Oldmillis > 10)
  {

    Oldmillis = millis();
    Count = (UOTGHS->UOTGHS_DEVFNUM & UOTGHS_DEVFNUM_FNUM_Msk) >> UOTGHS_DEVFNUM_FNUM_Pos;
    if (OldCount == Count)
    {
      digitalWrite(LED_BUILTIN, HIGH);
    }
    else
    {
      digitalWrite(LED_BUILTIN, LOW);
    }
    OldCount = Count;
    SerialUSB.println("hjk");
  }

}

rotunnoz

That's an excellent contribution, thank you! Sorry about not responding earlier, I got a little carried away with experimenting.

I tested your logic and it seems to work as expected, here's how I verified it:

- Disconnected the USB cable on the PC end just enough so the data lines stopped making contact, but without disconnecting the power lines (my Due is powered off the USB)
- LED went on
- Reconnected USB data lines by inserting the connector all the way
- LED went off

What is the purpose of the following line in your code? I left it aside and the logic still seems to work.

Code: [Select]
SerialUSB.println("hjk");

Also, is there a way to check if another device "listening" to the USB connection? Let's say my C++ application or a serial monitor closes the connection to the Due, is there a way to tell from the Due side?

Thanks again!

rotunnoz

I found a solution while looking through the USB stack files. There's a method in the SerialUSB class that returns true whenever the host (my C++ app, a serial monitor etc.) is connected:

Code: [Select]
bool Serial_::dtr() {
return _usbLineInfo.lineState & 0x1;
}


That information seems to be contained in the first bit of _usbLineInfo.lineState as you can see. For those who did not know (like me  :) ), the SerialUSB class is declared in USBAPI.h and defined in CDC.cpp.

I also found an alternative to checking the electrical connection of the data lines, as (beautifully) explained by ard_newbie. The method below:

Code: [Select]
// VBUS or counting frames
// Any frame counting?
uint32_t USBD_Connected(void)
{
uint8_t f = UDD_GetFrameNumber();

delay(3);

return f != UDD_GetFrameNumber();
}


Is declared in USBAPI.h, defined in USBCore.cpp, and can be called from the sketch directly as it is not part of any class or structure. The downside to this alternative is the 3 ms delay embedded to the method.

I have version 1.6.11 (the latest, to this date) of the Arduino Due libraries, where the files mentioned above are present.

Thanks!

Go Up