Leonardo, pause code whilst USB disconnects/reconnects then continue?

(This has been discussed at usb - Leonardo - send key command after HID connection with computer established automatically? - Arduino Stack Exchange too)

So I have a Leonardo project where it reboots a Mac system and I want it to then enter the boot menu.

I’ve convinced that BootKeyboard will work to enter the boot menus with the correct key presses however I was hoping it could “hold” the key down whilst the reboot was happening, but this doesn’t work.

Obviously when the reboot happens the USB-HID connection is terminated and then reconnects. The Leonardo is powered by an external source so it doesn’t reset it’s code. I verified the BootKeyboard code works and in theory this is possible by attaching a button. When the Mac reboots and the Leonardo makes it’s HID connection again the red LED on the Leonardo (Micro Pro) flashes at this point I pressed the button to run the code and it press the keys at the right time to enter the boot menu.

Unfortunately this takes manual intervention - the boot time always varies so I can’t program it with a pause command and the window for it to press the button at the right time is really small.

So what I need the code to do is in the middle of the loop, whilst the computer is rebooting, wait to see the USB HID reconnecting (indicated by the red LED flash on the Arduino) and then immediately press the key combination.

Is this possible? There was talk of serial.end to terminate the USB connection before the Mac reboots and then it would automatically be made again upon reboot, so I tried to use some kind of white/if statement but nothing i’ve tried worked.

Here is “some” of my code below. There will be buttons to start different parts from the top eventually - and there is an ESP82 connected which is triggered by pin 5 to send a push notification once everything is done. I also have the Mac talk to the Arduino via serial (as seen in the demo code) which makes it run this section of code that reboots computer (basically the Mac script tells it when it’s finished running so it knows its time to reboot the system)

#include <HID-Project.h>
#include <HID-Settings.h>
int buttonPin;
int buttonPin2;
char chr;   // for incoming serial data, type char is signed 8-bit, -128 to 127, ASCII is char codes. Save 1 byte over type int.
int incomingByte = 0;   // for incoming serial data

void setup() {
  BootKeyboard.begin();
  Keyboard.begin();
  Mouse.begin();
  Serial.begin(115200);
  buttonPin = 4; //whatever pin your button is plugged into
  buttonPin2 = 6; //whatever pin your button is plugged into
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(buttonPin2, INPUT_PULLUP);
  pinMode(5, OUTPUT);
}

void loop() {
  //check button pressed, if so enter program condition (inside if statement)
  if (Serial.available() > 1) 
    {
    // read the next char in the Serial input buffer, might be the last/latest arrived
    (chr = Serial.read() > 1);
    // run commands
  delay(1000); 
  Keyboard.press(KEY_LEFT_CTRL);
  Keyboard.press(KEY_F2);
  delay(100);
  Keyboard.releaseAll();
  Keyboard.write(KEY_DOWN_ARROW);
  delay(50);
  Keyboard.write(KEY_DOWN_ARROW);
  delay(50);
  Keyboard.write(KEY_DOWN_ARROW);
  delay(50);
  Keyboard.write(KEY_DOWN_ARROW);
  delay(50);
  Keyboard.write(KEY_DOWN_ARROW);
  delay(50);
  Keyboard.write(KEY_DOWN_ARROW);
  delay(50);
  Keyboard.write(KEY_DOWN_ARROW);
  delay(50);
  Keyboard.write(KEY_DOWN_ARROW);
  delay(50);
  Keyboard.write(KEY_RETURN);
  delay(1000);
  Keyboard.write(KEY_TAB);
  delay(100);
  Keyboard.write(KEY_TAB);
  delay(100);
  Keyboard.write(' ');

// This is where I need the code to wait for the USB-HID to disconnect then reconnect whilst the computer reboots. Perhaps serial.end after the space bar press above, but what code will make the Leonardo press the keys below as soon as its red LED has flashed after the reboot? If there's no suitable code I think perhaps the only, rather ott method, at this point would be to tell a light sensor to look for the flash before continuing to run the code. But surely there's a simpler way.

  BootKeyboard.press(KEY_LEFT_GUI);
  BootKeyboard.press('r');
  delay(120000);
  BootKeyboard.releaseAll();
  
  delay(1000);
// Language Select Screen
  Keyboard.write(KEY_RETURN);
  delay(11000);
// Recovery Partition
  Mouse.click(MOUSE_LEFT);
  delay(50);
  Keyboard.write(KEY_TAB);
  delay(50);
  Keyboard.write(KEY_TAB);
  delay(50);
  Keyboard.write(KEY_TAB);
  delay(50);
  Keyboard.write(KEY_TAB);
  delay(50);
  Keyboard.write(KEY_DOWN_ARROW);
  delay(50);
  Keyboard.write(KEY_DOWN_ARROW);
  delay(50);
  Keyboard.write(KEY_DOWN_ARROW);
  delay(50);
  Keyboard.write(KEY_RETURN);
  delay(4500);
  Keyboard.print("/Volumes/Macintosh");
  digitalWrite(5, HIGH);
  delay(100);   //short wait time
  digitalWrite(5, LOW);
 }
}

JSOTOLA posted this helpful link over at the StackExchange.

It seems from the reply that it’s possible to see if the USB bus is disconnected and then if the USB is connected. with UDADDR & _BV(ADDEN) and VBUS in USBSTA

So based on that, is it possible for me that the stage of the code above for the Arduino to look and wait for the USB to become disconnected (which will happen during the reboot) and then for it look and wait for it to be reconnected again (when the red led flashes I assume) and continue running the code from there? Could someone indicate how that would be programmed as i’m out of my depth here, i’m assuming something like…

Keyboard.write(' ');

// Reboot is activated - look for and wait for USB to be disconnected something like?...

