Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
505d585
feat: add internet connectivity verification, toast notifications, an…
jeffory Mar 28, 2026
a888a02
feat: enhance simulator with display diagnostics, nested callbacks, a…
jeffory Mar 28, 2026
c8078f9
feat: dedicated Core 1 memory pool for Mongoose allocations
jeffory Mar 30, 2026
5815f36
fix: address code review issues in Core 1 allocator
jeffory Mar 30, 2026
3961330
feat: lock-free SPSC ring buffer for WiFi IPC
jeffory Mar 30, 2026
6222c12
fix: add 5s total timeout to SD multi-block transfers
jeffory Mar 30, 2026
61bdc75
fix: add timeouts to Core 1 pause handshake
jeffory Mar 30, 2026
0fcf7d5
fix: make WiFi status variables atomic
jeffory Mar 31, 2026
a48d01c
fix: remove stale display_spi_lock comment from wifi.h
jeffory Mar 31, 2026
9ed5b35
fix: acquire SD mutex in USB MSC callbacks
jeffory Mar 31, 2026
3641aa7
fix: reduce SD SPI clock to 25 MHz and harden card recovery
jeffory Apr 3, 2026
3577d6c
fix: use C11 atomics for cross-core shared state and enhance crash ha…
jeffory Apr 3, 2026
e52c669
feat: add raycasting display primitives and styled toast notifications
jeffory Apr 3, 2026
1040331
fix: overhaul OTA to pre-read firmware into PSRAM before flash writes
jeffory Apr 3, 2026
3c44da1
feat: WiFi hardware disconnect tracking, new Lua APIs, HTTP hardening
jeffory Apr 3, 2026
bf9c055
fix: assorted hardening and SDK terminal extensions
jeffory Apr 3, 2026
b412c09
chore: add cdogs submodule and gitignore saves/
jeffory Apr 3, 2026
3df2c3b
chore: gitignore binary assets (WADs, ELFs, images)
jeffory Apr 5, 2026
d33b338
chore: add miniz as git submodule, move picos config outside
jeffory Apr 5, 2026
7916bd4
feat: add ZIP extraction support via miniz
jeffory Apr 5, 2026
c4ee68d
feat: add recursive file deletion to filesystem API
jeffory Apr 5, 2026
6a2e721
feat: expand sys.getMemInfo with PIO PSRAM and XIP cache metrics
jeffory Apr 5, 2026
d8ff768
fix: correct 3D backface culling and light direction
jeffory Apr 5, 2026
6c51798
feat: add category, repo, and min_firmware to app.json schema
jeffory Apr 5, 2026
faeed07
feat: implement launcher category grid with app icons
jeffory Apr 5, 2026
3f7054a
perf: optimize GBC emulator with palette LUT and remove spin-waits
jeffory Apr 5, 2026
61ed023
fix: feed watchdog during Doom initialization
jeffory Apr 5, 2026
06c7331
feat: replace 3D demo icosahedron with PicoCalc device model
jeffory Apr 5, 2026
9fad5f5
feat: improve editor, systest, updater, and picoforge apps
jeffory Apr 5, 2026
9391556
fix: update simulator stubs for new driver APIs
jeffory Apr 5, 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
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ testplan.md
# Debugging artifacts
screenshots/
screen.png
screenshot.png

# Binary assets (not tracked in git)
apps/doom/doom1.wad
apps/gbc/main.elf
apps/block.exe/inspiration.jpg
apps/tic-80/

# Simulator user data
data/
Expand All @@ -51,3 +58,5 @@ sim_*.log

tests/e2e/__pycache__/
*.patch

saves/
8 changes: 7 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,10 @@
url = https://github.com/wolfSSL/wolfssl.git
[submodule "apps/doom/src"]
path = apps/doom/src
url = https://github.com/ozkl/doomgeneric.git
url = https://github.com/ozkl/doomgeneric.git
[submodule "apps/cdogs"]
path = apps/cdogs
url = https://github.com/jeffory/cdogs-picos.git
[submodule "third_party/miniz"]
path = third_party/miniz
url = https://github.com/richgel999/miniz.git
22 changes: 22 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ add_executable(picocalc_os
src/os/lua_bridge_3d.c
src/os/lua_bridge_ui.c
src/os/ui_widgets.c
src/os/toast.c
src/os/text_wrap.c
src/os/lua_bridge_audio.c
src/os/lua_bridge_sound.c
Expand All @@ -244,6 +245,7 @@ add_executable(picocalc_os
src/os/lua_bridge_game_scene.c
src/os/lua_bridge_game_save.c
src/os/lua_psram_alloc.c
src/os/core1_alloc.c
src/os/system_menu.c
src/os/screenshot.c
src/os/terminal.c
Expand All @@ -253,6 +255,7 @@ add_executable(picocalc_os
src/os/crypto.c
src/os/lua_bridge_crypto.c
src/os/lua_bridge_mod.c
src/os/lua_bridge_zip.c
src/os/ota_update.c
src/fonts/font_6x11.c
src/fonts/font_scientifica.c
Expand Down Expand Up @@ -283,6 +286,10 @@ add_executable(picocalc_os
src/drivers/pio_psram_bulk.c
third_party/mongoose/mongoose.c
third_party/umm_malloc/src/umm_malloc.c
third_party/miniz/miniz.c
third_party/miniz/miniz_tinfl.c
third_party/miniz/miniz_tdef.c
third_party/miniz/miniz_zip.c
)

target_include_directories(picocalc_os PRIVATE
Expand All @@ -293,6 +300,7 @@ target_include_directories(picocalc_os PRIVATE
src/drivers/
third_party/mongoose/
third_party/umm_malloc/src/
third_party/miniz/
third_party/libmad/
third_party/pocketmod/
data/
Expand Down Expand Up @@ -321,6 +329,20 @@ target_link_libraries(picocalc_os
pio_psram_lib
)

# ── miniz compile options (decompression only, no stdio, PSRAM allocator) ────
# Redirect miniz heap allocations to umm_malloc (8MB PSRAM) instead of
# standard malloc (~28KB SRAM) so ZIP extraction can handle real app sizes.
# Force-include miniz_picos.h which defines MZ_MALLOC/MZ_FREE/MZ_REALLOC
# before miniz_common.h's #ifndef guards.
set_source_files_properties(
third_party/miniz/miniz.c
third_party/miniz/miniz_tinfl.c
third_party/miniz/miniz_tdef.c
third_party/miniz/miniz_zip.c
PROPERTIES COMPILE_FLAGS
"-DMINIZ_NO_STDIO -DMINIZ_NO_ARCHIVE_WRITING_APIS -DMINIZ_NO_ZLIB_COMPATIBLE_NAMES -include ${CMAKE_SOURCE_DIR}/third_party/miniz_picos.h"
)

# ── PIO PSRAM Bulk Transfer (improved driver with 16-bit counters) ─────────────
# Supports up to 8187 bytes per transaction (vs 27 bytes in polpo library).
# Uses a custom PIO program in src/drivers/pio_psram_bulk.pio.
Expand Down
5 changes: 4 additions & 1 deletion apps/3dtest/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@
"name": "3D Test",
"description": "Spinning 3D icosahedron with FPS counter",
"version": "1.0.0",
"author": "PicOS"
"author": "PicOS",
"category": "demos",
"repo": "jeffory/picos-apps",
"min_firmware": "1.0.0"
}
197 changes: 162 additions & 35 deletions apps/3dtest/main.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
-- 3D Spinning Icosahedron Demo
-- 3D PicoCalc Model Demo
-- Tests display performance with real-time 3D graphics

local pc = picocalc
Expand All @@ -10,37 +10,149 @@ local perf = picocalc.perf
-- Screen centre
local cx, cy = 160, 160

-- Regular icosahedron: 12 vertices, circumradius ~50.
-- Built from three mutually perpendicular golden rectangles.
-- φ = (1+√5)/2 ≈ 1.618; scale so circumradius = 50:
-- short half = 26.3, long half = 42.5 (= φ × 26.3)
-- PicoCalc model vertices (scaled up from [-1,1] to ~100 units)
-- Body: -100 to 100 in X/Y, +/- 15 in Z
-- Screen area: center X, upper Y
-- D-pad: left side
-- Buttons: right side
local vertices = {
0, 26.3, 42.5, -- 1
0, -26.3, 42.5, -- 2
0, 26.3, -42.5, -- 3
0, -26.3, -42.5, -- 4
26.3, 42.5, 0, -- 5
-26.3, 42.5, 0, -- 6
26.3, -42.5, 0, -- 7
-26.3, -42.5, 0, -- 8
42.5, 0, 26.3, -- 9
-42.5, 0, 26.3, -- 10
42.5, 0, -26.3, -- 11
-42.5, 0, -26.3, -- 12
-- Main body - front (1-4)
-100, -100, 15,
100, -100, 15,
100, 100, 15,
-100, 100, 15,
-- Main body - back (5-8)
-100, -100, -15,
100, -100, -15,
100, 100, -15,
-100, 100, -15,
-- Screen bezel front (9-12)
-60, -10, 16,
60, -10, 16,
60, 50, 16,
-60, 50, 16,
-- Screen display (13-16)
-50, -2, 13,
50, -2, 13,
50, 42, 13,
-50, 42, 13,
-- D-pad vertical (17-20)
-75, -55, 16,
-65, -55, 16,
-65, -45, 16,
-75, -45, 16,
-- D-pad horizontal (21-24)
-85, -65, 16,
-75, -65, 16,
-75, -55, 16,
-85, -55, 16,
-- A button (25-28)
65, -55, 16,
80, -55, 16,
80, -40, 16,
65, -40, 16,
-- B button (29-32)
55, -70, 16,
70, -70, 16,
70, -55, 16,
55, -55, 16,
-- Left shoulder (33-36)
-90, 90, 10,
-60, 90, 10,
-60, 100, 10,
-90, 100, 10,
-- Right shoulder (37-40)
60, 90, 10,
90, 90, 10,
90, 100, 10,
60, 100, 10,
-- Speaker grille (41-44)
60, -75, 16,
90, -75, 16,
90, -85, 16,
60, -85, 16,
}

-- 30 edges (each pair listed once, lower index first)
-- Scale down to 80% for better framing
local scale = 0.8
for i = 1, #vertices do
vertices[i] = vertices[i] * scale
end

-- Edges derived from quads (each quad = 4 edges)
local edges = {
1,2, 1,5, 1,6, 1,9, 1,10, -- vertex 1 fan
2,7, 2,8, 2,9, 2,10, -- vertex 2 new
3,4, 3,5, 3,6, 3,11, 3,12, -- vertex 3 fan
4,7, 4,8, 4,11, 4,12, -- vertex 4 new
5,6, 5,9, 5,11, -- vertex 5 new
6,10, 6,12, -- vertex 6 new
7,8, 7,9, 7,11, -- vertex 7 new
8,10, 8,12, -- vertex 8 new
9,11, -- vertex 9 new
10,12, -- vertex 10 new
-- Front face
1,2, 2,3, 3,4, 4,1,
-- Back face
5,6, 6,7, 7,8, 8,5,
-- Top face
4,3, 3,7, 7,8, 8,4,
-- Bottom face
1,5, 5,6, 6,2, 2,1,
-- Right face
2,6, 6,7, 7,3, 3,2,
-- Left face
5,1, 1,4, 4,8, 8,5,
-- Screen bezel front
9,10, 10,11, 11,12, 12,9,
-- Screen display
13,14, 14,15, 15,16, 16,13,
-- D-pad vertical
17,18, 18,19, 19,20, 20,17,
-- D-pad horizontal
21,22, 22,23, 23,24, 24,21,
-- A button
25,26, 26,27, 27,28, 28,25,
-- B button
29,30, 30,31, 31,32, 32,29,
-- Left shoulder
33,34, 34,35, 35,36, 36,33,
-- Right shoulder
37,38, 38,39, 39,40, 40,37,
-- Speaker grille
41,42, 42,43, 43,44, 44,41,
}

-- Triangular faces for proper fill (derived from quads)
local faces = {
-- Body front
1,2,3, 1,3,4,
-- Body back
5,7,6, 5,8,7,
-- Body top
4,3,8, 3,7,8,
-- Body bottom
1,5,6, 1,6,2,
-- Body right
2,7,3, 2,6,7,
-- Body left
1,4,8, 1,8,5,
-- Screen bezel
9,10,11, 9,11,12,
-- Screen display
13,14,15, 13,15,16,
-- D-pad
17,18,19, 17,19,20,
21,22,23, 21,23,24,
-- A button
25,26,27, 25,27,28,
-- B button
29,30,31, 29,31,32,
-- Left shoulder
33,34,35, 33,35,36,
-- Right shoulder
37,38,39, 37,39,40,
-- Speaker (Y decreases, so reverse winding)
41,43,42, 41,44,43,
}

-- Base fill colors
local fillColors = {
disp.rgb(60, 80, 100), -- Dark blue gray (body)
disp.rgb(40, 100, 60), -- Green (screen)
disp.rgb(200, 80, 80), -- Red (A button)
disp.rgb(80, 80, 200), -- Blue (B button)
disp.rgb(150, 150, 160), -- Light gray (shoulder)
}

-- Rotation angles (radians)
Expand All @@ -53,8 +165,10 @@ local rotSpeed = 0.02

-- Main loop
local mode = 1 -- 1=auto rotate, 2=manual control
local fillMode = 0 -- 0=wireframe only, 1=fill only, 2=both
local showHelp = true
local helpTimer = 0
local fillColorIndex = 1

while true do
perf.beginFrame()
Expand All @@ -72,6 +186,18 @@ while true do
helpTimer = 0
end

-- Toggle fill mode with F1
if pressed & input.BTN_F1 ~= 0 then
fillMode = (fillMode + 1) % 3
showHelp = true
helpTimer = 0
end

-- Cycle fill color with F2
if pressed & input.BTN_F2 ~= 0 then
fillColorIndex = (fillColorIndex % #fillColors) + 1
end

-- Update rotation
if mode == 1 then
angleX = angleX + rotSpeed
Expand All @@ -90,28 +216,29 @@ while true do
-- Clear screen
disp.clear(disp.BLACK)

-- Transform, project, and draw all edges + vertex dots in one C call.
-- Replaces: 24 Lua function calls, 24 table allocs, 15 bridge round-trips.
gfx.draw3DWireframe(
-- Use the new draw3DWireframeEx function with fill mode
-- fillMode: 0 = wireframe only, 1 = fill only, 2 = both
draw3DWireframeEx(
vertices, edges,
angleX, angleY, angleZ,
cx, cy, 200,
disp.CYAN, disp.YELLOW, 3)
disp.CYAN, fillColors[fillColorIndex], fillMode, 2, faces)

-- Draw title and mode
local modeText = mode == 1 and "AUTO" or "MANUAL"
pc.ui.drawHeader("3D Icosahedron - " .. modeText)
local fillText = fillMode == 0 and "WIRE" or (fillMode == 1 and "FILL" or "BOTH")
pc.ui.drawHeader("3D PicoCalc - " .. modeText .. " - " .. fillText)

-- Show help for 3 seconds
if showHelp then
helpTimer = helpTimer + 1
if helpTimer < 180 then
local y = 230
if mode == 1 then
disp.drawText(4, y, "ENTER: Manual mode", disp.GRAY, disp.BLACK)
disp.drawText(4, y, "ENTER: Manual F1: Fill Mode F2: Color", disp.GRAY, disp.BLACK)
else
disp.drawText(4, y, "D-Pad: Rotate X/Y", disp.GRAY, disp.BLACK)
disp.drawText(4, y + 10, "F1/F2: Rotate Z", disp.GRAY, disp.BLACK)
disp.drawText(4, y + 10, "F1: Fill F2: Color", disp.GRAY, disp.BLACK)
disp.drawText(4, y + 20, "ENTER: Auto mode", disp.GRAY, disp.BLACK)
end
else
Expand Down
5 changes: 4 additions & 1 deletion apps/block.exe/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@
"name": "block.exe",
"description": "A Tetris clone with neon graphics",
"author": "PicOS",
"version": "1.0.0"
"version": "1.0.0",
"category": "games",
"repo": "jeffory/picos-apps",
"min_firmware": "1.0.0"
}
5 changes: 4 additions & 1 deletion apps/burnin_fixer/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@
"name": "Burn-In Fixer",
"description": "Exercises screen pixels to reduce LCD burn-in and stuck pixels",
"version": "1.0",
"author": "PicOS"
"author": "PicOS",
"category": "system",
"repo": "jeffory/picos-apps",
"min_firmware": "1.0.0"
}
5 changes: 4 additions & 1 deletion apps/doom/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,8 @@
"type": "native",
"system_clock_khz": 300000,
"version": "1.0.0",
"requirements": ["audio"]
"requirements": ["audio"],
"category": "games",
"repo": "jeffory/picos-apps",
"min_firmware": "1.0.0"
}
Loading
Loading