@typecad/framework-zephyr 1.0.0-alpha.8
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.
- package/LICENSE +21 -0
- package/README.md +100 -0
- package/dist/async/timer-polyfill.d.ts +10 -0
- package/dist/async/timer-polyfill.js +95 -0
- package/dist/chips/controllers.d.ts +21 -0
- package/dist/chips/controllers.js +66 -0
- package/dist/chips/esp32.d.ts +2 -0
- package/dist/chips/esp32.js +59 -0
- package/dist/chips/esp32s3.d.ts +2 -0
- package/dist/chips/esp32s3.js +54 -0
- package/dist/chips/index.d.ts +15 -0
- package/dist/chips/index.js +45 -0
- package/dist/chips/resolve.d.ts +9 -0
- package/dist/chips/resolve.js +121 -0
- package/dist/chips/types.d.ts +154 -0
- package/dist/chips/types.js +14 -0
- package/dist/chips/xiao-ble.d.ts +2 -0
- package/dist/chips/xiao-ble.js +61 -0
- package/dist/debug-codegen.d.ts +33 -0
- package/dist/debug-codegen.js +162 -0
- package/dist/display/gfx.d.ts +17 -0
- package/dist/display/gfx.js +171 -0
- package/dist/display/index.d.ts +20 -0
- package/dist/display/index.js +53 -0
- package/dist/display/profiles.d.ts +25 -0
- package/dist/display/profiles.js +41 -0
- package/dist/display/touch-adapter.d.ts +9 -0
- package/dist/display/touch-adapter.js +95 -0
- package/dist/display/ui-adapter.d.ts +21 -0
- package/dist/display/ui-adapter.js +534 -0
- package/dist/dt-config/kconfig.d.ts +27 -0
- package/dist/dt-config/kconfig.js +283 -0
- package/dist/dt-config/overlay.d.ts +35 -0
- package/dist/dt-config/overlay.js +246 -0
- package/dist/framework.manifest.d.ts +98 -0
- package/dist/framework.manifest.js +525 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +12 -0
- package/dist/lowering/adc.d.ts +19 -0
- package/dist/lowering/adc.js +76 -0
- package/dist/lowering/ble.d.ts +20 -0
- package/dist/lowering/ble.js +419 -0
- package/dist/lowering/board.d.ts +9 -0
- package/dist/lowering/board.js +33 -0
- package/dist/lowering/gpio.d.ts +12 -0
- package/dist/lowering/gpio.js +123 -0
- package/dist/lowering/http.d.ts +23 -0
- package/dist/lowering/http.js +482 -0
- package/dist/lowering/i2c.d.ts +15 -0
- package/dist/lowering/i2c.js +114 -0
- package/dist/lowering/index.d.ts +29 -0
- package/dist/lowering/index.js +93 -0
- package/dist/lowering/interrupts.d.ts +21 -0
- package/dist/lowering/interrupts.js +91 -0
- package/dist/lowering/mqtt.d.ts +19 -0
- package/dist/lowering/mqtt.js +366 -0
- package/dist/lowering/power.d.ts +9 -0
- package/dist/lowering/power.js +64 -0
- package/dist/lowering/preferences.d.ts +23 -0
- package/dist/lowering/preferences.js +345 -0
- package/dist/lowering/pulse.d.ts +7 -0
- package/dist/lowering/pulse.js +82 -0
- package/dist/lowering/pwm.d.ts +15 -0
- package/dist/lowering/pwm.js +59 -0
- package/dist/lowering/random.d.ts +18 -0
- package/dist/lowering/random.js +129 -0
- package/dist/lowering/spi.d.ts +17 -0
- package/dist/lowering/spi.js +113 -0
- package/dist/lowering/timing.d.ts +9 -0
- package/dist/lowering/timing.js +63 -0
- package/dist/lowering/tone.d.ts +10 -0
- package/dist/lowering/tone.js +50 -0
- package/dist/lowering/uart.d.ts +15 -0
- package/dist/lowering/uart.js +102 -0
- package/dist/lowering/util.d.ts +4 -0
- package/dist/lowering/util.js +12 -0
- package/dist/lowering/wdt.d.ts +15 -0
- package/dist/lowering/wdt.js +80 -0
- package/dist/lowering/wifi.d.ts +21 -0
- package/dist/lowering/wifi.js +447 -0
- package/dist/lowering/worker-backing.d.ts +14 -0
- package/dist/lowering/worker-backing.js +79 -0
- package/dist/lowering/worker.d.ts +6 -0
- package/dist/lowering/worker.js +14 -0
- package/dist/strategy.d.ts +168 -0
- package/dist/strategy.js +1094 -0
- package/dist/toolchain/debug-config.d.ts +82 -0
- package/dist/toolchain/debug-config.js +359 -0
- package/dist/toolchain/index.d.ts +73 -0
- package/dist/toolchain/index.js +427 -0
- package/dist/toolchain/scaffold.d.ts +15 -0
- package/dist/toolchain/scaffold.js +196 -0
- package/dist/toolchain/west-discover.d.ts +40 -0
- package/dist/toolchain/west-discover.js +203 -0
- package/dist/toolchain/west-spawn.d.ts +39 -0
- package/dist/toolchain/west-spawn.js +117 -0
- package/package.json +82 -0
- package/src/async/timer-polyfill.ts +107 -0
- package/src/chips/controllers.ts +74 -0
- package/src/chips/esp32.ts +62 -0
- package/src/chips/esp32s3.ts +57 -0
- package/src/chips/index.ts +54 -0
- package/src/chips/resolve.ts +146 -0
- package/src/chips/types.ts +163 -0
- package/src/chips/xiao-ble.ts +64 -0
- package/src/debug-codegen.ts +207 -0
- package/src/display/gfx.ts +190 -0
- package/src/display/index.ts +70 -0
- package/src/display/profiles.ts +63 -0
- package/src/display/touch-adapter.ts +100 -0
- package/src/display/ui-adapter.ts +558 -0
- package/src/dt-config/kconfig.ts +308 -0
- package/src/dt-config/overlay.ts +293 -0
- package/src/framework.manifest.ts +545 -0
- package/src/index.ts +23 -0
- package/src/lowering/adc.ts +102 -0
- package/src/lowering/ble.ts +426 -0
- package/src/lowering/board.ts +38 -0
- package/src/lowering/gpio.ts +148 -0
- package/src/lowering/http.ts +488 -0
- package/src/lowering/i2c.ts +126 -0
- package/src/lowering/index.ts +86 -0
- package/src/lowering/interrupts.ts +114 -0
- package/src/lowering/mqtt.ts +371 -0
- package/src/lowering/power.ts +70 -0
- package/src/lowering/preferences.ts +354 -0
- package/src/lowering/pulse.ts +93 -0
- package/src/lowering/pwm.ts +74 -0
- package/src/lowering/random.ts +135 -0
- package/src/lowering/spi.ts +124 -0
- package/src/lowering/timing.ts +72 -0
- package/src/lowering/tone.ts +60 -0
- package/src/lowering/uart.ts +111 -0
- package/src/lowering/util.ts +12 -0
- package/src/lowering/wdt.ts +84 -0
- package/src/lowering/wifi.ts +452 -0
- package/src/lowering/worker-backing.ts +94 -0
- package/src/lowering/worker.ts +17 -0
- package/src/strategy.ts +1265 -0
- package/src/toolchain/debug-config.ts +399 -0
- package/src/toolchain/index.ts +459 -0
- package/src/toolchain/scaffold.ts +196 -0
- package/src/toolchain/west-discover.ts +233 -0
- package/src/toolchain/west-spawn.ts +141 -0
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// BLE lowering — Zephyr NimBLE GATT peripheral (runtime service registration)
|
|
3
|
+
//
|
|
4
|
+
// Ports the ESP32 shim architecture (framework-esp32/src/lowering/ble.ts) to
|
|
5
|
+
// Zephyr's bt_* GATT API. The HAL surface is an Arduino-bluedroid-style runtime
|
|
6
|
+
// GATT builder (add_service → add_char → on_read/on_write → advertise), which
|
|
7
|
+
// doesn't match Zephyr's idiomatic compile-time BT_GATT_SERVICE_DEFINE macro.
|
|
8
|
+
// Instead we use the runtime path: bt_gatt_service_register with a flat
|
|
9
|
+
// bt_gatt_attr[] array built at server_begin time from the deferred graph.
|
|
10
|
+
//
|
|
11
|
+
// Key Zephyr differences from the ESP32 NimBLE port (verified against the
|
|
12
|
+
// local SDK headers):
|
|
13
|
+
// - Flat bt_gatt_attr[] (1 svc + 2-per-char + 1 CCC-per-notify) not a tree.
|
|
14
|
+
// - BT_GATT_CHRC_READ/WRITE/NOTIFY (no _F_ suffix).
|
|
15
|
+
// - read/write are bt_gatt_attr_read_func_t/_write_func_t (ssize_t return,
|
|
16
|
+
// per-attr, not a single access_cb). Recover the char index from attr->user_data.
|
|
17
|
+
// - connect/disconnect via struct bt_conn_cb, not a GAP event handler.
|
|
18
|
+
// - bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ...) — no BT_LE_ADV_CONN.
|
|
19
|
+
// - bt_enable(NULL) is synchronous (no host task).
|
|
20
|
+
// - Register the service BEFORE bt_enable(NULL) (the supported timing window).
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
/**
|
|
23
|
+
* The BLE runtime shim. All helpers are `static` (file-scope) so unused ones
|
|
24
|
+
* don't trip -Wunused-function in the single generated TU.
|
|
25
|
+
*
|
|
26
|
+
* State mirrors the HAL BleStatus enum:
|
|
27
|
+
* 0 Idle, 1 Initializing, 2 Advertising, 3 Connected, 4 Error.
|
|
28
|
+
*/
|
|
29
|
+
export function bleInitLines() {
|
|
30
|
+
return [
|
|
31
|
+
`// CUTTLEFISH_BLE_BEGIN`,
|
|
32
|
+
`#define __TC_BLE_MAX_CHARS 16`,
|
|
33
|
+
`#define __TC_BLE_MAX_SVCS 8`,
|
|
34
|
+
`// Max attrs: per service (1 primary) + per char (2) + per notify char (1 CCC).`,
|
|
35
|
+
`// Worst case: all chars in one service, all notify: 1 + 2*16 + 16 = 49.`,
|
|
36
|
+
`#define __TC_BLE_MAX_ATTRS (1 + (2 * __TC_BLE_MAX_CHARS) + __TC_BLE_MAX_CHARS)`,
|
|
37
|
+
``,
|
|
38
|
+
`// Read handlers are stored as void* and cast based on the char's type.`,
|
|
39
|
+
`typedef int (*__tc_ble_read_int_cb_t)(void);`,
|
|
40
|
+
`typedef double (*__tc_ble_read_dbl_cb_t)(void);`,
|
|
41
|
+
`typedef const char* (*__tc_ble_read_str_cb_t)(void);`,
|
|
42
|
+
// The write callback takes double, not int: hoisted TS handlers have
|
|
43
|
+
// signature (value: number) => void, and the transpiler maps `number` to
|
|
44
|
+
// double. Typing the slot as (int) and assigning a (double) handler is the
|
|
45
|
+
// inverse of the double-vs-int UB called out for read handlers below (an
|
|
46
|
+
// int passed in r0 is read as a double across r0:r1). cb_val (int) promotes
|
|
47
|
+
// to double at the call — clean, no precision loss for GATT-scale values.
|
|
48
|
+
`typedef void (*__tc_ble_write_cb_t)(double value);`,
|
|
49
|
+
`typedef void (*__tc_ble_event_cb_t)(void);`,
|
|
50
|
+
``,
|
|
51
|
+
`// Deferred characteristic definition (populated before __tc_ble_server_begin).`,
|
|
52
|
+
`typedef struct {`,
|
|
53
|
+
` const char* uuid_str; // raw UUID string ("2A6E" or full 128-bit)`,
|
|
54
|
+
` bool uuid_is_128;`,
|
|
55
|
+
` int perms; // bitmask: READ=1, WRITE=2, NOTIFY=4`,
|
|
56
|
+
` int svc_index;`,
|
|
57
|
+
` const char* type; // value type: "int16", "uint8", "float32", "utf8", etc.`,
|
|
58
|
+
`} __tc_ble_char_def_t;`,
|
|
59
|
+
``,
|
|
60
|
+
`static struct {`,
|
|
61
|
+
` int status; // BleStatus enum`,
|
|
62
|
+
` bool inited;`,
|
|
63
|
+
` bool advertising;`,
|
|
64
|
+
` int connected_clients;`,
|
|
65
|
+
` struct bt_conn* conn; // active connection (NULL = none)`,
|
|
66
|
+
` uint16_t svc_count;`,
|
|
67
|
+
` int current_char; // set by add_char, read by on_read/on_write`,
|
|
68
|
+
` void* on_read[__TC_BLE_MAX_CHARS]; // typed fn pointer, cast by char type`,
|
|
69
|
+
` __tc_ble_write_cb_t on_write[__TC_BLE_MAX_CHARS];`,
|
|
70
|
+
` // value-attr index per char (the 2nd attr of BT_GATT_CHARACTERISTIC),`,
|
|
71
|
+
` // used by notify to pass the registered attr to bt_gatt_notify.`,
|
|
72
|
+
` int val_attr_idx[__TC_BLE_MAX_CHARS];`,
|
|
73
|
+
` __tc_ble_event_cb_t on_connect;`,
|
|
74
|
+
` __tc_ble_event_cb_t on_disconnect;`,
|
|
75
|
+
` char name[32];`,
|
|
76
|
+
`} __tc_ble = { 0, false, false, 0, NULL, 0, 0, {}, {}, {}, NULL, NULL, {} };`,
|
|
77
|
+
``,
|
|
78
|
+
`static __tc_ble_char_def_t __tc_ble_char_defs[__TC_BLE_MAX_CHARS];`,
|
|
79
|
+
`static int __tc_ble_char_count = 0;`,
|
|
80
|
+
`static const char* __tc_ble_svc_uuids[__TC_BLE_MAX_SVCS];`,
|
|
81
|
+
``,
|
|
82
|
+
`// Static pools for the synthesized GATT attribute table.`,
|
|
83
|
+
`// UUID objects + the attr array must persist for the lifetime of the stack.`,
|
|
84
|
+
`static struct bt_uuid_16 __tc_ble_svc_uuid16_objs[__TC_BLE_MAX_SVCS];`,
|
|
85
|
+
`static struct bt_uuid_128 __tc_ble_svc_uuid128_objs[__TC_BLE_MAX_SVCS];`,
|
|
86
|
+
`static struct bt_uuid_16 __tc_ble_chr_uuid16_objs[__TC_BLE_MAX_CHARS];`,
|
|
87
|
+
`static struct bt_uuid_128 __tc_ble_chr_uuid128_objs[__TC_BLE_MAX_CHARS];`,
|
|
88
|
+
`// bt_gatt_chrc metadata for each characteristic declaration attr.`,
|
|
89
|
+
`static struct bt_gatt_chrc __tc_ble_chrc_meta[__TC_BLE_MAX_CHARS];`,
|
|
90
|
+
`// The flat attribute array + its wrapping service. Plus per-char CCC cfg.`,
|
|
91
|
+
`static struct bt_gatt_attr __tc_ble_attrs[__TC_BLE_MAX_ATTRS];`,
|
|
92
|
+
`static size_t __tc_ble_attr_count = 0;`,
|
|
93
|
+
`static struct bt_gatt_service __tc_ble_svc;`,
|
|
94
|
+
``,
|
|
95
|
+
`// ── UUID helpers ──`,
|
|
96
|
+
`static bool __tc_ble_uuid_is_128(const char* s) { return strchr(s, '-') != NULL; }`,
|
|
97
|
+
``,
|
|
98
|
+
`// Parse a canonical "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" into the 16-byte`,
|
|
99
|
+
`// little-endian val array of bt_uuid_128 (Bluetooth Core Spec LE byte order).`,
|
|
100
|
+
`static void __tc_ble_uuid128_parse(uint8_t* value, const char* u) {`,
|
|
101
|
+
` int bi = 0;`,
|
|
102
|
+
` for (int i = 0; u[i] && bi < 16; i++) {`,
|
|
103
|
+
` if (u[i] == '-') continue;`,
|
|
104
|
+
` char hex[3] = {u[i], u[i+1], 0};`,
|
|
105
|
+
` value[15 - bi] = static_cast<uint8_t>(strtol(hex, NULL, 16));`,
|
|
106
|
+
` bi++;`,
|
|
107
|
+
` i++;`,
|
|
108
|
+
` }`,
|
|
109
|
+
`}`,
|
|
110
|
+
``,
|
|
111
|
+
`static const struct bt_uuid* __tc_ble_make_svc_uuid(int s) {`,
|
|
112
|
+
` const char* u = __tc_ble_svc_uuids[s];`,
|
|
113
|
+
` if (__tc_ble_uuid_is_128(u)) {`,
|
|
114
|
+
` __tc_ble_svc_uuid128_objs[s].uuid.type = BT_UUID_TYPE_128;`,
|
|
115
|
+
` __tc_ble_uuid128_parse(__tc_ble_svc_uuid128_objs[s].val, u);`,
|
|
116
|
+
` return &__tc_ble_svc_uuid128_objs[s].uuid;`,
|
|
117
|
+
` }`,
|
|
118
|
+
` __tc_ble_svc_uuid16_objs[s].uuid.type = BT_UUID_TYPE_16;`,
|
|
119
|
+
` __tc_ble_svc_uuid16_objs[s].val = static_cast<uint16_t>(strtol(u, NULL, 16));`,
|
|
120
|
+
` return &__tc_ble_svc_uuid16_objs[s].uuid;`,
|
|
121
|
+
`}`,
|
|
122
|
+
``,
|
|
123
|
+
`static const struct bt_uuid* __tc_ble_make_chr_uuid(int c) {`,
|
|
124
|
+
` const char* u = __tc_ble_char_defs[c].uuid_str;`,
|
|
125
|
+
` if (__tc_ble_char_defs[c].uuid_is_128) {`,
|
|
126
|
+
` __tc_ble_chr_uuid128_objs[c].uuid.type = BT_UUID_TYPE_128;`,
|
|
127
|
+
` __tc_ble_uuid128_parse(__tc_ble_chr_uuid128_objs[c].val, u);`,
|
|
128
|
+
` return &__tc_ble_chr_uuid128_objs[c].uuid;`,
|
|
129
|
+
` }`,
|
|
130
|
+
` __tc_ble_chr_uuid16_objs[c].uuid.type = BT_UUID_TYPE_16;`,
|
|
131
|
+
` __tc_ble_chr_uuid16_objs[c].val = static_cast<uint16_t>(strtol(u, NULL, 16));`,
|
|
132
|
+
` return &__tc_ble_chr_uuid16_objs[c].uuid;`,
|
|
133
|
+
`}`,
|
|
134
|
+
``,
|
|
135
|
+
`// ── GATT read/write dispatchers ──`,
|
|
136
|
+
`// A single pair registered as every value-attribute's read/write callback.`,
|
|
137
|
+
`// The char index is recovered from attr->user_data (set during table build).`,
|
|
138
|
+
`static ssize_t __tc_ble_attr_read(struct bt_conn* conn, const struct bt_gatt_attr* attr,`,
|
|
139
|
+
` void* buf, uint16_t len, uint16_t offset) {`,
|
|
140
|
+
` (void)conn; (void)len;`,
|
|
141
|
+
` int idx = attr && attr->user_data ? static_cast<int>(reinterpret_cast<intptr_t>(attr->user_data)) : 0;`,
|
|
142
|
+
` if (idx < 0 || idx >= __TC_BLE_MAX_CHARS || !__tc_ble.on_read[idx]) return 0;`,
|
|
143
|
+
` const char* t = __tc_ble_char_defs[idx].type;`,
|
|
144
|
+
` if (t && strcmp(t, "utf8") == 0) {`,
|
|
145
|
+
` const char* s_c = reinterpret_cast<const char*(*)(void)>(__tc_ble.on_read[idx])();`,
|
|
146
|
+
` return bt_gatt_attr_read(conn, attr, buf, len, offset, s_c, strlen(s_c));`,
|
|
147
|
+
` } else if (t && strcmp(t, "float32") == 0) {`,
|
|
148
|
+
` double d = reinterpret_cast<double(*)(void)>(__tc_ble.on_read[idx])();`,
|
|
149
|
+
` float f = static_cast<float>(d);`,
|
|
150
|
+
` return bt_gatt_attr_read(conn, attr, buf, len, offset, &f, sizeof(f));`,
|
|
151
|
+
` } else if (t && strcmp(t, "uint32") == 0) {`,
|
|
152
|
+
` // Hoisted read callbacks return double (TS number -> C++ double).`,
|
|
153
|
+
` // Calling a double-returning fn through an int-returning pointer is`,
|
|
154
|
+
` // UB: on ARM the low word of the double in r0:r1 is 0 for small`,
|
|
155
|
+
` // temperatures, so every read came back 0 (nRF Connect: 0.0C).`,
|
|
156
|
+
` double dv = reinterpret_cast<double(*)(void)>(__tc_ble.on_read[idx])();`,
|
|
157
|
+
` uint32_t u = static_cast<uint32_t>(dv);`,
|
|
158
|
+
` return bt_gatt_attr_read(conn, attr, buf, len, offset, &u, sizeof(u));`,
|
|
159
|
+
` } else if (t && strcmp(t, "boolean") == 0) {`,
|
|
160
|
+
` double dv = reinterpret_cast<double(*)(void)>(__tc_ble.on_read[idx])();`,
|
|
161
|
+
` uint8_t b = dv != 0 ? 1 : 0;`,
|
|
162
|
+
` return bt_gatt_attr_read(conn, attr, buf, len, offset, &b, sizeof(b));`,
|
|
163
|
+
` }`,
|
|
164
|
+
` // uint8/16, int8/16/32 → int16 default.`,
|
|
165
|
+
` double dv = reinterpret_cast<double(*)(void)>(__tc_ble.on_read[idx])();`,
|
|
166
|
+
` int16_t s16 = static_cast<int16_t>(dv);`,
|
|
167
|
+
` return bt_gatt_attr_read(conn, attr, buf, len, offset, &s16, sizeof(s16));`,
|
|
168
|
+
`}`,
|
|
169
|
+
``,
|
|
170
|
+
`static ssize_t __tc_ble_attr_write(struct bt_conn* conn, const struct bt_gatt_attr* attr,`,
|
|
171
|
+
` const void* buf, uint16_t len, uint16_t offset, uint8_t flags) {`,
|
|
172
|
+
` (void)conn; (void)offset; (void)flags;`,
|
|
173
|
+
` int idx = attr && attr->user_data ? static_cast<int>((intptr_t)attr->user_data) : 0;`,
|
|
174
|
+
` if (idx < 0 || idx >= __TC_BLE_MAX_CHARS || !__tc_ble.on_write[idx]) return len;`,
|
|
175
|
+
` const char* wt = __tc_ble_char_defs[idx].type;`,
|
|
176
|
+
` const uint8_t* data = static_cast<const uint8_t*>(buf);`,
|
|
177
|
+
` int cb_val = 0;`,
|
|
178
|
+
` if (wt && strcmp(wt, "utf8") == 0) {`,
|
|
179
|
+
` cb_val = (len >= 1) ? data[0] : 0;`,
|
|
180
|
+
` } else if (wt && strcmp(wt, "uint32") == 0) {`,
|
|
181
|
+
` uint32_t u = 0;`,
|
|
182
|
+
` if (len >= sizeof(u)) memcpy(&u, data, sizeof(u));`,
|
|
183
|
+
` cb_val = static_cast<int>(u);`,
|
|
184
|
+
` } else if (wt && strcmp(wt, "float32") == 0) {`,
|
|
185
|
+
` float f = 0;`,
|
|
186
|
+
` if (len >= sizeof(f)) memcpy(&f, data, sizeof(f));`,
|
|
187
|
+
` cb_val = static_cast<int>(f);`,
|
|
188
|
+
` } else {`,
|
|
189
|
+
` int16_t s16 = 0;`,
|
|
190
|
+
` if (len >= sizeof(s16)) memcpy(&s16, data, sizeof(s16));`,
|
|
191
|
+
` cb_val = s16;`,
|
|
192
|
+
` }`,
|
|
193
|
+
` __tc_ble.on_write[idx](cb_val);`,
|
|
194
|
+
` return len;`,
|
|
195
|
+
`}`,
|
|
196
|
+
``,
|
|
197
|
+
`// ── Connect/disconnect callbacks ──`,
|
|
198
|
+
`static void __tc_ble_connected(struct bt_conn* conn, uint8_t err) {`,
|
|
199
|
+
` if (err == 0) {`,
|
|
200
|
+
` __tc_ble.conn = bt_conn_ref(conn);`,
|
|
201
|
+
` __tc_ble.connected_clients = __tc_ble.connected_clients + 1;`,
|
|
202
|
+
` __tc_ble.status = 3; // Connected`,
|
|
203
|
+
` if (__tc_ble.on_connect) __tc_ble.on_connect();`,
|
|
204
|
+
` }`,
|
|
205
|
+
`}`,
|
|
206
|
+
`static void __tc_ble_disconnected(struct bt_conn* conn, uint8_t reason) {`,
|
|
207
|
+
` (void)reason;`,
|
|
208
|
+
` if (__tc_ble.conn) { bt_conn_unref(__tc_ble.conn); __tc_ble.conn = NULL; }`,
|
|
209
|
+
` if (__tc_ble.on_disconnect) __tc_ble.on_disconnect();`,
|
|
210
|
+
` __tc_ble.connected_clients = __tc_ble.connected_clients > 0 ? __tc_ble.connected_clients - 1 : 0;`,
|
|
211
|
+
` __tc_ble.status = 2; // Advertising`,
|
|
212
|
+
`}`,
|
|
213
|
+
`static struct bt_conn_cb __tc_ble_conn_cb = {`,
|
|
214
|
+
` .connected = __tc_ble_connected,`,
|
|
215
|
+
` .disconnected = __tc_ble_disconnected,`,
|
|
216
|
+
`};`,
|
|
217
|
+
``,
|
|
218
|
+
`// ── Advertising ──`,
|
|
219
|
+
`static void __tc_ble_advertise_start(void) {`,
|
|
220
|
+
` if (!__tc_ble.inited) return;`,
|
|
221
|
+
` const char* n = __tc_ble.name[0] ? __tc_ble.name : "TypeCAD";`,
|
|
222
|
+
` size_t nlen = strlen(n);`,
|
|
223
|
+
` struct bt_data ad[2];`,
|
|
224
|
+
` ad[0].type = BT_DATA_FLAGS;`,
|
|
225
|
+
` ad[0].data_len = 1;`,
|
|
226
|
+
` static const uint8_t __tc_ble_flags = (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR);`,
|
|
227
|
+
` ad[0].data = &__tc_ble_flags;`,
|
|
228
|
+
` ad[1].type = BT_DATA_NAME_COMPLETE;`,
|
|
229
|
+
` ad[1].data_len = static_cast<uint8_t>(nlen > 255 ? 255 : nlen);`,
|
|
230
|
+
` ad[1].data = reinterpret_cast<const uint8_t*>(n);`,
|
|
231
|
+
` int rc = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ad, 2, NULL, 0);`,
|
|
232
|
+
` if (rc != 0 && rc != -EALREADY && rc != -EBUSY) { printk("ble adv_start rc=%d\\n", rc); }`,
|
|
233
|
+
` __tc_ble.advertising = true;`,
|
|
234
|
+
` __tc_ble.status = 2;`,
|
|
235
|
+
`}`,
|
|
236
|
+
``,
|
|
237
|
+
`static void __tc_ble_advertise_stop(void) {`,
|
|
238
|
+
` bt_le_adv_stop();`,
|
|
239
|
+
` __tc_ble.advertising = false;`,
|
|
240
|
+
`}`,
|
|
241
|
+
``,
|
|
242
|
+
`// ── Deferred graph builders ──`,
|
|
243
|
+
`static void __tc_ble_add_service(const char* uuid_str) {`,
|
|
244
|
+
` if (__tc_ble.svc_count < __TC_BLE_MAX_SVCS) {`,
|
|
245
|
+
` __tc_ble_svc_uuids[__tc_ble.svc_count] = uuid_str;`,
|
|
246
|
+
` __tc_ble.svc_count++;`,
|
|
247
|
+
` }`,
|
|
248
|
+
`}`,
|
|
249
|
+
``,
|
|
250
|
+
`static void __tc_ble_add_char(int idx, const char* uuid_str, const char* type, int perms, int svc_index) {`,
|
|
251
|
+
` if (idx < 0 || idx >= __TC_BLE_MAX_CHARS) return;`,
|
|
252
|
+
` __tc_ble_char_defs[idx].uuid_str = uuid_str;`,
|
|
253
|
+
` __tc_ble_char_defs[idx].uuid_is_128 = __tc_ble_uuid_is_128(uuid_str);`,
|
|
254
|
+
` __tc_ble_char_defs[idx].perms = perms;`,
|
|
255
|
+
` __tc_ble_char_defs[idx].svc_index = svc_index;`,
|
|
256
|
+
` __tc_ble_char_defs[idx].type = type;`,
|
|
257
|
+
` __tc_ble.current_char = idx;`,
|
|
258
|
+
` if (idx + 1 > __tc_ble_char_count) __tc_ble_char_count = idx + 1;`,
|
|
259
|
+
`}`,
|
|
260
|
+
``,
|
|
261
|
+
`// ── GATT table builder (flat bt_gatt_attr[] for Zephyr runtime registration) ──`,
|
|
262
|
+
`// Emits: 1 primary-service attr per service; 2 attrs per characteristic`,
|
|
263
|
+
`// (declaration + value); the value attr carries the char index in user_data.`,
|
|
264
|
+
`static void __tc_ble_build_svc_table(void) {`,
|
|
265
|
+
` size_t a = 0;`,
|
|
266
|
+
` for (int s = 0; s < static_cast<int>(__tc_ble.svc_count); s++) {`,
|
|
267
|
+
` // Primary service declaration.`,
|
|
268
|
+
` __tc_ble_attrs[a].uuid = BT_UUID_GATT_PRIMARY;`,
|
|
269
|
+
` __tc_ble_attrs[a].read = bt_gatt_attr_read_service;`,
|
|
270
|
+
` __tc_ble_attrs[a].write = NULL;`,
|
|
271
|
+
` __tc_ble_attrs[a].user_data = static_cast<void*>(const_cast<struct bt_uuid*>(__tc_ble_make_svc_uuid(s)));`,
|
|
272
|
+
` __tc_ble_attrs[a].handle = 0;`,
|
|
273
|
+
` __tc_ble_attrs[a].perm = BT_GATT_PERM_READ;`,
|
|
274
|
+
` a++;`,
|
|
275
|
+
` for (int c = 0; c < __tc_ble_char_count; c++) {`,
|
|
276
|
+
` if (__tc_ble_char_defs[c].svc_index != s || !__tc_ble_char_defs[c].uuid_str) continue;`,
|
|
277
|
+
` // Characteristic declaration attr.`,
|
|
278
|
+
` __tc_ble_chrc_meta[c].uuid = __tc_ble_make_chr_uuid(c);`,
|
|
279
|
+
` __tc_ble_chrc_meta[c].value_handle = 0;`,
|
|
280
|
+
` uint8_t props = 0;`,
|
|
281
|
+
` if (__tc_ble_char_defs[c].perms & 1) props |= BT_GATT_CHRC_READ;`,
|
|
282
|
+
` if (__tc_ble_char_defs[c].perms & 2) props |= BT_GATT_CHRC_WRITE;`,
|
|
283
|
+
` if (__tc_ble_char_defs[c].perms & 4) props |= BT_GATT_CHRC_NOTIFY;`,
|
|
284
|
+
` __tc_ble_chrc_meta[c].properties = props;`,
|
|
285
|
+
` __tc_ble_attrs[a].uuid = BT_UUID_GATT_CHRC;`,
|
|
286
|
+
` __tc_ble_attrs[a].read = bt_gatt_attr_read_chrc;`,
|
|
287
|
+
` __tc_ble_attrs[a].write = NULL;`,
|
|
288
|
+
` __tc_ble_attrs[a].user_data = &__tc_ble_chrc_meta[c];`,
|
|
289
|
+
` __tc_ble_attrs[a].handle = 0;`,
|
|
290
|
+
` __tc_ble_attrs[a].perm = BT_GATT_PERM_READ;`,
|
|
291
|
+
` a++;`,
|
|
292
|
+
` // Characteristic value attr — the index goes in user_data.`,
|
|
293
|
+
` __tc_ble_attrs[a].uuid = __tc_ble_make_chr_uuid(c);`,
|
|
294
|
+
` __tc_ble_attrs[a].read = __tc_ble_attr_read;`,
|
|
295
|
+
` __tc_ble_attrs[a].write = __tc_ble_attr_write;`,
|
|
296
|
+
` __tc_ble_attrs[a].user_data = reinterpret_cast<void*>(static_cast<intptr_t>(c));`,
|
|
297
|
+
` __tc_ble_attrs[a].handle = 0;`,
|
|
298
|
+
` __tc_ble_attrs[a].perm = BT_GATT_PERM_READ | BT_GATT_PERM_WRITE;`,
|
|
299
|
+
` __tc_ble.val_attr_idx[c] = static_cast<int>(a);`,
|
|
300
|
+
` a++;`,
|
|
301
|
+
` }`,
|
|
302
|
+
` }`,
|
|
303
|
+
` __tc_ble_attr_count = a;`,
|
|
304
|
+
` __tc_ble_svc.attrs = __tc_ble_attrs;`,
|
|
305
|
+
` __tc_ble_svc.attr_count = a;`,
|
|
306
|
+
`}`,
|
|
307
|
+
``,
|
|
308
|
+
`// ── Server begin: build table, register (before bt_enable), enable, advertise ──`,
|
|
309
|
+
`static void __tc_ble_server_begin(const char* name) {`,
|
|
310
|
+
` if (__tc_ble.inited) return;`,
|
|
311
|
+
` strncpy(__tc_ble.name, name, sizeof(__tc_ble.name) - 1); __tc_ble.name[sizeof(__tc_ble.name) - 1] = 0;`,
|
|
312
|
+
` // If no service was added but characteristics exist, default to one service.`,
|
|
313
|
+
` if (__tc_ble.svc_count == 0 && __tc_ble_char_count > 0) {`,
|
|
314
|
+
` for (int c = 0; c < __tc_ble_char_count; c++) __tc_ble_char_defs[c].svc_index = 0;`,
|
|
315
|
+
` __tc_ble_add_service("181A"); // Environmental Sensing`,
|
|
316
|
+
` }`,
|
|
317
|
+
` __tc_ble_build_svc_table();`,
|
|
318
|
+
` bt_conn_cb_register(&__tc_ble_conn_cb);`,
|
|
319
|
+
` // Register BEFORE bt_enable (the supported timing window).`,
|
|
320
|
+
` bt_gatt_service_register(&__tc_ble_svc);`,
|
|
321
|
+
` __tc_ble.status = 1; // Initializing`,
|
|
322
|
+
` bt_enable(NULL); // synchronous`,
|
|
323
|
+
` __tc_ble.inited = true;`,
|
|
324
|
+
` __tc_ble_advertise_start();`,
|
|
325
|
+
`}`,
|
|
326
|
+
``,
|
|
327
|
+
`// ── Notify ──`,
|
|
328
|
+
`static void __tc_ble_notify(int idx, int16_t value) {`,
|
|
329
|
+
` if (idx < 0 || idx >= __TC_BLE_MAX_CHARS) return;`,
|
|
330
|
+
` int ai = __tc_ble.val_attr_idx[idx];`,
|
|
331
|
+
` if (ai == 0) return;`,
|
|
332
|
+
` const char* t = __tc_ble_char_defs[idx].type;`,
|
|
333
|
+
` if (t && strcmp(t, "uint32") == 0) {`,
|
|
334
|
+
` uint32_t u = static_cast<uint32_t>(value); bt_gatt_notify(NULL, &__tc_ble_attrs[ai], &u, sizeof(u));`,
|
|
335
|
+
` } else if (t && strcmp(t, "float32") == 0) {`,
|
|
336
|
+
` float f = static_cast<float>(value); bt_gatt_notify(NULL, &__tc_ble_attrs[ai], &f, sizeof(f));`,
|
|
337
|
+
` } else if (t && strcmp(t, "boolean") == 0) {`,
|
|
338
|
+
` uint8_t b = value ? 1 : 0; bt_gatt_notify(NULL, &__tc_ble_attrs[ai], &b, sizeof(b));`,
|
|
339
|
+
` } else {`,
|
|
340
|
+
` int16_t s16 = value; bt_gatt_notify(NULL, &__tc_ble_attrs[ai], &s16, sizeof(s16));`,
|
|
341
|
+
` }`,
|
|
342
|
+
`}`,
|
|
343
|
+
``,
|
|
344
|
+
`static inline bool __tc_ble_is_connected(void) {`,
|
|
345
|
+
` return __tc_ble.status == 3 && __tc_ble.connected_clients > 0;`,
|
|
346
|
+
`}`,
|
|
347
|
+
`static inline int __tc_ble_client_count(void) { return __tc_ble.connected_clients; }`,
|
|
348
|
+
`static inline void __tc_ble_set_name(const char* name) { strncpy(__tc_ble.name, name, sizeof(__tc_ble.name) - 1); __tc_ble.name[sizeof(__tc_ble.name) - 1] = 0; }`,
|
|
349
|
+
`static inline void __tc_ble_set_tx_power(int dbm) { (void)dbm; /* nRF TX power via bt_le_set_tx_power — deferred */ }`,
|
|
350
|
+
``,
|
|
351
|
+
`static inline bool __tc_ble_until_connected(uint32_t timeout_ms) {`,
|
|
352
|
+
` int64_t deadline = static_cast<int64_t>(k_uptime_get()) + static_cast<int64_t>(timeout_ms);`,
|
|
353
|
+
` while (!__tc_ble_is_connected()) {`,
|
|
354
|
+
` if (timeout_ms > 0 && k_uptime_get() >= deadline) return false;`,
|
|
355
|
+
` k_msleep(50);`,
|
|
356
|
+
` }`,
|
|
357
|
+
` return true;`,
|
|
358
|
+
`}`,
|
|
359
|
+
`static inline void __tc_ble_until_connected_start(void) { /* __tc_ble_server_begin already started advertising */ }`,
|
|
360
|
+
`// CUTTLEFISH_BLE_END`,
|
|
361
|
+
``,
|
|
362
|
+
];
|
|
363
|
+
}
|
|
364
|
+
/** Render a HAL field: pass through (already rendered by the resolver). */
|
|
365
|
+
function s(v) {
|
|
366
|
+
return String(v);
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Resolve a HAL ble.* op to Zephyr NimBLE C++ via the __tc_ble_* shim.
|
|
370
|
+
* Returns `{ code }` for statement ops, `{ expression }` for value-returning ops.
|
|
371
|
+
*
|
|
372
|
+
* The current_char-keyed callback assignment pattern (on_read/on_write set into
|
|
373
|
+
* the table by the index add_char last established) ports verbatim from ESP32.
|
|
374
|
+
*/
|
|
375
|
+
export function lowerBle(op) {
|
|
376
|
+
const o = op;
|
|
377
|
+
switch (op.operation) {
|
|
378
|
+
case 'ble.server_begin':
|
|
379
|
+
return { code: `__tc_ble_server_begin(${s(o.name)});` };
|
|
380
|
+
case 'ble.advertise_start':
|
|
381
|
+
return { code: `__tc_ble_advertise_start();` };
|
|
382
|
+
case 'ble.advertise_stop':
|
|
383
|
+
return { code: `__tc_ble_advertise_stop();` };
|
|
384
|
+
case 'ble.add_service':
|
|
385
|
+
return { code: `__tc_ble_add_service(${s(o.uuid)});` };
|
|
386
|
+
case 'ble.add_char':
|
|
387
|
+
return { code: `__tc_ble_add_char(${s(o.index)}, ${s(o.uuid)}, ${s(o.type)}, ${s(o.perms)}, ${s(o.svcIndex ?? 0)});` };
|
|
388
|
+
case 'ble.on_read':
|
|
389
|
+
// Store the typed read handler as void*; __tc_ble_attr_read casts it back
|
|
390
|
+
// to the right signature based on the char's type field. reinterpret_cast
|
|
391
|
+
// (not a C-style cast) keeps this AUTOSAR-compliant under --autosar=strict.
|
|
392
|
+
return { code: `__tc_ble.on_read[__tc_ble.current_char] = reinterpret_cast<void*>(${s(o.handler)});` };
|
|
393
|
+
case 'ble.on_write':
|
|
394
|
+
return { code: `__tc_ble.on_write[__tc_ble.current_char] = (${s(o.handler)});` };
|
|
395
|
+
case 'ble.on_connect':
|
|
396
|
+
return { code: `__tc_ble.on_connect = (${s(o.handler)});` };
|
|
397
|
+
case 'ble.on_disconnect':
|
|
398
|
+
return { code: `__tc_ble.on_disconnect = (${s(o.handler)});` };
|
|
399
|
+
case 'ble.notify':
|
|
400
|
+
return { expression: `__tc_ble_notify(__tc_ble.current_char, ${s(o.value)})` };
|
|
401
|
+
case 'ble.is_connected':
|
|
402
|
+
return { expression: `__tc_ble_is_connected()` };
|
|
403
|
+
case 'ble.client_count':
|
|
404
|
+
return { expression: `__tc_ble_client_count()` };
|
|
405
|
+
case 'ble.status':
|
|
406
|
+
return { expression: `__tc_ble.status` };
|
|
407
|
+
case 'ble.set_name':
|
|
408
|
+
return { code: `__tc_ble_set_name(${s(o.name)});` };
|
|
409
|
+
case 'ble.set_tx_power':
|
|
410
|
+
return { code: `__tc_ble_set_tx_power(${s(o.dbm)});` };
|
|
411
|
+
case 'ble.until_connected':
|
|
412
|
+
return { expression: `__tc_ble_until_connected(${s(o.timeoutMs)})` };
|
|
413
|
+
case 'ble.until_connected_start':
|
|
414
|
+
return { code: `__tc_ble_until_connected_start();` };
|
|
415
|
+
default:
|
|
416
|
+
throw new Error(`framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
|
|
417
|
+
`Open an issue or use rawCpp() to emit it manually.`);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve a HAL board.* op. Always returns `undefined`: the value is folded
|
|
4
|
+
* upstream at IR-build time, and this fn is only reached as a dead-letter.
|
|
5
|
+
*/
|
|
6
|
+
export declare function lowerBoard(op: HALOpIR): {
|
|
7
|
+
code?: string;
|
|
8
|
+
expression?: string;
|
|
9
|
+
} | undefined;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Board constant lowering — dead-letter for board.resolve
|
|
3
|
+
//
|
|
4
|
+
// The `board` HAL category has a single op, `board.resolve`, which carries a
|
|
5
|
+
// dot-`path` into the loaded board/MCU definition (e.g.
|
|
6
|
+
// "peripherals.pwm.resolution"). On Zephyr — exactly as on Arduino — these
|
|
7
|
+
// values are compile-time constants folded into literals by the transpiler
|
|
8
|
+
// BEFORE any framework lowering runs:
|
|
9
|
+
//
|
|
10
|
+
// - expression-to-ir.ts folds board()/boardResolve() *expressions* to a
|
|
11
|
+
// literal (number/string) or 0 on miss.
|
|
12
|
+
// - hal-emitter.ts folds a boardResolve() *return* and skips a
|
|
13
|
+
// boardResolve() *statement* entirely.
|
|
14
|
+
// - The Board.definition.<path> / Pins.definition.<path> *property-access*
|
|
15
|
+
// path is folded by ZephyrStrategy.renderBoardDefinitionAccess (which the
|
|
16
|
+
// expression-renderer calls with the populated board constants).
|
|
17
|
+
//
|
|
18
|
+
// Consequently a `board.resolve` HALOpIR only reaches this lowering as a
|
|
19
|
+
// dead-letter when the path could not be resolved. Returning `undefined` lets
|
|
20
|
+
// the emitter emit its standard unhandled-op warning, mirroring
|
|
21
|
+
// framework-arduino's `case "board.resolve"` (which likewise passes no board
|
|
22
|
+
// constants at resolve time). The manifest declares the op
|
|
23
|
+
// `probe-inconclusive` for the same reason: the minimal validator probe
|
|
24
|
+
// carries no path/board constants, so support cannot be cross-checked.
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
/**
|
|
27
|
+
* Resolve a HAL board.* op. Always returns `undefined`: the value is folded
|
|
28
|
+
* upstream at IR-build time, and this fn is only reached as a dead-letter.
|
|
29
|
+
*/
|
|
30
|
+
export function lowerBoard(op) {
|
|
31
|
+
void op;
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
|
|
2
|
+
import type { ZephyrChipDescriptor } from '../chips/types.js';
|
|
3
|
+
/** The C identifier emitted for a pin's gpio_dt_spec variable. */
|
|
4
|
+
export declare function dtSpecVarName(dtSpec: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* Resolve a HAL gpio.* op to Zephyr C++.
|
|
7
|
+
* Returns `{ code }` for statement ops, `{ expression }` for value-returning ops.
|
|
8
|
+
*/
|
|
9
|
+
export declare function lowerGpio(op: HALOpIR, chip: ZephyrChipDescriptor): {
|
|
10
|
+
code?: string;
|
|
11
|
+
expression?: string;
|
|
12
|
+
};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// GPIO lowering — devicetree-spec bridge
|
|
3
|
+
//
|
|
4
|
+
// Translates HAL gpio.* ops to Zephyr driver C++. Two addressing modes:
|
|
5
|
+
//
|
|
6
|
+
// 1. Devicetree spec (preferred): if the HAL pin matches a dtSpec in the
|
|
7
|
+
// active chip descriptor, emit gpio_pin_*_dt() calls against a
|
|
8
|
+
// `__tc_dt_<alias>` gpio_dt_spec. This honors the node's polarity flags
|
|
9
|
+
// (GPIO_ACTIVE_LOW), so logical value 1 = LED on for an active-low LED.
|
|
10
|
+
//
|
|
11
|
+
// 2. Raw fallback: pins without a dtSpec are addressed via the SoC's gpio
|
|
12
|
+
// controller node (DEVICE_DT_GET(DT_NODELABEL(gpio0))) and the
|
|
13
|
+
// gpio_pin_*_raw() API. Polarity is physical (raw bypasses DT flags).
|
|
14
|
+
// The manifest validator's probe (which sends {operation, pin:0} with no
|
|
15
|
+
// port) hits this path, so it must return a lowered result, not undefined.
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
import { controllerNodelabelForPin } from '../chips/controllers.js';
|
|
18
|
+
/** The C identifier emitted for a pin's gpio_dt_spec variable. */
|
|
19
|
+
export function dtSpecVarName(dtSpec) {
|
|
20
|
+
return `__tc_dt_${dtSpec}`;
|
|
21
|
+
}
|
|
22
|
+
/** Look up a dtSpec by GPIO pin number; undefined if the pin has none. */
|
|
23
|
+
function findDtSpec(chip, pin) {
|
|
24
|
+
return chip.gpio.dtSpecs.find((s) => s.pin === pin);
|
|
25
|
+
}
|
|
26
|
+
// HAL passes UPPERCASE modes ("OUTPUT") while docs say lowercase ("output").
|
|
27
|
+
// The *_pullup / *_pulldown modes map to GPIO_INPUT (Zephyr does not have
|
|
28
|
+
// separate input+pull mode flags) and OR in a GPIO_PULL_UP / GPIO_PULL_DOWN
|
|
29
|
+
// bit via `dtFlagsForMode` — without that bit the pin floats, so INPUT_PULLUP
|
|
30
|
+
// was a silent no-op (bug B1). Mirrors the gpio_pullup_en/gpio_pulldown_en
|
|
31
|
+
// extras framework-esp32 emits for the same modes.
|
|
32
|
+
const MODE_MAP = {
|
|
33
|
+
output: 'GPIO_OUTPUT',
|
|
34
|
+
OUTPUT: 'GPIO_OUTPUT',
|
|
35
|
+
input: 'GPIO_INPUT',
|
|
36
|
+
INPUT: 'GPIO_INPUT',
|
|
37
|
+
input_pullup: 'GPIO_INPUT',
|
|
38
|
+
INPUT_PULLUP: 'GPIO_INPUT',
|
|
39
|
+
input_pulldown: 'GPIO_INPUT',
|
|
40
|
+
INPUT_PULLDOWN: 'GPIO_INPUT',
|
|
41
|
+
};
|
|
42
|
+
/** Additional DT flag bits for a HAL mode, OR'd into the configure flags.
|
|
43
|
+
* Returns '' for modes with no extra bits so the join leaves the mode alone. */
|
|
44
|
+
function dtFlagsForMode(mode) {
|
|
45
|
+
const m = (mode ?? '').toLowerCase();
|
|
46
|
+
if (m === 'input_pullup')
|
|
47
|
+
return ' | GPIO_PULL_UP';
|
|
48
|
+
if (m === 'input_pulldown')
|
|
49
|
+
return ' | GPIO_PULL_DOWN';
|
|
50
|
+
return '';
|
|
51
|
+
}
|
|
52
|
+
/** Combined mode + pull flags for a HAL mode string, e.g.
|
|
53
|
+
* 'INPUT_PULLUP' → 'GPIO_INPUT | GPIO_PULL_UP'. */
|
|
54
|
+
function flagsForMode(mode) {
|
|
55
|
+
const base = MODE_MAP[mode] ?? 'GPIO_INPUT';
|
|
56
|
+
return base + dtFlagsForMode(mode);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Resolve a HAL gpio.* op to Zephyr C++.
|
|
60
|
+
* Returns `{ code }` for statement ops, `{ expression }` for value-returning ops.
|
|
61
|
+
*/
|
|
62
|
+
export function lowerGpio(op, chip) {
|
|
63
|
+
const o = op;
|
|
64
|
+
const pin = o.pin;
|
|
65
|
+
const spec = findDtSpec(chip, pin);
|
|
66
|
+
if (spec) {
|
|
67
|
+
return lowerGpioDtSpec(op, spec.dtSpec);
|
|
68
|
+
}
|
|
69
|
+
return lowerGpioRaw(op, chip);
|
|
70
|
+
}
|
|
71
|
+
/** Devicetree-spec path — polarity-correct via gpio_pin_*_dt(). */
|
|
72
|
+
function lowerGpioDtSpec(op, dtSpec) {
|
|
73
|
+
const o = op;
|
|
74
|
+
const varName = dtSpecVarName(dtSpec);
|
|
75
|
+
switch (op.operation) {
|
|
76
|
+
case 'gpio.set_mode': {
|
|
77
|
+
return { code: `gpio_pin_configure_dt(&${varName}, ${flagsForMode(o.mode)});` };
|
|
78
|
+
}
|
|
79
|
+
case 'gpio.write': {
|
|
80
|
+
// Literal 0/1 stays as-is; runtime expression coerced to int via ternary.
|
|
81
|
+
const v = o.value;
|
|
82
|
+
const rhs = typeof v === 'string' ? `((${v}) ? 1 : 0)` : v ? 1 : 0;
|
|
83
|
+
return { code: `gpio_pin_set_dt(&${varName}, ${rhs});` };
|
|
84
|
+
}
|
|
85
|
+
case 'gpio.read':
|
|
86
|
+
return { expression: `gpio_pin_get_dt(&${varName})` };
|
|
87
|
+
case 'gpio.toggle':
|
|
88
|
+
return { code: `gpio_pin_toggle_dt(&${varName});` };
|
|
89
|
+
default:
|
|
90
|
+
throw new Error(`framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
|
|
91
|
+
`Open an issue or use rawCpp() to emit it manually.`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Raw-controller path — for pins without a DT spec (and the manifest probe).
|
|
96
|
+
* Uses the SoC's primary GPIO controller node. Polarity is physical.
|
|
97
|
+
*/
|
|
98
|
+
function lowerGpioRaw(op, chip) {
|
|
99
|
+
const o = op;
|
|
100
|
+
const pin = o.pin;
|
|
101
|
+
// Resolve the owning controller by pin range (ESP32-S3 splits GPIO across
|
|
102
|
+
// gpio0/gpio1). For single-controller SoCs this is just chip.gpioController.
|
|
103
|
+
const controller = `DEVICE_DT_GET(DT_NODELABEL(${controllerNodelabelForPin(chip, pin)}))`;
|
|
104
|
+
switch (op.operation) {
|
|
105
|
+
case 'gpio.set_mode': {
|
|
106
|
+
return { code: `gpio_pin_configure(${controller}, ${pin}, ${flagsForMode(o.mode)});` };
|
|
107
|
+
}
|
|
108
|
+
case 'gpio.write': {
|
|
109
|
+
const v = o.value;
|
|
110
|
+
const rhs = typeof v === 'string' ? `((${v}) ? 1 : 0)` : v ? 1 : 0;
|
|
111
|
+
return { code: `gpio_pin_set_raw(${controller}, ${pin}, ${rhs});` };
|
|
112
|
+
}
|
|
113
|
+
case 'gpio.read':
|
|
114
|
+
return { expression: `gpio_pin_get_raw(${controller}, ${pin})` };
|
|
115
|
+
case 'gpio.toggle':
|
|
116
|
+
return {
|
|
117
|
+
code: `gpio_pin_set_raw(${controller}, ${pin}, !gpio_pin_get_raw(${controller}, ${pin}));`,
|
|
118
|
+
};
|
|
119
|
+
default:
|
|
120
|
+
throw new Error(`framework-zephyr does not yet support HAL op \`${op.operation}\`. ` +
|
|
121
|
+
`Open an issue or use rawCpp() to emit it manually.`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { HALOpIR } from '@typecad/cuttlefish/api/shared';
|
|
2
|
+
/**
|
|
3
|
+
* The HTTP runtime shim. All helpers are `static`/`inline` so unused ones
|
|
4
|
+
* don't trip -Wunused-function in the single generated TU (mirrors wifi.ts).
|
|
5
|
+
*
|
|
6
|
+
* The connect/perform path runs on the calling thread for the blocking send,
|
|
7
|
+
* and on the system workqueue for the async send_start/done split. Completion
|
|
8
|
+
* of the async path is signaled with a k_sem (give/take) which issues a full
|
|
9
|
+
* memory barrier, so the consumer observes the resp/status/ok writes the
|
|
10
|
+
* worker made before signaling — the same handoff guarantee ESP32's
|
|
11
|
+
* xTaskNotifyGive provides.
|
|
12
|
+
*/
|
|
13
|
+
export declare function httpInitLines(): string[];
|
|
14
|
+
/**
|
|
15
|
+
* Resolve a HAL http.* op to Zephyr C++ via the __tc_http_* shim. Returns
|
|
16
|
+
* `{ code }` for statement ops, `{ expression }` for value-returning ops.
|
|
17
|
+
* The method string on http.begin may arrive quoted ("GET"); strip quotes and
|
|
18
|
+
* normalize to the Zephyr enum constant (GET→HTTP_GET, etc.).
|
|
19
|
+
*/
|
|
20
|
+
export declare function lowerHttp(op: HALOpIR): {
|
|
21
|
+
code?: string;
|
|
22
|
+
expression?: string;
|
|
23
|
+
};
|