if (USBSTA & _BV(ADDEN)) {}

// Then wait for the USB bus to be connected again?

if (UDADDR & _BV(ADDEN)) {}

// Then immediately continue to code.

  BootKeyboard.press(KEY_LEFT_GUI);
  BootKeyboard.press('r');
  delay(120000);
  BootKeyboard.releaseAll();

Maybe the second answer here would also do what I want to achieve, but again I have no idea how to practically add this to my code

https://arduino.stackexchange.com/questions/20836/ifserial-not-working-correctly-on-micro-or-pro-micro/20896#20896

I assume I'd need a loop in the which checks to see if the USB has been disconnected (which it wont be physically but I assume as the computer reboots at some point it will be) and wait for it to return that answer. So it'd need to check, see it's still connected then check again and keep doing so until it sees the USB connection has been dropped. At which point it needs a loop to check to see if it's been reestablished and as soon as it finds it has continue running the rest of the code starting with pressing the Command+R buttons. This seems possible but if someone could show me some demo code as to how it might be work because i'm hugely of my depth.

Going to have to bump this, I’d hoped someone would know - could someone maybe at least help me with this bit of code?

Let’s assume as per that other post that USBCON |= 1<<OTGPADE; detects the cable is unplugged, and (USBSTA & (1<<VBUS)) detects if the cable is plugged in and connected.

Could someone provide an exact code example I could put into the middle of my void loop at the point I want it to happen where it just keeps checking for the USB cable to be disconnected and when it is, it keeps checking for it to be reconnected and when it is continues to run my code pressing the keys at hopefully the right time. At least I can copy and paste that code in and get troubleshooting from there - at the minute I have no idea what to do with that syntax or how to make an if loop that keeps checking.

Let’s assume as per that other post that USBCON |= 1<<OTGPADE; detects the cable is unplugged

Let’s NOT assume that. An assignment statement doesn’t detect anything. The assigned value MIGHT mean the the cable is unplugged.

Why don’t you write some code, as in the state change detection example, and print the value in USBCON every time it changes? Then, you’ll KNOW whether unplugging the cable causes a change, or not.

No sense trying to go ANY further until you KNOW that you can detect when the cable is unplugged.

Then, test your other assertion, that you can tell when the cable is plugged back in.

When you KNOW that you can detect both events, it will be quite obvious what to do to suspend and resume loop() when the cable is unplugged and plugged back in.

PaulS: Why don't you write some code, as in the state change detection example, and print the value in USBCON every time it changes? Then, you'll KNOW whether unplugging the cable causes a change, or not.

I have no idea how to do this, could you show me how?

Something like this:

byte currUSB =0;
byte prevUSB = 0;

void setup()
{
   Serial.begin(115200);
   Serial.println("Testing detection of USB cable changes");
}

void loop()
{
   USBCON |= 1<<OTGPADE;

   currUSB = USBCON;
   if(currUSB != prevUSB)
   {
      Serial.print("The value of USBCON changed, to: ");
      Serial.println(currUSB);
   }

   prebUSB = currUSB;
}

Looks kind of silly sending a USB message while USB is disconnected.

Maybe I would use Serial1 for the hardware serial. Then use another Micro/Leonardo to send that back to the monitoring PC.

MorganS: Looks kind of silly sending a USB message while USB is disconnected.

Maybe I would use Serial1 for the hardware serial. Then use another Micro/Leonardo to send that back to the monitoring PC.

For the purposes of testing you mean? I suppose that will make sense - the only way I can test what a reboot does is to pull out the physical cable and reattach, but as far as I can see from my quick tests that just interupts the serial monitor and doesn't send anything again when it's reconnected, though I haven't tested the above code properly yet.

The Serial Monitor will never automatically reconnect after the cable is plugged in. If you want to do that then you need a different program.

MorganS: The Serial Monitor will never automatically reconnect after the cable is plugged in. If you want to do that then you need a different program.

Right - so i'm not sure what the above really tells me?

Am I just seeing first of all if it detects the USB is connected and outputs something meaningful that we can then use as a variable later on?

There are a lot of different levels of "USB connected" to detect:

  1. Is there valid 5V power? 1a. For high-current devices, can we request more power?
  2. Is there a computer on the other end?
  3. Is there a program open, such as Serial Monitor, looking at what we send?

The code if(!Serial) that you see in a lot of Arduino programs does detect #3. But it only does it once. If you plug in and open Serial Monitor, then Serial is true. But it never goes back to false.

MorganS:
There are a lot of different levels of “USB connected” to detect:

  1. Is there valid 5V power?
    1a. For high-current devices, can we request more power?
  2. Is there a computer on the other end?
  3. Is there a program open, such as Serial Monitor, looking at what we send?

The code if(!Serial) that you see in a lot of Arduino programs does detect #3. But it only does it once. If you plug in and open Serial Monitor, then Serial is true. But it never goes back to false.

Number 2 is what I need. But I need it to check for when the computer is disconnected and then reconnected.

It’s really frustrating that there’s a light which flashes on the Arduino telling me exactly when it’s reconnected and I can press the button, but there’s seemingly no way to just act on this status in code.

PaulS:
Something like this:

byte currUSB =0;

byte prevUSB = 0;

void setup()
{
  Serial.begin(115200);
  Serial.println(“Testing detection of USB cable changes”);
}

void loop()
{
  USBCON |= 1<<OTGPADE;

currUSB = USBCON;
  if(currUSB != prevUSB)
  {
      Serial.print("The value of USBCON changed, to: ");
      Serial.println(currUSB);
  }

prebUSB = currUSB;
}

I gave this a go and for some reason nothing appeared is the serial monitor at all.

Add a while(!Serial) {} above the first print in setup() that should enable you to see that message.

Or print to Serial1 and use another device to read that output.