Skip to content

Conversation

@pipe01
Copy link
Contributor

@pipe01 pipe01 commented Dec 27, 2025

This PR adds very rudimentary support for using the Pawn language to write apps and watchfaces and load them at runtime. It's only a proof of concept right now, it simply loads a hardcoded program from ROM (source below) and runs it when the digital watchface is shown or the Pawn app is opened (the one with a P icon).

There's still a lot of work left to be done, but I wanted to know your thoughts before fully sending it. We should also include the Pawn code as a submodule instead of vendoring the files directly.

This PR replaces the digital watchface implementation with a Pawn one whose source code is in the watchface_digital.p file.

Simple hello world example:

#include "infinitime"

@start() {
	var lv_obj: label = lv_label_create(screen)
	lv_obj_set_pos(label, 20, 20)
	lv_label_set_text(label, "Hello world")
}

@github-actions
Copy link

github-actions bot commented Dec 27, 2025

Build size and comparison to main:

Section Size Difference
text 394776B 11900B
data 944B 0B
bss 22632B 0B

Run in InfiniEmu

@mark9064
Copy link
Member

This looks super cool. Question: could the example program here live in ROM rather than static memory (I assume that's where the +600 is coming from)? Otherwise if all programs live in RAM all the time I think it'll be really tough memory wise

@pipe01
Copy link
Contributor Author

pipe01 commented Dec 28, 2025

Yeah, we can even dynamically load the program from the external flash in small chunks to the RAM

@mark9064
Copy link
Member

Cool, so if we made that char array static constexpr it'd still work fine? In that case the static memory usage added by this is only a few bytes which sounds very promising (and the program size looks reasonable). As I investigated in #2392, loading a few Ks from flash can be done in <40ms or so having apps/watchfaces loaded this way sounds very plausible. I guess my one concern is larger apps might have enough bytecode that we can't load it all into memory at once. But it sounds like from what you say we can load in chunks, so that might not be an issue

@JF002 would be very interesting to hear your thoughts on this

@pipe01
Copy link
Contributor Author

pipe01 commented Dec 29, 2025

I've implemented the chunk loading I mentioned, now the code will only use up to 512 bytes (configurable, should probably be closer to a couple KBs). Obviously right now it's useless since it's loading from program ROM, but when loading from external flash it will also act as an LRU cache

@mark9064
Copy link
Member

Awesome :)

How does calling native functions e.g. LVGL functions work? Can we autogenerate bindings or do we need to implement our own micro-API for apps/watchfaces. I guess I'm not opposed to a micro-API anyway as we can make it more user friendly

@pipe01
Copy link
Contributor Author

pipe01 commented Dec 29, 2025

I was thinking of a mix of autogenerating bindings for LVGL and some auxiliary functions on top, e.g. the handful currently provided. Some sort of high level API would definitely make the programs smaller although I don't know what such an API would look like; both options are definitely possible

@pipe01
Copy link
Contributor Author

pipe01 commented Dec 30, 2025

I've reimplemented the digital watchface in Pawn here and removed the original one. I'm not sure if we should actually do this or not but it's a good exercise, although if we do we could consider moving it to the external flash to free up internal flash space

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants