Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
67fa5eb
apps: ported hydrate app
thirdr Feb 2, 2026
539e8df
apps: better icon for hydrate
thirdr Feb 2, 2026
c41712c
apps: port of tomato app
thirdr Feb 3, 2026
63ce7b2
apps: battery charging and low warning on menu
thirdr Feb 3, 2026
c5c31ab
firmware: use case lights to show when MSC is busy
thirdr Feb 4, 2026
dd0ead1
Sync with Tufty
thirdr Feb 4, 2026
eb41858
More changes to sync with Tufty
thirdr Feb 4, 2026
0841c19
system: attempt to rescue a corrupted FAT.
thirdr Feb 4, 2026
90a93c5
CI: Use ffsmake to set filesystem label.
Gadgetoid Feb 5, 2026
33c3dc5
badgeware: Refactor for new badge API.
Gadgetoid Feb 5, 2026
0f0b05d
badgeware/badge: Fix sleep.
Gadgetoid Feb 5, 2026
e1f9f1c
board: Set USB VID/PID.
Gadgetoid Feb 5, 2026
39bdac2
hydrate: Fix clamp use.
Gadgetoid Feb 5, 2026
0c24342
tomato: Fix case lights.
Gadgetoid Feb 5, 2026
1467519
CI: Update allowed builtins.
Gadgetoid Feb 5, 2026
0ed70e1
badgeware/badge: implement battery_voltage.
Gadgetoid Feb 5, 2026
11040f0
badgeware: background and foreground to default_clear and default_pen.
Gadgetoid Feb 5, 2026
7b163c8
powman: Disable PWM in all cases for long press sleep.
Gadgetoid Feb 6, 2026
445d524
powman: remove redundant i2c_disable.
Gadgetoid Feb 6, 2026
83702f1
powman: tidyup and tweak code/comments.
Gadgetoid Feb 6, 2026
8b54094
pngdec: Support up to 2048 pixel wide PNGs.
Gadgetoid Feb 7, 2026
ab2e300
board: Set PicoVector config in usermodules.cmake.
Gadgetoid Feb 7, 2026
ecde77a
picovector: Sync with Tufty for jpeg support.
Gadgetoid Feb 7, 2026
c90ecae
msc: Update caselight code.
Gadgetoid Feb 8, 2026
90d72c2
apps: hardcoded badge text to allow user to edit in Disk Mode
thirdr Feb 9, 2026
46040a5
hardware_test: press and hold down button to skip to display test
thirdr Feb 9, 2026
11e4adc
hardware_test: changed to UP button as requested
thirdr Feb 9, 2026
50e8e6b
apps: fixed scrolling on tomato app
thirdr Feb 9, 2026
4f62fc1
badgeware/text: Simplify and fix text.scroll.
Gadgetoid Feb 11, 2026
cf09158
badgeware/text: Add vertical align options to scroll.
Gadgetoid Feb 11, 2026
78f5867
picovector: Fix font UTF-8 support.
Gadgetoid Feb 11, 2026
2db7b21
picovector: Fix pixel_font UTF-8 support.
Gadgetoid Feb 11, 2026
3cfb78f
fonts/yolk: Now supports 15+ languages.
Gadgetoid Feb 11, 2026
b0056eb
fonts: Add custom badgeware fonts.
Gadgetoid Feb 11, 2026
f3944b8
picovector: Better utf8 continuation for text rendering.
Gadgetoid Feb 11, 2026
1ae063d
system: Clean up main frozen module.
Gadgetoid Feb 12, 2026
48ef4a2
badgeware/text: Make rom_fonts singleton/cached on load.
Gadgetoid Feb 12, 2026
ea26932
badgeware/badge: fix disk_free.
Gadgetoid Feb 12, 2026
30f19e3
apps: Fixes for updated text.scroll.
Gadgetoid Feb 12, 2026
52879e7
badgeware: simplify main, make run take an app path.
Gadgetoid Feb 12, 2026
f088a42
badgeware/badge: Make disk_free make sense.
Gadgetoid Feb 12, 2026
f3ce230
secrets: Make require check for empty strings.
Gadgetoid Feb 12, 2026
df72a74
badgeware/state: make State a builtin.
Gadgetoid Feb 12, 2026
8d3506c
QA: Add State to linting config.
Gadgetoid Feb 12, 2026
f4790c5
badgeware/badge: API tidyup.
Gadgetoid Feb 16, 2026
a22aab2
boot_fat: Drop unnused FS_LABEL.
Gadgetoid Feb 16, 2026
c469186
badgeware: Return correct bounds from text.draw
MichaelBell Feb 10, 2026
e4433f7
badgeware/badge: Caselights gamma.
Gadgetoid Feb 17, 2026
8ccf742
badgeware/badge: Expose first_update.
Gadgetoid Feb 18, 2026
8d45c0e
input: Expose actual button objects.
Gadgetoid Feb 20, 2026
5ffc78b
badgeware: Support for procedural apps.
Gadgetoid Feb 20, 2026
3eed758
msc: Disable HOME button, simplify app.
Gadgetoid Feb 20, 2026
c91c4b3
badgeware: Split run into launch and run.
Gadgetoid Feb 20, 2026
e185cff
pngdec: Fix spurious decoding error.
Feb 23, 2026
b322b25
pngdec: Sync zlib with upstream.
Feb 23, 2026
2092a60
jpegdec: Fixes to RGB888 mode.
MichaelBell Feb 7, 2026
39219b7
Sync CMake tooling with simulator.
Gadgetoid Feb 24, 2026
856b4a1
png/jpegdec: Support for image downscaling on load.
MichaelBell Feb 24, 2026
5056ec3
jpegdec: Fix quarter scale and 1x2 subsampling.
MichaelBell Feb 24, 2026
10293c5
rtc: add alarm_status.
Gadgetoid Feb 24, 2026
b7f10e0
lsm6ds3: Add module.
Gadgetoid Feb 24, 2026
331fd28
powman: universal module for all badgeware boards.
Gadgetoid Feb 24, 2026
f80d2c7
apps/zoooom: update vspan_tex to blit_vspan.
Gadgetoid Feb 24, 2026
8299a1b
badgeware: Fix on_exit.
Gadgetoid Feb 24, 2026
03941a8
apps: adding gallery app
thirdr Feb 24, 2026
e8f4a1a
main: Discard initial button press.
Gadgetoid Feb 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion board/filesystem.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ if (EXISTS "${PIMORONI_TOOLS_DIR}/ffsmake/build/ffsmake" AND EXISTS "${PIMORONI_
MESSAGE("ffsmake: Using root ${PIMORONI_FATFS_DIR}.")
MESSAGE("ffsmake: Outputting filesystem binary: ${CMAKE_BINARY_DIR}/${MICROPY_TARGET}-fatfs.bin")
add_custom_target("${MICROPY_TARGET}-fatfs.bin" ALL
COMMAND "${PIMORONI_TOOLS_DIR}/ffsmake/build/ffsmake" --sector-count=3076 --force --directory "${PIMORONI_FATFS_DIR}" --output "${CMAKE_BINARY_DIR}/${MICROPY_TARGET}-fatfs.bin"
COMMAND "${PIMORONI_TOOLS_DIR}/ffsmake/build/ffsmake" --label="${PIMORONI_FATFS_LABEL}" --sector-count=3076 --force --directory "${PIMORONI_FATFS_DIR}" --output "${CMAKE_BINARY_DIR}/${MICROPY_TARGET}-fatfs.bin"
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "ffsmake: Packing FatFS filesystem to ${MICROPY_TARGET}-fatfs.bin."
DEPENDS ${MICROPY_TARGET}
Expand Down
1 change: 1 addition & 0 deletions board/mpconfigboard.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@ set(MICROPY_BLUETOOTH_BTSTACK ON)
set(MICROPY_PY_BLUETOOTH_CYW43 ON)

set(PIMORONI_FATFS_DIR ${CMAKE_CURRENT_LIST_DIR}/../firmware)
set(PIMORONI_FATFS_LABEL "BLINKY")
set(PIMORONI_ROMFS_DIR ${CMAKE_CURRENT_LIST_DIR}/../romfs)
include(${CMAKE_CURRENT_LIST_DIR}/filesystem.cmake)
6 changes: 6 additions & 0 deletions board/mpconfigboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#define MICROPY_HW_ROMFS_BYTES (1 * 1024 * 1024)
#define MICROPY_HW_FLASH_STORAGE_BYTES (PICO_FLASH_SIZE_BYTES - (2 * 1024 * 1024) - MICROPY_HW_ROMFS_BYTES)

#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_C)

// Set up networking.
#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "Blinky2350"

Expand Down Expand Up @@ -33,6 +35,10 @@ int mp_hal_is_pin_reserved(int n);

#define MICROPY_PY_THREAD (0)

// Configure USB
#define MICROPY_HW_USB_VID (0x2e8a)
#define MICROPY_HW_USB_PID (0x1102)

#define MICROPY_HW_USB_MSC (1)
#define MICROPY_HW_USB_DESC_STR_MAX (40)
#define MICROPY_HW_USB_MANUFACTURER_STRING "Pimoroni"
Expand Down
14 changes: 13 additions & 1 deletion board/usermodules.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ list(APPEND CMAKE_MODULE_PATH "${PIMORONI_PICO_PATH}/micropython/modules")
# Local modules in modules/
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/..")

set(CMAKE_C_STANDARD 11)
set(PNGDEC_DIR "${CMAKE_CURRENT_LIST_DIR}/../modules/c/pngdec")
set(JPEGDEC_DIR "${CMAKE_CURRENT_LIST_DIR}/../modules/c/jpegdec")

set(CMAKE_C_STANDARD 17)
set(CMAKE_CXX_STANDARD 17)

# Essential
Expand All @@ -25,6 +28,14 @@ include(pimoroni_i2c/micropython)
include(modules/c/blinky/micropython)
include(modules/c/picovector/micropython)

# Build picovector for Pico
target_compile_definitions(usermod_picovector INTERFACE BLINKY=1 PICO=1)

# Build jpegdec for Pico
target_compile_definitions(jpegdec PRIVATE PICO_BUILD)

include(qrcode/micropython/micropython)

# Sensors & Breakouts
include(micropython-common-breakouts)

Expand All @@ -36,6 +47,7 @@ include(adcfft/micropython)

# Sleep / Wake Reason
include(modules/c/powman/micropython)
target_compile_definitions(usermod_sleep INTERFACE BLINKY=1)

# C++ Magic Memory
include(cppmem/micropython)
Expand Down
2 changes: 1 addition & 1 deletion ci/micropython.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ PIMORONI_PICO_VERSION="37a1b6500f77924b2a3287009734bb24d4809bf1"

PY_DECL_VERSION="v0.0.5"
DIR2UF2_VERSION="v0.1.0"
FFSMAKE_VERSION="main"
FFSMAKE_VERSION="v0.0.3"


function log_success {
Expand Down
70 changes: 56 additions & 14 deletions ci/ruff.toml
Original file line number Diff line number Diff line change
@@ -1,29 +1,71 @@
builtins = [
"mode",
"HIRES",
"LORES",
"SpriteSheet",
"load_font",
"rom_font",
"clamp",
"rnd",
"frnd",
# micropython
"micropython",
"const",
"ptr8",
"ptr32",

# picovector
"algorithm",
"brush",
"color",
"default_target",
"font",
"image",
"io",
"mat3",
"pen",
"pixel_font",
"vec2",
"rect",
"shape",
"screen",
"scroll_text",
"micropython"

# badgeware.py
"display",
"launch",
"run",
"loop",
"reset",
"fatal_error",

# math.py
"clamp",
"rnd",
"frnd",

# text.py
"rom_font",
"load_font",
"text",

# sprite.py
"SpriteSheet",
"AnimatedSprite",

# filesystem.py
"file_exists",
"is_dir",

# rtc.py
"rtc",

# state.py
"State",

# badge.py
"badge",
"HIRES",
"LORES",
"VSYNC",
"FAST_UPDATE",
"FULL_UPDATE",
"MEDIUM_UPDATE",
"DITHER",
"BUTTON_A",
"BUTTON_B",
"BUTTON_C",
"BUTTON_UP",
"BUTTON_DOWN",
"BUTTON_HOME"
]

# Include:
Expand Down Expand Up @@ -70,4 +112,4 @@ lint.ignore = [
"E402",
"COM812",
"ICN001"
]
]
21 changes: 11 additions & 10 deletions firmware/apps/badge/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import sys
import os
from badgeware import run, set_brightness, scroll_text, State, clamp
from badgeware import set_brightness, State

sys.path.insert(0, "/system/apps/badge")
os.chdir("/system/apps/badge")

TEXT = "Hello! I'm Blinky2350!"

state = {
"text": "Hello, I'm a Blinky2350!",
"font": "ignore",
"brightness": 0.1
}
Expand All @@ -17,35 +18,36 @@
font_list = dir(rom_font)
font_index = font_list.index(state["font"])

scroll = scroll_text(state["text"], font_face=getattr(rom_font, state["font"]), bg=color.black)
scroll = text.scroll(TEXT, font_face=getattr(rom_font, state["font"]))

changed = False


def update():
global state, scroll, changed, font_index

if io.BUTTON_UP in io.pressed:
if badge.pressed(BUTTON_UP):
state["brightness"] += 0.1

if io.BUTTON_DOWN in io.pressed:
if badge.pressed(BUTTON_DOWN):
state["brightness"] -= 0.1

state["brightness"] = clamp(state["brightness"], 0.1, 1.0)

if io.BUTTON_C in io.pressed:
if badge.pressed(BUTTON_C):
if font_index < len(font_list) - 1:
font_index += 1
changed = True

if io.BUTTON_A in io.pressed:
if badge.pressed(BUTTON_A):
if font_index > 0:
font_index -= 1
changed = True

if changed:
state["font"] = font_list[font_index]
scroll = scroll_text(state["text"], font_face=getattr(rom_font, state["font"]), bg=color.black)
scroll = text.scroll(TEXT, font_face=getattr(rom_font, state["font"]))
State.save("badge", state)
changed = False

set_brightness(state["brightness"])
Expand All @@ -57,5 +59,4 @@ def on_exit():
State.save("badge", state)


if __name__ == "__main__":
run(update=update, on_exit=on_exit)
run(update)
18 changes: 7 additions & 11 deletions firmware/apps/clock/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# Standalone bootstrap for module imports
sys.path.insert(0, APP_DIR)

from badgeware import run, State, rtc
from badgeware import State
import time
import ntptime
from daylightsaving import DaylightSavingPolicy, DaylightSaving
Expand All @@ -20,9 +20,7 @@
import secrets
from fallingsand import FallingSand

# enable the RTC interrupts.
# Timers run without this but they won't be able to wake the board.
rtc.enable_timer_interrupt(True)
# Enable a 1s timer
rtc.set_timer(1)

SCREEN_MAIN_W = screen.width - 4
Expand Down Expand Up @@ -191,8 +189,7 @@ def display_time():
# Here we're seeing if the timer's gone off from one second ago,
# and if it has we're checking if we need to drop any grains and
# resetting the RTC timer for one second's time.
if rtc.read_timer_flag():
rtc.clear_timer_flag()
if rtc.timer_elapsed():
falling_sand.assess_drop(currenttime)
rtc.set_timer(1)
falling_sand.drop_grains()
Expand Down Expand Up @@ -434,20 +431,20 @@ def update():
wifi.tick()

# First we check if anything's been pressed before choosing what to display.
if io.BUTTON_C in io.pressed:
if badge.pressed(BUTTON_C):
state["clock_style"] += 1
if state["clock_style"] > 4:
state["clock_style"] = 1
write_settings()

if io.BUTTON_A in io.pressed:
if badge.pressed(BUTTON_A):
state["clock_style"] -= 1
if state["clock_style"] < 1:
state["clock_style"] = 4
write_settings()

# If the year in the RTC is 2021 or earlier, we need to sync so it has the same effect as pressing B.
if io.BUTTON_B in io.pressed or time.gmtime()[0] <= 2021 and clock_state == ClockState.Running:
if badge.pressed(BUTTON_B) or time.gmtime()[0] <= 2021 and clock_state == ClockState.Running:
user_message("updating", "time")
clock_state = ClockState.ConnectWiFi

Expand Down Expand Up @@ -475,5 +472,4 @@ def update():
clock_state = ClockState.UpdateTime


if __name__ == "__main__":
run(update)
run(update)
11 changes: 4 additions & 7 deletions firmware/apps/demos/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
sys.path.insert(0, APP_DIR)
os.chdir(APP_DIR)

from badgeware import run

mode(LORES)
badge.mode(LORES)


import gc
Expand Down Expand Up @@ -46,10 +44,10 @@ def load_demo(index):
def update():
global selected, menu_index

if io.BUTTON_DOWN in io.pressed:
if badge.pressed(BUTTON_DOWN):
load_demo(selected + 1)

if io.BUTTON_UP in io.pressed:
if badge.pressed(BUTTON_UP):
load_demo(selected - 1)

# make sure a font is loaded by default in case the example wishes to use it
Expand Down Expand Up @@ -88,5 +86,4 @@ def update():
screen.text(name, 5, y)


if __name__ == "__main__":
run(update)
run(update)
4 changes: 2 additions & 2 deletions firmware/apps/demos/demos/blur.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

def update():
star = shape.star(0, 0, 5, 7.5, 12.5)
star.transform = mat3().translate(screen.width // 2, screen.height // 2).rotate(io.ticks / 10)
star.transform = mat3().translate(screen.width // 2, screen.height // 2).rotate(badge.ticks / 10)
screen.shape(star)
screen.antialias = image.X4

b = math.sin(io.ticks / 500) * 2 + 2
b = math.sin(badge.ticks / 500) * 2 + 2
screen.blur(b)
6 changes: 3 additions & 3 deletions firmware/apps/demos/demos/pattern.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ def update():
0b01111110,
0b00000000))
screen.pen = custom_pattern
screen.shape(shape.circle(x + math.cos(io.ticks / 500) * 10, y + math.sin(io.ticks / 1000) * 10, 10))
screen.shape(shape.circle(x + math.cos(badge.ticks / 500) * 10, y + math.sin(badge.ticks / 1000) * 10, 10))

built_in_pattern = brush.pattern(color.rgb(255, 255, 255, 100), color.rgb(0, 0, 0, 0), 11)
screen.pen = built_in_pattern
screen.shape(shape.circle(x + math.sin(io.ticks / 250) * 20, y + math.cos(io.ticks / 500) * 20, 10))
screen.shape(shape.circle(x + math.sin(badge.ticks / 250) * 20, y + math.cos(badge.ticks / 500) * 20, 10))

built_in_pattern = brush.pattern(color.rgb(255, 255, 255, 50), color.rgb(0, 0, 0, 0), 8)
screen.pen = built_in_pattern
screen.shape(shape.circle(x + math.cos(io.ticks / 250) * 10, y + math.sin(io.ticks / 500) * 10, 10))
screen.shape(shape.circle(x + math.cos(badge.ticks / 250) * 10, y + math.sin(badge.ticks / 500) * 10, 10))
8 changes: 4 additions & 4 deletions firmware/apps/demos/demos/sprites.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
def update():
random.seed(0)
for i in range(5):
s = (math.sin(io.ticks / 500 + i / 5) * 1) + 1
s = (math.sin(badge.ticks / 500 + i / 5) * 1) + 1

skull.alpha = int((math.sin((io.ticks + i * 30) / 500) + 1) * 127)
skull.alpha = int((math.sin((badge.ticks + i * 30) / 500) + 1) * 127)

x = math.sin(i + io.ticks / 1000) * (screen.width / 2)
y = math.cos(i + io.ticks / 1000) * (screen.height / 2)
x = math.sin(i + badge.ticks / 1000) * (screen.width / 2)
y = math.cos(i + badge.ticks / 1000) * (screen.height / 2)

pos = vec2(x + rnd(-20, 20), y + rnd(-20, 20))

Expand Down
4 changes: 2 additions & 2 deletions firmware/apps/demos/demos/transform_sprite.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ def magic_sprite(src, pos, scale=1, angle=0):


def update():
scale = ((math.sin(io.ticks / 1000) + 1.0) + 1) / 2
angle = math.cos(io.ticks / 500) * 45
scale = ((math.sin(badge.ticks / 1000) + 1.0) + 1) / 2
angle = math.cos(badge.ticks / 500) * 45
magic_sprite(skull, (screen.width // 2, screen.height - 5), scale, angle)
Loading