Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial alarm and sleep PR: time alarms with light and deep sleep; PinAlarms not yet implemented #3767

Merged
merged 41 commits into from
Dec 2, 2020

Conversation

dhalbert
Copy link
Collaborator

@dhalbert dhalbert commented Nov 27, 2020

Initial working version of light sleep and deep sleep, after several API iterations. Started coding from https://github.com/tannewt/circuitpython/tree/sleepio/ .

  • alarm.time.TimeAlarm implemented for both monotonic time and epoch time values.
  • alarm.pin.PinAlarm objects can be created, but cannot yet be used to sleep. (So not yet completely implemented.)
  • Three ways to wait for alarms:
    1. alarm.wait_until_alarms(alarm1, ...): Wait for alarms without sleeping. Does not disturb WiFi or USB connections.
    2. alarm.sleep_until_alarms(): Do a light sleep while waiting. esp-idf requires that wifi be disabled while sleeping.
    3. alarm.exit_and_deep_sleep_until_alarms(): Do a deep sleep. Restart when an alarm triggers.

For both sleep modes (ii and iii), if the board is connected to USB, then CircuitPython does not really sleep, but instead just does .wait_for_alarms(). For deep sleep (iii), it will of course restart the program after waiting. Not going to sleep allows you to change or interrupt a sleeping program while debugging it. Otherwise you can get trapped in a sleep loop without being able to modify the program.

Other changes:

  • Renamed some routines common_hal to make their purpose or arguments clearer.
  • Did some cleanup on main.c
  • Added microcontroller.ResetReason enum and microcontroller.cpu.reset_reason.
  • Added supervisor.RunReason enum and supervisor.runtime.run_reason.
  • Made sure QSTR processing handled files containing only enum macros.
  • Moved frozen requests library commit up to tag commit.

Left to do in future PR's:

  • PinAlarm
  • support for other ports
  • optional but seems good: when not connected to host, sleep when program exits normally or by exception. Display a message to indicate board has gone to sleep. This will save battery if there's an uncaught exception, etc.

@tannewt tannewt added this to the 6.1.0 milestone Nov 30, 2020
Copy link
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

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

Overall this is looking good! A few comments and suggestions but nothing earth shattering.

Why is the requests library being updated?

ports/atmel-samd/common-hal/microcontroller/Processor.c Outdated Show resolved Hide resolved
ports/esp32s2/common-hal/alarm/__init__.c Outdated Show resolved Hide resolved
ports/esp32s2/common-hal/alarm/__init__.c Show resolved Hide resolved
shared-bindings/alarm/__init__.c Outdated Show resolved Hide resolved
shared-bindings/alarm/__init__.c Outdated Show resolved Hide resolved
shared-bindings/alarm/__init__.c Show resolved Hide resolved
shared-bindings/alarm/__init__.c Outdated Show resolved Hide resolved
shared-bindings/alarm/pin/PinAlarm.c Outdated Show resolved Hide resolved
@dhalbert
Copy link
Collaborator Author

dhalbert commented Dec 1, 2020

Why is the requests library being updated?

The requests library was updated in an upstream merge, but it appeared to me that the commit used was not the merge commit to the library, but the PR commit, which made it not be on the master branch for the library. This updates it to the PR commit, which is also tagged with 1.9.0.

@microdev1
Copy link
Collaborator

Thanks for the continued work on deep sleep api. 👍

I will start running tests on my microS2... will be monitoring the deep sleep current as well... I think we will have the least current consumption in timer alarms as every other type of alarm requires more RTC peripherals to be on.

Looking forward to adding Touch and ULP based alarms as well... :)

@dhalbert dhalbert requested a review from tannewt December 2, 2020 01:04
@dhalbert
Copy link
Collaborator Author

dhalbert commented Dec 2, 2020

8b7c23c
Dropped wait_until_alarms() and now have two calls:

  • light_sleep_until_alarms()
  • exit_and_deep_sleep_until_alarms()

