Badger2040: Create badger_os utils module.

MichaelBell-battery-improvements
Phil Howard 2022-03-24 23:17:25 +00:00
rodzic 0ab44ef10a
commit 5bd13a5cd1
5 zmienionych plików z 146 dodań i 80 usunięć

Wyświetl plik

@ -0,0 +1,104 @@
"""Keep track of app state in persistent flash storage."""
import os
import gc
import machine
import badger2040
STATE_FILE = "appstate.txt"
def get_battery_level():
# Battery measurement
vbat_adc = machine.ADC(badger2040.PIN_BATTERY)
vref_adc = machine.ADC(badger2040.PIN_1V2_REF)
vref_en = machine.Pin(badger2040.PIN_VREF_POWER)
vref_en.init(machine.Pin.OUT)
vref_en.value(0)
# Enable the onboard voltage reference
vref_en.value(1)
# Calculate the logic supply voltage, as will be lower that the usual 3.3V when running off low batteries
vdd = 1.24 * (65535 / vref_adc.read_u16())
vbat = (
(vbat_adc.read_u16() / 65535) * 3 * vdd
) # 3 in this is a gain, not rounding of 3.3V
# Disable the onboard voltage reference
vref_en.value(0)
# Convert the voltage to a level to display onscreen
return vbat
def get_disk_usage():
# f_bfree and f_bavail should be the same?
# f_files, f_ffree, f_favail and f_flag are unsupported.
f_bsize, f_frsize, f_blocks, f_bfree, _, _, _, _, _, f_namemax = os.statvfs("/")
f_total_size = f_frsize * f_blocks
f_total_free = f_bsize * f_bfree
f_total_used = f_total_size - f_total_free
f_used = 100 / f_total_size * f_total_used
f_free = 100 / f_total_size * f_total_free
return f_total_size, f_used, f_free
def state_app():
try:
with open(STATE_FILE, "r") as f:
return f.readline().strip()
except OSError:
return None
def state_launch():
app = state_app()
if app is not None:
launch("_" + app)
def state_delete():
try:
os.remove(STATE_FILE)
except OSError:
pass
def state_save(title, *args):
with open(STATE_FILE, "w") as f:
f.write("{}\n".format(title))
for arg in args:
f.write("{}\n".format(arg))
def state_load(title, *defaults):
data = []
try:
with open(STATE_FILE, "r") as f:
if f.readline().strip() != title:
return defaults
for default in defaults:
t = type(default)
if t is bool:
data.append(f.readline().strip() == "True")
else:
data.append(t(f.readline().strip()))
return data
except OSError:
return defaults
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

Wyświetl plik

@ -3,6 +3,7 @@ import sys
import time import time
import badger2040 import badger2040
from badger2040 import WIDTH, HEIGHT from badger2040 import WIDTH, HEIGHT
import badger_os
REAMDE = """ REAMDE = """
@ -52,14 +53,6 @@ image = bytearray(int(296 * 128 / 8))
current_image = 0 current_image = 0
show_info = True show_info = True
try:
with open("appstate.txt", "r") as f:
f.readline()
current_image = int(f.readline().strip('\n'))
show_info = f.readline().strip('\n') == "True"
except OSError:
pass
# Draw an overlay box with a given message within it # Draw an overlay box with a given message within it
def draw_overlay(message, width, height, line_spacing, text_size): def draw_overlay(message, width, height, line_spacing, text_size):
@ -127,28 +120,37 @@ if TOTAL_IMAGES == 0:
display.update() display.update()
sys.exit() sys.exit()
if display.pressed_to_wake(badger2040.BUTTON_UP):
current_image, show_info = badger_os.state_load("image", 0, True)
changed = not display.woken()
while True:
if display.pressed(badger2040.BUTTON_UP):
if current_image > 0: if current_image > 0:
current_image -= 1 current_image -= 1
if display.pressed_to_wake(badger2040.BUTTON_DOWN): changed = True
if display.pressed(badger2040.BUTTON_DOWN):
if current_image < TOTAL_IMAGES - 1: if current_image < TOTAL_IMAGES - 1:
current_image += 1 current_image += 1
if display.pressed_to_wake(badger2040.BUTTON_A): changed = True
if display.pressed(badger2040.BUTTON_A):
show_info = not show_info show_info = not show_info
if display.pressed_to_wake(badger2040.BUTTON_B) or display.pressed_to_wake(badger2040.BUTTON_C): changed = True
if display.pressed(badger2040.BUTTON_B) or display.pressed(badger2040.BUTTON_C):
display.pen(15) display.pen(15)
display.clear() display.clear()
draw_overlay("To add images connect Badger2040 to a PC, load up Thonny, and see readme.txt in images/", WIDTH - OVERLAY_BORDER, HEIGHT - OVERLAY_BORDER, OVERLAY_SPACING, 0.5) draw_overlay("To add images connect Badger2040 to a PC, load up Thonny, and see readme.txt in images/", WIDTH - OVERLAY_BORDER, HEIGHT - OVERLAY_BORDER, OVERLAY_SPACING, 0.5)
display.update() display.update()
print(current_image)
time.sleep(4) time.sleep(4)
changed = True
if changed:
badger_os.state_save("image", current_image, show_info)
show_image(current_image) show_image(current_image)
changed = False
# Tell launcher to relaunch this app on wake and record state
with open("appstate.txt", "w") as f:
f.write("image\n")
f.write("{}\n{}\n".format(current_image, show_info))
# Halt the Badger to save power, it will wake up if any of the front buttons are pressed # Halt the Badger to save power, it will wake up if any of the front buttons are pressed
display.halt() display.halt()

