arduino-esp32 icon indicating copy to clipboard operation
arduino-esp32 copied to clipboard

ESP32-S3 - Arduino v3.1 - USBHIDKeyboard won't wake up pc from sleep

Open TheCrypt0 opened this issue 11 months ago • 7 comments

Board

ESP32-S3

Device Description

Custom ESP32-S3 keyboard but it should work on any ESP32-S3 devkit with USB connection.

Hardware Configuration

N.A.

Version

v3.1.0

IDE Name

Arduino IDE

Operating System

macOS 15.2

Flash frequency

80MHz

PSRAM enabled

no

Upload speed

921600

Description

I’m using an ESP32-S3 with Arduino’s USBHIDKeyboard library to emulate a USB keyboard. However, the device never enters USB suspend mode when the host (PC) is put to sleep. This prevents the ESP32-S3 from waking the PC using the remote wakeup feature.

Expected Behavior: • When the PC enters sleep mode, the ESP32-S3 should detect the USB suspend signal and enter suspend mode. • Upon a key press or specific action, the ESP32-S3 should trigger a remote wakeup to wake the PC.

Actual Behavior: • The ESP32-S3 simply detects the USB being disconnected. • The remote wakeup functionality does not work because the device never transitions to suspend mode.

I tested this behavior using a windows notebook and a generic logitech keyboard and once the pc goes (or is forced) to sleep, the keyboard is able to wake it up. Important: the keyboard must be connected before going to sleep.

I tested this with both Arduino version v2.0.17 and v3.1.0, so it appears it's not a new issue.

I must specify I added the REMOTE_WAKEUP attribute before initializing the USB.

USB.usbAttributes(TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP);
USB.begin();

I found another repository that doesn't use the Arduino Core and it seems this is something possible with the ESP32-S3 hardware and TinyUSB: https://github.com/nonoo/esp-remote-wakeup/

I also tried to manually call the tud_remote_wakeup function but without success, it is probably because the bus is not in the suspended mode.

In the example sketch you can replace the Serial Printf for ARDUINO_USB_SUSPEND_EVENT and ARDUINO_USB_RESUME_EVENT with a digitalWrite to a LED to see the behavior without having access to the serial.

Let me know if I can help by providing more details or other stuff I tested.

Sketch

#include <USB.h>
#include <USBCDC.h>
#include <USBHIDKeyboard.h>

USBHIDKeyboard m_keyboard;
USBCDC         m_serial;
ESPUSB*        m_usb;

static void
usbEventCallback(void*            arg,
                 esp_event_base_t event_base,
                 int32_t          event_id,
                 void*            event_data)
{
  if (event_base == ARDUINO_USB_EVENTS) {
    arduino_usb_event_data_t* data = (arduino_usb_event_data_t*)event_data;
    switch (event_id) {
      case ARDUINO_USB_STARTED_EVENT:
        m_serial.println("USB PLUGGED");
        break;
      case ARDUINO_USB_STOPPED_EVENT:
        m_serial.println("USB UNPLUGGED");
        break;
      case ARDUINO_USB_SUSPEND_EVENT:
        m_serial.printf("USB SUSPENDED: remote_wakeup_en: %u\n",
                        data->suspend.remote_wakeup_en);
        break;
      case ARDUINO_USB_RESUME_EVENT:
        m_serial.println("USB RESUMED");
        break;

      default:
        break;
    }
  } else if (event_base == ARDUINO_USB_HID_EVENTS) {
    arduino_usb_hid_event_data_t* data =
      (arduino_usb_hid_event_data_t*)event_data;
    switch (event_id) {
      case ARDUINO_USB_HID_SET_PROTOCOL_EVENT:
        m_serial.printf("HID SET PROTOCOL: %s\n",
                        data->set_protocol.protocol ? "REPORT" : "BOOT");
        break;
      case ARDUINO_USB_HID_SET_IDLE_EVENT:
        m_serial.printf("HID SET IDLE: %u\n", data->set_idle.idle_rate);
        break;

      default:
        break;
    }
  }
}

void
setup()
{
  // put your setup code here, to run once:
  // m_serial.begin(115200);

  USB.onEvent(usbEventCallback);
  m_keyboard.onEvent(usbEventCallback);
  m_serial.onEvent(usbEventCallback);

  m_keyboard.begin();
  m_serial.begin(115200);
  // m_serial.enableReboot(false);

  m_usb = &USB; // get the USB object
  m_usb->manufacturerName("TEST MAN");
  m_usb->productName("TEST DEV");

  // also tried with just TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP no change
  m_usb->usbAttributes(TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP);



  m_usb->begin();
}