The first will light-sleep to the extent possible, but will not shut down wifi, etc. In other words you can start up from where you left off. The addition of light is meant to differentiate from deep. Documentation updated to address this semantics change.

I tested both of these both connected to USB and not, and saw that they were sleeping (or not) appropriately, based on current consumption and on ESP_LOGI() prints.

Internal exception DeepSleepRequest is now used to pass back the deep sleep request to main.c.

Copy link
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

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

Overall the API looks really good! Just one code move to do.

shared-bindings/alarm/__init__.c Show resolved Hide resolved
@dhalbert
Copy link
Collaborator Author

dhalbert commented Dec 2, 2020

I discussed more implementation details for simulated deep sleep with @tannewt. We decided to roll back the last 72fa7d8 commi. We can merge the current implementation as is. The API is in good shape and can be presented in a beta.

@tannewt will finish some refactoring and additional implementation to make simulated deep sleep more like real deep sleep, in that it will not start sleeping until after exiting the current VM. This assures that whatever stops when the VM is exited is really stopped, and whatever status messages or other workflow handling is done in real deep sleep is also done on simulated deep sleep.

Copy link
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

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

Looks good! Thank you!

@tannewt tannewt merged commit d7ba641 into adafruit:main Dec 2, 2020
@dhalbert
Copy link
Collaborator Author

dhalbert commented Dec 3, 2020

Sample deep sleep program:

import alarm
import time
from adafruit_magtag.magtag import MagTag
from adafruit_requests import OutOfRetries

# Set up where we'll be fetching data from
DATA_SOURCE = "https://www.adafruit.com/api/quotes.php"
QUOTE_LOCATION = [0, 'text']
AUTHOR_LOCATION = [0, 'author']

magtag = MagTag(
    url=DATA_SOURCE,
    json_path=(QUOTE_LOCATION, AUTHOR_LOCATION),
)
magtag.network.connect()

# quote in bold text, with text wrapping
magtag.add_text(
    text_font="Arial-Bold-12.bdf",
    text_wrap=33,
    text_maxlen=160,
    text_position=(10, 10),
    text_anchor_point=(0,0),
    line_spacing=0.75,
)

# author in italic text, no wrapping
magtag.add_text(
    text_font="Arial-Italic-12.bdf",
    text_position=(100, 110),
)

try:
    value = magtag.fetch()
    print("Response is", value)
except (ValueError, RuntimeError, OutOfRetries) as e:
    print("Some error occured, retrying! -", e)

# Refresh display before sleeping.
magtag.refresh()

# Exit program and restart in 20 seconds.
pause = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + 20)
alarm.exit_and_deep_sleep_until_alarms(pause)

@ladyada
Copy link
Member

ladyada commented Dec 3, 2020

@dhalbert does it sleep for 60 seconds or 20?

@dhalbert
Copy link
Collaborator Author

dhalbert commented Dec 3, 2020

It sleeps for 20; I just forgot to change the comment. Will fix.

@dhalbert dhalbert deleted the sleep branch December 3, 2020 05:22
@dhalbert
Copy link
Collaborator Author

dhalbert commented Dec 3, 2020

I sped it up for testing purposes.

@d-c-d
Copy link

d-c-d commented Dec 4, 2020

Where is "Arial-Bold-12.bdf" and "Arial-Italic-12.bdf"
( not in adafruit-circuitpython-bundle-6.x-mpy-20201203.zip )

Found in the learning guides - thanks to hints in #discord

@kevinjwalters
Copy link

kevinjwalters commented Jan 13, 2021

Is the monotonic_time argument for TimeAlarm going to suffer from the same (30bit) fp resolution issues as time.monotonic() does?

Would something like relative_time (or a better name) be a better solution for most users (i.e. pause = alarm.time.TimeAlarm(relative_time=20) and leave the library to deal with maintaining decent precision?

@dhalbert
Copy link
Collaborator Author

@kevinjwalters Could you open a new issue for this discussion? Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants