@typecad/hal 1.0.0-alpha.13 → 1.0.0-alpha.15

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 +7 -8
  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
@@ -0,0 +1,91 @@
1
+ // ---------------------------------------------------------------------------
2
+ // GPIO — the thin Zephyr-shaped digital pin class
3
+ //
4
+ // One configured pin handle ≈ gpio_dt_spec + flags, mirroring Zephyr's verbs:
5
+ // construction carries the flag combination (GPIO.OUTPUT | GPIO.PULL_UP),
6
+ // set/get/toggle lower to gpio_pin_set_dt / get_dt / toggle_dt (logical
7
+ // levels — polarity comes from the board's DT node when the pin has a dtSpec),
8
+ // and the configure itself is emitted guarded-per-pin ahead of the first use,
9
+ // so construction flags apply exactly once. No mode strings, no shadow reads.
10
+ //
11
+ // Flag and interrupt tokens are Zephyr's names under the GPIO. namespace
12
+ // (GPIO_OUTPUT ↔ GPIO.OUTPUT, GPIO_INT_EDGE_FALLING ↔ GPIO.INT_EDGE_FALLING);
13
+ // the lowering maps token NAMES to macros, so any Zephyr doc greps both ways.
14
+ // ----------------------------------------------------------------------------
15
+
16
+ import { gpioWrite, gpioReadCfg, gpioToggle, gpioConfigure, interruptAttachFlags, interruptDetach } from './emit.js';
17
+ import { callback } from './callback.js';
18
+ import type { Pin } from './gpio.js';
19
+
20
+ export class GPIO {
21
+ // ── Config flags (gpio.h) ──────────────────────────────────────────────
22
+ static readonly INPUT = 0x001;
23
+ static readonly OUTPUT = 0x002;
24
+ /** Configure the output buffer's initial level atomically — no
25
+ * configure-then-write glitch window. */
26
+ static readonly OUTPUT_INIT_LOW = 0x004;
27
+ static readonly OUTPUT_INIT_HIGH = 0x008;
28
+ static readonly PULL_UP = 0x010;
29
+ static readonly PULL_DOWN = 0x020;
30
+ static readonly OPEN_DRAIN = 0x040;
31
+ static readonly OPEN_SOURCE = 0x080;
32
+ static readonly DISCONNECTED = 0x100;
33
+
34
+ // ── Interrupt flags (GPIO_INT_* minus the prefix) ──────────────────────
35
+ static readonly INT_DISABLE = 0x01;
36
+ static readonly INT_EDGE_RISING = 0x02;
37
+ static readonly INT_EDGE_FALLING = 0x04;
38
+ static readonly INT_EDGE_BOTH = 0x08;
39
+ static readonly INT_LEVEL_LOW = 0x10;
40
+ static readonly INT_LEVEL_HIGH = 0x20;
41
+
42
+ private readonly _pin: number;
43
+ private readonly _flags: number;
44
+
45
+ /** Construct a configured pin. `flags` is a combination of the GPIO.*
46
+ * statics (the transpiler carries the token text; the values are for the
47
+ * editor only). The configure applies once, ahead of the first
48
+ * set/get/toggle/onInterrupt call. */
49
+ constructor(pin: number | Pin, flags: number) {
50
+ this._pin = typeof pin === 'number' ? pin : pin.number;
51
+ this._flags = flags;
52
+ }
53
+
54
+ /** Drive the pin (gpio_pin_set_dt / set_raw). Logical level: on a pin with
55
+ * a board dtSpec (LED, BUTTON), true means "active" — the DT node's
56
+ * GPIO_ACTIVE_LOW is honored. */
57
+ set(value: boolean): void {
58
+ gpioConfigure(this._pin, this._flags);
59
+ gpioWrite(this._pin, value);
60
+ }
61
+
62
+ /** Read the pin (gpio_pin_get_dt / get_raw). Logical level. The guarded
63
+ * configure is FUSED into the read's lowering (one statement-expression),
64
+ * so the pin is correctly configured even when the call sits in a pure
65
+ * expression position (if-conditions, comparisons) where a method's
66
+ * leading side-effect ops would otherwise be dropped. */
67
+ get(): boolean {
68
+ return gpioReadCfg(this._pin, this._flags) as unknown as boolean;
69
+ }
70
+
71
+ /** Toggle the pin (gpio_pin_toggle_dt — the driver's atomic toggle). */
72
+ toggle(): void {
73
+ gpioConfigure(this._pin, this._flags);
74
+ gpioToggle(this._pin);
75
+ }
76
+
77
+ /** Attach an interrupt (gpio_pin_interrupt_configure_dt +
78
+ * gpio_init_callback + gpio_add_callback). `intFlags` is one GPIO.INT_*
79
+ * token — Zephyr's names verbatim, covering the level modes the legacy
80
+ * onHigh/onLow strings could not express. */
81
+ onInterrupt(intFlags: number, handler: () => void): void {
82
+ gpioConfigure(this._pin, this._flags);
83
+ interruptAttachFlags(this._pin, callback(handler), intFlags);
84
+ }
85
+
86
+ /** Detach the interrupt (disable + remove callback). */
87
+ offInterrupt(): void {
88
+ interruptDetach(this._pin);
89
+ }
90
+ }
91
+
package/src/gpio.ts CHANGED
@@ -1,320 +1,49 @@
1
- import { gpioWrite, gpioRead, gpioToggle, gpioSetMode, tonePlay, toneStop, adcRead, adcReadVoltage, adcSetReference, interruptAttach, interruptDetach, pwmWrite, rawCpp, boardResolve } from './emit.js';
2
- import { callback } from './callback.js';
3
- import { ADC } from './adc.js';
4
-
5
- export class OutputPin {
6
- private _pin: number;
7
- readonly number: number;
8
- readonly gpio: number;
9
-
10
- constructor(pin: number) {
11
- this._pin = pin;
12
- this.number = pin;
13
- this.gpio = pin;
14
- }
15
-
16
- high(): void {
17
- gpioWrite(this._pin, 1);
18
- }
19
-
20
- low(): void {
21
- gpioWrite(this._pin, 0);
22
- }
23
-
24
- toggle(): void {
25
- gpioToggle(this._pin);
26
- }
27
-
28
- write(value: number | boolean): void {
29
- gpioWrite(this._pin, value);
30
- }
31
-
32
- /**
33
- * Returns the level the program last drove onto this output pin.
34
- *
35
- * The transpiler tracks every write (high/low/write/toggle and the
36
- * asOutput initial value) and lowers this to a compile-time constant
37
- * when the state is statically known, or to a tracked shadow variable
38
- * the generated writes keep updated. No hardware pin read is performed
39
- * reading back an OUTPUT-only pin is not portable (e.g. Zephyr), so this
40
- * reports software truth, not electrical truth.
41
- */
42
- read(): boolean {
43
- return gpioRead(this._pin) as unknown as boolean;
44
- }
45
-
46
- isHigh(): boolean {
47
- return this.read();
48
- }
49
-
50
- isLow(): boolean {
51
- return !this.read();
52
- }
53
-
54
- pulse(durationMs: number): void {
55
- gpioWrite(this._pin, 1);
56
- rawCpp(`delay(${durationMs});`);
57
- gpioWrite(this._pin, 0);
58
- }
59
-
60
- tone(frequency: number): ToneChain {
61
- tonePlay(this._pin, frequency);
62
- return new ToneChain(this._pin, frequency);
63
- }
64
-
65
- toneFor(frequency: number, duration: number): void {
66
- tonePlay(this._pin, frequency, duration);
67
- }
68
-
69
- noTone(): void {
70
- toneStop(this._pin);
71
- }
72
-
73
- pwm(duty: number): void {
74
- pwmWrite(this._pin, duty);
75
- }
76
-
77
- getPwmFrequency(): number {
78
- return boardResolve("peripherals.pwm.maxFrequency");
79
- }
80
-
81
- getPwmResolution(): number {
82
- return boardResolve("peripherals.pwm.resolution");
83
- }
84
- }
85
-
86
- export class InputPin {
87
- private _pin: number;
88
- readonly number: number;
89
- readonly gpio: number;
90
-
91
- constructor(pin: number) {
92
- this._pin = pin;
93
- this.number = pin;
94
- this.gpio = pin;
95
- }
96
-
97
- read(): boolean {
98
- return gpioRead(this._pin) as unknown as boolean;
99
- }
100
-
101
- isHigh(): boolean {
102
- return this.read();
103
- }
104
-
105
- isLow(): boolean {
106
- return !this.read();
107
- }
108
-
109
- readAnalog(): number {
110
- return adcRead(this._pin);
111
- }
112
-
113
- readVoltage(): number {
114
- return adcReadVoltage(this._pin);
115
- }
116
-
117
- getAnalogResolution(): number {
118
- return boardResolve("peripherals.adc.0.resolution");
119
- }
120
-
121
- setAnalogReference(ref: string): void {
122
- ADC._reference = ref;
123
- adcSetReference(ref);
124
- }
125
-
126
- onFalling(handler: () => void): void {
127
- interruptAttach(this._pin, callback(handler), "FALLING");
128
- }
129
-
130
- onRising(handler: () => void): void {
131
- interruptAttach(this._pin, callback(handler), "RISING");
132
- }
133
-
134
- onChange(handler: () => void): void {
135
- interruptAttach(this._pin, callback(handler), "CHANGE");
136
- }
137
-
138
- offAll(): void {
139
- interruptDetach(this._pin);
140
- }
141
-
142
- /** Alias matching the BasePin.offInterrupts() interface name. */
143
- offInterrupts(): void {
144
- interruptDetach(this._pin);
145
- }
146
-
147
- /**
148
- * Wait for a RISING edge on this input pin.
149
- * Returns a Promise<void> that resolves when the pin transitions from LOW to HIGH.
150
- * The platform strategy controls whether this uses interrupts, polling, or a stub.
151
- *
152
- * @param timeout Optional timeout in milliseconds. If provided, the promise
153
- * rejects (or resolves with a false/error) after the timeout expires.
154
- */
155
- waitForRising(timeout?: number): Promise<void> {
156
- rawCpp(`__cuttlefish_wait_pin_edge(${this._pin}, RISING, ${timeout ?? -1});`);
157
- return Promise.resolve();
158
- }
159
-
160
- /**
161
- * Wait for a FALLING edge on this input pin.
162
- * Returns a Promise<void> that resolves when the pin transitions from HIGH to LOW.
163
- *
164
- * @param timeout Optional timeout in milliseconds. If provided, the promise
165
- * rejects (or resolves with a false/error) after the timeout expires.
166
- */
167
- waitForFalling(timeout?: number): Promise<void> {
168
- rawCpp(`__cuttlefish_wait_pin_edge(${this._pin}, FALLING, ${timeout ?? -1});`);
169
- return Promise.resolve();
170
- }
171
- }
172
-
173
- export class ToneChain {
174
- private _pin: number;
175
- private _lastFreq: number;
176
-
177
- constructor(pin: number, frequency: number) {
178
- this._pin = pin;
179
- this._lastFreq = frequency;
180
- }
181
-
182
- for(duration: number): void {
183
- tonePlay(this._pin, this._lastFreq, duration);
184
- }
185
- }
186
-
187
- /**
188
- * Represents a physical hardware pin before it has been configured for a specific mode.
189
- * Use `.asInput()` or `.asOutput()` to obtain a functional pin instance.
190
- *
191
- * Pins can be created two ways:
192
- * - `new Pin(number)` — legacy, using framework pin number (e.g. Arduino pin 13)
193
- * - `Pin.fromPort("PB5")` — preferred, using MCU datasheet port name
194
- *
195
- * When created via `fromPort()`, the pin carries its canonical port identity.
196
- * The transpiler resolves the port name to a framework pin number at compile time
197
- * using the MCU package's pin mapping (e.g. arduino-map.ts).
198
- */
199
- export class Pin {
200
- /** MCU port name (e.g. "PB5") — empty string for legacy numeric pins */
201
- private _port: string;
202
- /** Framework pin number (e.g. 13 for Arduino). -1 for port-based pins. */
203
- private _pin: number;
204
- /** Public readonly access to port name */
205
- readonly port: string;
206
- readonly number: number;
207
- readonly gpio: number;
208
-
209
- /** Legacy constructor — creates a Pin from a framework pin number */
210
- constructor(pin: number) {
211
- this._port = '';
212
- this._pin = pin;
213
- this.port = '';
214
- this.number = pin;
215
- this.gpio = pin;
216
- }
217
-
218
- /**
219
- * Create a Pin from its MCU datasheet port name (e.g. "PB5", "PC0").
220
- * The port name is the canonical identity; framework-specific pin numbers
221
- * are resolved at transpile time via the MCU package's pin mapping.
222
- */
223
- static fromPort(portName: string): Pin {
224
- const p = new Pin(-1);
225
- p._port = portName;
226
- // Bypass readonly for factory method
227
- (p as any).port = portName;
228
- return p;
229
- }
230
-
231
- asOutput(initial?: number | boolean): OutputPin {
232
- gpioSetMode(this._pin, "OUTPUT");
233
- if (initial !== undefined) {
234
- gpioWrite(this._pin, initial);
235
- }
236
- // Returns `this` so the transpiler can suppress the C++ return emission
237
- // (it resolves `this` to the same instance and tracks the result as an
238
- // OutputPin via the method name). Returning `new OutputPin(this._pin)`
239
- // would leak the literal text into generated C++. The cast is required
240
- // because Pin and OutputPin are structurally distinct classes; the
241
- // transpiler handles the mode transition semantically.
242
- return this as unknown as OutputPin;
243
- }
244
-
245
- /** Alias for asOutput() — shorter fluent form. */
246
- output(initial?: number | boolean): OutputPin {
247
- gpioSetMode(this._pin, "OUTPUT");
248
- if (initial !== undefined) {
249
- gpioWrite(this._pin, initial);
250
- }
251
- return this as unknown as OutputPin;
252
- }
253
-
254
- asInput(): InputPin {
255
- gpioSetMode(this._pin, "INPUT");
256
- return this as unknown as InputPin;
257
- }
258
-
259
- asInputPullUp(): InputPin {
260
- gpioSetMode(this._pin, "INPUT_PULLUP");
261
- return this as unknown as InputPin;
262
- }
263
-
264
- asInputPullDown(): InputPin {
265
- gpioSetMode(this._pin, "INPUT_PULLDOWN");
266
- return this as unknown as InputPin;
267
- }
268
-
269
- inputPullUp(): InputPin {
270
- gpioSetMode(this._pin, "INPUT_PULLUP");
271
- return this as unknown as InputPin;
272
- }
273
-
274
- /** Alias for asInputPullDown() — shorter fluent form. */
275
- inputPullDown(): InputPin {
276
- gpioSetMode(this._pin, "INPUT_PULLDOWN");
277
- return this as unknown as InputPin;
278
- }
279
-
280
- read(): boolean {
281
- return gpioRead(this._pin) as unknown as boolean;
282
- }
283
-
284
- isHigh(): boolean {
285
- return this.read();
286
- }
287
-
288
- isLow(): boolean {
289
- return !this.read();
290
- }
291
-
292
- write(value: number | boolean): void {
293
- gpioWrite(this._pin, value);
294
- }
295
-
296
- high(): void {
297
- gpioWrite(this._pin, 1);
298
- }
299
-
300
- low(): void {
301
- gpioWrite(this._pin, 0);
302
- }
303
-
304
- toggle(): void {
305
- gpioToggle(this._pin);
306
- }
307
-
308
- pwm(duty: number): void {
309
- pwmWrite(this._pin, duty);
310
- }
311
-
312
- tone(frequency: number): ToneChain {
313
- tonePlay(this._pin, frequency);
314
- return new ToneChain(this._pin, frequency);
315
- }
316
-
317
- noTone(): void {
318
- toneStop(this._pin);
319
- }
320
- }
1
+ // ---------------------------------------------------------------------------
2
+ // Pin the board-addressable pin identity (legacy GPIO classes removed)
3
+ //
4
+ // A Pin carries its canonical datasheet port name (Pin.fromPort("PB5")) and/or
5
+ // framework pin number; the transpiler resolves it via the MCU package's pin
6
+ // mapping. It is an ADDRESS, not a configured peripheral — configure pins by
7
+ // constructing the thin peripherals with them:
8
+ //
9
+ // new GPIO(PB5, GPIO.OUTPUT | GPIO.PULL_UP)
10
+ // new PWM(PA5, { periodNs: 20_000_000 })
11
+ // new ADC(A1)
12
+ //
13
+ // The former OutputPin/InputPin/ToneChain classes (and their as*/read/write/
14
+ // pwm methods) were removed with the legacy Arduino surface. Their thin
15
+ // replacements are gpio-pin.ts / pwm-pin.ts / adc-pin.ts.
16
+ // ---------------------------------------------------------------------------
17
+
18
+ export class Pin {
19
+ /** MCU port name (e.g. "PB5") — empty string for legacy numeric pins */
20
+ private _port: string;
21
+ /** Framework pin number (e.g. 13 for Arduino). -1 for port-based pins. */
22
+ private _pin: number;
23
+ /** Public readonly access to port name */
24
+ readonly port: string;
25
+ readonly number: number;
26
+ readonly gpio: number;
27
+
28
+ /** Legacy constructor creates a Pin from a framework pin number */
29
+ constructor(pin: number) {
30
+ this._port = '';
31
+ this._pin = pin;
32
+ this.port = '';
33
+ this.number = pin;
34
+ this.gpio = pin;
35
+ }
36
+
37
+ /**
38
+ * Create a Pin from its MCU datasheet port name (e.g. "PB5", "PC0").
39
+ * The port name is the canonical identity; framework-specific pin numbers
40
+ * are resolved at transpile time via the MCU package's pin mapping.
41
+ */
42
+ static fromPort(portName: string): Pin {
43
+ const p = new Pin(-1);
44
+ p._port = portName;
45
+ // Bypass readonly for factory method
46
+ (p as any).port = portName;
47
+ return p;
48
+ }
49
+ }
package/src/http.ts CHANGED
@@ -1,9 +1,31 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Request — the thin HTTP/S client
3
+ //
4
+ // The request is CONSTRUCTION facts: method, URL, and the policy opts
5
+ // (timeout, body, TLS mode) ride the constructor; headers attach with the
6
+ // header() chain; send() lowers the facts into the shim and performs the
7
+ // request; the response is read from this request afterwards (the shim
8
+ // holds the response until the next request).
9
+ //
10
+ // const req = new Request(Request.POST, url, {
11
+ // timeoutMs: 10_000,
12
+ // body: '{"v":1}', json: true,
13
+ // caCert: PEM, // pin a CA (verified TLS)
14
+ // });
15
+ // req.header('X-Custom', 'v');
16
+ // if (req.send()) { console.log(req.status()); }
17
+ //
18
+ // Method tokens: Request.GET / POST / PUT / DELETE / HEAD / PATCH (plain
19
+ // 'GET' strings also accepted). `insecure: true` skips TLS certificate
20
+ // verification (development only). Awaiting send() inside async functions
21
+ // still splits into a background request + done-poll (the async machinery
22
+ // intercepts the send op; the facts were already lowered at send()).
23
+ // ----------------------------------------------------------------------------
24
+
1
25
  import {
2
26
  httpBegin,
3
- httpReset,
4
27
  httpSetHeader,
5
28
  httpSetTimeout,
6
- httpSetMaxBody,
7
29
  httpSetBody,
8
30
  httpSetInsecure,
9
31
  httpSetCaCert,
@@ -15,80 +37,71 @@ import {
15
37
  httpResponseHeader,
16
38
  } from './emit.js';
17
39
 
18
- export enum HttpMethod {
19
- GET = 0,
20
- POST = 1,
21
- PUT = 2,
22
- DELETE = 3,
23
- HEAD = 4,
24
- PATCH = 5,
40
+ /** Request construction facts beyond method + URL. */
41
+ export interface RequestOpts {
42
+ /** Response timeout in ms (default 10_000). */
43
+ timeoutMs?: number;
44
+ /** Request body (raw). */
45
+ body?: string;
46
+ /** The body is JSON — sets the JSON content type. */
47
+ json?: boolean;
48
+ /** Skip TLS certificate verification (development only). */
49
+ insecure?: boolean;
50
+ /** PEM of a trusted CA — enables verified TLS. */
51
+ caCert?: string;
25
52
  }
26
53
 
27
- /**
28
- * Fluent HTTP/S request builder, lowered to native ESP-IDF
29
- * `esp_http_client` by framework-esp32 (TLS via esp-tls / mbedTLS bundle).
30
- * Response fields are read from this object after send() — mirrors
31
- * `await WiFi.connect(); WiFi.localIP()`.
32
- *
33
- * No `include()` calls here — ESP-IDF headers are framework-owned and added
34
- * via forcedIncludes when the program uses http.* ops.
35
- */
36
- export class HttpRequest {
37
- private _method: string;
38
- private _url: string;
39
-
40
- constructor(method: string, url: string) {
41
- this._method = method;
54
+ export class Request {
55
+ static readonly GET = 'GET';
56
+ static readonly POST = 'POST';
57
+ static readonly PUT = 'PUT';
58
+ static readonly DELETE = 'DELETE';
59
+ static readonly HEAD = 'HEAD';
60
+ static readonly PATCH = 'PATCH';
61
+
62
+ private readonly _method: string;
63
+ private readonly _url: string;
64
+ private readonly _timeoutMs: number;
65
+ private readonly _body: string;
66
+ private readonly _json: boolean;
67
+ private readonly _insecure: boolean;
68
+ private readonly _caCert: string;
69
+
70
+ constructor(method: string, url: string, opts: RequestOpts = {}) {
71
+ this._method = method.toUpperCase();
42
72
  this._url = url;
73
+ this._timeoutMs = opts.timeoutMs ?? 10_000;
74
+ this._body = opts.body ?? '';
75
+ this._json = opts.json === true;
76
+ this._insecure = opts.insecure === true;
77
+ this._caCert = opts.caCert ?? '';
43
78
  }
44
79
 
80
+ /** Attach a request header. Chainable — one per header. */
45
81
  header(name: string, value: string): this {
46
82
  httpSetHeader(name, value);
47
83
  return this;
48
84
  }
49
85
 
50
- timeout(ms: number): this {
51
- httpSetTimeout(ms);
52
- return this;
53
- }
54
-
55
- maxBody(bytes: number): this {
56
- httpSetMaxBody(bytes);
57
- return this;
58
- }
59
-
60
- body(data: string): this {
61
- httpSetBody(data, false);
62
- return this;
63
- }
64
-
65
- jsonBody(json: string): this {
66
- httpSetBody(json, true);
67
- return this;
68
- }
69
-
70
- /** Skip TLS certificate verification (development only). */
71
- insecure(): this {
72
- httpSetInsecure();
73
- return this;
74
- }
75
-
76
- caCert(pem: string): this {
77
- httpSetCaCert(pem);
78
- return this;
79
- }
80
-
81
- /** Blocking at top level; cooperatively awaitable inside async functions. */
82
- send(): Promise<boolean> {
86
+ /** Send the request (blocking). The construction facts lower into the
87
+ * shim first (timeout/body/TLS mode), then the request performs.
88
+ * Awaitable inside async functions — the async machinery splits the
89
+ * send into a background request + done-poll. */
90
+ send(): boolean {
91
+ httpSetTimeout(this._timeoutMs);
92
+ httpSetBody(this._body, this._json);
93
+ httpSetInsecure(this._insecure);
94
+ httpSetCaCert(this._caCert);
83
95
  httpBegin(this._method, this._url);
84
- httpSend();
85
- return Promise.resolve(false);
96
+ return httpSend();
86
97
  }
87
98
 
99
+ /** Response status code (0 before a completed send). */
88
100
  status(): number {
89
101
  return httpStatus();
90
102
  }
91
103
 
104
+ /** True when the response status is 2xx. */
92
105
  ok(): boolean {
93
106
  return httpOk();
94
107
  }
@@ -98,47 +111,14 @@ export class HttpRequest {
98
111
  return httpBody();
99
112
  }
100
113
 
114
+ /** Response Content-Length (0 when absent). */
101
115
  contentLength(): number {
102
116
  return httpContentLength();
103
117
  }
104
118
 
119
+ /** One response header value ("" when absent; valid until the next
120
+ * request). */
105
121
  responseHeader(name: string): string {
106
122
  return httpResponseHeader(name);
107
123
  }
108
124
  }
109
-
110
- export class HttpClass {
111
- static readonly __instance_name = "Http";
112
-
113
- get(url: string): HttpRequest {
114
- httpReset();
115
- return new HttpRequest("GET", url);
116
- }
117
-
118
- post(url: string): HttpRequest {
119
- httpReset();
120
- return new HttpRequest("POST", url);
121
- }
122
-
123
- put(url: string): HttpRequest {
124
- httpReset();
125
- return new HttpRequest("PUT", url);
126
- }
127
-
128
- del(url: string): HttpRequest {
129
- httpReset();
130
- return new HttpRequest("DELETE", url);
131
- }
132
-
133
- head(url: string): HttpRequest {
134
- httpReset();
135
- return new HttpRequest("HEAD", url);
136
- }
137
-
138
- patch(url: string): HttpRequest {
139
- httpReset();
140
- return new HttpRequest("PATCH", url);
141
- }
142
- }
143
-
144
- export const Http = new HttpClass();