175 lines
8.7 KiB
Markdown
175 lines
8.7 KiB
Markdown
# Current API Landscape
|
|
|
|
Snapshot taken 2026-08-03 from the generated LuaLS stubs in Slate32 and CrossPoint Reader.
|
|
This inventory explains the gaps between the current firmwares and the contracts under
|
|
`lua/api/core/` and `lua/api/features/`.
|
|
|
|
## Summary
|
|
|
|
| | LCD / Slate32 | E-ink / CrossPoint |
|
|
|---|---:|---:|
|
|
| Declared functions | 77 | 67 |
|
|
| Names present in both | 27 | 27 |
|
|
| Same parameter list | 21 | 21 |
|
|
| Same name, different parameter list | 6 | 6 |
|
|
|
|
Matching declarations do not guarantee matching behavior. Important differences remain in
|
|
filesystem limits and ordering, TLS verification, network ownership, colors, and lifecycle.
|
|
|
|
## Original Common Ground
|
|
|
|
These names and parameter lists matched before the clean contract was defined. They are useful
|
|
implementation inventory, not constraints on `lua/api/core/`.
|
|
|
|
| Namespace | Functions | Remaining decisions |
|
|
|---|---|---|
|
|
| `http` | `get`, `head`, `delete`, `post`, `patch`, `download`, `urlencode` | The contract now returns `HttpResponse|nil, error`, requires a response `maxBytes`, and authenticates TLS. |
|
|
| `fs` | `exists`, `readFile`, `writeFile`, `listFiles`, `listDirs` | Standardize the read cap, sorted listings, path validation, and failure returns. |
|
|
| `log` | `debug`, `info`, `error` | Mostly ready. |
|
|
| `sys` | `delay`, `setTickInterval` | The clean contract drops both; callback timers replace periodic ticks and blocking delays. |
|
|
| `wifi` | `disconnect`, `isConnected` | Decide whether disconnect ownership is app-specific or device-wide. |
|
|
|
|
The basic `gui` drawing primitives are also intended for core. Colors will be opaque,
|
|
platform-native integers produced by `gui.color(r, g, b)`: RGB565 on LCD and quantized grayscale
|
|
on e-ink. Apps that need to be portable use `gui.color` rather than hard-coded values.
|
|
|
|
## Same Name, Different Signature
|
|
|
|
| Function | LCD | E-ink |
|
|
|---|---|---|
|
|
| `gui.clear` | `(color)` | `()` |
|
|
| `gui.drawLine` | `(x1, y1, x2, y2, color)` | `(x1, y1, x2, y2, width, color)` |
|
|
| `gui.drawText` | `(text, x, y, color, bg)` | `(font, x, y, text, color, style)` |
|
|
| `gui.fillCircle` | `(x, y, radius, color, bg)` | `(cx, cy, radius, color)` |
|
|
| `gui.getTextWidth` | `(text)` | `(font, text, style)` |
|
|
| `wifi.connect` | `(ssid, password)` | `()` using stored credentials |
|
|
|
|
These GUI differences are current implementation drift, not permanent display features. Wi-Fi
|
|
is also generic drift: both connection forms are useful, so the eventual shared signature can
|
|
make credentials optional after both firmwares implement both behaviors.
|
|
|
|
## Agreed GUI Direction
|
|
|
|
Basic geometry and text measurement belong in core with identical signatures:
|
|
|
|
```lua
|
|
gui.getWidth()
|
|
gui.getHeight()
|
|
gui.color(r, g, b)
|
|
|
|
gui.clear(color?)
|
|
gui.fillRect(x, y, w, h, color)
|
|
gui.drawRect(x, y, w, h, color)
|
|
gui.drawLine(x1, y1, x2, y2, color, width?)
|
|
gui.fillCircle(x, y, radius, color, background?)
|
|
|
|
gui.getTextWidth(font, text, style?)
|
|
gui.getFontHeight(font, style?)
|
|
gui.drawText(font, x, y, text, color?, style?, background?)
|
|
```
|
|
|
|
Fonts are opaque, zero-based integer IDs selected through shared semantic constants:
|
|
|
|
```lua
|
|
gui.FONT_SMALL
|
|
gui.FONT_UI
|
|
gui.FONT_BODY
|
|
gui.FONT_LARGE
|
|
```
|
|
|
|
Each implementation maps those roles to its available fonts or scales. Portable apps use the
|
|
named constants and metric functions rather than literal IDs or assumed pixel dimensions.
|
|
Physical names such as Bookerly and Noto Sans remain legacy implementation APIs, not part of
|
|
the core or e-ink feature contracts.
|
|
|
|
The optional background describes the surface behind anti-aliased output; it can have no visible
|
|
effect on a renderer without partial edge pixels. E-ink refresh policy and LCD live-frame
|
|
behavior remain feature-specific.
|
|
|
|
## Generic Features to Converge
|
|
|
|
These are not inherently LCD or e-ink concerns and should not be permanently assigned to a
|
|
display feature.
|
|
|
|
### Present only on E-ink
|
|
|
|
- Filesystem mutation and paging: `fileSize`, `mkdir`, `readLineAt`, `remove`, `removeTree`, `rename`.
|
|
These are intentionally under `lua/api/core/`; Slate32 must still implement them.
|
|
- Independent timers: `timer.after`, `timer.every`, `timer.cancel`
|
|
- `sys.uptime` / `sys.millis` naming
|
|
|
|
### Present only on LCD
|
|
|
|
- App routing: `sys.launch`, `sys.replace`, `sys.back`
|
|
- Runtime state: `sys.getAppName`, `setAppName`, `getMemory`, `isClockSynced`
|
|
- Wi-Fi management: `scan`, explicit credential connection, `forget`
|
|
- SD-backed `require` and app-local modules (runtime behavior, not a binding declaration)
|
|
- Native compact widget tree in `node.*`
|
|
|
|
The contract intentionally includes all of these generic capabilities. Both firmwares are under
|
|
our control, so they migrate to the clean API without compatibility aliases. The compact node
|
|
tree remains useful on e-ink for layout, painting, invalidation, and directional focus. Focus is
|
|
tree-level state with a deliberate appearance; moving it invalidates only the old and new nodes.
|
|
|
|
## Feature Contracts
|
|
|
|
- `buttons` guarantees physical-button polling/callbacks and button hints.
|
|
- `touch` guarantees calibrated/raw coordinates, touch callbacks, and calibration persistence.
|
|
|
|
A feature exists only where an app can call something a device may not have. Panel technology is
|
|
not such a case: firmware-owned publication and waveform policy already hold for every display, and
|
|
`gui.setFullscreen()` and `gui.roundRect()` are core, with a panel that has no gradient flattening
|
|
it exactly as `gui.color()` quantizes to grayscale. So the display is never a feature, and input is
|
|
never inferred from it. BLE/GATT remains
|
|
required core `ble`; a future `bt` namespace is reserved for Classic Bluetooth. Generic BMP,
|
|
polygon, shape, rotation, color, and text operations are core. Rotation and timezone settings are
|
|
also core, while theme persistence and application belong to shared `ui.lua`.
|
|
|
|
## Lifecycle Differences
|
|
|
|
| Concern | LCD | E-ink |
|
|
|---|---|---|
|
|
| Entry | required `init(arg)` | required `init()` |
|
|
| Navigation | Lua route stack | exit to C++ launcher |
|
|
| Input callbacks | touch down/move/up/tap | button callback and polling |
|
|
| Publication | drawing is immediately visible | apps currently call explicit refresh |
|
|
| Modules | app-local and shared `require` | effectively single-file apps |
|
|
|
|
The contract standardizes `init(arg?)`, navigation, and module loading. Optional `draw(deltaMs)`
|
|
runs once after initialization and then at most 30 FPS, best effort. The host passes monotonic
|
|
elapsed milliseconds, with zero on the first frame. Callback timers replace `on_tick`. Input
|
|
callbacks remain feature-specific. Firmware commits dirty content after callback batches and owns panel
|
|
refresh policy, including e-ink waveforms. `sys.getAPIVersion()` identifies the integer contract
|
|
version implemented by the firmware.
|
|
|
|
## Contract Rules
|
|
|
|
1. This is a clean API. Backward compatibility has no weight because all consumers are controlled
|
|
and migrate with the implementations.
|
|
2. A core function matches in name, parameters, returns, and observable behavior.
|
|
3. GUI coordinates use a top-left origin, including text; implementations translate driver
|
|
baselines and orientation details.
|
|
4. Invalid arguments raise Lua errors. Runtime failures return `nil, error`; filesystem reads
|
|
take an explicit `maxBytes` up to 64 KiB and fail rather than truncate. `fs.writeFile()` is
|
|
atomic: failure leaves the previous contents intact.
|
|
5. Apps live under `/.lua/apps`, shared modules under `/.lua/lib`, and persistent app data under
|
|
`/.lua/data/<AppId>`. Launch paths name directories relative to `apps`; firmware appends
|
|
`main.lua`. The first path component is the immutable app ID and determines `getAppDataPath()`.
|
|
6. `node` owns one focused ID outside its 16-byte nodes. Directional movement is geometric and
|
|
non-wrapping, with a distinct focused appearance.
|
|
7. `draw(deltaMs)` is the optional frame loop, capped at 30 FPS; the host supplies elapsed
|
|
monotonic milliseconds and callback-based `timer.after/every` handle periodic work.
|
|
8. Firmware commits dirty display content and owns panel refresh policy; no refresh API is
|
|
exposed to apps.
|
|
9. Apps are fully trusted; the contract adds no permissions or sandbox.
|
|
10. BLE/GATT is core `ble`; Classic Bluetooth remains undefined rather than sharing an inaccurate
|
|
namespace.
|
|
11. This repository owns portable modules under `lua/lib/`, including global theme behavior and the
|
|
declarative widget toolkit in `ui.lua`. Widgets expose only `on_enter`, `on_exit`, and
|
|
`on_click`: touch and directional focus map onto the same active-state lifecycle.
|
|
12. HTTPS authenticates certificates.
|
|
13. Generated firmware stubs are checked against this repository rather than copied here as
|
|
competing sources of truth.
|
|
14. Feature contracts contain only their declared hardware capability.
|
|
15. Runtime smoke tests cover semantics that LuaLS declarations cannot express.
|