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 badger2040
from badger2040 import WIDTH, HEIGHT
import badger_os
REAMDE = """
@ -52,14 +53,6 @@ image = bytearray(int(296 * 128 / 8))
current_image = 0
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
def draw_overlay(message, width, height, line_spacing, text_size):
@ -127,28 +120,37 @@ if TOTAL_IMAGES == 0:
display.update()
sys.exit()
if display.pressed_to_wake(badger2040.BUTTON_UP):
if current_image > 0:
current_image -= 1
if display.pressed_to_wake(badger2040.BUTTON_DOWN):
if current_image < TOTAL_IMAGES - 1:
current_image += 1
if display.pressed_to_wake(badger2040.BUTTON_A):
show_info = not show_info
if display.pressed_to_wake(badger2040.BUTTON_B) or display.pressed_to_wake(badger2040.BUTTON_C):
display.pen(15)
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)
display.update()
time.sleep(4)
show_image(current_image)
current_image, show_info = badger_os.state_load("image", 0, True)
changed = not display.woken()
# 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))
while True:
if display.pressed(badger2040.BUTTON_UP):
if current_image > 0:
current_image -= 1
changed = True
if display.pressed(badger2040.BUTTON_DOWN):
if current_image < TOTAL_IMAGES - 1:
current_image += 1
changed = True
if display.pressed(badger2040.BUTTON_A):
show_info = not show_info
changed = True
if display.pressed(badger2040.BUTTON_B) or display.pressed(badger2040.BUTTON_C):
display.pen(15)
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)
display.update()
print(current_image)
time.sleep(4)
changed = True
# Halt the Badger to save power, it will wake up if any of the front buttons are pressed
display.halt()
if changed:
badger_os.state_save("image", current_image, show_info)
show_image(current_image)
changed = False
# Halt the Badger to save power, it will wake up if any of the front buttons are pressed
display.halt()

Wyświetl plik

@ -1,11 +1,10 @@
import gc
import os
import time
import math
import machine
import badger2040
from badger2040 import WIDTH
import launchericons
import badger_os
# for e.g. 2xAAA batteries, try max 3.4 min 3.0
MAX_BATTERY_VOLTAGE = 4.0
@ -15,33 +14,18 @@ MIN_BATTERY_VOLTAGE = 3.2
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")
badger_os.state_delete()
else:
with open("appstate.txt", "r") as f:
# Try to launch app
launch("_" + f.readline().strip('\n'))
badger_os.state_launch()
except OSError:
pass
except ImportError:
# Happens if appstate names an unknown app. Delete appstate and reset
import os
os.remove("appstate.txt")
badger_os.state_delete()
machine.reset()
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
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):
# Outline
display.thickness(1)
@ -138,17 +105,7 @@ def draw_battery(level, x, y):
def draw_disk_usage(x):
# 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
_, f_used, _ = badger_os.get_disk_usage()
display.image(
bytearray(
@ -207,7 +164,9 @@ def render():
display.rectangle(0, 0, WIDTH, 16)
display.thickness(1)
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.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():
time.sleep(0.01)
try:
launch(examples[(page * 3) + index][0])
badger_os.launch(examples[(page * 3) + index][0])
return True
except IndexError:
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}/info.py _info)
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 {
struct 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_dir(pimoroni::Badger2040::ENABLE_3V3, GPIO_OUT);