void
loop()
{
  // put your main code here, to run repeatedly:
  delay(1000);
}

Debug Message

N.A.

Other Steps to Reproduce

No response

I have checked existing issues, online documentation and the Troubleshooting Guide

  • [X] I confirm I have checked existing issues, online documentation and Troubleshooting guide.

TheCrypt0 avatar Jan 08 '25 20:01 TheCrypt0

I confirm the problem with an ESP32-S2 board, using the OP source plus the following loop().

#include "tusb.h"  // for tud_suspended(), tud_remote_wakeup()

const int buttonPin = 0;         // input pin for pushbutton
int previousButtonState = HIGH;  // for checking the state of a pushButton
int counter = 0;                 // button push counter

void loop() {
  // read the pushbutton:
  int buttonState = digitalRead(buttonPin);
  // if the button state has changed, and it's currently pressed:
  if ((buttonState != previousButtonState) && (buttonState == LOW)) {
    if (tud_suspended()) {  // Ensure the PC is actually in sleep mode
      tud_remote_wakeup();  // TinyUSB wakeup function
      webSerial.println("Wakeup send.");
    } else
      webSerial.println("Not suspended.");

    // increment the button counter
    counter++;
    // type out a message
    webSerial.print("You pressed the button ");
    webSerial.print(counter);
    webSerial.println(" times.");
  }
  // save the current button state for comparison next time:
  previousButtonState = buttonState;
}

Since USB SUSPENDED, USB RESUMED are never received (the only events received are USB UNPLUGGED and USB PLUGGED), tud_suspended() is always false, but even if we ignore it and send tud_remote_wakeup() anyway, nothing happens.

Actual State	State received by ESP-S2
------------	------------------------
Sleep		USB UNPLUGGED
Resume		-- nothing!
Shut down	USB UNPLUGGED
Power on	USB PLUGGED(at bios logo), USB UNPLUGGED(while loading windows), USB PLUGGED(at windows login)

Tested on a Desktop with Windows 10, USB power is always ON (ESP32-S2 has power even when PC is shut down or during sleep) Arduino version v3.1.1

dat-master avatar Mar 02 '25 18:03 dat-master

@me-no-dev @SuGlider Is there anything we can do to help troubleshoot the issue? It seems @dat-master has confirmed the behaviour on the S2 as well.

TheCrypt0 avatar Mar 03 '25 08:03 TheCrypt0

Any updates on this? @SuGlider

Legendary-Wizard avatar Mar 21 '25 09:03 Legendary-Wizard

Hi all, sorry to bump this, but it’s been open for 4 months without any updates or feedback.

It would be really appreciated if someone from the team could take a moment to confirm whether this is on the radar, or if there’s anything we (or other contributors) can do to help investigate or work toward a fix.

Even a quick comment would go a long way in clarifying the current status. Thanks in advance for your time and for all the hard work on the project.

TheCrypt0 avatar Apr 16 '25 16:04 TheCrypt0

To anyone having the same problem, Wake up from sleep works with the Adafruit TinyUSB Library. I tested it with:

  • ESP32 core v3.1.1 and Adafruit TinyUSB Library v3.4.3
  • ESP32 core v3.2.0 and Adafruit TinyUSB Library v3.7.0 I attach pic of the S2 dongle I have (costs <10€ on ebay). It should definitely work with S3 and even P4 (if you don't need WiFi).

Image

dat-master avatar Jul 01 '25 13:07 dat-master

To anyone having the same problem, Wake up from sleep works with the Adafruit TinyUSB Library. I tested it with:

* ESP32 core v3.1.1 and Adafruit TinyUSB Library v3.4.3

* ESP32 core v3.2.0 and Adafruit TinyUSB Library v3.7.0
  I attach pic of the S2 dongle I have (costs <10€ on ebay).
  It should definitely work with S3 and even P4 (if you don't need WiFi).

Image

Can you explain how you managed to get it to compile with the Adafruit TinyUSB library, if I try to use it with the 3.2.x core on platformIO, i get a lot of multiple definition errors, the following also seems to suggest that the core's packaged TInyUSB takes precendence.

https://github.com/platformio/platform-espressif32/issues/1539

Brisk4t avatar Aug 17 '25 00:08 Brisk4t

It may be a PlatformIO problem. I use Arduino IDE 2.3.2 and compiles fine. I don't know why PlatformIO would use esp32-hal-tinyusb.h if you are only including Adafruit_TinyUSB.h I currently have core esp32 v3.3.0 and Adafruit TinyUSB Library v3.7.1 Use the hid_boot_keyboard example from Adafruit TinyUSB Library to test.

dat-master avatar Aug 18 '25 12:08 dat-master