@typecad/framework-zephyr 1.0.0-alpha.14 → 1.0.0-alpha.16

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.
Files changed (185) hide show
  1. package/README.md +22 -47
  2. package/dist/as-built.d.ts +33 -0
  3. package/dist/as-built.js +188 -0
  4. package/dist/async/timer-polyfill.js +1 -1
  5. package/dist/boardgen.d.ts +128 -0
  6. package/dist/boardgen.js +1366 -0
  7. package/dist/chips/board-overrides.d.ts +7 -0
  8. package/dist/chips/board-overrides.js +11 -0
  9. package/dist/chips/esp32s3.js +49 -0
  10. package/dist/chips/index.d.ts +6 -12
  11. package/dist/chips/index.js +18 -34
  12. package/dist/chips/resolve.d.ts +16 -2
  13. package/dist/chips/resolve.js +267 -10
  14. package/dist/chips/soc/.d.ts +2 -0
  15. package/dist/chips/soc/.js +129 -0
  16. package/dist/chips/soc/esp32.d.ts +2 -0
  17. package/dist/chips/soc/esp32.js +120 -0
  18. package/dist/chips/soc/esp32c3.d.ts +2 -0
  19. package/dist/chips/soc/esp32c3.js +90 -0
  20. package/dist/chips/soc/esp32c6.d.ts +2 -0
  21. package/dist/chips/soc/esp32c6.js +109 -0
  22. package/dist/chips/soc/esp32s3.d.ts +2 -0
  23. package/dist/chips/soc/esp32s3.js +189 -0
  24. package/dist/chips/soc/index.d.ts +2 -0
  25. package/dist/chips/soc/index.js +23 -0
  26. package/dist/chips/soc/nrf52840.d.ts +2 -0
  27. package/dist/chips/soc/nrf52840.js +130 -0
  28. package/dist/chips/soc/rp2040.d.ts +2 -0
  29. package/dist/chips/soc/rp2040.js +141 -0
  30. package/dist/chips/soc/rp2350a.d.ts +2 -0
  31. package/dist/chips/soc/rp2350a.js +145 -0
  32. package/dist/chips/soc/samd21g18a.d.ts +2 -0
  33. package/dist/chips/soc/samd21g18a.js +143 -0
  34. package/dist/chips/soc/stm32f411xe.d.ts +2 -0
  35. package/dist/chips/soc/stm32f411xe.js +251 -0
  36. package/dist/chips/types.d.ts +319 -0
  37. package/dist/chips/xiao-ble.js +21 -0
  38. package/dist/display/profiles.js +1 -1
  39. package/dist/doctor.js +38 -4
  40. package/dist/dt-config/custom-board.d.ts +23 -0
  41. package/dist/dt-config/custom-board.js +227 -0
  42. package/dist/dt-config/kconfig.d.ts +72 -1
  43. package/dist/dt-config/kconfig.js +115 -26
  44. package/dist/dt-config/overlay.js +548 -28
  45. package/dist/framework.manifest.d.ts +3 -3
  46. package/dist/framework.manifest.js +122 -185
  47. package/dist/index.d.ts +4 -1
  48. package/dist/index.js +8 -2
  49. package/dist/lowering/adc.d.ts +20 -2
  50. package/dist/lowering/adc.js +121 -29
  51. package/dist/lowering/ble.js +31 -28
  52. package/dist/lowering/dac.js +9 -9
  53. package/dist/lowering/fs.js +18 -10
  54. package/dist/lowering/gpio.d.ts +2 -0
  55. package/dist/lowering/gpio.js +82 -5
  56. package/dist/lowering/http.js +39 -14
  57. package/dist/lowering/hwtimer.d.ts +4 -0
  58. package/dist/lowering/hwtimer.js +35 -10
  59. package/dist/lowering/i2c.js +46 -54
  60. package/dist/lowering/index.d.ts +5 -5
  61. package/dist/lowering/index.js +15 -16
  62. package/dist/lowering/interrupts.d.ts +22 -5
  63. package/dist/lowering/interrupts.js +104 -22
  64. package/dist/lowering/mqtt.js +3 -5
  65. package/dist/lowering/power.js +0 -4
  66. package/dist/lowering/preferences.js +49 -77
  67. package/dist/lowering/pulse.js +0 -31
  68. package/dist/lowering/pwm.d.ts +12 -1
  69. package/dist/lowering/pwm.js +78 -14
  70. package/dist/lowering/random.js +3 -3
  71. package/dist/lowering/sensor.d.ts +37 -0
  72. package/dist/lowering/sensor.js +119 -0
  73. package/dist/lowering/spi.d.ts +12 -0
  74. package/dist/lowering/spi.js +65 -40
  75. package/dist/lowering/thread.d.ts +14 -0
  76. package/dist/lowering/thread.js +55 -0
  77. package/dist/lowering/timing.js +20 -46
  78. package/dist/lowering/tone.js +16 -4
  79. package/dist/lowering/uart.d.ts +13 -0
  80. package/dist/lowering/uart.js +72 -51
  81. package/dist/lowering/usb.d.ts +34 -0
  82. package/dist/lowering/usb.js +206 -0
  83. package/dist/lowering/wdt.d.ts +1 -1
  84. package/dist/lowering/wdt.js +17 -7
  85. package/dist/lowering/wifi.d.ts +3 -2
  86. package/dist/lowering/wifi.js +97 -111
  87. package/dist/sdk/board-catalog-sync.d.ts +16 -0
  88. package/dist/sdk/board-catalog-sync.js +41 -0
  89. package/dist/sdk/board-data.generated.d.ts +2 -0
  90. package/dist/sdk/board-data.generated.js +4 -0
  91. package/dist/sdk/catalog-walker.d.ts +90 -0
  92. package/dist/sdk/catalog-walker.js +682 -0
  93. package/dist/sdk/dts-reader.d.ts +83 -0
  94. package/dist/sdk/dts-reader.js +596 -0
  95. package/dist/strategy.d.ts +136 -17
  96. package/dist/strategy.js +839 -222
  97. package/dist/toolchain/bossac-touch.d.ts +18 -0
  98. package/dist/toolchain/bossac-touch.js +88 -0
  99. package/dist/toolchain/compat.d.ts +2 -2
  100. package/dist/toolchain/compat.js +8 -3
  101. package/dist/toolchain/debug-config.d.ts +21 -26
  102. package/dist/toolchain/debug-config.js +226 -76
  103. package/dist/toolchain/env-check.d.ts +4 -4
  104. package/dist/toolchain/env-check.js +5 -5
  105. package/dist/toolchain/index.d.ts +115 -1
  106. package/dist/toolchain/index.js +680 -71
  107. package/dist/toolchain/scaffold.js +39 -7
  108. package/dist/toolchain/west-discover.d.ts +4 -0
  109. package/dist/toolchain/west-discover.js +17 -6
  110. package/installer/CHANGELOG.md +473 -0
  111. package/installer/README.md +328 -0
  112. package/installer/environment.yml +46 -0
  113. package/installer/etc/conda/activate.d/zephyr.bat +7 -0
  114. package/installer/etc/conda/activate.d/zephyr.ps1 +12 -0
  115. package/installer/etc/conda/activate.d/zephyr.sh +20 -0
  116. package/installer/etc/conda/deactivate.d/zephyr.bat +6 -0
  117. package/installer/etc/conda/deactivate.d/zephyr.ps1 +6 -0
  118. package/installer/etc/conda/deactivate.d/zephyr.sh +4 -0
  119. package/installer/install.mjs +580 -0
  120. package/installer/install.ps1 +619 -0
  121. package/installer/install.sh +310 -0
  122. package/installer/lib/detect-platform.sh +62 -0
  123. package/installer/lib/fetch-sdk.sh +304 -0
  124. package/installer/lib/init-workspace.sh +153 -0
  125. package/installer/lib/write-activation.sh +76 -0
  126. package/installer/patches/tfm-c-include-separators.patch +19 -0
  127. package/installer/patches/zephyr-tfm-nordic-zephyr-include.patch +24 -0
  128. package/installer/templates/project/.typecad/activate-zephyr.ps1 +31 -0
  129. package/installer/templates/project/.typecad/activate-zephyr.sh +31 -0
  130. package/installer/templates/project/.vscode/settings.json +30 -0
  131. package/installer/templates/project/README.md +58 -0
  132. package/installer/versions.env +110 -0
  133. package/package.json +15 -15
  134. package/src/as-built.ts +206 -0
  135. package/src/boardgen.ts +1428 -0
  136. package/src/chips/index.ts +35 -54
  137. package/src/chips/resolve.ts +285 -10
  138. package/src/chips/types.ts +325 -1
  139. package/src/display/profiles.ts +1 -1
  140. package/src/doctor.ts +110 -77
  141. package/src/dt-config/custom-board.ts +325 -0
  142. package/src/dt-config/kconfig.ts +165 -18
  143. package/src/dt-config/overlay.ts +537 -25
  144. package/src/framework.manifest.ts +123 -185
  145. package/src/index.ts +57 -41
  146. package/src/lowering/adc.ts +222 -118
  147. package/src/lowering/ble.ts +32 -28
  148. package/src/lowering/dac.ts +82 -82
  149. package/src/lowering/fs.ts +18 -10
  150. package/src/lowering/gpio.ts +242 -155
  151. package/src/lowering/http.ts +512 -488
  152. package/src/lowering/hwtimer.ts +139 -101
  153. package/src/lowering/i2c.ts +116 -126
  154. package/src/lowering/index.ts +91 -93
  155. package/src/lowering/interrupts.ts +113 -21
  156. package/src/lowering/mqtt.ts +3 -5
  157. package/src/lowering/preferences.ts +327 -354
  158. package/src/lowering/pwm.ts +167 -99
  159. package/src/lowering/random.ts +3 -3
  160. package/src/lowering/sensor.ts +155 -0
  161. package/src/lowering/spi.ts +164 -124
  162. package/src/lowering/thread.ts +63 -0
  163. package/src/lowering/timing.ts +46 -72
  164. package/src/lowering/uart.ts +73 -51
  165. package/src/lowering/usb.ts +221 -0
  166. package/src/lowering/wdt.ts +95 -84
  167. package/src/lowering/wifi.ts +97 -112
  168. package/src/sdk/board-catalog-sync.ts +62 -0
  169. package/src/strategy.ts +848 -237
  170. package/src/toolchain/bossac-touch.ts +112 -0
  171. package/src/toolchain/compat.ts +8 -3
  172. package/src/toolchain/debug-config.ts +676 -522
  173. package/src/toolchain/env-check.ts +9 -9
  174. package/src/toolchain/index.ts +1359 -645
  175. package/src/toolchain/scaffold.ts +38 -7
  176. package/src/toolchain/west-discover.ts +19 -6
  177. package/src/async/timer-polyfill.ts +0 -107
  178. package/src/chips/esp32.ts +0 -74
  179. package/src/chips/esp32s3.ts +0 -57
  180. package/src/chips/xiao-ble.ts +0 -82
  181. package/src/lowering/power.ts +0 -70
  182. package/src/lowering/pulse.ts +0 -93
  183. package/src/lowering/tone.ts +0 -60
  184. package/src/lowering/worker-backing.ts +0 -94
  185. package/src/lowering/worker.ts +0 -17
@@ -1,7 +1,7 @@
1
1
  // ---------------------------------------------------------------------------
2
- // WiFi lowering — net_mgmt (connect/scan/radio) + conn_mgr monitor (L4 events)
2
+ // WiFi lowering — net_mgmt (join/scan/radio) + conn_mgr monitor (L4 events)
3
3
  //
4
- // Hybrid: the WiFi connect/disconnect/scan/radio-query requests go directly
4
+ // Hybrid: the WiFi join/disconnect/scan/radio-query requests go directly
5
5
  // through net_mgmt + wifi_mgmt.h (NET_REQUEST_WIFI_CONNECT/DISCONNECT/SCAN/...),
6
6
  // taking the iface admin-up with net_if_up first. IP-level connectivity is
7
7
  // still signaled by conn_mgr's monitoring layer (conn_mgr_monitor.c raises
@@ -27,8 +27,9 @@ function s(v: unknown): string {
27
27
  *
28
28
  * State is driven by two net_mgmt event handlers:
29
29
  * - L4 connectivity (NET_EVENT_L4_CONNECTED/DISCONNECTED) → connected flag.
30
- * This reflects IP connectivity (post-DHCP), not just the WiFi link — the
31
- * events are raised by conn_mgr's monitoring layer (conn_mgr_monitor.c).
30
+ * This reflects IP connectivity (post-DHCP, or right after static IPv4
31
+ * facts are applied) — the events are raised by conn_mgr's monitoring
32
+ * layer (conn_mgr_monitor.c).
32
33
  * - WiFi scan (NET_EVENT_WIFI_SCAN_RESULT/SCAN_DONE) → scan_results pool.
33
34
  */
34
35
  export function wifiInitLines(): string[] {
@@ -39,12 +40,12 @@ export function wifiInitLines(): string[] {
39
40
  `// ── core (always needed when wifi.* is used) ────────────────────────────`,
40
41
  `// CUTTLEFISH_WIFI_CORE_BEGIN`,
41
42
  `// WiFi event callback signature (wifi.on_event). One slot per supported`,
42
- `// event — a second registration overwrites the first (matches framework-esp32).`,
43
+ `// event — a second registration overwrites the first.`,
43
44
  `typedef void (*__tc_wifi_cb_t)(void);`,
44
45
  ``,
45
46
  `// WiFi state. connected reflects IP connectivity (L4), not just link —`,
46
- `// connect takes the iface admin-up (net_if_up) and conn_mgr_monitor raises`,
47
- `// the L4 event once DHCP completes. is_connected polls this flag.`,
47
+ `// join takes the iface admin-up (net_if_up) and conn_mgr_monitor raises`,
48
+ `// the L4 event once DHCP completes (or the static-IPv4 facts are applied).`,
48
49
  `static struct {`,
49
50
  ` bool inited; // net_mgmt handlers registered + iface resolved`,
50
51
  ` bool connected; // set by NET_EVENT_L4_CONNECTED/DISCONNECTED`,
@@ -75,15 +76,15 @@ export function wifiInitLines(): string[] {
75
76
  ` __tc_wifi.connected = true;`,
76
77
  ` } else if (mgmt_event == NET_EVENT_L4_DISCONNECTED) {`,
77
78
  ` __tc_wifi.connected = false;`,
78
- ` // Defer on_disconnect via k_work_submit so the user callback (which`,
79
- ` // typically calls connectAsync) runs outside the net_mgmt event`,
80
- ` // chain. Calling NET_REQUEST_WIFI_CONNECT from within the disconnect`,
79
+ ` // Defer on_drop via k_work_submit so the user callback (which`,
80
+ ` // typically re-joins) runs outside the net_mgmt event chain.`,
81
+ ` // Calling NET_REQUEST_WIFI_CONNECT from within the disconnect`,
81
82
  ` // callback causes re-entrancy that prevents re-association.`,
82
83
  ` if (__tc_wifi.on_disconnect != nullptr) {`,
83
84
  ` (void)k_work_submit(&__tc_wifi.disconnect_work);`,
84
85
  ` }`,
85
86
  ` } else if (mgmt_event == NET_EVENT_IPV4_ADDR_ADD) {`,
86
- ` // DHCP assigned an IPv4 address — the true "got IP" signal. Fires`,
87
+ ` // An IPv4 address was assigned — the true "got IP" signal. Fires`,
87
88
  ` // after NET_EVENT_L4_CONNECTED on a successful DHCP join.`,
88
89
  ` if (__tc_wifi.on_connect != nullptr) __tc_wifi.on_connect();`,
89
90
  ` } else if (mgmt_event == NET_EVENT_WIFI_SCAN_RESULT) {`,
@@ -133,8 +134,8 @@ export function wifiInitLines(): string[] {
133
134
  `// duration. Each wait slice sleeps 20ms and, in the entry TU of a UI build`,
134
135
  `// (the only TU carrying the ui_tick definition), pumps one frame so`,
135
136
  `// animations and touch stay live during the wait. Constraint: do NOT call`,
136
- `// blocking wifi waits from inside UI event handlers — that re-enters`,
137
- `// ui_tick mid-tick; use wifi.connect_start + wifi.is_connected there.`,
137
+ `// join() from inside UI event handlers — that re-enters ui_tick mid-tick;`,
138
+ `// use joinStart() + linked() there.`,
138
139
  `#ifdef CUTTLEFISH_ENTRY_UI_TU`,
139
140
  `static void ui_tick(uint16_t deltaMs); // defined by the UI runtime header`,
140
141
  `#endif`,
@@ -151,17 +152,20 @@ export function wifiInitLines(): string[] {
151
152
  `}`,
152
153
  `// CUTTLEFISH_WIFI_CORE_END`,
153
154
  ``,
154
- `// ── connect / disconnect (net_mgmt — conn_mgr monitor supplies L4 events) ─`,
155
+ `// ── join / leave (net_mgmt — conn_mgr monitor supplies L4 events) ────────`,
155
156
  `// CUTTLEFISH_WIFI_CONNECT_BEGIN`,
156
157
  `// SSID/PSK are staged into static buffers (wifi_connect_req_params.ssid/psk`,
157
158
  `// are const uint8_t* — they point at caller-owned storage that must outlive`,
158
159
  `// the request), then net_if_up takes the iface admin-up and NET_REQUEST_WIFI_CONNECT`,
159
- `// is issued. conn_mgr_monitor raises the L4 event once DHCP completes.`,
160
+ `// is issued with the station's construction facts (security/band/channel).`,
161
+ `// conn_mgr_monitor raises the L4 event once DHCP completes.`,
160
162
  `static struct wifi_connect_req_params __tc_wifi_conn_params;`,
161
163
  `static uint8_t __tc_wifi_ssid_buf[33]; // SSID ≤32 + slack`,
162
164
  `static uint8_t __tc_wifi_psk_buf[64]; // PSK ≤63 + slack`,
163
165
  ``,
164
- `static void __tc_wifi_stage_creds(const char* ssid, const char* password) {`,
166
+ `static void __tc_wifi_stage_creds(const char* ssid, const char* password,`,
167
+ ` enum wifi_security_type security, int32_t channel,`,
168
+ ` enum wifi_frequency_bands band) {`,
165
169
  ` __tc_wifi_ensure_init();`,
166
170
  ` if (__tc_wifi.iface == nullptr) return;`,
167
171
  ` uint32_t ssid_len = strlen(ssid);`,
@@ -178,15 +182,16 @@ export function wifiInitLines(): string[] {
178
182
  ` } else {`,
179
183
  ` __tc_wifi_conn_params.psk_length = 0U;`,
180
184
  ` }`,
181
- ` __tc_wifi_conn_params.security = WIFI_SECURITY_TYPE_PSK;`,
182
- ` __tc_wifi_conn_params.channel = WIFI_CHANNEL_ANY;`,
183
- ` __tc_wifi_conn_params.band = WIFI_FREQ_BAND_2_4_GHZ;`,
184
- ` // Stage the connection request (wifi_connect). The L4 handler sets`,
185
- ` // \`connected\` once DHCP completes.`,
185
+ ` __tc_wifi_conn_params.security = security;`,
186
+ ` __tc_wifi_conn_params.channel = (channel > 0) ? static_cast<uint8_t>(channel) : WIFI_CHANNEL_ANY;`,
187
+ ` __tc_wifi_conn_params.band = band;`,
186
188
  ` (void)net_mgmt(NET_REQUEST_WIFI_CONNECT, __tc_wifi.iface,`,
187
189
  ` &__tc_wifi_conn_params, sizeof(__tc_wifi_conn_params));`,
188
190
  `}`,
189
191
  ``,
192
+ `// joinStart(): stage the association without waiting — poll linked() or`,
193
+ `// await join() in an async function (the async machinery splits it into`,
194
+ `// this + the is_connected poll).`,
190
195
  `static void __tc_wifi_connect_start(const char* ssid, const char* password) {`,
191
196
  ` __tc_wifi_ensure_init();`,
192
197
  ` if (__tc_wifi.iface == nullptr) {`,
@@ -194,21 +199,58 @@ export function wifiInitLines(): string[] {
194
199
  ` return;`,
195
200
  ` }`,
196
201
  ` net_if_up(__tc_wifi.iface);`,
197
- ` __tc_wifi_stage_creds(ssid, password);`,
202
+ ` __tc_wifi_stage_creds(ssid, password, WIFI_SECURITY_TYPE_PSK, 0, WIFI_FREQ_BAND_2_4_GHZ);`,
198
203
  ` __tc_wifi.connected = false;`,
199
204
  ` printk("tc-wifi: connecting to %s\\n", ssid);`,
200
205
  `}`,
201
206
  ``,
202
- `// CUTTLEFISH_WIFI_CONNECT_BLOCKING_BEGIN`,
203
- `static void __tc_wifi_connect(const char* ssid, const char* password, int32_t timeout_ms) {`,
204
- ` __tc_wifi_connect_start(ssid, password);`,
205
- ` // Block until the L4 handler signals connectivity or the deadline passes.`,
206
- ` // 20ms slices let __tc_wifi_wait_slice pump the UI between polls.`,
207
+ `// join(): the thin station verb — associate from the construction facts,`,
208
+ `// apply the optional static-IPv4 / power-save facts, then bounded-wait for`,
209
+ `// IP connectivity. Returns whether the link came up (boolean, no exceptions).`,
210
+ `static bool __tc_wifi_join(const char* ssid, const char* psk,`,
211
+ ` enum wifi_security_type security, int32_t channel,`,
212
+ ` enum wifi_frequency_bands band, int32_t timeout_ms,`,
213
+ ` bool ps_off, const char* ip_addr, const char* gateway,`,
214
+ ` const char* netmask) {`,
215
+ ` __tc_wifi_ensure_init();`,
216
+ ` if (__tc_wifi.iface == nullptr) {`,
217
+ ` printk("tc-wifi: no WiFi iface found\\n");`,
218
+ ` return false;`,
219
+ ` }`,
220
+ ` net_if_up(__tc_wifi.iface);`,
221
+ ` __tc_wifi_stage_creds(ssid, psk, security, channel, band);`,
222
+ ` __tc_wifi.connected = false;`,
223
+ ` if (ip_addr != nullptr && gateway != nullptr && netmask != nullptr) {`,
224
+ ` // Static IPv4 facts: stop DHCP, configure the address manually. The`,
225
+ ` // addr-add raises the events conn_mgr_monitor listens for, so`,
226
+ ` // \`connected\` flips without a lease.`,
227
+ ` net_dhcpv4_stop(__tc_wifi.iface);`,
228
+ ` struct in_addr addr = { 0 }, gw = { 0 }, mask = { 0 };`,
229
+ ` if (net_addr_pton(AF_INET, ip_addr, &addr) == 0`,
230
+ ` && net_addr_pton(AF_INET, netmask, &mask) == 0`,
231
+ ` && net_addr_pton(AF_INET, gateway, &gw) == 0) {`,
232
+ ` (void)net_if_ipv4_addr_add(__tc_wifi.iface, &addr, NET_ADDR_MANUAL, 0);`,
233
+ ` // set_netmask() is __deprecated on Zephyr >= 4.3 — the`,
234
+ ` // by-addr form carries the prefix it belongs to.`,
235
+ ` (void)net_if_ipv4_set_netmask_by_addr(__tc_wifi.iface, &addr, &mask);`,
236
+ ` (void)net_if_ipv4_set_gw(__tc_wifi.iface, &gw);`,
237
+ ` } else {`,
238
+ ` printk("tc-wifi: bad static ipv4 facts, falling back to DHCP\\n");`,
239
+ ` net_dhcpv4_start(__tc_wifi.iface);`,
240
+ ` }`,
241
+ ` }`,
242
+ ` if (ps_off) {`,
243
+ ` // WiFi.PS_OFF — disable the radio's modem sleep (wifi_ps_params).`,
244
+ ` struct wifi_ps_params ps = {}; // value-init: first member is an enum`,
245
+ ` ps.enabled = WIFI_PS_DISABLED;`,
246
+ ` (void)net_mgmt(NET_REQUEST_WIFI_PS_CONFIG, __tc_wifi.iface, &ps, sizeof(ps));`,
247
+ ` }`,
248
+ ` printk("tc-wifi: joining %s\\n", ssid);`,
207
249
  ` int32_t waited = 0;`,
208
250
  ` while (!__tc_wifi.connected && waited < timeout_ms) { __tc_wifi_wait_slice(20); waited += 20; }`,
209
- ` printk("tc-wifi: connect %s after %dms\\n", __tc_wifi.connected ? "ok" : "timeout", waited);`,
251
+ ` printk("tc-wifi: join %s after %dms\\n", __tc_wifi.connected ? "ok" : "timeout", waited);`,
252
+ ` return __tc_wifi.connected;`,
210
253
  `}`,
211
- `// CUTTLEFISH_WIFI_CONNECT_BLOCKING_END`,
212
254
  ``,
213
255
  `static void __tc_wifi_disconnect(void) {`,
214
256
  ` __tc_wifi_ensure_init();`,
@@ -221,10 +263,6 @@ export function wifiInitLines(): string[] {
221
263
  ``,
222
264
  `// ── status / radio queries ───────────────────────────────────────────────`,
223
265
  `// CUTTLEFISH_WIFI_QUERY_BEGIN`,
224
- `static int32_t __tc_wifi_status(void) {`,
225
- ` return __tc_wifi.connected ? 3 : 0; // 3=Connected in the HAL status enum`,
226
- `}`,
227
- ``,
228
266
  `static const char* __tc_wifi_local_ip(void) {`,
229
267
  ` __tc_wifi_ensure_init();`,
230
268
  ` if (__tc_wifi.iface == nullptr || !__tc_wifi.connected) return "0.0.0.0";`,
@@ -251,7 +289,7 @@ export function wifiInitLines(): string[] {
251
289
  ` struct wifi_iface_status status = { 0 };`,
252
290
  ` (void)net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, __tc_wifi.iface,`,
253
291
  ` &status, sizeof(status));`,
254
- ` // Pack the 6 MAC bytes (status.bssid) into a uint64 (HAL returns a number).`,
292
+ ` // Pack the 6 MAC bytes (status.bssid) into a uint64 (the HAL returns a number).`,
255
293
  ` uint64_t m = 0;`,
256
294
  ` for (int32_t b = 0; b < 6; b++) { m = (m << 8) | static_cast<uint64_t>(status.bssid[b]); }`,
257
295
  ` return m;`,
@@ -295,62 +333,12 @@ export function wifiInitLines(): string[] {
295
333
  `}`,
296
334
  `// CUTTLEFISH_WIFI_SCAN_END`,
297
335
  ``,
298
- `// ── config ───────────────────────────────────────────────────────────────`,
299
- `// CUTTLEFISH_WIFI_CONFIG_BEGIN`,
300
- `// NOTE: wifi.set_tx_power is intentionally NOT lowered here. The Zephyr esp32`,
301
- `// WiFi driver owns esp_wifi_start/esp_wifi_connect, and calling`,
302
- `// esp_wifi_set_max_tx_power from this shim fights the driver for control of`,
303
- `// the radio (brownout). The compile-time PHY ceiling (ESP_PHY_MAX_WIFI_TX_POWER`,
304
- `// in ESP-IDF's components/esp_phy/Kconfig) is NOT sourced into Zephyr's Kconfig`,
305
- `// tree, so it cannot be lowered via prj.conf either (zephyr#45580). TX power`,
306
- `// stays at its default until a Zephyr-native surface exists.`,
307
- `static void __tc_wifi_set_hostname(const char* name) {`,
308
- ` // Best-effort: Zephyr has no net_if_set_hostname; the system hostname`,
309
- ` // comes from the hostname subsystem (net_hostname.h) + CONFIG_NET_HOSTNAME.`,
310
- ` // The interface name is set via net_if_set_name, which is not the same as`,
311
- ` // a DHCP hostname. No-op until the hostname subsystem is wired.`,
312
- ` (void)name;`,
313
- ` (void)__tc_wifi;`,
314
- `}`,
315
- ``,
316
- `// ── power save (NET_REQUEST_WIFI_PS_CONFIG) ─────────────────────────────`,
317
- `// wifi.set_power_save: HAL modes are "default" (enabled) / "none" (disabled).`,
318
- `// The Zephyr esp32 driver implements esp32_wifi_set_power_save, so this is a`,
319
- `// real net_mgmt request — not a no-op like set_hostname above.`,
320
- `static void __tc_wifi_set_power_save(const char* mode) {`,
321
- ` __tc_wifi_ensure_init();`,
322
- ` if (__tc_wifi.iface == nullptr) return;`,
323
- ` struct wifi_ps_params ps = { 0 };`,
324
- ` ps.type = WIFI_PS_PARAM_TYPE_ENABLED;`,
325
- ` // HAL mode "default" → power save on; "none" → off. (The full HAL surface`,
326
- ` // only exposes those two; deeper ps_mode/wakeup tuning isn't exposed.)`,
327
- ` bool on = (mode != nullptr && strcmp(mode, "none") != 0);`,
328
- ` ps.enabled = on ? WIFI_PS_ENABLED : WIFI_PS_DISABLED;`,
329
- ` (void)net_mgmt(NET_REQUEST_WIFI_PS_CONFIG, __tc_wifi.iface,`,
330
- ` &ps, sizeof(ps));`,
331
- `}`,
332
- ``,
333
- `// ── waits (block on the L4 connectivity flag) ───────────────────────────`,
334
- `// wifi.wait_connected / wait_disconnected: poll __tc_wifi.connected (set by`,
335
- `// the L4 net_mgmt handler) with a deadline. Same blocking pattern as`,
336
- `// __tc_wifi_connect.`,
337
- `static void __tc_wifi_wait_connected(int32_t timeout_ms) {`,
338
- ` __tc_wifi_ensure_init();`,
339
- ` int32_t waited = 0;`,
340
- ` while (!__tc_wifi.connected && waited < timeout_ms) { __tc_wifi_wait_slice(20); waited += 20; }`,
341
- `}`,
342
-
343
- `static void __tc_wifi_wait_disconnected(void) {`,
344
- ` __tc_wifi_ensure_init();`,
345
- ` // No timeout in the HAL surface — block until the L4 handler clears the flag.`,
346
- ` while (__tc_wifi.connected) { __tc_wifi_wait_slice(20); }`,
347
- `}`,
348
- ``,
349
336
  `// ── AP mode (NET_REQUEST_WIFI_AP_ENABLE / DISABLE) ──────────────────────`,
350
- `// wifi.ap_start / ap_stop: bring the iface up as an AP. The esp32 driver's`,
351
- `// ap_enable takes the same struct as connect (ssid/psk/channel/security).`,
352
- `// hidden/maxClients/channel-after-start have no driver hook (see manifest) —`,
353
- `// only ssid/password/channel at start are honored.`,
337
+ `// CUTTLEFISH_WIFI_CONFIG_BEGIN`,
338
+ `// WiFiAP.start()/stop(): bring the iface up as an AP. The esp32 driver's`,
339
+ `// ap_enable takes the same struct as join (ssid/psk/channel/security).`,
340
+ `// hidden/maxClients have no driver hook — the thin WiFiAP facts carry only`,
341
+ `// what the driver honors.`,
354
342
  `static struct wifi_connect_req_params __tc_wifi_ap_params;`,
355
343
  `static uint8_t __tc_wifi_ap_ssid_buf[33];`,
356
344
  `static uint8_t __tc_wifi_ap_psk_buf[64];`,
@@ -402,15 +390,21 @@ export function wifiInitLines(): string[] {
402
390
  export function lowerWifi(op: HALOpIR): { code?: string; expression?: string } | undefined {
403
391
  const o = op as any;
404
392
  switch (op.operation) {
405
- // ── Connection ──
406
- case 'wifi.connect':
407
- return { code: `__tc_wifi_connect(${s(o.ssid)}, ${s(o.password ?? 'nullptr')}, ${s(o.timeoutMs ?? 15000)});` };
393
+ // ── Station ──
394
+ case 'wifi.join': {
395
+ // Token Zephyr enum mapping (WiFi.OPEN/WPA2/WPA3/WPA2_WPA3).
396
+ const sec = Number(o.security ?? 1);
397
+ const secEnum = sec === 0 ? 'WIFI_SECURITY_TYPE_NONE'
398
+ : sec === 2 ? 'WIFI_SECURITY_TYPE_SAE'
399
+ : sec === 3 ? 'WIFI_SECURITY_TYPE_PSK_SAE'
400
+ : 'WIFI_SECURITY_TYPE_PSK';
401
+ const bandEnum = Number(o.band ?? 0) === 1 ? 'WIFI_FREQ_BAND_5_GHZ' : 'WIFI_FREQ_BAND_2_4_GHZ';
402
+ return { expression: `__tc_wifi_join(${s(o.ssid)}, ${o.psk != null ? s(o.psk) : 'nullptr'}, ${secEnum}, ${s(o.channel ?? 0)}, ${bandEnum}, ${s(o.timeoutMs ?? 15000)}, ${Number(o.ps ?? 0) !== 0 ? 'true' : 'false'}, ${o.ipAddr != null ? s(o.ipAddr) : 'nullptr'}, ${o.gateway != null ? s(o.gateway) : 'nullptr'}, ${o.netmask != null ? s(o.netmask) : 'nullptr'})` };
403
+ }
408
404
  case 'wifi.connect_start':
409
- return { code: `__tc_wifi_connect_start(${s(o.ssid)}, ${s(o.password ?? 'nullptr')});` };
405
+ return { code: `__tc_wifi_connect_start(${s(o.ssid)}, ${o.password != null ? s(o.password) : 'nullptr'});` };
410
406
  case 'wifi.disconnect':
411
407
  return { code: `__tc_wifi_disconnect();` };
412
- case 'wifi.status':
413
- return { expression: `__tc_wifi_status()` };
414
408
  case 'wifi.is_connected':
415
409
  return { expression: `(__tc_wifi.connected)` };
416
410
  case 'wifi.local_ip':
@@ -422,6 +416,8 @@ export function lowerWifi(op: HALOpIR): { code?: string; expression?: string } |
422
416
  // ── Scan ──
423
417
  case 'wifi.scan':
424
418
  return { code: `__tc_wifi_scan_blocking();` };
419
+ // Async split of wifi.scan (synthesized by the async tier's netWaitInfo —
420
+ // no TS-facing method maps here). Kick without waiting; poll scan_done.
425
421
  case 'wifi.scan_start':
426
422
  return { code: `__tc_wifi_scan_start();` };
427
423
  case 'wifi.scan_done':
@@ -438,14 +434,9 @@ export function lowerWifi(op: HALOpIR): { code?: string; expression?: string } |
438
434
  : '__tc_wifi_scan_channel';
439
435
  return { expression: `${helper}(${s(o.index ?? 0)})` };
440
436
  }
441
- // ── Config ──
442
- case 'wifi.set_hostname':
443
- return { code: `__tc_wifi_set_hostname(${s(o.name)});` };
444
- case 'wifi.set_power_save':
445
- // HAL modes are "default" (on) / "none" (off) — see the shim's note.
446
- return { code: `__tc_wifi_set_power_save(${s(o.mode)});` };
437
+ // ── Events ──
447
438
  case 'wifi.on_event': {
448
- // Event callbacks (wifi.on_event). 'disconnect' and 'connect' are supported.
439
+ // 'disconnect' and 'connect' are the supported events.
449
440
  if (o.event === 'disconnect') {
450
441
  return { code: `__tc_wifi.on_disconnect = ${s(o.handler)};` };
451
442
  }
@@ -454,11 +445,6 @@ export function lowerWifi(op: HALOpIR): { code?: string; expression?: string } |
454
445
  }
455
446
  return undefined;
456
447
  }
457
- // ── Waits (block on the L4 connectivity flag) ──
458
- case 'wifi.wait_connected':
459
- return { code: `__tc_wifi_wait_connected(${s(o.timeoutMs ?? 15000)});` };
460
- case 'wifi.wait_disconnected':
461
- return { code: `__tc_wifi_wait_disconnected();` };
462
448
  // ── AP mode (esp32 driver: ap_enable/ap_disable wired; only ssid/psk/channel
463
449
  // honored — hidden/maxClients have no driver hook). ──
464
450
  case 'wifi.ap_start':
@@ -466,11 +452,10 @@ export function lowerWifi(op: HALOpIR): { code?: string; expression?: string } |
466
452
  case 'wifi.ap_stop':
467
453
  return { code: `__tc_wifi_ap_stop();` };
468
454
  default:
469
- // Out of scope (genuinely not lowered): ap_client_count/ap_ip/ap_set_*,
470
- // credentials (save/connect_saved/clear), set_static_ip, set_auto_reconnect,
471
- // set_tx_power. Each has no driver/Kconfig hook on Zephyr — see the manifest's
472
- // per-op reasons. Return undefined so the resolver falls back and the
473
- // 'unsupported' declaration is honest (the validator probes these).
455
+ // Out of scope (genuinely not lowered): each remaining wifi.* kind has no
456
+ // driver/Kconfig hook on Zephyr — see the manifest's per-op reasons.
457
+ // Return undefined so the resolver falls back and the 'unsupported'
458
+ // declaration is honest (the validator probes these).
474
459
  return undefined;
475
460
  }
476
461
  }
@@ -0,0 +1,62 @@
1
+ // ---------------------------------------------------------------------------
2
+ // sdk/board-catalog-sync.ts — framework-side catalog orchestration.
3
+ //
4
+ // The catalog tooling (walker, overlay store, fs-only discovery) lives in
5
+ // @typecad/cuttlefish/board-catalog — the create flow needs it before any
6
+ // framework is installed. This module adds the one thing the framework owns
7
+ // — the full spawn-based west discovery cascade for an explicit
8
+ // `cuttlefish board sync` — and re-exports the store for the strategy's
9
+ // import surface.
10
+ // ----------------------------------------------------------------------------
11
+
12
+ import path from 'node:path';
13
+ import * as catalog from '@typecad/cuttlefish/board-catalog';
14
+ import { discoverWest } from '../toolchain/west-discover.js';
15
+
16
+ export type BoardCatalogSyncReport = catalog.BoardCatalogSyncReport;
17
+ export type BoardCatalogEnsureResult = catalog.BoardCatalogEnsureResult;
18
+ export type BoardCatalogOverlay = catalog.BoardCatalogOverlay;
19
+
20
+ export const {
21
+ GENERATOR_REV,
22
+ isZephyrBase,
23
+ locateZephyrBaseCheap,
24
+ overlayPathFor,
25
+ readBoardCatalogOverlayFile,
26
+ loadBoardCatalogOverlay,
27
+ resetBoardCatalogOverlayCache,
28
+ isOverlayStale,
29
+ diffBoardCatalogs,
30
+ boardRecordFingerprint,
31
+ findBoardInCatalog,
32
+ activeBoardCatalog,
33
+ resetActiveBoardCatalog,
34
+ } = catalog;
35
+
36
+ /** Sync with the full west discovery cascade behind it (the CLI's path):
37
+ * falls back through spawn-based discovery when the cheap fs probes find
38
+ * nothing. */
39
+ export function syncBoardCatalog(opts: { zephyrBase?: string } = {}): catalog.BoardCatalogSyncReport {
40
+ if (opts.zephyrBase) return catalog.syncBoardCatalog(opts);
41
+ const cheap = catalog.locateZephyrBaseCheap();
42
+ if (cheap) return catalog.syncBoardCatalog({ zephyrBase: cheap });
43
+ const install = discoverWest();
44
+ const base = install?.zephyrBase && catalog.isZephyrBase(install.zephyrBase)
45
+ ? path.resolve(install.zephyrBase)
46
+ : undefined;
47
+ return catalog.syncBoardCatalog(base ? { zephyrBase: base } : {});
48
+ }
49
+
50
+ /** The build-path pre-step: refresh a stale overlay before a regen
51
+ * (fs-only discovery — no spawns during builds). */
52
+ export function ensureFreshBoardCatalog(): catalog.BoardCatalogEnsureResult {
53
+ return catalog.ensureFreshBoardCatalog();
54
+ }
55
+
56
+ /** Locate a Zephyr tree by any means (spawn cascade included). */
57
+ export function locateZephyrBaseFull(): string | undefined {
58
+ const install = discoverWest();
59
+ return install?.zephyrBase && catalog.isZephyrBase(install.zephyrBase)
60
+ ? path.resolve(install.zephyrBase)
61
+ : undefined;
62
+ }