s3w 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,19 @@
1
+ Metadata-Version: 2.4
2
+ Name: s3w
3
+ Version: 0.1.0
4
+ Summary: S3Wear mini app CLI: new, build, pack, sign, run-sim, install, logs
5
+ License: Apache-2.0
6
+ Project-URL: Homepage, https://s3wear.fiqraat.com/developers/
7
+ Project-URL: Source, https://github.com/asmsaifs/S3Wear-SDK
8
+ Requires-Python: >=3.9
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: pyserial>=3.5
11
+
12
+ # s3w
13
+
14
+ Command-line tool for S3Wear mini apps: `new`, `build`, `pack`, `sign`, `run-sim`, `install`, `logs`.
15
+
16
+ pipx install s3w
17
+ s3w new my-app && s3w build my-app
18
+
19
+ Docs: https://s3wear.fiqraat.com/developers/
@@ -0,0 +1,26 @@
1
+ s3w_cli/__init__.py,sha256=qFIGyqJJmVGK-JuZHV2DHaf_qVm5s5yTaZSTmP7Ce8A,61
2
+ s3w_cli/__main__.py,sha256=E6Gls0DNz8GQK2K-kOUIx8cYhgANW_CH54VKrfCfs14,52
3
+ s3w_cli/cli.py,sha256=sgGqbmAx5nMfuyKIb25EBrT-cVSChmnfW8kMX62xVZI,9515
4
+ s3w_cli/device.py,sha256=1CName3Z_u3VmRtG2Yj1-wpIeo-0Huk6rM4f0J80x0Q,5123
5
+ s3w_cli/project.py,sha256=wbK-Ln9KH21qCuxEmYZH-pzXrZgXFTGYXGqspHjPamg,11743
6
+ s3w_cli/s3app.py,sha256=T9RgKGUb_WtATzxW5z_mNNVsFQOiRgdgUHUTSi3Kmfk,9274
7
+ s3w_cli/s3face.py,sha256=YSTVWstCM-1ITPuh8NZJBAPzYzZKfuC2nKQZ8C0Y0-w,9492
8
+ s3w_cli/sim.py,sha256=wnaT23c-t7Jhl5vQS9ccOCwPo8dYXOte_X1JRlrQ_Tg,2308
9
+ s3w_cli/_sdk/include/s3w.h,sha256=st9oIyCYI4YORZIZ1sEkVZaT0MBlLvKwJjJALtjjwIk,32637
10
+ s3w_cli/_sdk/rust/README.md,sha256=WthAEvHVtoRP_m-lPo7v6rEc2T8dK_WxerJbsKwL5M0,769
11
+ s3w_cli/_sdk/rust/s3w/Cargo.lock,sha256=oJ0BYZEaZReox2zGRLoHrveY_OL4rH3XXkjlCw0UbHk,226
12
+ s3w_cli/_sdk/rust/s3w/Cargo.toml,sha256=82mMjz62POWi_P_aDzS9Svj_LkYbGoy1IAP6wyan-_g,286
13
+ s3w_cli/_sdk/rust/s3w/src/lib.rs,sha256=_jUW1deU-oxchIGccwG5VcaUmRDoWb2pJYFrQ6c5e68,7555
14
+ s3w_cli/_sdk/rust/s3w-sys/Cargo.toml,sha256=oc57mgPeWjXX-7_FEl3vAYTdMIxHo185PONRG3y61PA,264
15
+ s3w_cli/_sdk/rust/s3w-sys/gen.py,sha256=Ouonju7GxUrwqW-zFVHjquBkY_YJU0Cvt1P9Lx5eHPU,6667
16
+ s3w_cli/_sdk/rust/s3w-sys/src/lib.rs,sha256=adOHtvL6XS4jI0CsQREgdGq-QqYZOdpZUyOCMLB5K_w,11505
17
+ s3w_cli/_sdk/templates/c/manifest.json,sha256=rq4Ka17EnxmTcnaLmpSVwJJbqpYvxR0cCrhlCa3fd3E,228
18
+ s3w_cli/_sdk/templates/c/src/main.c,sha256=px8UQiupn43HaUKKkW_Mg3wF0ezckwdooP1WkkID9Q8,2217
19
+ s3w_cli/_sdk/templates/rust/Cargo.toml,sha256=qv207tyIl1e4LVN_gmRgqaEkqLh3NFnyU_1-tZcpErE,378
20
+ s3w_cli/_sdk/templates/rust/manifest.json,sha256=rq4Ka17EnxmTcnaLmpSVwJJbqpYvxR0cCrhlCa3fd3E,228
21
+ s3w_cli/_sdk/templates/rust/src/lib.rs,sha256=iNkD_wFVNVUmrBVYk8MkRromSS8nwMhmJjYo7XDDwGU,2030
22
+ s3w-0.1.0.dist-info/METADATA,sha256=isDd6JSwpBAS6Tc7p3Bo0pmsB9MkwZFQFhEib1yQPxI,575
23
+ s3w-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
24
+ s3w-0.1.0.dist-info/entry_points.txt,sha256=sPVeQ4GFaCdh-doYTqXoGA3iyHSroB5tl8APQGV3Kzs,41
25
+ s3w-0.1.0.dist-info/top_level.txt,sha256=1qesqrnW2OCdhdGqDeNKn6SGNmJEVoigURca-n0N128,8
26
+ s3w-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ s3w = s3w_cli.cli:main
@@ -0,0 +1 @@
1
+ s3w_cli
s3w_cli/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ """The S3Wear mini app CLI (`s3w`)."""
2
+ __version__ = "0.1.0"
s3w_cli/__main__.py ADDED
@@ -0,0 +1,5 @@
1
+ import sys
2
+
3
+ from .cli import main
4
+
5
+ sys.exit(main())
@@ -0,0 +1,554 @@
1
+ /*
2
+ * s3w.h — the S3Wear mini app API, api_level 1.
3
+ *
4
+ * Apps are WebAssembly modules. Every function below is an import from module "s3w"; the app
5
+ * exports the lifecycle callbacks it wants (all optional). Handles are small integers, never
6
+ * pointers into firmware memory. Strings are UTF-8 (pointer, length) in app memory; the runtime
7
+ * checks that every pointer argument lies inside the app's memory and traps the app if not.
8
+ *
9
+ * Error handling: functions that return int give a value >= 0 on success, or a negative
10
+ * S3W_ERR_*. Calling a function with a handle that is not live (never made, deleted, or of the
11
+ * wrong kind) traps the app: that is a bug in the app, not a runtime condition.
12
+ *
13
+ * The same header is compiled into the firmware (for the types and constants); the import
14
+ * declarations are only visible when compiling for wasm.
15
+ *
16
+ * Implemented: lifecycle, system, timers, widgets mode (P8-02), canvas mode (P8-03), input,
17
+ * sensors, audio, storage, health, network and notifications (P8-04); packages (P8-05); game
18
+ * services (P8-08); device files (P8-18, api_level 2).
19
+ *
20
+ * Permissions (docs/05 §4): functions marked [perm: x] need permission x in the app's manifest;
21
+ * calling one without it traps the app. (The firmware's built-in samples get theirs from the
22
+ * firmware.)
23
+ *
24
+ * UI mode: the manifest's "ui_mode" (a built-in sample: canvas mode when it exports s3w_on_frame,
25
+ * else widgets mode). Calling a function of the other mode
26
+ * traps, except s3w_ui_toast and s3w_ui_dialog (both modes) and s3w_ui_screen (S3W_ERR_UNSUPPORTED
27
+ * in canvas mode).
28
+ */
29
+ #ifndef S3W_H
30
+ #define S3W_H
31
+
32
+ #include <stdbool.h>
33
+ #include <stdint.h>
34
+
35
+ #ifdef __cplusplus
36
+ extern "C" {
37
+ #endif
38
+
39
+ /* 2 adds the device file functions (s3w_fs_*, s3w_ui_image_file), 3 the Game Boy core (s3w_gb_*); a manifest
40
+ * with api_level 3 does not install on firmware that only has level 2. */
41
+ #define S3W_API_LEVEL 3
42
+
43
+ /* --- Errors ------------------------------------------------------------------------------- */
44
+ #define S3W_OK 0
45
+ #define S3W_ERR_INVALID (-1) /* an argument is out of range */
46
+ #define S3W_ERR_NO_RESOURCE (-2) /* a limit is reached (512 UI handles, 8 timers, ...) */
47
+ #define S3W_ERR_NOT_FOUND (-3) /* no such asset, ... */
48
+ #define S3W_ERR_UNSUPPORTED (-4) /* not available on this watch or api_level */
49
+ #define S3W_ERR_NOT_READY (-5) /* e.g. the wall clock is not set yet, no phone connected */
50
+ #define S3W_ERR_DENIED (-6) /* refused: a host not in the manifest's allowlist, ... */
51
+ #define S3W_ERR_IO (-7) /* storage failed */
52
+ #define S3W_ERR_NO_SPACE (-8) /* the app's storage quota is full */
53
+ #define S3W_ERR_TIMEOUT (-9) /* no answer in time (HTTP: 20 s) */
54
+ #define S3W_ERR_NETWORK (-10) /* the phone could not reach the server */
55
+
56
+ /* --- Events (s3w_on_event) ---------------------------------------------------------------- */
57
+ enum {
58
+ S3W_EV_TIMER = 1, /* handle = timer id */
59
+ S3W_EV_CLICK = 2, /* handle = button or list row */
60
+ S3W_EV_VALUE = 3, /* handle = slider or switch, value = new value (switch: 0/1) */
61
+ S3W_EV_DIALOG = 4, /* handle = dialog id from s3w_ui_dialog, value = 1 ok, 0 cancelled */
62
+ /* Touch, canvas mode only (x, y: canvas px). Widgets mode has CLICK and VALUE instead. */
63
+ S3W_EV_TOUCH_DOWN = 5,
64
+ S3W_EV_TOUCH_MOVE = 6, /* at most every 30 ms */
65
+ S3W_EV_TOUCH_UP = 7,
66
+ S3W_EV_TAP = 8, /* a short press */
67
+ S3W_EV_LONG_PRESS = 9, /* held, without moving */
68
+ S3W_EV_SWIPE = 10, /* value = S3W_DIR_* */
69
+ S3W_EV_IMU = 11, /* x, y, value = acceleration x, y, z in mg (watch frame: +x to 3 o'clock,
70
+ +y to 12, +z out of the screen); handle = samples since the last
71
+ event (later samples replace earlier ones while the app is busy) */
72
+ S3W_EV_HTTP = 12, /* handle = request id, value = HTTP status or S3W_ERR_*, x = body
73
+ bytes written to resp, y = 1 if the body was cut at resp_cap */
74
+ S3W_EV_BUTTON = 13, /* a hardware button of an app whose manifest has "capture_back": true, while its
75
+ screen is up. handle = S3W_BTN_*, value = 1 pressed, 0 released. The system
76
+ then does nothing with that button (no back, no shortcut); PWR still goes home. */
77
+ };
78
+ #define S3W_BTN_BOOT 0
79
+
80
+ /* S3W_EV_SWIPE directions (where the finger went). The screen's edges and the buttons belong to
81
+ * the system (back, home). */
82
+ enum { S3W_DIR_LEFT = 1, S3W_DIR_RIGHT, S3W_DIR_UP, S3W_DIR_DOWN };
83
+
84
+ typedef struct {
85
+ int32_t type; /* S3W_EV_* */
86
+ int32_t handle;
87
+ int32_t value;
88
+ int32_t x, y; /* touch and IMU events */
89
+ int32_t reserved[3];
90
+ } s3w_event_t; /* 32 bytes, layout fixed for api_level 1 */
91
+
92
+ /* Local time (s3w_time_local). */
93
+ typedef struct {
94
+ int32_t year; /* e.g. 2026 */
95
+ int32_t month; /* 1..12 */
96
+ int32_t day; /* 1..31 */
97
+ int32_t hour; /* 0..23 */
98
+ int32_t minute; /* 0..59 */
99
+ int32_t second; /* 0..59 */
100
+ int32_t wday; /* 0 = Sunday */
101
+ int32_t yday; /* 0..365 */
102
+ } s3w_tm_t;
103
+
104
+ /* s3w_health_today. */
105
+ typedef struct {
106
+ int32_t steps;
107
+ int32_t distance_m;
108
+ int32_t active_min;
109
+ int32_t kcal;
110
+ int32_t sleep_min; /* last night */
111
+ int32_t resting_hr; /* 0: unknown (no heart rate sensor) */
112
+ int32_t reserved[2];
113
+ } s3w_health_summary_t; /* 32 bytes, layout fixed for api_level 1 */
114
+
115
+ /* s3w_file_open modes. */
116
+ enum { S3W_FILE_READ = 0, S3W_FILE_WRITE = 1 /* create or truncate */, S3W_FILE_APPEND = 2 };
117
+
118
+ /* Game Boy core (api_level 3, functions below): buttons, sizes and the cartridge info. */
119
+ #define S3W_GB_A 0x01 /* s3w_gb_input mask: 1 = pressed */
120
+ #define S3W_GB_B 0x02
121
+ #define S3W_GB_SELECT 0x04
122
+ #define S3W_GB_START 0x08
123
+ #define S3W_GB_RIGHT 0x10
124
+ #define S3W_GB_LEFT 0x20
125
+ #define S3W_GB_UP 0x40
126
+ #define S3W_GB_DOWN 0x80
127
+ #define S3W_GB_W 160 /* the emulated screen */
128
+ #define S3W_GB_H 144
129
+ #define S3W_GB_SCALE_1X 2 /* s3w_gb_run_frame scale: twice the factor */
130
+ #define S3W_GB_SCALE_2X 4
131
+ #define S3W_GB_SCALE_2_5X 5
132
+ #define S3W_GB_NO_DRAW 1 /* s3w_gb_run_frame flags: emulate only (the core skips its pixel work too) */
133
+ #define S3W_GB_REDRAW 2 /* write every line, not only the changed ones */
134
+ typedef struct {
135
+ char title[16]; /* cartridge header title, NUL padded, printable ASCII */
136
+ uint8_t mapper; /* 0 none, 1 MBC1, 2 MBC2, 3 MBC3, 5 MBC5; 0xFF: not supported */
137
+ uint8_t cgb_flag; /* header byte 0x143: 0 DMG, 0x80 DMG and CGB, 0xC0 CGB only */
138
+ uint16_t rom_banks; /* 16 KiB banks the header declares */
139
+ uint8_t ram_kb; /* cartridge RAM in KiB */
140
+ uint8_t has_battery; /* the game keeps a save */
141
+ uint8_t has_rtc; /* MBC3 clock */
142
+ uint8_t supported; /* 1: this core can run it */
143
+ uint32_t key; /* CRC-32 of header bytes 0x100..0x14F: a stable id for per-game settings */
144
+ uint8_t reserved[4];
145
+ } s3w_gb_info_t; /* 32 bytes, layout fixed for api_level 3 */
146
+ /* Device files (api_level 2, functions below): limits and the list entry. */
147
+ #define S3W_FS_PATH_MAX 190
148
+ #define S3W_FS_NAME_MAX 95
149
+ #define S3W_FS_DIR 1 /* s3w_fs_entry_t.flags: a directory (size 0) */
150
+ typedef struct {
151
+ char name[96]; /* NUL terminated, S3W_FS_NAME_MAX + 1 bytes */
152
+ uint32_t size; /* bytes; 0 for a directory */
153
+ uint32_t flags; /* S3W_FS_* */
154
+ } s3w_fs_entry_t; /* 104 bytes */
155
+
156
+ /* s3w_http_request methods. */
157
+ enum { S3W_HTTP_GET = 0, S3W_HTTP_POST = 1 };
158
+
159
+ /* Limits. */
160
+ #define S3W_FILE_IMAGE_MAX_PIXELS 524288 /* s3w_ui_image_file: PNG and BMP, half a megapixel */
161
+ #define S3W_FILE_JPEG_MAX_PIXELS 8388608 /* JPEG, 8 megapixels */
162
+ #define S3W_FILE_IMAGE_MAX_SIDE 512
163
+ #define S3W_STORAGE_DEFAULT_KB 256 /* without the "storage" permission */
164
+ #define S3W_NAME_MAX 32 /* kv keys and file names */
165
+ #define S3W_KV_VALUE_MAX 4096
166
+ #define S3W_FILES_OPEN_MAX 4
167
+ #define S3W_HTTP_URL_MAX 511
168
+ #define S3W_HTTP_BODY_MAX 4096 /* request body */
169
+ #define S3W_HTTP_RESP_MAX 65536 /* response body */
170
+ #define S3W_HTTP_MAX 2 /* requests at once */
171
+ #define S3W_HIGHSCORE_BOARDS 8 /* boards 0..7 per app */
172
+ #define S3W_HIGHSCORE_LOWER 0x100 /* or into a board for s3w_highscore_submit: lower is better */
173
+
174
+ /* Log levels (s3w_log). */
175
+ enum { S3W_LOG_ERROR = 0, S3W_LOG_WARN = 1, S3W_LOG_INFO = 2, S3W_LOG_DEBUG = 3 };
176
+
177
+ /* --- Widgets mode constants --------------------------------------------------------------- */
178
+
179
+ /* s3w_ui_set_size: a size in px, or one of these. */
180
+ #define S3W_SIZE_CONTENT (-1) /* fit the content */
181
+ #define S3W_SIZE_FULL (-2) /* 100 % of the parent's content area */
182
+
183
+ /* s3w_ui_list_add icons (0 = none). */
184
+ enum {
185
+ S3W_ICON_NONE = 0,
186
+ S3W_ICON_OK,
187
+ S3W_ICON_CLOSE,
188
+ S3W_ICON_PLUS,
189
+ S3W_ICON_MINUS,
190
+ S3W_ICON_PLAY,
191
+ S3W_ICON_PAUSE,
192
+ S3W_ICON_STOP,
193
+ S3W_ICON_REFRESH,
194
+ S3W_ICON_SETTINGS,
195
+ S3W_ICON_HOME,
196
+ S3W_ICON_BELL,
197
+ S3W_ICON_EDIT,
198
+ S3W_ICON_TRASH,
199
+ S3W_ICON_LEFT,
200
+ S3W_ICON_RIGHT,
201
+ S3W_ICON_UP,
202
+ S3W_ICON_DOWN,
203
+ S3W_ICON_WARNING,
204
+ S3W_ICON_LIST,
205
+ S3W_ICON_COUNT
206
+ };
207
+
208
+ /* s3w_ui_set_style properties and their values. */
209
+ enum {
210
+ S3W_STYLE_TEXT_COLOR = 1, /* 0xRRGGBB (on a button: its text) */
211
+ S3W_STYLE_BG_COLOR, /* 0xRRGGBB (also makes the background opaque) */
212
+ S3W_STYLE_BG_OPA, /* 0..255 */
213
+ S3W_STYLE_FONT, /* S3W_FONT_* (on a button: its text) */
214
+ S3W_STYLE_RADIUS, /* px, 0..255 */
215
+ S3W_STYLE_ALIGN, /* S3W_ALIGN_*: placement in the parent; s3w_ui_set_pos then offsets */
216
+ S3W_STYLE_FLEX, /* S3W_FLEX_*: lays out the children */
217
+ S3W_STYLE_PAD, /* inner padding, px, 0..255 */
218
+ S3W_STYLE_GAP, /* space between flex children, px, 0..255 */
219
+ S3W_STYLE_TEXT_ALIGN, /* S3W_TEXT_ALIGN_* */
220
+ };
221
+
222
+ enum { S3W_FONT_CAPTION = 0, S3W_FONT_BODY, S3W_FONT_TITLE, S3W_FONT_DISPLAY }; /* 22/26/32/96 px */
223
+
224
+ enum {
225
+ S3W_ALIGN_TOP_LEFT = 0,
226
+ S3W_ALIGN_TOP_MID,
227
+ S3W_ALIGN_TOP_RIGHT,
228
+ S3W_ALIGN_LEFT_MID,
229
+ S3W_ALIGN_CENTER,
230
+ S3W_ALIGN_RIGHT_MID,
231
+ S3W_ALIGN_BOTTOM_LEFT,
232
+ S3W_ALIGN_BOTTOM_MID,
233
+ S3W_ALIGN_BOTTOM_RIGHT,
234
+ };
235
+
236
+ enum { S3W_FLEX_NONE = 0, S3W_FLEX_ROW, S3W_FLEX_COLUMN, S3W_FLEX_ROW_WRAP };
237
+
238
+ enum { S3W_TEXT_ALIGN_LEFT = 0, S3W_TEXT_ALIGN_CENTER, S3W_TEXT_ALIGN_RIGHT };
239
+
240
+ /* Display (410 x 502, rounded corners: keep text ~24 px in from the edges). */
241
+ #define S3W_SCREEN_W 410
242
+ #define S3W_SCREEN_H 502
243
+
244
+ /* --- Canvas mode constants ---------------------------------------------------------------- */
245
+
246
+ /* Canvas colours are RGB565: 5 bits red, 6 green, 5 blue. */
247
+ #define S3W_RGB565(r, g, b) ((uint16_t)((((r) & 0xF8) << 8) | (((g) & 0xFC) << 3) | (((b) & 0xFF) >> 3)))
248
+
249
+ #define S3W_GFX_FPS_DEFAULT 30
250
+ #define S3W_GFX_FPS_MAX 60
251
+
252
+ /* s3w_gfx_sprite flags. */
253
+ enum { S3W_SPRITE_FLIP_X = 1, S3W_SPRITE_FLIP_Y = 2 };
254
+
255
+ /* s3w_gfx_sprite_create: no transparent colour. */
256
+ #define S3W_SPRITE_NO_KEY (-1)
257
+
258
+ #define S3W_SPRITE_MAX 64 /* sprites per app */
259
+ #define S3W_SPRITE_MAX_BYTES (512 * 1024) /* all sprites' pixels together */
260
+
261
+ #if defined(__wasm__)
262
+
263
+ #define S3W_IMPORT(name) __attribute__((import_module("s3w"), import_name(#name)))
264
+ #define S3W_EXPORT(name) __attribute__((export_name(#name)))
265
+
266
+ /* --- Lifecycle: the app exports these (all optional) --------------------------------------- */
267
+ /* s3w_on_start: build the UI, read saved state. 250 ms budget; a hang kills the app.
268
+ * s3w_on_resume / s3w_on_pause: visible again / covered or screen off.
269
+ * s3w_on_stop: the system ends the app (not after s3w_exit).
270
+ * s3w_on_event: one event (see S3W_EV_*); e is valid only during the call.
271
+ * Every callback except s3w_on_start must return within 50 ms (3 overruns kill the app). */
272
+ void s3w_on_start(void) S3W_EXPORT(s3w_on_start);
273
+ void s3w_on_resume(void) S3W_EXPORT(s3w_on_resume);
274
+ void s3w_on_pause(void) S3W_EXPORT(s3w_on_pause);
275
+ void s3w_on_stop(void) S3W_EXPORT(s3w_on_stop);
276
+ void s3w_on_event(const s3w_event_t *e) S3W_EXPORT(s3w_on_event);
277
+
278
+ /* Canvas mode: called at the requested frame rate (s3w_gfx_set_fps) while the app is visible.
279
+ * dt_ms is the time since the previous frame (0 for the first one after start or resume). */
280
+ void s3w_on_frame(uint32_t dt_ms) S3W_EXPORT(s3w_on_frame);
281
+
282
+ /* Where the runtime writes the event it passes to s3w_on_event. Defined here (weak, so any
283
+ * number of files may include this header); apps do not call it. */
284
+ __attribute__((weak, export_name("s3w_event_buf"))) s3w_event_t *s3w_event_buf(void)
285
+ {
286
+ static s3w_event_t ev;
287
+ return &ev;
288
+ }
289
+
290
+ /* --- System ------------------------------------------------------------------------------- */
291
+ /* Milliseconds since the app started (monotonic). */
292
+ uint32_t s3w_millis(void) S3W_IMPORT(s3w_millis);
293
+ /* Seconds since 1970 (UTC), or 0 while the watch does not know the time. */
294
+ int64_t s3w_time_unix(void) S3W_IMPORT(s3w_time_unix);
295
+ /* Local time in the watch's time zone. S3W_ERR_NOT_READY while the time is unknown. */
296
+ int s3w_time_local(s3w_tm_t *out) S3W_IMPORT(s3w_time_local);
297
+ void s3w_log(int level, const char *msg, int len) S3W_IMPORT(s3w_log);
298
+ /* Ends the app at once (s3w_on_stop is not called). */
299
+ void s3w_exit(void) S3W_IMPORT(s3w_exit);
300
+ /* Starts a timer (at least 20 ms, up to 8 at once): S3W_EV_TIMER with its id after each period.
301
+ * Returns the id (> 0) or S3W_ERR_*. */
302
+ int s3w_timer_start(uint32_t period_ms, bool repeat) S3W_IMPORT(s3w_timer_start);
303
+ /* Stops a timer. An id that is not running (a one-shot that fired) is ignored. */
304
+ void s3w_timer_stop(int id) S3W_IMPORT(s3w_timer_stop);
305
+ /* Holds the screen on while the app is in the foreground (released when it ends).
306
+ * [perm: keep_screen_on] */
307
+ void s3w_keep_screen_on(bool on) S3W_IMPORT(s3w_keep_screen_on);
308
+ /* The UI language as a BCP 47 tag ("en", "de", "bn"), like snprintf: writes at most cap bytes
309
+ * including a terminating NUL and returns the tag's length. */
310
+ int s3w_locale(char *buf, int cap) S3W_IMPORT(s3w_locale);
311
+
312
+ /* --- Widgets mode ------------------------------------------------------------------------- */
313
+ /* The app's full-screen root container (black, no padding, scrolls vertically if needed). */
314
+ int s3w_ui_screen(void) S3W_IMPORT(s3w_ui_screen);
315
+ int s3w_ui_label(int parent, const char *text, int len) S3W_IMPORT(s3w_ui_label);
316
+ /* Pill button: S3W_EV_CLICK. */
317
+ int s3w_ui_button(int parent, const char *text, int len) S3W_IMPORT(s3w_ui_button);
318
+ /* Full-size vertical list inset from the round corners. */
319
+ int s3w_ui_list(int parent) S3W_IMPORT(s3w_ui_list);
320
+ /* A tappable row (S3W_EV_CLICK with the row's handle); icon is S3W_ICON_*. */
321
+ int s3w_ui_list_add(int list, int icon, const char *text, int len) S3W_IMPORT(s3w_ui_list_add);
322
+ /* An image from the app's assets. S3W_ERR_NOT_FOUND for now: packages carry assets/ (P8-05), loading them is not done yet. */
323
+ int s3w_ui_image(int parent, const char *asset_path, int len) S3W_IMPORT(s3w_ui_image);
324
+ /* A picture from the device's files (path as in s3w_fs_list): PNG, baseline JPEG or BMP (24 / 32 bit), reduced
325
+ * to fit max_w x max_h px (1..S3W_FILE_IMAGE_MAX_SIDE; aspect kept, never enlarged). The watch decodes it
326
+ * before returning, off the UI task: a PNG or BMP of up to S3W_FILE_IMAGE_MAX_PIXELS, a JPEG of up to
327
+ * S3W_FILE_JPEG_MAX_PIXELS, a file of up to 3 MB, shrunk by at most 16 times; more is S3W_ERR_NO_RESOURCE.
328
+ * S3W_ERR_NOT_FOUND (no such file), S3W_ERR_INVALID (path, size, progressive JPEG, damaged or another format),
329
+ * S3W_ERR_DENIED (not a user place). Returns the widget. api_level 2. [perm: files] */
330
+ int s3w_ui_image_file(int parent, const char *path, int len, int max_w, int max_h) S3W_IMPORT(s3w_ui_image_file);
331
+ /* Progress ring (display only). */
332
+ int s3w_ui_arc(int parent, int min, int max, int value) S3W_IMPORT(s3w_ui_arc);
333
+ /* S3W_EV_VALUE while dragged. */
334
+ int s3w_ui_slider(int parent, int min, int max, int value) S3W_IMPORT(s3w_ui_slider);
335
+ /* S3W_EV_VALUE (0/1) when toggled. */
336
+ int s3w_ui_switch(int parent, bool on) S3W_IMPORT(s3w_ui_switch);
337
+ /* Label or button text. */
338
+ void s3w_ui_set_text(int h, const char *text, int len) S3W_IMPORT(s3w_ui_set_text);
339
+ /* Arc, slider (clamped to their range) or switch (0/1). */
340
+ void s3w_ui_set_value(int h, int v) S3W_IMPORT(s3w_ui_set_value);
341
+ void s3w_ui_set_pos(int h, int x, int y) S3W_IMPORT(s3w_ui_set_pos);
342
+ /* Buttons are at least 160 px wide until their size is set. */
343
+ void s3w_ui_set_size(int h, int w, int hgt) S3W_IMPORT(s3w_ui_set_size);
344
+ /* prop is S3W_STYLE_*; an unknown prop or bad value returns quietly (nothing changes). */
345
+ void s3w_ui_set_style(int h, int prop, int value) S3W_IMPORT(s3w_ui_set_style);
346
+ /* Deletes the widget and its children (their handles die too). Not the screen. */
347
+ void s3w_ui_delete(int h) S3W_IMPORT(s3w_ui_delete);
348
+ void s3w_ui_toast(const char *text, int len) S3W_IMPORT(s3w_ui_toast);
349
+ /* Confirm dialog over the app: S3W_EV_DIALOG with the returned id. One at a time. */
350
+ int s3w_ui_dialog(const char *title, int tl, const char *body, int bl, const char *ok, int ol)
351
+ S3W_IMPORT(s3w_ui_dialog);
352
+
353
+ /* --- Canvas mode -------------------------------------------------------------------------- */
354
+ /* A 410 x 502 RGB565 canvas that keeps its pixels between frames: draw what changed, then call
355
+ * s3w_gfx_present() once. Only the areas drawn since the last present reach the display (dirty
356
+ * rectangles), so small changes are cheap. Coordinates are px from the top left; everything is
357
+ * clipped to the canvas. The canvas starts black. */
358
+
359
+ /* Frames per second for s3w_on_frame, clamped to 1..S3W_GFX_FPS_MAX (default 30). */
360
+ void s3w_gfx_set_fps(int fps) S3W_IMPORT(s3w_gfx_set_fps);
361
+ void s3w_gfx_clear(uint16_t color) S3W_IMPORT(s3w_gfx_clear);
362
+ /* Filled, or a 1 px outline. */
363
+ void s3w_gfx_rect(int x, int y, int w, int h, uint16_t color, bool fill) S3W_IMPORT(s3w_gfx_rect);
364
+ void s3w_gfx_circle(int cx, int cy, int r, uint16_t color, bool fill) S3W_IMPORT(s3w_gfx_circle);
365
+ /* width 1..16 px. */
366
+ void s3w_gfx_line(int x0, int y0, int x1, int y1, uint16_t color, int width) S3W_IMPORT(s3w_gfx_line);
367
+ /* (x, y) is the top left of the first line; '\n' starts a new line. font is S3W_FONT_*. At most
368
+ * 255 bytes of UTF-8. */
369
+ void s3w_gfx_text(int x, int y, const char *t, int len, int font, uint16_t color) S3W_IMPORT(s3w_gfx_text);
370
+ /* Width in px of one line of text in that font (for centring). */
371
+ int s3w_gfx_text_width(const char *t, int len, int font) S3W_IMPORT(s3w_gfx_text_width);
372
+ /* A sprite from RGB565 pixels in app memory (copied: the app may reuse its buffer). frames
373
+ * frames of w x h px are stacked top to bottom (pixels holds w * h * frames values). key is the
374
+ * transparent colour, or S3W_SPRITE_NO_KEY. Returns the sprite id (> 0) or S3W_ERR_INVALID (bad
375
+ * size) / S3W_ERR_NO_RESOURCE (S3W_SPRITE_MAX or S3W_SPRITE_MAX_BYTES reached). */
376
+ int s3w_gfx_sprite_create(const uint16_t *pixels, int w, int h, int frames, int key)
377
+ S3W_IMPORT(s3w_gfx_sprite_create);
378
+ /* A sprite from the app's assets. S3W_ERR_NOT_FOUND for now: packages carry assets/ (P8-05), loading them is not done yet. */
379
+ int s3w_gfx_sprite_load(const char *asset, int len) S3W_IMPORT(s3w_gfx_sprite_load);
380
+ /* Draws frame (0-based) of sprite id with its top left at (x, y); flags S3W_SPRITE_FLIP_*.
381
+ * An unknown id or a frame out of range traps. */
382
+ void s3w_gfx_sprite(int id, int x, int y, int frame, int flags) S3W_IMPORT(s3w_gfx_sprite);
383
+ /* Copies w x h RGB565 pixels (row by row) from app memory. */
384
+ void s3w_gfx_blit(const uint16_t *pixels, int x, int y, int w, int h) S3W_IMPORT(s3w_gfx_blit);
385
+ /* Ends the frame: what was drawn since the last present goes to the display once the current
386
+ * callback returns. */
387
+ void s3w_gfx_present(void) S3W_IMPORT(s3w_gfx_present);
388
+
389
+ /* --- Sensors [perm: imu] ----------------------------------------------------------------- */
390
+ /* Streams the accelerometer as S3W_EV_IMU events at about rate_hz (1..100 asked; the sensor runs
391
+ * at 62.5 Hz) while the app is visible. Returns the rate used. No gyroscope data yet. */
392
+ int s3w_imu_start(int rate_hz) S3W_IMPORT(s3w_imu_start);
393
+ void s3w_imu_stop(void) S3W_IMPORT(s3w_imu_stop);
394
+ /* Pitch and roll in degrees from the latest sample (0, 0 lying face up; pitch > 0: 12 o'clock
395
+ * raised, roll > 0: 3 o'clock raised). Starts the accelerometer if no stream runs (no events
396
+ * then): S3W_ERR_NOT_READY until it has a sample. */
397
+ int s3w_tilt(float *pitch, float *roll) S3W_IMPORT(s3w_tilt);
398
+
399
+ /* --- Audio ------------------------------------------------------------------------------- */
400
+ /* volume 0..100 of the watch's media volume; Silent mutes. [perm: audio.play] */
401
+ /* A tone, freq_hz 20..8000 for ms 1..10000 (replaces the app's tone if one plays). */
402
+ int s3w_audio_tone(int freq_hz, int ms, int volume) S3W_IMPORT(s3w_audio_tone);
403
+ /* A WAV from the app's assets. S3W_ERR_NOT_FOUND for now: packages carry assets/ (P8-05), loading them is not done yet. */
404
+ int s3w_audio_play(const char *asset, int len, int volume) S3W_IMPORT(s3w_audio_play);
405
+ /* 16-bit mono PCM; sample_rate 16000 only (else S3W_ERR_UNSUPPORTED). One stream: returns its
406
+ * handle. The volume is the media volume. */
407
+ int s3w_audio_stream_open(int sample_rate) S3W_IMPORT(s3w_audio_stream_open);
408
+ /* Queues samples without waiting (the buffer holds 1 s); returns how many were taken. */
409
+ int s3w_audio_stream_write(int h, const int16_t *pcm, int samples) S3W_IMPORT(s3w_audio_stream_write);
410
+ /* Stops a stream (its handle), or with 0 the app's tone and stream. */
411
+ void s3w_audio_stop(int h) S3W_IMPORT(s3w_audio_stop);
412
+ /* Microphone [perm: audio.record]: S3W_ERR_UNSUPPORTED until voice support (P7). */
413
+ int s3w_mic_start(int sample_rate) S3W_IMPORT(s3w_mic_start);
414
+ void s3w_mic_stop(void) S3W_IMPORT(s3w_mic_stop);
415
+
416
+ /* --- Storage ----------------------------------------------------------------------------- */
417
+ /* The app's own files: S3W_STORAGE_DEFAULT_KB in all, or the manifest's quota with the "storage"
418
+ * permission (no permission needed). Keys and file names: 1..S3W_NAME_MAX bytes of
419
+ * [A-Za-z0-9._-], not starting with '.' (S3W_ERR_INVALID otherwise). */
420
+ /* The value's length (copies at most cap bytes), or S3W_ERR_NOT_FOUND. */
421
+ int s3w_kv_get(const char *k, int kl, void *buf, int cap) S3W_IMPORT(s3w_kv_get);
422
+ /* vl ≤ S3W_KV_VALUE_MAX. S3W_ERR_NO_SPACE over the quota. */
423
+ int s3w_kv_set(const char *k, int kl, const void *v, int vl) S3W_IMPORT(s3w_kv_set);
424
+ int s3w_kv_delete(const char *k, int kl) S3W_IMPORT(s3w_kv_delete);
425
+ /* mode S3W_FILE_*: returns fd (≥ 1), S3W_ERR_NOT_FOUND (read), S3W_ERR_NO_RESOURCE (4 open). */
426
+ int s3w_file_open(const char *name, int len, int mode) S3W_IMPORT(s3w_file_open);
427
+ /* Bytes read (0 at the end) or written (S3W_ERR_NO_SPACE over the quota). */
428
+ int s3w_file_read(int fd, void *buf, int n) S3W_IMPORT(s3w_file_read);
429
+ int s3w_file_write(int fd, const void *buf, int n) S3W_IMPORT(s3w_file_write);
430
+ void s3w_file_close(int fd) S3W_IMPORT(s3w_file_close);
431
+ int s3w_file_delete(const char *name, int len) S3W_IMPORT(s3w_file_delete);
432
+
433
+ /* --- Device files [perm: files] (api_level 2) --------------------------------------------- */
434
+ /* The watch's own files, not the app's: the internal flash "/flash" and the card "/sd" (only while one is in).
435
+ * Paths are absolute, '/'-separated, without "." or ".." parts, at most S3W_FS_PATH_MAX bytes. "/" lists the
436
+ * roots. All of the card is open; of the flash only the user's data: /flash/memos, /flash/shots and
437
+ * /flash/logs (everything else there is the system's: apps, keys, settings, stores). Other paths in /flash are
438
+ * not listed and give S3W_ERR_DENIED. Names that start with '.' (temporary files) are not listed, and neither
439
+ * is an entry whose name is longer than S3W_FS_NAME_MAX bytes. */
440
+ /* Lists a directory in name order (ASCII letters ignore their case; directories and files together): the
441
+ * entries whose name sorts after `after` (al = 0: from the first), at most max of them. Paging: pass the last
442
+ * name of a page to get the next, so the pages stay right while files come and go. Returns how many were
443
+ * written (0 = past the end), S3W_ERR_NOT_FOUND (no such directory, or no card), S3W_ERR_DENIED,
444
+ * S3W_ERR_INVALID (path, `after` longer than S3W_FS_NAME_MAX, max 1..32). */
445
+ int s3w_fs_list(const char *dir, int dl, const char *after, int al, s3w_fs_entry_t *out, int max)
446
+ S3W_IMPORT(s3w_fs_list);
447
+ /* Deletes a file or an empty directory (one that holds only hidden files, which are not listed, counts as
448
+ * empty and they go with it). S3W_ERR_NOT_FOUND, S3W_ERR_DENIED (not a user place, a root, or a directory with
449
+ * anything else in it), S3W_ERR_IO. */
450
+ int s3w_fs_delete(const char *path, int len) S3W_IMPORT(s3w_fs_delete);
451
+ /* Opens a file for reading; one at a time (S3W_ERR_NO_RESOURCE while another is open). Returns the file's
452
+ * size in bytes (a file over 2 GB: S3W_ERR_INVALID) or S3W_ERR_NOT_FOUND / S3W_ERR_DENIED. Closed with the
453
+ * app. */
454
+ int s3w_fs_open(const char *path, int len) S3W_IMPORT(s3w_fs_open);
455
+ /* Bytes read from the open file (0 at the end), up to n (≤ 4096 per call). S3W_ERR_NOT_READY: none is open. */
456
+ int s3w_fs_read(void *buf, int n) S3W_IMPORT(s3w_fs_read);
457
+ void s3w_fs_close(void) S3W_IMPORT(s3w_fs_close);
458
+
459
+ /* --- Game Boy core [perm: gameboy] (api_level 3, Pro edition) ------------------------------- */
460
+ /* A native emulator for DMG cartridge files on the card (docs/12). The app passes the file's path, the
461
+ * buttons and where to draw; the picture is drawn into the canvas by the firmware (canvas apps only).
462
+ * ROMs must be on the card ("/sd/..."), anywhere else is S3W_ERR_DENIED. The cartridge RAM is kept next to
463
+ * the ROM as "<name>.sav" (portable to PC emulators). One game at a time. */
464
+ /* Lists a folder of the card for the game library: like s3w_fs_list (name order, paging by the last name,
465
+ * at most 32 entries per call), but only folders and cartridge files (.gb, .gbc, any case); anything else
466
+ * is left out. The permission "gameboy" is enough: the app cannot see, read or delete other files.
467
+ * S3W_ERR_DENIED outside "/sd", S3W_ERR_NOT_FOUND (no such folder, or no card). */
468
+ int s3w_gb_list(const char *dir, int dl, const char *after, int al, s3w_fs_entry_t *out, int max)
469
+ S3W_IMPORT(s3w_gb_list);
470
+ /* Reads the header of a cartridge file into `out`. S3W_OK; S3W_ERR_INVALID: damaged header, truncated file
471
+ * (`out` is still filled when the header could be read); S3W_ERR_NOT_FOUND, S3W_ERR_DENIED (not on the
472
+ * card), S3W_ERR_IO. Check `out->supported` before loading. */
473
+ int s3w_gb_probe(const char *path, int len, s3w_gb_info_t *out) S3W_IMPORT(s3w_gb_probe);
474
+ /* Opens the cartridge and its save file and resets the console. S3W_ERR_UNSUPPORTED (mapper, colour-only
475
+ * game), S3W_ERR_INVALID (damaged header, or a save of the wrong size, which is never overwritten),
476
+ * S3W_ERR_NO_RESOURCE (a game is already loaded, or out of memory), S3W_ERR_IO. */
477
+ int s3w_gb_load(const char *path, int len) S3W_IMPORT(s3w_gb_load);
478
+ /* Writes the cartridge RAM if it changed and closes the game (also done when the app ends).
479
+ * S3W_ERR_NOT_READY: nothing loaded; S3W_ERR_IO: the save could not be written. */
480
+ int s3w_gb_unload(void) S3W_IMPORT(s3w_gb_unload);
481
+ /* The buttons held now (S3W_GB_* or-ed together); stays until the next call. */
482
+ void s3w_gb_input(uint32_t buttons) S3W_IMPORT(s3w_gb_input);
483
+ /* Runs the console for one video frame (1/59.7 s) and draws it with its top left at (x, y) of the canvas at
484
+ * scale S3W_GB_SCALE_*: 160x144, 320x288 or 400x360 px. The whole picture must lie inside the canvas
485
+ * (S3W_ERR_INVALID). Only the lines that changed since the last call that drew are written to the canvas
486
+ * and marked as drawn (a still screen costs next to nothing); present as usual (s3w_gfx_present). After you
487
+ * draw over the picture (a menu) pass S3W_GB_REDRAW; moving it, changing the scale or the palette redraws it
488
+ * by itself. S3W_GB_NO_DRAW emulates the frame without drawing: when the display cannot keep up, run the
489
+ * missed frames this way and draw only the last, so the game keeps its speed (the app paces: dt_ms of
490
+ * s3w_on_frame / 16.74 ms per frame). Returns the milliseconds it took, S3W_ERR_NOT_READY (nothing loaded, or
491
+ * drawing without a canvas), S3W_ERR_IO (the card failed mid-game: stop), S3W_ERR_UNSUPPORTED (the game did
492
+ * something the core cannot do). */
493
+ int s3w_gb_run_frame(int x, int y, int scale, uint32_t flags) S3W_IMPORT(s3w_gb_run_frame);
494
+ /* Writes the cartridge RAM now if it changed. */
495
+ int s3w_gb_flush_ram(void) S3W_IMPORT(s3w_gb_flush_ram);
496
+ /* The four shades from lightest to darkest, RGB565 (default: white to black). */
497
+ int s3w_gb_set_palette(const uint16_t *pal) S3W_IMPORT(s3w_gb_set_palette);
498
+ /* Save states: the whole console in "<game>.st<slot>" next to the ROM (slot 0..3; the card, not the flash).
499
+ * s3w_gb_save_state writes it atomically; s3w_gb_load_state puts the console back (the next frame is drawn in
500
+ * full). Errors: S3W_ERR_NOT_READY (nothing loaded), S3W_ERR_INVALID (slot, or a file that is not a state of this
501
+ * game and this firmware's core, or damaged: the console is left as it was), S3W_ERR_NOT_FOUND (load: no such
502
+ * state), S3W_ERR_IO. A state does not survive a firmware update that changes the core. */
503
+ int s3w_gb_save_state(int slot) S3W_IMPORT(s3w_gb_save_state);
504
+ int s3w_gb_load_state(int slot) S3W_IMPORT(s3w_gb_load_state);
505
+ /* The console's sound: on = true opens the 16 kHz PCM stream (the one s3w_audio_stream_open uses: one at a time,
506
+ * S3W_ERR_NO_RESOURCE while the app has its own open) and from then on every frame run by s3w_gb_run_frame, drawn
507
+ * or not, adds its sound (mono, volume 0..100 of full); false closes it. Calling again with on = true only changes
508
+ * the volume. Needs "audio.play" as well as "gameboy". Sound that is more than about 150 ms ahead of the speaker
509
+ * is dropped, so the picture can fall behind without the sound lagging. Muted by the watch's Silent mode like any
510
+ * stream. S3W_ERR_UNSUPPORTED: no audio on this watch. The sound registers follow the game whether or not sound is
511
+ * on, and switching it on mid-game plays what is playing. [perm: gameboy, audio.play] */
512
+ int s3w_gb_set_audio(bool on, int volume) S3W_IMPORT(s3w_gb_set_audio);
513
+
514
+ /* --- Health [perm: health.read] ---------------------------------------------------------- */
515
+ /* S3W_ERR_UNSUPPORTED until activity tracking exists (P5). */
516
+ int s3w_health_today(s3w_health_summary_t *out) S3W_IMPORT(s3w_health_today);
517
+
518
+ /* --- Network [perm: phone.http or wifi.http] --------------------------------------------- */
519
+ typedef struct {
520
+ int32_t method; /* S3W_HTTP_GET / S3W_HTTP_POST */
521
+ const char *url; /* http:// or https://, ≤ S3W_HTTP_URL_MAX bytes; its host must be */
522
+ int32_t url_len; /* in the manifest's allowlist (S3W_ERR_DENIED otherwise) */
523
+ const char *content_type; /* POST */
524
+ int32_t content_type_len;
525
+ const void *body; /* POST, ≤ S3W_HTTP_BODY_MAX bytes */
526
+ int32_t body_len;
527
+ void *resp; /* the response body goes here: keep it until S3W_EV_HTTP */
528
+ int32_t resp_cap; /* 0..S3W_HTTP_RESP_MAX */
529
+ } s3w_http_req_t; /* 36 bytes */
530
+ /* Through the phone (Wi-Fi comes with P9). Returns the request id (S3W_EV_HTTP follows),
531
+ * S3W_ERR_NOT_READY (no phone), S3W_ERR_NO_RESOURCE (S3W_HTTP_MAX running). */
532
+ int s3w_http_request(const s3w_http_req_t *req) S3W_IMPORT(s3w_http_request);
533
+
534
+ /* --- Notifications [perm: notify] -------------------------------------------------------- */
535
+ /* A notification from the app (at most one every 10 s: S3W_ERR_NO_RESOURCE). */
536
+ int s3w_notify(const char *title, int tl, const char *body, int bl) S3W_IMPORT(s3w_notify);
537
+
538
+ /* --- Game services ----------------------------------------------------------------------- */
539
+ /* Records score on board (0..S3W_HIGHSCORE_BOARDS - 1) if it beats the best: higher wins, or
540
+ * lower with S3W_HIGHSCORE_LOWER (times). Kept in the app's storage (not counted in its quota),
541
+ * so it survives restarts and updates. Returns 1 for a new best, 0 if not, or S3W_ERR_*. */
542
+ int s3w_highscore_submit(int board, int score) S3W_IMPORT(s3w_highscore_submit);
543
+ /* The board's best: S3W_OK with *best, or S3W_ERR_NOT_FOUND before the first score. */
544
+ int s3w_highscore_get(int board, int *best) S3W_IMPORT(s3w_highscore_get);
545
+ /* A random number 0..0x7FFFFFFF (the watch's hardware RNG). */
546
+ int s3w_random(void) S3W_IMPORT(s3w_random);
547
+
548
+ #endif /* __wasm__ */
549
+
550
+ #ifdef __cplusplus
551
+ }
552
+ #endif
553
+
554
+ #endif /* S3W_H */
@@ -0,0 +1,10 @@
1
+ # Rust SDK
2
+
3
+ - `s3w-sys`: raw bindings, generated from `sdk/include/s3w.h` by `s3w-sys/gen.py` (do not edit `src/lib.rs`;
4
+ re-run the script after changing the header — the CLI tests check it is fresh).
5
+ - `s3w`: safe wrappers for the common parts (log, time, timers, widgets, canvas, key-value storage, game services, events),
6
+ the panic handler and the `s3w::export_event_buf!()` macro every app calls once. Anything else: `s3w::sys`.
7
+
8
+ Apps are `no_std` `cdylib`s for `wasm32-unknown-unknown` (`rustup target add wasm32-unknown-unknown`), built by
9
+ `s3w build` (`sdk/tools/s3w-cli`), which passes `-C target-cpu=mvp` plus the features WAMR supports: the watch's
10
+ runtime has no reference types, which rustc enables by default. Start from `s3w new <dir> --lang rust`.
@@ -0,0 +1,14 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "s3w"
7
+ version = "0.1.0"
8
+ dependencies = [
9
+ "s3w-sys",
10
+ ]
11
+
12
+ [[package]]
13
+ name = "s3w-sys"
14
+ version = "0.1.0"