@typecad/hal 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 (121) hide show
  1. package/README.md +145 -87
  2. package/dist/adc-pin.d.ts +53 -0
  3. package/dist/adc-pin.js +69 -0
  4. package/dist/async.d.ts +3 -11
  5. package/dist/async.js +3 -15
  6. package/dist/ble.d.ts +42 -78
  7. package/dist/ble.js +79 -98
  8. package/dist/counter.d.ts +16 -0
  9. package/dist/counter.js +32 -0
  10. package/dist/dac-pin.d.ts +13 -0
  11. package/dist/dac-pin.js +21 -0
  12. package/dist/emit.d.ts +123 -196
  13. package/dist/emit.js +146 -208
  14. package/dist/fs.d.ts +12 -31
  15. package/dist/fs.js +30 -40
  16. package/dist/gpio-pin.d.ts +46 -0
  17. package/dist/gpio-pin.js +77 -0
  18. package/dist/gpio.d.ts +0 -103
  19. package/dist/gpio.js +16 -227
  20. package/dist/http.d.ts +38 -39
  21. package/dist/http.js +53 -78
  22. package/dist/i2c-target.d.ts +28 -0
  23. package/dist/i2c-target.js +52 -0
  24. package/dist/i2c.d.ts +5 -43
  25. package/dist/i2c.js +17 -130
  26. package/dist/index.d.ts +30 -42
  27. package/dist/index.js +27 -39
  28. package/dist/math.d.ts +0 -13
  29. package/dist/math.js +9 -13
  30. package/dist/mqtt.d.ts +15 -25
  31. package/dist/mqtt.js +32 -28
  32. package/dist/power.d.ts +9 -17
  33. package/dist/power.js +22 -20
  34. package/dist/preferences.d.ts +17 -25
  35. package/dist/preferences.js +54 -52
  36. package/dist/pulse.d.ts +4 -4
  37. package/dist/pulse.js +6 -2
  38. package/dist/pwm-pin.d.ts +24 -0
  39. package/dist/pwm-pin.js +38 -0
  40. package/dist/random.d.ts +0 -2
  41. package/dist/random.js +14 -20
  42. package/dist/sensor-catalog.generated.d.ts +997 -0
  43. package/dist/sensor-catalog.generated.js +764 -0
  44. package/dist/sensor.d.ts +46 -0
  45. package/dist/sensor.js +52 -0
  46. package/dist/shift-pin.d.ts +2 -0
  47. package/dist/shift-pin.js +13 -0
  48. package/dist/spi-target.d.ts +25 -0
  49. package/dist/spi-target.js +42 -0
  50. package/dist/spi.d.ts +8 -26
  51. package/dist/spi.js +15 -87
  52. package/dist/thread.d.ts +18 -0
  53. package/dist/thread.js +36 -0
  54. package/dist/time.d.ts +23 -0
  55. package/dist/time.js +43 -0
  56. package/dist/timing.d.ts +17 -7
  57. package/dist/timing.js +17 -7
  58. package/dist/types.d.ts +4 -34
  59. package/dist/types.js +5 -47
  60. package/dist/uart-port.d.ts +26 -0
  61. package/dist/uart-port.js +52 -0
  62. package/dist/uart.d.ts +0 -17
  63. package/dist/uart.js +10 -53
  64. package/dist/usb.d.ts +26 -0
  65. package/dist/usb.js +66 -0
  66. package/dist/watchdog.d.ts +12 -0
  67. package/dist/watchdog.js +28 -0
  68. package/dist/wifi.d.ts +88 -64
  69. package/dist/wifi.js +112 -126
  70. package/dist/zephyr-tokens.generated.d.ts +8 -0
  71. package/dist/zephyr-tokens.generated.js +73 -0
  72. package/package.json +6 -7
  73. package/src/adc-pin.ts +89 -0
  74. package/src/async.ts +3 -16
  75. package/src/ble.ts +84 -111
  76. package/src/counter.ts +40 -0
  77. package/src/dac-pin.ts +28 -0
  78. package/src/emit.ts +157 -238
  79. package/src/fs.ts +47 -54
  80. package/src/gpio-pin.ts +91 -0
  81. package/src/gpio.ts +49 -320
  82. package/src/http.ts +75 -95
  83. package/src/i2c-target.ts +63 -0
  84. package/src/i2c.ts +29 -167
  85. package/src/index.ts +32 -46
  86. package/src/math.ts +9 -14
  87. package/src/mqtt.ts +39 -31
  88. package/src/preferences.ts +52 -61
  89. package/src/pwm-pin.ts +54 -0
  90. package/src/random.ts +14 -21
  91. package/src/sensor-catalog.generated.ts +1238 -0
  92. package/src/sensor.ts +80 -0
  93. package/src/shift-pin.ts +16 -0
  94. package/src/spi-target.ts +53 -0
  95. package/src/spi.ts +27 -121
  96. package/src/thread.ts +44 -0
  97. package/src/time.ts +50 -0
  98. package/src/types.ts +14 -89
  99. package/src/uart-port.ts +64 -0
  100. package/src/usb.ts +82 -0
  101. package/src/watchdog.ts +35 -0
  102. package/src/wifi.ts +147 -179
  103. package/src/zephyr-tokens.generated.ts +77 -0
  104. package/src/adc.ts +0 -30
  105. package/src/capacitive.ts +0 -31
  106. package/src/constants.ts +0 -23
  107. package/src/dac.ts +0 -21
  108. package/src/eeprom.ts +0 -26
  109. package/src/interrupts.ts +0 -35
  110. package/src/mdns.ts +0 -50
  111. package/src/ota.ts +0 -44
  112. package/src/power.ts +0 -36
  113. package/src/pulse.ts +0 -63
  114. package/src/rmt.ts +0 -125
  115. package/src/shift.ts +0 -88
  116. package/src/temperature.ts +0 -20
  117. package/src/timer.ts +0 -58
  118. package/src/timing.ts +0 -67
  119. package/src/uart.ts +0 -77
  120. package/src/utils.ts +0 -17
  121. package/src/wdt.ts +0 -17
