Skip to content

alarm.light_sleep_until_alarms() returns None for PinAlarms when not plugged into PC #6476

@raymond-li

Description

@raymond-li

I'm having trouble getting light sleep working with PinAlarms on my MagTag. Any ideas or workarounds for using light sleep and getting the button state when not plugged into a PC?

Steps to reproduce:

  1. Copy code.py onto the MagTag (CircuitPython)
  2. Unplug the MagTag from the PC
  3. Re-boot the Magtag
  4. Press either of the two middle buttons (B or C) to exit deep sleep and enter the light sleep function
  5. Press any button (A, B, C, D) to wake up from the light sleep
  6. Observe that the alarm.wake_alarm is being set to None
    While that's probably sufficient for telling that a button was pressed, I'm not sure how to figure out which button was pressed.

What does work:

  • Skip step 2 above, leaving the MagTag connected to the PC
  • Using a busy waiting strategy instead. Replace the light_sleep_wait() call with busy_button_wait(magtag, active_mode_s) and move the button deinit() calls to just before the deep sleep call

Example code.py to reproduce the issue:

import alarm
import board
import time
from adafruit_magtag.magtag import MagTag

# This works when plugged in or not plugged in
# I'd prefer the light sleep way, however, instead of writing a busy loop.
def busy_button_wait(magtag, active_mode_s):
    start_time = time.monotonic()
    while time.monotonic() < (start_time + active_mode_s):
        # Refresh the timer at the start of each loop
        if magtag.peripherals.any_button_pressed:
            start_time = time.monotonic()
            if magtag.peripherals.button_a_pressed:
                button_name = "A"
            if magtag.peripherals.button_b_pressed:
                button_name = "B"
            if magtag.peripherals.button_c_pressed:
                button_name = "C"
            if magtag.peripherals.button_d_pressed:
                button_name = "D"
            magtag.set_text(f"button_name: {button_name}")
        time.sleep(.1)

# This only works when plugged into a PC
def light_sleep_wait(magtag, active_mode_s, pin_alarms):
    while True:
        light_timer_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + active_mode_s)

        # Exit the program, and then deep sleep until the alarm wakes us,
        # either from a button press or a timer.
        triggered_alarm = alarm.light_sleep_until_alarms(
            pin_alarms[0],
            pin_alarms[1],
            pin_alarms[2],
            pin_alarms[3],
            light_timer_alarm
        )
        if type(triggered_alarm) is alarm.time.TimeAlarm:
            # Leave interactive state because active_mode_s time has lapsed
            return
        elif (type(triggered_alarm) is alarm.pin.PinAlarm) or (triggered_alarm == None):
            # Inspect what triggered it:
            # magtag.set_text(triggered_alarm)
            # time.sleep(5)

            # When connected to PC and a button is pressed, light_sleep_until_alarms gives us back the PinAlarm
            button_name = ""
            if type(triggered_alarm) is alarm.pin.PinAlarm:
                if triggered_alarm.pin == board.BUTTON_A:
                    button_name += "A"
                if triggered_alarm.pin == board.BUTTON_B:
                    button_name += "B"
                if triggered_alarm.pin == board.BUTTON_C:
                    button_name += "C"
                if triggered_alarm.pin == board.BUTTON_D:
                    button_name += "D"
            # But when disconnected from a PC and a button is pressed, light_sleep_until_alarms gives us back None
            else:
                magtag.set_text(triggered_alarm)
                time.sleep(5)
                # My poor attempt at getting the button state anyways
                # magtag.peripherals.button_x_pressed can't be used because we deinitialized them earlier so this code crashes.
                if magtag.peripherals.button_a_pressed:
                    button_name += "A"
                if magtag.peripherals.button_b_pressed:
                    button_name += "B"
                if magtag.peripherals.button_c_pressed:
                    button_name += "C"
                if magtag.peripherals.button_d_pressed:
                    button_name += "D"
            magtag.set_text(f"button_name: {button_name}")

def wakeup_into_active(active_mode_s=15, deep_mode_s=30):
    # On a button press, we wakeup from deep sleep and go into an active waiting state for 15 seconds
    magtag = MagTag()
    magtag.add_text( text_scale=.1, text_wrap=50, text_maxlen=300, text_position=(10, 10), text_anchor_point=(0, 0))
    is_deep_button_wake = type(alarm.wake_alarm) is alarm.pin.PinAlarm
    is_deep_timer_wake = type(alarm.wake_alarm) is alarm.time.TimeAlarm

    magtag.peripherals.buttons[0].deinit()
    magtag.peripherals.buttons[1].deinit()
    magtag.peripherals.buttons[2].deinit()
    magtag.peripherals.buttons[3].deinit()
    pin_alarm_A = alarm.pin.PinAlarm(pin=board.BUTTON_A, value=False, pull=True)
    pin_alarm_B = alarm.pin.PinAlarm(pin=board.BUTTON_B, value=False, pull=True)
    pin_alarm_C = alarm.pin.PinAlarm(pin=board.BUTTON_C, value=False, pull=True)
    pin_alarm_D = alarm.pin.PinAlarm(pin=board.BUTTON_D, value=False, pull=True)

    # If button, go into interactive state
    # Else if timer, do any non-interactive updates
    if is_deep_button_wake:
        magtag.set_text(f"Entering interactive mode for {active_mode_s} seconds")
        # busy_button_wait(magtag, active_mode_s) # Works
        light_sleep_wait(magtag, active_mode_s, [pin_alarm_A, pin_alarm_B, pin_alarm_C, pin_alarm_D]) # Only works when plugged into a PC
    elif is_deep_timer_wake:
        magtag.set_text(f"Performing non-interactive updates")
    else:
        magtag.set_text(f"First time around")

    deep_timer_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + deep_mode_s)
    # Only two PinAlarms can be used for deep sleep at a time
    alarm.exit_and_deep_sleep_until_alarms(
        pin_alarm_B,
        pin_alarm_C,
        deep_timer_alarm
    )

# Main
wakeup_into_active()

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions