Skip to content

fix: short-press power button to wakeup#482

Merged
daveallie merged 6 commits intocrosspoint-reader:masterfrom
ngxson:xsn/no_delay_pwr
Jan 27, 2026
Merged

fix: short-press power button to wakeup#482
daveallie merged 6 commits intocrosspoint-reader:masterfrom
ngxson:xsn/no_delay_pwr

Conversation

@ngxson
Copy link
Contributor

@ngxson ngxson commented Jan 22, 2026

Summary

Fix #288

Based on my observation, it seems like the problem was that inputManager.isPressed(InputManager::BTN_POWER) takes a bit of time after waking up to report the correct value. I haven't tested this behavior with a standalone ESP32C3, but if you know more about this, feel free to comment.

However, if we just want short press, I think it's enough to check for wake up source. If we plan to allow multiple buttons to wake up in the future, may consider using ext1 / esp_sleep_get_ext1_wakeup_status() to allow identify which pin triggered wake up.

Note that I'm not particularly experienced in esp32 developments, just happen to have prior knowledge hacking esphome.

Additional Context

N/A


AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? NO

@olearycrew
Copy link
Contributor

@ngxson this looks pretty good - thanks for it!

I'd love if we don't define the "10" in two places - mabe we could

Add a static constant in the CrossPointSettings class near the SHORT_PWRBTN enum

Something like:

enum SHORT_PWRBTN { IGNORE = 0, SLEEP = 1, PAGE_TURN = 2 };
static constexpr uint16_t SHORT_PRESS_DURATION_MS = 10;
static constexpr uint16_t LONG_PRESS_DURATION_MS = 400;

Then update both locations:

  • CrossPointSettings.h line 104 return (shortPwrBtn == SHORT_PWRBTN::SLEEP) ? SHORT_PRESS_DURATION_MS : LONG_PRESS_DURATION_MS;
  • main.cpp line 157 if (SETTINGS.getPowerButtonDuration() <= CrossPointSettings::SHORT_PRESS_DURATION_MS)

What are your thoughts there?

Copy link
Contributor

@olearycrew olearycrew left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my other comment above

@ngxson
Copy link
Contributor Author

ngxson commented Jan 22, 2026

Yes that sounds good, thanks! I applied your suggestions in the last commit

@osteotek
Copy link
Member

In my experience, esp_reset_reason() and esp_sleep_get_wakeup_cause() return different results based on whether the device is connected via USB or not. Has this not been an issue for you?

@ngxson
Copy link
Contributor Author

ngxson commented Jan 22, 2026

@osteotek I cannot find a way to test it without USB cable connected, but what I found was:

  • Upon connected to USB, I get ESP_SLEEP_WAKEUP_UNDEFINED and ESP_RST_POWERON that triggers wake up
  • When USB stays connected, I got ESP_SLEEP_WAKEUP_GPIO and ESP_RST_UNKNOWN as expected

Waking up when USB is connected is a side effect of this PR. We can optionally check isUsbConnected() to avoid this. But in terms of UX, I think it make more sense to wake up when usb is connected. WDYT?

Just realized that isWakeupAfterFlashing() is now left unused. I'm not sure if we still want to keep it around.


inputManager.update();
// Verify the user has actually pressed
// Needed because inputManager.isPressed() may take up to ~500ms to return the correct state
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Eloren1 as explained here, it seems like inputManager.isPressed() take a bit of time to report the correct value. Due to this, I'm a bit doubt if this logic can reliably tell if power button held for 400ms or 600ms. Not sure if you have the same problem on your side?

Re. removal of the constexpr, I think I can simply check shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::SLEEP

Copy link
Contributor

@Eloren1 Eloren1 Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I left 400-600ms variants almost untested because the difference should be barely noticeable. Maybe I keep just one of them like 500ms? I mainly used 1000ms and it worked without problems.

@osteotek
Copy link
Member

osteotek commented Jan 22, 2026

@osteotek I cannot find a way to test it without USB cable connected, but what I found was:

  • Upon connected to USB, I get ESP_SLEEP_WAKEUP_UNDEFINED and ESP_RST_POWERON that triggers wake up
  • When USB stays connected, I got ESP_SLEEP_WAKEUP_GPIO and ESP_RST_UNKNOWN as expected

Waking up when USB is connected is a side effect of this PR. We can optionally check isUsbConnected() to avoid this. But in terms of UX, I think it make more sense to wake up when usb is connected. WDYT?

Just realized that isWakeupAfterFlashing() is now left unused. I'm not sure if we still want to keep it around.

We probably shouldn't wakeup after connecting to usb. That's not how ereaders work in general.

I output to screen. My testing results:

device wakes up from power button:

  • usb is not connected: wakeup cause - ESP_SLEEP_WAKEUP_UNDEFINED, reset reason - ESP_RST_POWERON
  • usb is connected: wakeup cause - ESP_SLEEP_WAKEUP_GPIO, reset reason - ESP_RST_DEEPSLEEP

This is likely explained by the fact that the device disconnects the battery when it enters deep sleep mode (when it is not connected via USB).

Also when device wakes up after flashing firmware (hard reset via RTS pin) and usb is connected:

  • wakeup cause ESP_SLEEP_WAKEUP_UNDEFINED, reset reason - ESP_RST_UNKNOWN

@osteotek
Copy link
Member

osteotek commented Jan 22, 2026

@ngxson based on my findings above I propose following logic for determining if device woke up from power button:

bool isWakeupByPowerButton() {
  const auto wakeupCause = esp_sleep_get_wakeup_cause();
  const auto resetReason = esp_reset_reason()
  if (isUsbConnected()) {
    return wakeupCause == ESP_SLEEP_WAKEUP_GPIO;
  } else {
    return (wakeupCause == ESP_SLEEP_WAKEUP_UNDEFINED) && (resetReason == ESP_RST_POWERON)
  }
}

I haven't tested it though. Need to be careful testing this, I managed to softbrick my device once working on this part before, device was going to deepsleep immediately after waking up without checking any logic 🙂 probably some kind of safe guard would be nice

@ngxson
Copy link
Contributor Author

ngxson commented Jan 22, 2026

Thanks, that works!

I haven't tested it though. Need to be careful testing this, I managed to softbrick my device once working on this part before, device was going to deepsleep immediately after waking up without checking any logic 🙂 probably some kind of safe guard would be nice

It seems to me that the current check guard can be SdMan.begin(), simply removing SD card will skip the isWakeupByPowerButton / verifyPowerButtonDuration

Probably should write a small comment so that this use case is visible in the code.

@osteotek
Copy link
Member

osteotek commented Jan 22, 2026

It seems to me that the current check guard can be SdMan.begin(), simply removing SD card will skip the isWakeupByPowerButton / verifyPowerButtonDuration

@ngxson It will work for now. But I actually tried implement checking power button duration before SD init, to avoid constant io work on every button press using RTC Attributes, but it didn't work, likely because of the aforementioned issue with battery disconnect on entering deepsleep
#447

@ngxson
Copy link
Contributor Author

ngxson commented Jan 22, 2026

It will work for now. But I actually tried implement checking power button duration before SD init, to avoid constant io work on every button press using RTC Attributes, but it didn't work, likely because of the aforementioned issue with battery disconnect on entering deepsleep

Interestingly, I gave it a try on my side for a different reason (was wondering if I can improve the boot speed). But I decided it's not worth the effort as the action taking the most boot time was display initialization.

Just out of curiosity, is there circuit diagram available? I was a little bit regretful buying this device because for some reasons they decided to cramp multiple buttons into an analog GPIO, which make light sleep impossible 😂 Before buying it, I though one button == one GPIO (or maybe 3 digital GPIO, which make it 2^3-1 button combination)

@ngxson
Copy link
Contributor Author

ngxson commented Jan 22, 2026

Another idea for the safe guard path, does it make sense if we enter a "debug mode / safe mode" if the down button is held on wakeup? Kinda like holding vol down for download mode on android

(I can add it in a follow-up PR)

@DaniPhii
Copy link
Contributor

Hi team, I have no idea whether the following idea would be possible and/or safe, but I was reading this thread, and this made me think about the possibility of dual booting between the original firmware and CrossPoint with a key combination, for those who want to use both firmwares. This would allow to jump between them without connecting the device to a PC in order to change the active app partition.

@ngxson
Copy link
Contributor Author

ngxson commented Jan 23, 2026

@DaniPhii I don't think it would be possible (or possible but requires hacking bootloader, which is hard to do)

Implementing on custom fw can allow switching custom -> stock but not the way around, because the stock fw doesn't know how to handle the key combination

@ngxson ngxson requested a review from olearycrew January 23, 2026 12:42
osteotek
osteotek previously approved these changes Jan 23, 2026
@osteotek
Copy link
Member

osteotek commented Jan 23, 2026

@ngxson I've just tested this with and without short power button setting, works nicely.

@daveallie this PR fixes #288

src/main.cpp Outdated
Comment on lines 292 to 297
@@ -288,6 +296,16 @@ bool isWakeupAfterFlashing() {
return isUsbConnected() && (wakeupCause == ESP_SLEEP_WAKEUP_UNDEFINED) && (resetReason == ESP_RST_UNKNOWN);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, this can be removed now as it's no longer used.

@daveallie daveallie merged commit 1b9c8ab into crosspoint-reader:master Jan 27, 2026
1 check passed
@osteotek
Copy link
Member

osteotek commented Jan 27, 2026

now device wakes up from USB connect because it sends exactly same signal as wakeup from power button 😭 Trying to fix that (if CrossPointSettings::SHORT_PWRBTN set to SLEEP)

Comment on lines +336 to 340
if (isWakeupByPowerButton()) {
// For normal wakeups, verify power button press duration
Serial.printf("[%lu] [ ] Verifying power button press duration\n", millis());
verifyPowerButtonDuration();
}
Copy link
Contributor Author

@ngxson ngxson Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@osteotek hmm right, I just realized the logic fault here: if the wakeup is not caused by button press, we skip and nothing is checked

here we just need to add the else branch:

  } else {
    // Case: when USB is connected, do not wake up automatically
   startDeepSleep();
  }

I'll push a fix for that

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, we also need to wake up after flash completed

Jessica765 pushed a commit to Jessica765/crosspoint-reader that referenced this pull request Feb 3, 2026
## Summary

Fix crosspoint-reader#288

Based on my observation, it seems like the problem was that
`inputManager.isPressed(InputManager::BTN_POWER)` takes a bit of time
after waking up to report the correct value. I haven't tested this
behavior with a standalone ESP32C3, but if you know more about this,
feel free to comment.

However, if we just want short press, I think it's enough to check for
wake up source. If we plan to allow multiple buttons to wake up in the
future, may consider using ext1 / `esp_sleep_get_ext1_wakeup_status()`
to allow identify which pin triggered wake up.

Note that I'm not particularly experienced in esp32 developments, just
happen to have prior knowledge hacking esphome.

## Additional Context

N/A

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? NO

---------

Co-authored-by: Dave Allie <[email protected]>
Unintendedsideeffects pushed a commit to Unintendedsideeffects/crosspoint-reader that referenced this pull request Feb 17, 2026
## Summary

Fix crosspoint-reader#288

Based on my observation, it seems like the problem was that
`inputManager.isPressed(InputManager::BTN_POWER)` takes a bit of time
after waking up to report the correct value. I haven't tested this
behavior with a standalone ESP32C3, but if you know more about this,
feel free to comment.

However, if we just want short press, I think it's enough to check for
wake up source. If we plan to allow multiple buttons to wake up in the
future, may consider using ext1 / `esp_sleep_get_ext1_wakeup_status()`
to allow identify which pin triggered wake up.

Note that I'm not particularly experienced in esp32 developments, just
happen to have prior knowledge hacking esphome.

## Additional Context

N/A

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? NO

---------

Co-authored-by: Dave Allie <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fast wake up option not working?

6 participants