package/README.md CHANGED
@@ -1,127 +1,185 @@
1
1
  # `@typecad/hal`
2
2
 
3
3
  Hardware abstraction layer for [TypeCAD](https://cuttlefish.typecad.net) —
4
- GPIO, I2C, SPI, UART, timers, ADC/DAC, EEPROM, WiFi/HTTP, and more, written as
5
- regular TypeScript.
4
+ GPIO, timing, threads, PWM/ADC/DAC, I2C/SPI/UART/USB, persistent storage,
5
+ sensors, and WiFi/HTTP/MQTT/BLE, written as regular TypeScript.
6
6
 
7
7
  `@typecad/hal` is what firmware code imports to talk to hardware. You write
8
- normal TypeScript (`pin.high()`, `i2c.write(...)`, `Serial0.print(...)`); the
9
- TypeCAD transpiler (`@typecad/cuttlefish`) resolves each HAL call against the
10
- active MCU/board packages and emits the equivalent C++ at build time.
8
+ normal TypeScript (`led.toggle()`, `bus.writeReg(...)`, `Time.sleep(250)`);
9
+ the transpiler (`@typecad/cuttlefish`) resolves each HAL call against the
10
+ active board's facts and emits the equivalent C++ at build time. There are
11
+ no runtime fallbacks — if the HAL doesn't lower it, it doesn't appear in the
12
+ firmware.
11
13
 
12
14
  ## Install
13
15
 
16
+ HAL projects are scaffolded by cuttlefish, which wires the framework,
17
+ board target, and the Zephyr SDK for you:
18
+
14
19
  ```bash
15
- npm install @typecad/hal @typecad/cuttlefish
20
+ npx @typecad/cuttlefish create my-firmware
21
+ cd my-firmware && npx cuttlefish build --compile
16
22
  ```
17
23
 
18
- You'll also want an MCU package (e.g. `@typecad/mcu-esp32`) and a board package
19
- (e.g. `@typecad/board-esp32-devkit`) to pin and bus definitions for your target.
20
-
21
- ## Overview
22
-
23
- The HAL is built on three compile-time directives that look like ordinary
24
- TypeScript but are intercepted by the transpiler:
25
-
26
- - **`emit(text)`** — appends a line of C++ to the output (with parameter/field substitution).
27
- - **`include(header)`** — adds a deduplicated `#include` to the output.
28
- - **`board(path)`** — looks up a board-specific constant (e.g. pin numbers) inside an `emit()` template.
29
-
30
- This means there are no runtime fallbacks: if the HAL doesn't `emit()` it, it
31
- doesn't appear in the firmware. See [`HAL-GUIDE.md`](./HAL-GUIDE.md) for how to
32
- add new HAL features.
24
+ A project imports hardware from **`@typecad/board`** the module cuttlefish
25
+ generates per project from the Zephyr board catalog. That module is the
26
+ narrowed gateway: it re-exports a hardware class only when this board's
27
+ facts support it, so importing unavailable hardware fails at module
28
+ resolution (editor and transpile), not at a deep diagnostic. `@typecad/hal`
29
+ is the implementation package.
33
30
 
34
31
  ## What's included
35
32
 
33
+ Every class is thin and Zephyr-shaped: construction carries the facts, and
34
+ each method maps onto the kernel/driver API verbatim — no Arduino
35
+ vocabulary, no transaction dance.
36
+
36
37
  | Area | Exports |
37
38
  | --- | --- |
38
- | **Digital I/O** | `Pin`, `OutputPin`, `InputPin`, `PinMode`, `HIGH`, `LOW`, `INPUT`, `OUTPUT`, `INPUT_PULLUP` |
39
- | **Pin groups** | `createPinGroup`, `IPinGroup`, `PinCapabilityFlags` |
40
- | **Analog** | `ADC`, `ADCClass`, `DAC`, `DACClass`, `AnalogValue` |
41
- | **I2C** | `I2CBus`, `II2CBus`, `I2CStatus`, `i2cName` |
42
- | **SPI** | `SPIBus`, `ISPIBus`, `SPIStatus`, `SPISettings`, `spiName` |
43
- | **UART / Serial** | `SerialPort`, `IUARTBus`, `UARTStatus`, `serialName` |
44
- | **Networking** | `WiFi`, `WiFiClass`, `WiFiStatus`, `WiFiEncryption`, `Http`, `HttpClass`, `HttpRequest`, `HttpMethod` |
45
- | **Timing** | `delay`, `millis`, `micros`, `delayMicroseconds`, `Timing`, `map`, `constrain` |
46
- | **Pulse / Shift** | `pulseIn`, `shiftIn`, `shiftOut` |
47
- | **Interrupts** | `attachInterrupt`, `detachInterrupt`, `noInterrupts`, `interrupts`, `InterruptMode` |
48
- | **Timers** | `HardwareTimer`, `Timer0`, `Timer1`, `Timer2` |
49
- | **Storage** | `EEPROM`, `Preferences` (NVFlash), `FS` |
50
- | **Power / Watchdog** | `Power`, `WDT` (`WDTO_1S`, …) |
51
- | **Math / Random** | `abs`, `min`, `max`, `Num`, `random`, `randomSeed` |
52
- | **Async** | `Async` (cooperative scheduling) |
53
- | **Directives** | `emit`, `include`, `board`, `callback` |
39
+ | **Digital I/O** | `Pin` (identity), `GPIO` (configure/read/write/toggle, `onInterrupt`/`offInterrupt`), `shiftOut`/`shiftIn` |
40
+ | **Timing** | `Time` (`sleep`/`now`/`nowUs`/`busyWaitUs`) |
41
+ | **Concurrency** | `Thread` (kernel threads), `Async` (cooperative await), `Counter` (hardware timers) |
42
+ | **PWM** | `PWM` (`setPulse`/`setDuty`/`setPeriod`; ns-true verbs) |
43
+ | **Analog in** | `ADC` (`read`/`readMillivolts`, gain/reference tokens; every ADC controller the SoC declares) |
44
+ | **Analog out** | `DAC` (`write`) |
45
+ | **I2C** | `I2CTarget` (register verbs; also the Sensor fact-carrier), `I2CBus` (controller selector: `I2C0.device(0x44)` returns a ready target) |
46
+ | **SPI** | `SPITarget` (transceive/register verbs), `SPIBus` (controller selector: `SPI0.device(PA4)` returns a ready target) |
47
+ | **UART** | `UART` (writeLine/read ring) — the board exports ready-to-use instances (`UART0.writeLine(...)`) |
48
+ | **USB** | `USBConsole` (CDC console: open/write/read/linked) |
49
+ | **Storage** | `Store` (persistent typed keys), `File` (littlefs text files) |
50
+ | **Watchdog** | `Watchdog` |
51
+ | **Sensors** | `Sensor` + the generated `SENSOR`/`CHAN` catalog |
52
+ | **Networking** | `WiFi`, `Request` (HTTP), `Mqtt`, `BLE` (GATT peripheral) |
53
+ | **Math / Random** | `abs`/`min`/`max`/`Num`, `Random` (`seed`/`upTo`/`between`/`int`) |
54
+ | **Registers** | `@register`/`@bits` (memory-mapped struct decorators) |
55
+ | **Zephyr tokens** | `ZEPHYR_ADC_GAINS`, `ZEPHYR_ADC_REFERENCES`, `ZEPHYR_GPIO_FLAGS`, `ZEPHYR_GPIO_INTS` (generated from the pinned tree's headers) |
56
+
57
+ Periodic and deferred work is a `Thread` (or a `Counter` for hardware
58
+ timers) — there are no JS-named timers (`setInterval`/`setTimeout`) on
59
+ embedded targets.
60
+
61
+ ## Compile-time directives
62
+
63
+ Directives look like ordinary TypeScript but are intercepted by the
64
+ transpiler:
65
+
66
+ - **`rawCpp(text)`** — appends a line of C++ to the output (with field/parameter substitution).
67
+ - **`rawCppExpr(text)`** — the same, in expression position.
68
+ - **`include(header)`** — adds a deduplicated `#include` to the output.
69
+ - **`board(path)`** — resolves a board-fact constant inside a template.
70
+
71
+ `callback(fn)` registers a function value so it can be passed to APIs that
72
+ take handlers (interrupts, threads, bus events). See
73
+ [`HAL-GUIDE.md`](./HAL-GUIDE.md) for how HAL features are built.
54
74
 
55
75
  ## Example
56
76
 
57
77
  ```ts
58
- import { OutputPin, HIGH, LOW, delay } from '@typecad/hal';
78
+ import { LED } from '@typecad/board';
79
+ import { GPIO, Time, Thread } from '@typecad/hal';
80
+
81
+ const led = new GPIO(LED, GPIO.OUTPUT);
82
+
83
+ // A kernel thread blinks concurrently with main.
84
+ const blinker = new Thread(0, { stackKb: 2 });
85
+ blinker.start((): void => {
86
+ while (true) {
87
+ led.toggle();
88
+ Time.sleep(250);
89
+ }
90
+ });
91
+ blinker.join();
92
+ ```
59
93
 
60
- const led = new OutputPin('LED_BUILTIN');
94
+ Bus singletons from `@typecad/board` are directly usable — the board
95
+ exports functional instances (no strings, no construction, and unavailable
96
+ buses are simply not exported):
61
97
 
62
- export function setup() {
63
- led.mode();
64
- }
98
+ ```ts
99
+ import { UART0 } from '@typecad/board';
65
100
 
66
- export function loop() {
67
- led.write(HIGH);
68
- delay(500);
69
- led.write(LOW);
70
- delay(500);
71
- }
101
+ UART0.writeLine('hello'); // usart1, default 115200
72
102
  ```
73
103
 
74
- For I2C/SPI/UART, instantiate the bus class with the board's pinned instance
75
- (see your `@typecad/board-*` package for available bus names).
76
-
77
- ## Hardware tests
104
+ Explicit construction remains for non-default facts, and takes the board
105
+ instance or the name; targets and sensors carry the bus instance and the
106
+ 7-bit address / chip-select from construction:
78
107
 
79
- The [`tests/`](./tests/) directory contains a hardware test suite that
80
- exercises every AVR-compilable HAL subsystem against real Arduino Uno hardware,
81
- using [`@typecad/expect`](https://cuttlefish.typecad.net)
82
- (`describe()` / `.it()` / `.expect()` / `done()`) over serial. Each file covers
83
- one subsystem: GPIO, timing, math, random, pulse, shift, interrupts, UART,
84
- I2C, SPI, ADC, EEPROM, WDT, Preferences, async, and constants.
108
+ ```ts
109
+ import { I2C0, SENSOR, CHAN } from '@typecad/board';
85
110
 
86
- ESP32-only subsystems (DAC, `FS`, `Power`, `HardwareTimer`) are intentionally
87
- omitted they require an ESP32 target.
111
+ // device() hands back the FUNCTIONAL target — verbs callable immediately,
112
+ // and the same object is the Sensor fact-carrier.
113
+ const dev = I2C0.device(0x44);
114
+ dev.writeReg(0x30, 0xA2); // i2c_reg_write_byte
88
115
 
89
- Run on a connected Uno:
116
+ const sht3x = new Sensor(SENSOR.sensirion_sht3xd, I2C0.device(0x44));
117
+ sht3x.fetch();
118
+ const temp = sht3x.get(CHAN.AMBIENT_TEMP);
90
119
 
91
- ```bash
92
- npm exec --workspace @typecad/hal -- cuttlefish-test
120
+ // Explicit construction is equivalent: new I2CTarget(I2C0, 0x44).
93
121
  ```
94
122
 
95
- The suite is configured by [`cuttlefish.config.ts`](./cuttlefish.config.ts).
96
- Like the [`@typecad/framework-arduino`](https://cuttlefish.typecad.net)
97
- tests, it imports through `@typecad/board` (the board package) and ambient globals
98
- declared in `cuttlefish-env.d.ts`, never directly from `@typecad/board`, so the
99
- transpiler resolves each call against the active MCU/board packages.
100
-
101
- ### Skipped on AVR
102
-
103
- One file is skipped on AVR by a `@typecad-skip-target` directive, for a
104
- genuine hardware reason (not a transpiler limitation):
123
+ ## Hardware tests
105
124
 
106
- - **`08-uart`** the Uno has a single hardware UART, which the test runner
107
- itself uses as the `[TC:...]` protocol channel. Any `UART0` call disrupts
108
- that channel. Runs on multi-UART targets (ESP32).
125
+ The [`tests/`](./tests/) directory is the HAL hardware suite the on-metal
126
+ proof that the HAL works. It runs via
127
+ [`@typecad/expect`](../expect/README.md) (`describe()` / `.it()` /
128
+ `.expect()` / `done()`) over the board's console, and one shared suite
129
+ covers every board:
130
+
131
+ - **`tests/common/`** — board-agnostic groups, one file per subsystem:
132
+ timing, math, random, shift, interrupts, UART, I2C, ADC, WDT, Store,
133
+ File, async, constants, Counter.
134
+ - **`tests/board/`** — board-level groups (GPIO, PWM, SPI, LED). These
135
+ import **role names** from the `@typecad/test-pins` virtual module
136
+ (`GPIO_OUT`, `PWM_PIN`, `ADC_PIN`, `I2C_BUS`, …); each board's
137
+ `boards/<name>/test-pins.json` declares which pins fill each role, and the
138
+ runner substitutes them before transpiling. A file whose required roles
139
+ (declared with `// @typecad-requires-roles …`) are absent skips cleanly —
140
+ coverage differences are data, never per-board test copies.
141
+ - **`tests/network/`** — on-hardware HTTP/MQTT/BLE suites against a local
142
+ host server (see [`tests/network/README.md`](./tests/network/README.md)).
143
+ - **`tests/wired/`** — opt-in loopback tier (jumper `gpioOut` → `gpioIn`);
144
+ not part of the default runs.
145
+
146
+ Each board has a config in [`boards/`](./boards/) (currently the WeAct
147
+ Black Pill STM32F411 and the ESP32-S3 DevKitC). Run a suite:
109
148
 
110
- The async test (`15-async`) **runs on AVR**: on heap-less targets the
111
- transpiler emits a fixed-capacity, allocation-free static timer/task runtime
112
- (`async-runtime-static.ts`) in place of the full `Promise<T>` runtime used on
113
- ESP32, so `Async.sleep`/`yield`/`sleepUntil`/`currentTask` link and run on the
114
- ATmega328P.
149
+ ```bash
150
+ npm run test:hw --workspace @typecad/hal # Black Pill (ST-Link + console UART)
151
+ npm run test:hw:esp32s3 --workspace @typecad/hal # DevKitC (esptool + CH34x console)
152
+ ```
115
153
 
116
- ESP32-only subsystems (DAC, `FS`, `Power`, `HardwareTimer`) are omitted
117
- entirely they require an ESP32 target.
154
+ The `[TC:...]` test protocol rides the board's console (its devicetree
155
+ `zephyr,console` node). Port resolution: `--port` / `CUTTLEFISH_PORT` wins,
156
+ then `test.port` in the board's config, then USB-identity discovery
157
+ (`test-pins.json` carries `usb: { vid, pid }` — e.g. the DevKitC's CH34x
158
+ bridge `1A86:55D3`), and the port re-resolves after every flash
159
+ re-enumeration. A program that also constructs `USB0` composes a CDC device
160
+ enumerating at the shared Zephyr-test identity `2FE3:0001`.
161
+
162
+ ### Board parity and documented hardware limits
163
+
164
+ Every board runs every group its silicon supports. Gaps are hard hardware
165
+ limits expressed as role skips: the ESP32-S3 DevKitC declares no I2C
166
+ controller and no `led0` node (and its UART0 is the protocol channel), so
167
+ those groups skip there by role. Everything else — GPIO, PWM, ADC (both
168
+ SARADC units), SPI, timing, math, random, shift, interrupts, WDT, Store,
169
+ File, async, constants, Counter — runs on both boards.
170
+
171
+ `Sensor` and `DAC` have a full pipeline (catalog → devicetree
172
+ synthesis → Zephyr driver API) but no sensor or DAC-capable board on the
173
+ current rig, so they are compile-verified only until one is attached. The
174
+ network tier needs the host server (`npm run test:http`) and credentials in
175
+ `tests/network/secrets.ts`.
118
176
 
119
177
  ## Ecosystem
120
178
 
121
- - [`@typecad/cuttlefish`](https://cuttlefish.typecad.net) — the transpiler that resolves HAL calls to C++.
122
- - [`@typecad/ui`](https://cuttlefish.typecad.net) — HTML/CSS-driven display graphics.
123
- - `@typecad/mcu-*`silicon pin/port/peripheral definitions.
124
- - `@typecad/board-*`board-level pin mappings and bus aliases.
179
+ - [`@typecad/cuttlefish`](../../README.md) — the transpiler that resolves HAL calls to C++.
180
+ - [`@typecad/framework-zephyr`](../framework-zephyr/README.md) — the Zephyr lowering, board catalog, and toolchain.
181
+ - [`@typecad/expect`](../expect/README.md)the on-hardware test framework.
182
+ - [`@typecad/ui`](../ui/README.md)HTML/CSS-driven display graphics.
125
183
 
126
184
  ## License
127
185
 
@@ -0,0 +1,53 @@
1
+ import type { Pin } from './gpio.js';
2
+ export declare class ADC {
3
+ static readonly GAIN_1_6 = 1;
4
+ static readonly GAIN_1_5 = 2;
5
+ static readonly GAIN_1_4 = 3;
6
+ static readonly GAIN_2_7 = 4;
7
+ static readonly GAIN_1_3 = 5;
8
+ static readonly GAIN_2_5 = 6;
9
+ static readonly GAIN_1_2 = 7;
10
+ static readonly GAIN_2_3 = 8;
11
+ static readonly GAIN_4_5 = 9;
12
+ static readonly GAIN_1 = 10;
13
+ static readonly GAIN_2 = 11;
14
+ static readonly GAIN_3 = 12;
15
+ static readonly GAIN_4 = 13;
16
+ static readonly GAIN_6 = 14;
17
+ static readonly GAIN_8 = 15;
18
+ static readonly GAIN_12 = 16;
19
+ static readonly GAIN_16 = 17;
20
+ static readonly GAIN_24 = 18;
21
+ static readonly GAIN_32 = 19;
22
+ static readonly GAIN_64 = 20;
23
+ static readonly GAIN_128 = 21;
24
+ static readonly REF_VDD_1 = 256;
25
+ static readonly REF_VDD_1_2 = 257;
26
+ static readonly REF_VDD_1_3 = 258;
27
+ static readonly REF_VDD_1_4 = 259;
28
+ static readonly REF_INTERNAL = 260;
29
+ static readonly REF_EXTERNAL0 = 261;
30
+ static readonly REF_EXTERNAL1 = 262;
31
+ private readonly _pin;
32
+ private readonly _gain;
33
+ private readonly _reference;
34
+ private readonly _channel;
35
+ private readonly _device;
36
+ private readonly _pinctrl;
37
+ /** Construct an analog input channel. Omitted gain/reference fall back to
38
+ * the chip descriptor's pair (the values the platform's driver validates
39
+ * against, e.g. STM32's ADC_GAIN_1 + ADC_REF_INTERNAL). */
40
+ constructor(pin: number | Pin, opts?: {
41
+ gain?: number;
42
+ reference?: number;
43
+ channel?: number;
44
+ device?: string;
45
+ pinctrl?: string;
46
+ });
47
+ /** Read raw counts at the chip's resolution (adc_channel_setup on first
48
+ * use with the construction gain/reference, then adc_read). */
49
+ read(): number;
50
+ /** Read millivolts (adc_raw_to_millivolts against the descriptor's
51
+ * vref). Returns mV. */
52
+ readMillivolts(): number;
53
+ }
@@ -0,0 +1,69 @@
1
+ // ---------------------------------------------------------------------------
2
+ // ADC — the thin Zephyr-shaped analog input
3
+ //
4
+ // Construction IS the channel setup: gain and reference are constructor
5
+ // options (exactly struct adc_channel_cfg), defaulting to the chip
6
+ // descriptor's pair when omitted. read() returns raw counts at the chip's
7
+ // resolution; readMillivolts() applies adc_raw_to_millivolts. There is no
8
+ // setReference() — Zephyr applies the reference at channel-setup time, and
9
+ // this surface doesn't promise otherwise.
10
+ //
11
+ // Gain/reference tokens are Zephyr's enum names under the ADC
12
+ // namespace (ADC_GAIN_1_4 ↔ ADC.GAIN_1_4, ADC_REF_INTERNAL ↔
13
+ // ADC.REF_INTERNAL); the lowering maps token names to macros.
14
+ // ----------------------------------------------------------------------------
15
+ import { adcReadRaw, adcReadMv } from './emit.js';
16
+ export class ADC {
17
+ /** Construct an analog input channel. Omitted gain/reference fall back to
18
+ * the chip descriptor's pair (the values the platform's driver validates
19
+ * against, e.g. STM32's ADC_GAIN_1 + ADC_REF_INTERNAL). */
20
+ constructor(pin, opts) {
21
+ this._pin = typeof pin === 'number' ? pin : pin.number;
22
+ this._gain = opts?.gain ?? '';
23
+ this._reference = opts?.reference ?? '';
24
+ this._channel = opts?.channel ?? -1;
25
+ this._device = opts?.device ?? '';
26
+ this._pinctrl = opts?.pinctrl ?? '';
27
+ }
28
+ /** Read raw counts at the chip's resolution (adc_channel_setup on first
29
+ * use with the construction gain/reference, then adc_read). */
30
+ read() {
31
+ return adcReadRaw(this._pin, this._gain, this._reference, this._channel, this._device, this._pinctrl);
32
+ }
33
+ /** Read millivolts (adc_raw_to_millivolts against the descriptor's
34
+ * vref). Returns mV. */
35
+ readMillivolts() {
36
+ return adcReadMv(this._pin, this._gain, this._reference, this._channel, this._device, this._pinctrl);
37
+ }
38
+ }
39
+ // ── Gain tokens (enum adc_gain, verbatim — generated set, see the
40
+ // token-sync test) ───────────────────────────────────────────────────
41
+ ADC.GAIN_1_6 = 0x01;
42
+ ADC.GAIN_1_5 = 0x02;
43
+ ADC.GAIN_1_4 = 0x03;
44
+ ADC.GAIN_2_7 = 0x04;
45
+ ADC.GAIN_1_3 = 0x05;
46
+ ADC.GAIN_2_5 = 0x06;
47
+ ADC.GAIN_1_2 = 0x07;
48
+ ADC.GAIN_2_3 = 0x08;
49
+ ADC.GAIN_4_5 = 0x09;
50
+ ADC.GAIN_1 = 0x0a;
51
+ ADC.GAIN_2 = 0x0b;
52
+ ADC.GAIN_3 = 0x0c;
53
+ ADC.GAIN_4 = 0x0d;
54
+ ADC.GAIN_6 = 0x0e;
55
+ ADC.GAIN_8 = 0x0f;
56
+ ADC.GAIN_12 = 0x10;
57
+ ADC.GAIN_16 = 0x11;
58
+ ADC.GAIN_24 = 0x12;
59
+ ADC.GAIN_32 = 0x13;
60
+ ADC.GAIN_64 = 0x14;
61
+ ADC.GAIN_128 = 0x15;
62
+ // ── Reference tokens (enum adc_reference, verbatim) ────────────────────
63
+ ADC.REF_VDD_1 = 0x100;
64
+ ADC.REF_VDD_1_2 = 0x101;
65
+ ADC.REF_VDD_1_3 = 0x102;
66
+ ADC.REF_VDD_1_4 = 0x103;
67
+ ADC.REF_INTERNAL = 0x104;
68
+ ADC.REF_EXTERNAL0 = 0x105;
69
+ ADC.REF_EXTERNAL1 = 0x106;
package/dist/async.d.ts CHANGED
@@ -2,10 +2,9 @@ export declare class AsyncClass {
2
2
  static readonly __instance_name = "Async";
3
3
  /**
4
4
  * Non-blocking sleep for `ms` milliseconds.
5
- * Returns a Promise<void> that resolves after the given delay.
6
- * The underlying C++ implementation uses the platform's timer/microtask
7
- * mechanism (e.g. millis-based polling on Arduino, std::this_thread::sleep_for
8
- * on native, or a FreeRTOS vTaskDelay in the future).
5
+ * Returns a Promise<void> that resolves after the given delay. The async
6
+ * runtime resolves it cooperatively (the static state machine on
7
+ * heap-less targets polls the clock in the scheduler loop).
9
8
  */
10
9
  sleep(ms: number): Promise<void>;
11
10
  /**
@@ -13,13 +12,6 @@ export declare class AsyncClass {
13
12
  * (microtasks, timers) to run. Resumes on the next microtask pump cycle.
14
13
  */
15
14
  yield(): Promise<void>;
16
- /**
17
- * Await a polling condition.
18
- * Repeatedly checks `condition()` every `pollIntervalMs` milliseconds
19
- * until it returns true, then resolves.
20
- * The underlying implementation uses the platform's timer mechanism.
21
- */
22
- sleepUntil(condition: () => boolean, pollIntervalMs?: number): Promise<void>;
23
15
  /**
24
16
  * Return a human-readable description of the currently executing async task.
25
17
  * Useful for debugging / logging in cooperative multitasking environments.
package/dist/async.js CHANGED
@@ -4,7 +4,6 @@
4
4
  // Provides a platform-independent API for:
5
5
  // - sleep(ms) — non-blocking delay via Promise + microtask
6
6
  // - yield() — cooperative yield to other tasks
7
- // - sleepUntil(condition) — await a condition (promise-based)
8
7
  // - currentTask() — return a description of the currently executing task
9
8
  //
10
9
  // Framework packages (Arduino, Native, etc.) provide the C++ runtime behind
@@ -15,10 +14,9 @@ import { rawCpp } from './emit.js';
15
14
  export class AsyncClass {
16
15
  /**
17
16
  * Non-blocking sleep for `ms` milliseconds.
18
- * Returns a Promise<void> that resolves after the given delay.
19
- * The underlying C++ implementation uses the platform's timer/microtask
20
- * mechanism (e.g. millis-based polling on Arduino, std::this_thread::sleep_for
21
- * on native, or a FreeRTOS vTaskDelay in the future).
17
+ * Returns a Promise<void> that resolves after the given delay. The async
18
+ * runtime resolves it cooperatively (the static state machine on
19
+ * heap-less targets polls the clock in the scheduler loop).
22
20
  */
23
21
  sleep(ms) {
24
22
  rawCpp(`__cuttlefish_async_sleep(${ms});`);
@@ -32,16 +30,6 @@ export class AsyncClass {
32
30
  rawCpp(`__cuttlefish_async_yield();`);
33
31
  return Promise.resolve();
34
32
  }
35
- /**
36
- * Await a polling condition.
37
- * Repeatedly checks `condition()` every `pollIntervalMs` milliseconds
38
- * until it returns true, then resolves.
39
- * The underlying implementation uses the platform's timer mechanism.
40
- */
41
- sleepUntil(condition, pollIntervalMs = 10) {
42
- rawCpp(`__cuttlefish_async_sleep_until(${pollIntervalMs});`);
43
- return Promise.resolve();
44
- }
45
33
  /**
46
34
  * Return a human-readable description of the currently executing async task.
47
35
  * Useful for debugging / logging in cooperative multitasking environments.
package/dist/ble.d.ts CHANGED
@@ -17,18 +17,6 @@ export declare enum BlePerm {
17
17
  Write = 2,
18
18
  Notify = 4
19
19
  }
20
- /** BLE peripheral status (mirrored by the runtime shim). */
21
- export declare enum BleStatus {
22
- Idle = 0,
23
- Initializing = 1,
24
- Advertising = 2,
25
- Connected = 3,
26
- Error = 4
27
- }
28
- export declare enum BleAdvertisingMode {
29
- Connectable = "connectable",
30
- NonConnectable = "non_connectable"
31
- }
32
20
  /** A well-known GATT characteristic entry in the catalog. */
33
21
  export interface GattCharacteristicDef {
34
22
  readonly uuid: string;
@@ -38,9 +26,10 @@ export interface GattCharacteristicDef {
38
26
  readonly notify?: boolean;
39
27
  }
40
28
  /**
41
- * Standard GATT services/characteristics. Autocomplete walks the hierarchy:
42
- * GATT.ENVIRONMENTAL. -> TEMPERATURE, HUMIDITY, ...
43
- * Pass the .uuid, .type, and computed perms to BleServer.characteristic().
29
+ * Standard GATT services/characteristics uuid/type/perms reference data.
30
+ * Pass the pieces explicitly to char():
31
+ * GATT.ENVIRONMENTAL.TEMPERATURE
32
+ * char('2A6E', BleValueType.Int16, BlePerm.Read | BlePerm.Notify)
44
33
  */
45
34
  export declare const GATT: {
46
35
  readonly DEVICE_INFO: {
@@ -92,69 +81,44 @@ export declare const GATT: {
92
81
  /** The value passed to/from callbacks — narrowed per characteristic by type. */
93
82
  export type CharValue = number | string | boolean | Uint8Array;
94
83
  /**
95
- * BLE GATT peripheral control, lowered to native ESP-IDF NimBLE
96
- * (`nimble_host` / `ble_gap` / `ble_gatts`) by framework-esp32.
97
- *
98
- * No `include()` calls here — NimBLE headers are framework-owned and added via
99
- * forcedIncludes when the program uses ble.* ops.
100
- *
101
- * Transpiler note: method bodies pass parameters directly into semantic calls
102
- * (no local consts / module counters) so the resolver can statically track every
103
- * argument. The characteristic index is carried through the chain via
104
- * `this._charCount` fieldValues, mirroring how HttpRequest carries _method/_url.
84
+ * The GATT declaration chain returned by BLE.service()/BLE.char(). Each char()
85
+ * appends a characteristic; onRead/onWrite/notify bind to the most recent one.
105
86
  */
106
- export declare class BleClass {
107
- static readonly __instance_name = "Ble";
108
- /** Begin building a GATT server with the given advertised device name. */
109
- server(name: string): BleServer;
110
- /** Initialize NimBLE, register services, and start advertising. */
111
- begin(): void;
112
- advertise(): void;
113
- stopAdvertising(): void;
114
- /** Blocking at top level; cooperatively awaitable inside async functions. */
115
- untilConnected(timeoutMs?: number): Promise<boolean>;
116
- untilConnectedStart(): void;
117
- isConnected(): boolean;
118
- status(): BleStatus;
119
- clientCount(): number;
120
- txPower(dbm: number): this;
121
- notify(index: number, value: number): void;
87
+ export declare class BleChain {
88
+ /** Begin a new service grouping; subsequent char() calls attach to it. */
89
+ service(uuid: string): BleChain;
90
+ /** Append a characteristic by uuid, value type, and permissions
91
+ * (`BlePerm.Read | BlePerm.Notify`). Returns this for chaining. */
92
+ char(uuid: string, type: BleValueType, perms: number): BleChain;
93
+ /** Read handler for the most recently declared characteristic. */
94
+ onRead(handler: () => CharValue): BleChain;
95
+ /** Write handler for the most recently declared characteristic. */
96
+ onWrite(handler: (value: number) => void): BleChain;
122
97
  }
123
- /**
124
- * Fluent GATT server builder. Returned by `Ble.server()`.
125
- *
126
- * Single-class fluent chain (like HttpRequest): characteristic() returns `this`,
127
- * so onRead/onWrite/onSubscribe chain directly. The _charCount field tracks
128
- * which characteristic slot the callbacks attach to.
129
- *
130
- * Field tracking (read by the transpiler resolver via ctor field assignment):
131
- * _name — advertised device name
132
- * _charCount current characteristic index (the last characteristic() target)
133
- * _svcCount current service index
134
- */
135
- export declare class BleServer {
136
- private _name;
137
- private _charCount;
138
- private _lastChar;
139
- private _svcCount;
140
- constructor(name: string, charCount: number, svcCount: number);
141
- /** Add a characteristic by UUID, value type, and permissions.
142
- * Combine permissions with `|`: `BlePerm.Read | BlePerm.Notify`.
143
- * Returns this for chaining. */
144
- characteristic(uuid: string, type: BleValueType, perms: number): this;
145
- /** Begin a new service grouping. Subsequent characteristics attach to it. */
146
- service(uuid: string): this;
147
- /** Register a read handler for the most recently added characteristic. */
148
- onRead(handler: () => CharValue): this;
149
- /** Register a write handler for the most recently added characteristic. */
150
- onWrite(handler: (value: number) => void): this;
151
- /** Register a connect handler (called when a central connects). */
152
- onConnect(handler: () => void): this;
153
- /** Register a disconnect handler (called when a central disconnects). */
154
- onDisconnect(handler: () => void): this;
155
- /** Push a new value to subscribed clients on the most recently added characteristic. */
156
- notify(value: number): void;
157
- /** Initialize NimBLE, register services, and start advertising. */
158
- begin(): void;
98
+ /** A GATT peripheral. The advertised device name is the construction fact. */
99
+ export declare class BLE {
100
+ private readonly _name;
101
+ constructor(name: string);
102
+ /** Begin a service grouping; chain char() declarations off it. */
103
+ service(uuid: string): BleChain;
104
+ /** Append a characteristic under the default (Environmental Sensing)
105
+ * service the common single-service case. */
106
+ char(uuid: string, type: BleValueType, perms: number): BleChain;
107
+ /** Register the declared GATT database, enable the stack, and start
108
+ * advertising the construction name. */
109
+ start(): void;
110
+ /** Stop advertising (the GATT database and any link stay up). */
111
+ stop(): void;
112
+ /** True while a central is connected. */
113
+ linked(): boolean;
114
+ /** Number of connected centrals (0 or 1 — the shim is single-connection). */
115
+ clients(): number;
116
+ /** Fires when a central connects. */
117
+ onConnect(handler: () => void): void;
118
+ /** Fires when the central disconnects. */
119
+ onDrop(handler: () => void): void;
120
+ /** Push a value to subscribed clients on a characteristic
121
+ * (bt_gatt_notify). `index` is the characteristic's declaration order
122
+ * (0-based the first char() is 0). */
123
+ notify(index: number, value: number): void;
159
124
  }
160
- export declare const Ble: BleClass;