Wyświetl plik

@ -1,11 +1,10 @@
import gc
import os
import time import time
import math import math
import machine import machine
import badger2040 import badger2040
from badger2040 import WIDTH from badger2040 import WIDTH
import launchericons import launchericons
import badger_os
# for e.g. 2xAAA batteries, try max 3.4 min 3.0 # for e.g. 2xAAA batteries, try max 3.4 min 3.0
MAX_BATTERY_VOLTAGE = 4.0 MAX_BATTERY_VOLTAGE = 4.0
@ -15,33 +14,18 @@ MIN_BATTERY_VOLTAGE = 3.2
machine.freq(48000000) 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 # Restore previously running app
try: try:
# Pressing A and C together at start quits app # 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): if badger2040.pressed_to_wake(badger2040.BUTTON_A) and badger2040.pressed_to_wake(badger2040.BUTTON_C):
os.remove("appstate.txt") badger_os.state_delete()
else: else:
with open("appstate.txt", "r") as f: badger_os.state_launch()
# Try to launch app
launch("_" + f.readline().strip('\n'))
except OSError: except OSError:
pass pass
except ImportError: except ImportError:
# Happens if appstate names an unknown app. Delete appstate and reset # Happens if appstate names an unknown app. Delete appstate and reset
import os badger_os.state_delete()
os.remove("appstate.txt")
machine.reset() machine.reset()
badger2040.clear_pressed_to_wake() badger2040.clear_pressed_to_wake()
@ -96,23 +80,6 @@ def map_value(input, in_min, in_max, out_min, out_max):
return (((input - in_min) * (out_max - out_min)) / (in_max - in_min)) + out_min return (((input - in_min) * (out_max - out_min)) / (in_max - in_min)) + out_min
def get_battery_level():
# Enable the onboard voltage reference
vref_en.value(1)
# Calculate the logic supply voltage, as will be lower that the usual 3.3V when running off low batteries
vdd = 1.24 * (65535 / vref_adc.read_u16())
vbat = (
(vbat_adc.read_u16() / 65535) * 3 * vdd
) # 3 in this is a gain, not rounding of 3.3V
# Disable the onboard voltage reference
vref_en.value(0)
# Convert the voltage to a level to display onscreen
return int(map_value(vbat, MIN_BATTERY_VOLTAGE, MAX_BATTERY_VOLTAGE, 0, 4))
def draw_battery(level, x, y): def draw_battery(level, x, y):
# Outline # Outline
display.thickness(1) display.thickness(1)
@ -138,17 +105,7 @@ def draw_battery(level, x, y):
def draw_disk_usage(x): def draw_disk_usage(x):
# f_bfree and f_bavail should be the same? _, f_used, _ = badger_os.get_disk_usage()
# f_files, f_ffree, f_favail and f_flag are unsupported.
f_bsize, f_frsize, f_blocks, f_bfree, _, _, _, _, _, f_namemax = os.statvfs(
"/")
f_total_size = f_frsize * f_blocks
f_total_free = f_bsize * f_bfree
f_total_used = f_total_size - f_total_free
f_used = 100 / f_total_size * f_total_used
# f_free = 100 / f_total_size * f_total_free
display.image( display.image(
bytearray( bytearray(
@ -207,7 +164,9 @@ def render():
display.rectangle(0, 0, WIDTH, 16) display.rectangle(0, 0, WIDTH, 16)
display.thickness(1) display.thickness(1)
draw_disk_usage(90) draw_disk_usage(90)
draw_battery(get_battery_level(), WIDTH - 22 - 3, 3) vbat = badger_os.get_battery_level()
bat = int(map_value(vbat, MIN_BATTERY_VOLTAGE, MAX_BATTERY_VOLTAGE, 0, 4))
draw_battery(bat, WIDTH - 22 - 3, 3)
display.pen(15) display.pen(15)
display.text("badgerOS", 3, 8, 0.4) display.text("badgerOS", 3, 8, 0.4)
@ -218,7 +177,7 @@ def launch_example(index):
while button_a.value() or button_b.value() or button_c.value() or button_up.value() or button_down.value(): while button_a.value() or button_b.value() or button_c.value() or button_up.value() or button_down.value():
time.sleep(0.01) time.sleep(0.01)
try: try:
launch(examples[(page * 3) + index][0]) badger_os.launch(examples[(page * 3) + index][0])
return True return True
except IndexError: except IndexError:
return False return False

Wyświetl plik

@ -52,3 +52,4 @@ copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/badge.py _badge)
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/help.py _help) copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/help.py _help)
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/info.py _info) copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/info.py _info)
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/qrgen.py _qrgen) copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/qrgen.py _qrgen)
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/badger_os.py badger_os)

Wyświetl plik

@ -7,7 +7,7 @@
namespace { namespace {
struct Badger2040_WakeUpInit { struct Badger2040_WakeUpInit {
Badger2040_WakeUpInit() Badger2040_WakeUpInit()
: state(gpio_get_all() & (0x1f << 11)) // Record state of all the front buttons : state(gpio_get_all() & (0x1f << pimoroni::Badger2040::DOWN)) // Record state of front buttons
{ {
gpio_set_function(pimoroni::Badger2040::ENABLE_3V3, GPIO_FUNC_SIO); gpio_set_function(pimoroni::Badger2040::ENABLE_3V3, GPIO_FUNC_SIO);
gpio_set_dir(pimoroni::Badger2040::ENABLE_3V3, GPIO_OUT); gpio_set_dir(pimoroni::Badger2040::ENABLE_3V3, GPIO_OUT);