|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +This file provides guidance to agents when working with code in this repository. |
| 4 | + |
| 5 | +- Build is driven by `./scripts/build_mpos.sh <target>`; it mutates tracked files (patches `lvgl_micropython/lib/micropython/ports/esp32/main/idf_component.yml`, appends include to `micropython-camera-API/src/manifest.py`, and toggles `@micropython.viper` in `internal_filesystem/lib/mpos/audio/stream_wav.py`). Re-run builds expecting these edits to persist unless reverted. |
| 6 | +- Unix/macOS builds rely on symlinks created by `build_mpos.sh` in `lvgl_micropython/ext_mod/` for `c_mpos` and `secp256k1-embedded-ecdh` because `USER_C_MODULE` is unreliable on those targets. |
| 7 | +- Syntax tests run via `./tests/syntax.sh` and compile every `internal_filesystem/**/*.py` with `mpy-cross`; failing files are reported by path. |
| 8 | +- Unit tests run via `./tests/unittest.sh [test_file] [--ondevice]`; runner injects `main.py` and disables `mpos.TaskManager` for desktop, but on-device runs must NOT re-run boot/main (the script handles this). |
| 9 | +- Graphical tests are detected by filename containing `graphical` and run with LVGL boot/main injected; non-graphical tests run without boot files. |
| 10 | +- To run a single test, pass a file path to `./tests/unittest.sh` (absolute path is resolved inside the script). |
| 11 | +- Testing workflow details and examples live in `tests/README.md`; check it before adding new tests. |
| 12 | +- Code formatting for Python in this repo is ruff with double quotes configured in `ruff.toml` (quote-style = "double"). |
| 13 | + |
| 14 | +Guidelines: |
| 15 | +- If something is incomplete or lacks functionality that is needed to finish the task, then implement the missing functionality, rather than working around it. |
| 16 | +- Always add a timeout -s 9 30 to ./scripts/run_desktop.sh so run: timeout -s 9 30 ./scripts/run_desktop.sh |
| 17 | + |
| 18 | +Guidelines for writing or updating tests: |
| 19 | +- Use the testing facilities in ./internal_filesystem/lib/mpos/ui/testing.py and feel free to add new ones there, NOT ad hoc in the test itself. |
| 20 | +- When adding graphical tests, follow the helpers and conventions described in tests/README.md. |
| 21 | + |
| 22 | +LVGL tips: |
| 23 | +- import lvgl as `lv` and use `lv.` to access it |
| 24 | +- `lv.screen_active()` (not `lv.scr_act()`) |
| 25 | +- use `button` instead of `btn`, `image` instead of `img` |
| 26 | +- use `lv.EVENT.VALUE_CHANGED` instead of `lv.EVENT_VALUE_CHANGED` |
| 27 | +- instead of `lv.OBJ_FLAG.CLICKABLE`, use `lv.obj.FLAG.CLICKABLE` (same pattern for other flags) |
| 28 | +- instead of `.set_hidden(True)` use `.add_flag(lv.obj.FLAG.HIDDEN)`; instead of `.set_hidden(False)` use `.remove_flag(lv.obj.FLAG.HIDDEN)` |
| 29 | +- use `.remove_flag()` instead of `.clear_flag()` |
| 30 | +- use `obj.remove_state(...)` not `obj.clear_state(...)` |
| 31 | +- event handlers need 3 arguments: `button.add_event_cb(button_cb, lv.EVENT.CLICKED, None)` |
| 32 | +- don't hard-code display resolution; use `lv.pct(100)` or other techniques to scale the interface |
| 33 | +- `DRAW_PART_BEGIN` does not exist anymore |
| 34 | +- don't use `get_child_by_type()`; use a global variable with the child you want instead |
| 35 | +- msgbox: `msgbox = lv.msgbox()` then `msgbox.add_title("title")` |
| 36 | +- use `lv.buttonmatrix.CTRL.CHECKABLE` instead of `lv.BUTTONMATRIX_CTRL_CHECKABLE` |
| 37 | +- use `lv.buttonmatrix.CTRL.CHECKED` instead of `lv.BUTTONMATRIX_CTRL_CHECKED` |
| 38 | +- colors: `RED = lv.palette_main(lv.PALETTE.RED)` or `DARKPINK = lv.color_hex(0xEC048C)` |
| 39 | +- use `lv.anim_t.path_ease_in_out` not `lv.anim_path_ease_in_out` |
| 40 | +- instead of `label.set_long_mode(lv.label.LONG.WRAP)` use `label.set_long_mode(lv.label.LONG_MODE.WRAP)` |
| 41 | +- use `style_obj = lv.style_t()` then `style_obj.init()` instead of `lv.style()` |
| 42 | +- always call `style.init()` after `lv.style_t()` before calling setters like `set_bg_color()` — without it the device may hang |
| 43 | +- In LVGL 9.x style setters take only the value (no selector). The selector goes in `add_style()`. E.g. `style.set_bg_color(lv.color_hex(0x...))` then `obj.add_style(style, lv.PART.ITEMS | lv.STATE.CHECKED)`. |
| 44 | +- `lv.buttonmatrix` has no `set_button_text()` or `set_button_ctrl()` in this binding. To update text, rebuild and call `set_map()`. To mark buttons visually (e.g. solved state), change the text symbol itself (e.g. append "!"). |
| 45 | +- `lv.buttonmatrix.set_map()` fires `LV_EVENT_VALUE_CHANGED` asynchronously (next LVGL tick), causing phantom second-selection events. Guard with a time-based debounce (`time.ticks_diff(now, last_ts) < 50`) rather than a simple flag. |
| 46 | + |
| 47 | +MicroPython compatibility: |
| 48 | +- Some builds ship a minimal `random` module without `random.Random` or `random.shuffle`. For shuffling, implement Fisher-Yates manually with `random.randint`. |
| 49 | +- For deterministic jitter in apps, prefer a tiny local LCG (linear congruential generator) instead of `random.Random`. |
0 commit comments