Skip to content

Commit

Permalink
Merge pull request #32 from pimoroni/launch-and-quit
Browse files Browse the repository at this point in the history
MicroPython: Add start() and quit() functions.
  • Loading branch information
Gadgetoid authored Oct 21, 2021
2 parents 07afe5a + 8fc02eb commit 3573fe1
Show file tree
Hide file tree
Showing 11 changed files with 135 additions and 38 deletions.
2 changes: 2 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ builtins =
pen,
tick,
init,
start,
quit,
_reset,
_logo,
play,
Expand Down
4 changes: 1 addition & 3 deletions micropython/examples/picosystem/colour.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,4 @@ def draw(tick):

prepare_rgb_palette()


while True:
tick()
start()
48 changes: 26 additions & 22 deletions micropython/examples/picosystem/launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@


notes = [
(None, 100), ("G6", 10), ("E6", 30), ("A6", 10), ("G6", 30), (None, 50), ("B7", 1), ("C7", 1)
(None, 50), ("G6", 5), ("E6", 15), ("A6", 5), ("G6", 15), (None, 25), ("B7", 1), ("C7", 1)
]
intro = Voice()
intro.envelope(attack=50, decay=10, sustain=70, release=2000)
Expand All @@ -27,12 +27,14 @@
if "colour.py" not in files:
files.append("colour")

# HACK to add a quick menu item
files.append("__quit__")

filecount = len(files)

target_angle = 0
current_angle = 0
selected = 0
running = True

blip = Voice(10, 10, 10, 10, 40, 2)

Expand All @@ -51,32 +53,32 @@ def update_melody(tick):
last_note = tick
note, note_duration = notes[note_idx]
if note:
intro.play(note, note_duration * 4)
intro.play(note, note_duration * 8)
note_idx += 1
if note_idx >= len(notes):
intro_melody = False


def update(tick):
global selected, target_angle, running
global selected, target_angle

if intro_melody:
update_melody(tick)
else:
if pressed(LEFT):
selected -= 1
blip.play(1600, 30, 100)

if pressed(LEFT):
selected -= 1
blip.play(1600, 30, 100)

if pressed(RIGHT):
selected += 1
blip.play(1800, 30, 100)
if pressed(RIGHT):
selected += 1
blip.play(1800, 30, 100)

if pressed(A):
ding.play(880, 30, 100)
running = False
if pressed(A):
ding.play(880, 30, 100)
quit()

selected %= filecount
target_angle = -get_item_angle(selected)
selected %= filecount
target_angle = -get_item_angle(selected)

if tick <= 75:
backlight(tick)
Expand Down Expand Up @@ -123,15 +125,17 @@ def draw(tick):
)

# centre name of file at bottom of screen
label_width = text_width(files[selected])
label = files[selected]
if label == "__quit__":
label = "quit"
label_width = text_width(label)
pen(11, 11, 8)
frect(int(60 - label_width / 2 - 3), 102 - 3, label_width + 6, 13)
pen(0, 0, 0)
text(files[selected], int(60 - (label_width / 2)), 102)
text(label, int(60 - (label_width / 2)), 102)


while running:
tick()
start() # Will unblock when "quit" is called


__launch_file__ = files[selected]
Expand All @@ -140,5 +144,5 @@ def draw(tick):
del locals()[k]

gc.collect()
_reset()
__import__(__launch_file__)
if __launch_file__ != "__quit__":
__import__(__launch_file__)
3 changes: 1 addition & 2 deletions micropython/examples/picosystem/shapes.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,5 +147,4 @@ def draw(tick):

reset()

while True:
tick()
start()
4 changes: 1 addition & 3 deletions micropython/examples/picosystem/sprites.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,4 @@ def draw(tick):
text(weapons[selected][1], int(60 - (label_width / 2)), 102)


while True:
tick()
time.sleep(1.0 / 50)
start()
3 changes: 1 addition & 2 deletions micropython/examples/picosystem/spritesheets.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,4 @@ def draw(tick):
sprite(x + y * int(120 / 8), x * 8, y * 8)


while True:
tick()
start()
3 changes: 1 addition & 2 deletions micropython/examples/picosystem/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,4 @@ def draw(tick):
line(110, 10, 10, 110)


while True:
tick()
start()
1 change: 0 additions & 1 deletion micropython/modules/picosystem/micropython.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ target_include_directories(usermod_${MOD_NAME} INTERFACE

target_compile_definitions(usermod_${MOD_NAME} INTERFACE
MODULE_${MOD_NAME_UPPER}_ENABLED=1
DYNAMIC_BUFFER=1
PIXEL_DOUBLE=1
)

Expand Down
2 changes: 2 additions & 0 deletions micropython/modules/picosystem/picosystem.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ MP_DEFINE_CONST_FUN_OBJ_0(picosystem_init_obj, picosystem_init);
MP_DEFINE_CONST_FUN_OBJ_0(picosystem_reset_obj, picosystem_reset);
MP_DEFINE_CONST_FUN_OBJ_0(picosystem_tick_obj, picosystem_tick);
MP_DEFINE_CONST_FUN_OBJ_0(picosystem_logo_obj, picosystem_logo);
MP_DEFINE_CONST_FUN_OBJ_0(picosystem_run_obj, picosystem_run);
MP_DEFINE_CONST_FUN_OBJ_0(picosystem_quit_obj, picosystem_quit);

// stats.cpp

Expand Down
101 changes: 98 additions & 3 deletions micropython/modules/picosystem/picosystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ extern "C" {
#include "picosystem.h"
#include "math.h"
#include "cstring"
#include "py/gc.h"

//#define NOT_INITIALISED_MSG "Cannot call this function, as picodisplay is not initialised. Call picodisplay.init(<bytearray>) first."

Expand All @@ -30,6 +31,7 @@ extern "C" {
uint32_t update_rate_ms = 10;
uint32_t pending_update_ms = 0;
uint32_t last_ms = time();
bool running = true;

uint32_t tick = 0;

Expand Down Expand Up @@ -57,8 +59,10 @@ mp_obj_t pimoroni_mp_load_global(qstr qst) {
}

mp_obj_t picosystem_reset() {
running = false;
update_callback_obj = mp_const_none;
draw_callback_obj = mp_const_none;
tick = 0;
return mp_const_none;
}

Expand All @@ -81,8 +85,8 @@ mp_obj_t picosystem_logo() {

mp_obj_t picosystem_init() {

MP_STATE_PORT(picosystem_framebuffer) = m_new(color_t, 120 * 120);
SCREEN = buffer(120, 120, MP_STATE_PORT(picosystem_framebuffer));
//MP_STATE_PORT(picosystem_framebuffer) = m_new(color_t, 120 * 120);
//SCREEN = buffer(120, 120, MP_STATE_PORT(picosystem_framebuffer));
target(SCREEN);

update_callback_obj = mp_const_none;
Expand Down Expand Up @@ -132,6 +136,95 @@ mp_obj_t picosystem_init() {
return mp_const_none;
}

mp_obj_t picosystem_run() {
if(update_callback_obj == mp_const_none) {
update_callback_obj = pimoroni_mp_load_global(qstr_from_str("update"));
if(update_callback_obj == mp_const_none) {
//TODO switch out this URL for the final one
mp_raise_msg(&mp_type_NameError, "a function named 'update(ticks)' is not defined. Check out https://github.com/pimoroni/picosystem/blob/main/micropython/README.md for instructions");
}
}

if(draw_callback_obj == mp_const_none) {
draw_callback_obj = mp_load_global(qstr_from_str("draw"));
if(draw_callback_obj == mp_const_none) {
//TODO switch out this URL for the final one
mp_raise_msg(&mp_type_NameError, "a function named 'draw()' is not defined. Check out https://github.com/pimoroni/picosystem/blob/main/micropython/README.md for instructions");
}
}

_io = _gpio_get();
running = true;

while(running) {
uint32_t start_tick_us = time_us();

// store previous io state and get new io state
_lio = _io;
_io = _gpio_get();

// call users update() function
uint32_t start_update_us = time_us();
mp_call_function_1(update_callback_obj, mp_obj_new_int(tick++));
stats.update_us = time_us() - start_update_us;

// if we're currently transferring the the framebuffer to the screen then
// wait until that is complete before allowing the user to do their drawing
uint32_t wait_us = 0;
uint32_t start_wait_flip_us = time_us();
while(_is_flipping()) {
best_effort_wfe_or_timeout(make_timeout_time_us(500));
}
wait_us += time_us() - start_wait_flip_us;

// call user render function to draw world
uint32_t start_draw_us = time_us();
mp_call_function_1(draw_callback_obj, mp_obj_new_int(tick));
stats.draw_us = time_us() - start_draw_us;

// wait for the screen to vsync before triggering flip
// to ensure no tearing
uint32_t start_wait_vsync_us = time_us();
_wait_vsync();
wait_us += time_us() - start_wait_vsync_us;

// flip the framebuffer to the screen
_flip();

// force a per-frame gc.collect() to avoid stutter
// cost on the order of microseconds.
gc_collect();

stats.tick_us = time_us() - start_tick_us;

// calculate fps and round to nearest value (instead of truncating/floor)
stats.fps = (1000000 - 1) / stats.tick_us + 1;

if(stats.fps > 40) {
// if fps is high enough then we definitely didn't miss vsync
stats.idle = (wait_us * 100) / stats.tick_us;
}else{
// if we missed vsync then we overran the frame time and hence had
// no idle time
stats.idle = 0;
}

MICROPY_EVENT_POLL_HOOK

}

update_callback_obj = mp_const_none;
draw_callback_obj = mp_const_none;
tick = 0;

return mp_const_none;
}

mp_obj_t picosystem_quit(){
running = false;
return mp_const_none;
}

mp_obj_t picosystem_tick() {
uint32_t start_tick_us = time_us();

Expand Down Expand Up @@ -164,7 +257,9 @@ mp_obj_t picosystem_tick() {
// wait until that is complete before allowing the user to do their drawing
uint32_t wait_us = 0;
uint32_t start_wait_flip_us = time_us();
while(_is_flipping()) {}
while(_is_flipping()) {
MICROPY_EVENT_POLL_HOOK
}
wait_us += time_us() - start_wait_flip_us;

// call user render function to draw world
Expand Down
2 changes: 2 additions & 0 deletions micropython/modules/picosystem/picosystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ extern mp_obj_t picosystem_init();
extern mp_obj_t picosystem_tick();
extern mp_obj_t picosystem_reset();
extern mp_obj_t picosystem_logo();
extern mp_obj_t picosystem_run();
extern mp_obj_t picosystem_quit();

// stats.cpp
extern mp_obj_t picosystem_stats();
Expand Down

0 comments on commit 3573fe1

Please sign in to comment.