From 51b0e472e13a5cfe9b10fbdc53701b3a9e67dd5c Mon Sep 17 00:00:00 2001 From: Mike Bell Date: Wed, 23 Mar 2022 00:12:10 +0000 Subject: [PATCH] Add ability to halt the Badger from Micropython and get wake button presses. Change badge app to halt when image displayed --- micropython/examples/badger2040/badge.py | 75 ++++++------------- micropython/examples/badger2040/launcher.py | 49 ++++++++---- micropython/modules/badger2040/badger2040.c | 14 +++- micropython/modules/badger2040/badger2040.cpp | 31 +++++++- micropython/modules/badger2040/badger2040.h | 7 +- 5 files changed, 106 insertions(+), 70 deletions(-) diff --git a/micropython/examples/badger2040/badge.py b/micropython/examples/badger2040/badge.py index fdeae159..5f930fe9 100644 --- a/micropython/examples/badger2040/badge.py +++ b/micropython/examples/badger2040/badge.py @@ -205,63 +205,34 @@ detail2_title = truncatestring(detail2_title, DETAILS_TEXT_SIZE, TEXT_WIDTH) detail2_text = truncatestring(detail2_text, DETAILS_TEXT_SIZE, TEXT_WIDTH - DETAIL_SPACING - display.measure_text(detail2_title, DETAILS_TEXT_SIZE)) -# Set up the buttons -button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_b = machine.Pin(badger2040.BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_up = machine.Pin(badger2040.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_down = machine.Pin(badger2040.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN) - - -# Button handling function -def button(pin): - global show_overlay - - if pin == button_a: - show_overlay = True - return - - if pin == button_b: - show_overlay = True - return - - if pin == button_c: - show_overlay = True - return - - if pin == button_up: - show_overlay = True - return - - if pin == button_down: - show_overlay = True - return - - -# Register the button handling function with the buttons -button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button) -button_b.irq(trigger=machine.Pin.IRQ_RISING, handler=button) -button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=button) -button_up.irq(trigger=machine.Pin.IRQ_RISING, handler=button) -button_down.irq(trigger=machine.Pin.IRQ_RISING, handler=button) - +# Show overlay if any of the buttons were pressed to wake up the Badger +if (badger2040.pressed_to_wake(badger2040.BUTTON_A) or + badger2040.pressed_to_wake(badger2040.BUTTON_B) or + badger2040.pressed_to_wake(badger2040.BUTTON_C) or + badger2040.pressed_to_wake(badger2040.BUTTON_UP) or + badger2040.pressed_to_wake(badger2040.BUTTON_DOWN)): + show_overlay = True # ------------------------------ -# Main program loop +# Main program # ------------------------------ draw_badge() -display.update() -while True: - if show_overlay: - draw_overlay("To change the text, connect Badger2040 to a PC, load up Thonny, and modify badge.txt", - WIDTH - OVERLAY_BORDER, HEIGHT - OVERLAY_BORDER, OVERLAY_SPACING, OVERLAY_TEXT_SIZE) - display.update() - time.sleep(4) +if show_overlay: + draw_overlay("To change the text, connect Badger2040 to a PC, load up Thonny, and modify badge.txt", + WIDTH - OVERLAY_BORDER, HEIGHT - OVERLAY_BORDER, OVERLAY_SPACING, OVERLAY_TEXT_SIZE) + display.update() + time.sleep(4) - draw_badge() - display.update() - show_overlay = False + draw_badge() + display.update() +else: + display.update() - time.sleep(0.1) +# Tell launcher to relaunch this app on wake +with open("appstate.txt", "w") as f: + f.write("badge\n") + +# Halt the Badger to save power, it will wake up if any of the front buttons are pressed +display.halt() diff --git a/micropython/examples/badger2040/launcher.py b/micropython/examples/badger2040/launcher.py index 0f0c1082..f27098c8 100644 --- a/micropython/examples/badger2040/launcher.py +++ b/micropython/examples/badger2040/launcher.py @@ -11,6 +11,39 @@ import launchericons MAX_BATTERY_VOLTAGE = 4.0 MIN_BATTERY_VOLTAGE = 3.2 +# Reduce clock speed to 48MHz, that's fast enough! +machine.freq(48000000) + +def launch(file): + for k in locals().keys(): + if k not in ("gc", "file", "machine"): + del locals()[k] + gc.collect() + try: + __import__(file[1:]) # Try to import _[file] (drop underscore prefix) + except ImportError: + __import__(file) # Failover to importing [_file] + machine.reset() # Exit back to launcher + +# Restore previously running app +try: + # Pressing A and C together at start quits app + if badger2040.pressed_to_wake(badger2040.BUTTON_A) and badger2040.pressed_to_wake(badger2040.BUTTON_C): + os.remove("appstate.txt") + else: + with open("appstate.txt", "r") as f: + # Try to launch app + launch("_" + f.readline().strip('\n')) +except OSError: + pass +except ImportError: + # Happens if appstate names an unknown app. Delete appstate and reset + import os + os.remove("appstate.txt") + machine.reset() + +badger2040.clear_pressed_to_wake() + page = 0 font_size = 1 @@ -179,19 +212,9 @@ def render(): display.update() -def launch(file): - for k in locals().keys(): - if k not in ("gc", "file", "machine"): - del locals()[k] - gc.collect() - try: - __import__(file[1:]) # Try to import _[file] (drop underscore prefix) - except ImportError: - __import__(file) # Failover to importing [_file] - machine.reset() # Exit back to launcher - - def launch_example(index): + while button_a.value() or button_b.value() or button_c.value() or button_up.value() or button_down.value(): + time.sleep(0.01) try: launch(examples[(page * 3) + index][0]) return True @@ -241,7 +264,7 @@ display.update_speed(badger2040.UPDATE_FAST) # Wait for wakeup button to be released while button_a.value() or button_b.value() or button_c.value() or button_up.value() or button_down.value(): - pass + time.sleep(0.01) while True: diff --git a/micropython/modules/badger2040/badger2040.c b/micropython/modules/badger2040/badger2040.c index 3a09276a..0693f88d 100644 --- a/micropython/modules/badger2040/badger2040.c +++ b/micropython/modules/badger2040/badger2040.c @@ -9,6 +9,8 @@ MP_DEFINE_CONST_FUN_OBJ_1(Badger2040_is_busy_obj, Badger2040_is_busy); MP_DEFINE_CONST_FUN_OBJ_1(Badger2040_update_obj, Badger2040_update); MP_DEFINE_CONST_FUN_OBJ_KW(Badger2040_partial_update_obj, 4, Badger2040_partial_update); +MP_DEFINE_CONST_FUN_OBJ_1(Badger2040_halt_obj, Badger2040_halt); + MP_DEFINE_CONST_FUN_OBJ_2(Badger2040_invert_obj, Badger2040_invert); MP_DEFINE_CONST_FUN_OBJ_2(Badger2040_led_obj, Badger2040_led); MP_DEFINE_CONST_FUN_OBJ_2(Badger2040_font_obj, Badger2040_font); @@ -32,6 +34,9 @@ MP_DEFINE_CONST_FUN_OBJ_KW(Badger2040_measure_glyph_obj, 2, Badger2040_measure_g MP_DEFINE_CONST_FUN_OBJ_3(Badger2040_command_obj, Badger2040_command); +MP_DEFINE_CONST_FUN_OBJ_1(Badger2040_pressed_to_wake_obj, Badger2040_pressed_to_wake); +MP_DEFINE_CONST_FUN_OBJ_0(Badger2040_clear_pressed_to_wake_obj, Badger2040_clear_pressed_to_wake); + /***** Binding of Methods *****/ STATIC const mp_rom_map_elem_t Badger2040_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&Badger2040___del___obj) }, @@ -40,6 +45,8 @@ STATIC const mp_rom_map_elem_t Badger2040_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&Badger2040_update_obj) }, { MP_ROM_QSTR(MP_QSTR_partial_update), MP_ROM_PTR(&Badger2040_partial_update_obj) }, + { MP_ROM_QSTR(MP_QSTR_halt), MP_ROM_PTR(&Badger2040_halt_obj) }, + { MP_ROM_QSTR(MP_QSTR_invert), MP_ROM_PTR(&Badger2040_invert_obj) }, { MP_ROM_QSTR(MP_QSTR_led), MP_ROM_PTR(&Badger2040_led_obj) }, { MP_ROM_QSTR(MP_QSTR_font), MP_ROM_PTR(&Badger2040_font_obj) }, @@ -78,10 +85,13 @@ const mp_obj_type_t Badger2040_type = { /***** Globals Table *****/ -STATIC const mp_map_elem_t badger2040_globals_table[] = { +STATIC const mp_rom_map_elem_t badger2040_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_badger2040) }, { MP_OBJ_NEW_QSTR(MP_QSTR_Badger2040), (mp_obj_t)&Badger2040_type }, + { MP_ROM_QSTR(MP_QSTR_pressed_to_wake), MP_ROM_PTR(&Badger2040_pressed_to_wake_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear_pressed_to_wake), MP_ROM_PTR(&Badger2040_clear_pressed_to_wake_obj) }, + { MP_ROM_QSTR(MP_QSTR_UPDATE_NORMAL), MP_ROM_INT(0) }, { MP_ROM_QSTR(MP_QSTR_UPDATE_MEDIUM), MP_ROM_INT(1) }, { MP_ROM_QSTR(MP_QSTR_UPDATE_FAST), MP_ROM_INT(2) }, @@ -121,4 +131,4 @@ const mp_obj_module_t badger2040_user_cmodule = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_badger2040_globals, }; -MP_REGISTER_MODULE(MP_QSTR_badger2040, badger2040_user_cmodule, MODULE_BADGER2040_ENABLED); \ No newline at end of file +MP_REGISTER_MODULE(MP_QSTR_badger2040, badger2040_user_cmodule, MODULE_BADGER2040_ENABLED); diff --git a/micropython/modules/badger2040/badger2040.cpp b/micropython/modules/badger2040/badger2040.cpp index 657b0400..79e9232e 100644 --- a/micropython/modules/badger2040/badger2040.cpp +++ b/micropython/modules/badger2040/badger2040.cpp @@ -3,6 +3,19 @@ #define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o)) +namespace { + struct Badger2040_ButtonStateOnWake { + Badger2040_ButtonStateOnWake() + : state(gpio_get_all()) + {} + + uint32_t get() const { return state; } + void clear() { state = 0; } + + private: + uint32_t state; + } button_wake_state __attribute__ ((init_priority (101))); +}; extern "C" { #include "badger2040.h" @@ -170,7 +183,11 @@ MICROPY_EVENT_POLL_HOOK return mp_const_none; } -// halt +mp_obj_t Badger2040_halt(mp_obj_t self_in) { + _Badger2040_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Badger2040_obj_t); + self->badger2040->halt(); + return mp_const_none; +} // sleep mp_obj_t Badger2040_invert(mp_obj_t self_in, mp_obj_t invert) { @@ -210,6 +227,16 @@ mp_obj_t Badger2040_pressed(mp_obj_t self_in, mp_obj_t button) { return state ? mp_const_true : mp_const_false; } +mp_obj_t Badger2040_pressed_to_wake(mp_obj_t button) { + bool state = (button_wake_state.get() >> mp_obj_get_int(button)) & 1; + return state ? mp_const_true : mp_const_false; +} + +mp_obj_t Badger2040_clear_pressed_to_wake() { + button_wake_state.clear(); + return mp_const_none; +} + // pressed // pressed_to_wake // wait_for_press - implement in terms of MicroPython! @@ -467,4 +494,4 @@ mp_obj_t Badger2040_measure_glyph(size_t n_args, const mp_obj_t *pos_args, mp_ma return mp_obj_new_int(self->badger2040->measure_glyph(c, scale)); } -} \ No newline at end of file +} diff --git a/micropython/modules/badger2040/badger2040.h b/micropython/modules/badger2040/badger2040.h index b60a3154..62c55f75 100644 --- a/micropython/modules/badger2040/badger2040.h +++ b/micropython/modules/badger2040/badger2040.h @@ -15,6 +15,8 @@ extern mp_obj_t Badger2040_update_speed(mp_obj_t self_in, mp_obj_t speed); extern mp_obj_t Badger2040_update(mp_obj_t self_in); extern mp_obj_t Badger2040_partial_update(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t Badger2040_halt(mp_obj_t self_in); + extern mp_obj_t Badger2040_invert(mp_obj_t self_in, mp_obj_t invert); extern mp_obj_t Badger2040_led(mp_obj_t self_in, mp_obj_t brightness); extern mp_obj_t Badger2040_font(mp_obj_t self_in, mp_obj_t font); @@ -37,4 +39,7 @@ extern mp_obj_t Badger2040_glyph(size_t n_args, const mp_obj_t *pos_args, mp_map extern mp_obj_t Badger2040_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t Badger2040_measure_glyph(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t Badger2040_command(mp_obj_t self_in, mp_obj_t reg, mp_obj_t data); \ No newline at end of file +extern mp_obj_t Badger2040_command(mp_obj_t self_in, mp_obj_t reg, mp_obj_t data); + +extern mp_obj_t Badger2040_pressed_to_wake(mp_obj_t button); +extern mp_obj_t Badger2040_clear_pressed_to_wake();