@typecad/hal 1.0.0-alpha.3 → 1.0.0-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/wifi.js ADDED
@@ -0,0 +1,154 @@
1
+ import { wifiConnect, wifiConnectStart, wifiDisconnect, wifiStatus, wifiIsConnected, wifiLocalIp, wifiRssi, wifiMac, wifiSetHostname, wifiSetStaticIp, wifiSetAutoReconnect, wifiSetPowerSave, wifiSetTxPower, wifiOnEvent, wifiApStart, wifiApStop, wifiApClientCount, wifiApIp, wifiApSetChannel, wifiApSetHidden, wifiApSetMaxClients, wifiScan, wifiScanStart, wifiScanCount, wifiScanSsid, wifiScanRssi, wifiScanEncryption, wifiScanChannel, wifiSaveCredentials, wifiConnectSaved, wifiClearCredentials, wifiWaitConnected, wifiWaitDisconnected, } from './emit.js';
2
+ import { callback } from './callback.js';
3
+ /** Normalized WiFi link status (mapped from esp_wifi events by the runtime shim). */
4
+ export var WiFiStatus;
5
+ (function (WiFiStatus) {
6
+ WiFiStatus[WiFiStatus["Idle"] = 0] = "Idle";
7
+ WiFiStatus[WiFiStatus["Connecting"] = 1] = "Connecting";
8
+ WiFiStatus[WiFiStatus["Connected"] = 2] = "Connected";
9
+ WiFiStatus[WiFiStatus["ConnectFailed"] = 3] = "ConnectFailed";
10
+ WiFiStatus[WiFiStatus["Disconnected"] = 4] = "Disconnected";
11
+ })(WiFiStatus || (WiFiStatus = {}));
12
+ export var WiFiEncryption;
13
+ (function (WiFiEncryption) {
14
+ WiFiEncryption[WiFiEncryption["Open"] = 0] = "Open";
15
+ WiFiEncryption[WiFiEncryption["WEP"] = 1] = "WEP";
16
+ WiFiEncryption[WiFiEncryption["WPA"] = 2] = "WPA";
17
+ WiFiEncryption[WiFiEncryption["WPA2"] = 3] = "WPA2";
18
+ WiFiEncryption[WiFiEncryption["WPA3"] = 4] = "WPA3";
19
+ WiFiEncryption[WiFiEncryption["Enterprise"] = 5] = "Enterprise";
20
+ })(WiFiEncryption || (WiFiEncryption = {}));
21
+ /**
22
+ * WiFi radio / link control, lowered to native ESP-IDF (`esp_wifi` /
23
+ * `esp_netif` / `esp_event` / `nvs_flash`) by framework-esp32.
24
+ *
25
+ * No `include()` calls here — ESP-IDF headers are framework-owned and added
26
+ * via forcedIncludes when the program uses wifi.* ops (the Preferences
27
+ * lesson: HAL files must not carry platform headers). Frameworks without a
28
+ * wifi lowering reject these ops with a diagnostic.
29
+ */
30
+ export class WiFiClass {
31
+ /** Blocking at top level; cooperatively awaitable inside async functions. */
32
+ connect(ssid, password, timeoutMs = 15000) {
33
+ wifiConnect(ssid, password, timeoutMs);
34
+ return Promise.resolve(false);
35
+ }
36
+ /** Fire-and-forget STA begin; poll status() / untilConnected(). */
37
+ connectAsync(ssid, password) {
38
+ wifiConnectStart(ssid, password);
39
+ }
40
+ untilConnected(timeoutMs = 15000) {
41
+ wifiWaitConnected(timeoutMs);
42
+ return Promise.resolve(false);
43
+ }
44
+ untilDisconnected() {
45
+ wifiWaitDisconnected();
46
+ return Promise.resolve();
47
+ }
48
+ disconnect() {
49
+ wifiDisconnect();
50
+ }
51
+ isConnected() {
52
+ return wifiIsConnected();
53
+ }
54
+ status() {
55
+ return wifiStatus();
56
+ }
57
+ localIP() {
58
+ return wifiLocalIp();
59
+ }
60
+ rssi() {
61
+ return wifiRssi();
62
+ }
63
+ macAddress() {
64
+ return wifiMac();
65
+ }
66
+ hostname(name) {
67
+ wifiSetHostname(name);
68
+ return this;
69
+ }
70
+ staticIP(ip, gateway, subnet, dns) {
71
+ wifiSetStaticIp(ip, gateway, subnet, dns);
72
+ return this;
73
+ }
74
+ autoReconnect(enabled) {
75
+ wifiSetAutoReconnect(enabled);
76
+ return this;
77
+ }
78
+ powerSave(mode) {
79
+ wifiSetPowerSave(mode);
80
+ return this;
81
+ }
82
+ /** Cap TX power in dBm (roughly 2–20). Safe to call before connect() —
83
+ * the value is applied after the radio starts. */
84
+ txPower(dbm) {
85
+ wifiSetTxPower(dbm);
86
+ return this;
87
+ }
88
+ saveCredentials(ssid, password) {
89
+ wifiSaveCredentials(ssid, password);
90
+ }
91
+ connectSaved(timeoutMs = 15000) {
92
+ return wifiConnectSaved(timeoutMs);
93
+ }
94
+ clearCredentials() {
95
+ wifiClearCredentials();
96
+ }
97
+ onConnect(handler) {
98
+ wifiOnEvent("connect", callback(handler));
99
+ }
100
+ onDisconnect(handler) {
101
+ wifiOnEvent("disconnect", callback(handler));
102
+ }
103
+ onGotIP(handler) {
104
+ wifiOnEvent("got_ip", callback(handler));
105
+ }
106
+ startAP(ssid, password) {
107
+ return wifiApStart(ssid, password);
108
+ }
109
+ apChannel(ch) {
110
+ wifiApSetChannel(ch);
111
+ return this;
112
+ }
113
+ apHidden(hidden) {
114
+ wifiApSetHidden(hidden);
115
+ return this;
116
+ }
117
+ apMaxClients(n) {
118
+ wifiApSetMaxClients(n);
119
+ return this;
120
+ }
121
+ stopAP() {
122
+ wifiApStop();
123
+ }
124
+ apClientCount() {
125
+ return wifiApClientCount();
126
+ }
127
+ apIP() {
128
+ return wifiApIp();
129
+ }
130
+ scan() {
131
+ return wifiScan();
132
+ }
133
+ scanAsync() {
134
+ wifiScanStart();
135
+ return Promise.resolve();
136
+ }
137
+ scanCount() {
138
+ return wifiScanCount();
139
+ }
140
+ scanSSID(i) {
141
+ return wifiScanSsid(i);
142
+ }
143
+ scanRSSI(i) {
144
+ return wifiScanRssi(i);
145
+ }
146
+ scanEncryption(i) {
147
+ return wifiScanEncryption(i);
148
+ }
149
+ scanChannel(i) {
150
+ return wifiScanChannel(i);
151
+ }
152
+ }
153
+ WiFiClass.__instance_name = "WiFi";
154
+ export const WiFi = new WiFiClass();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typecad/hal",
3
- "version": "1.0.0-alpha.3",
3
+ "version": "1.0.0-alpha.7",
4
4
  "description": "TypeCAD hardware abstraction layer — GPIO, I2C, SPI, UART as regular TypeScript",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -49,9 +49,9 @@
49
49
  },
50
50
  "author": "typecad0",
51
51
  "devDependencies": {
52
- "@typecad/expect": "1.0.0-alpha.3",
53
- "@typecad/board-arduino-uno": "1.0.0-alpha.3",
54
- "@typecad/mcu-atmega328p": "1.0.0-alpha.3"
52
+ "@typecad/expect": "1.0.0-alpha.7",
53
+ "@typecad/board-arduino-uno": "1.0.0-alpha.7",
54
+ "@typecad/mcu-atmega328p": "1.0.0-alpha.7"
55
55
  },
56
56
  "sideEffects": false,
57
57
  "exports": {
package/src/ble.ts ADDED
@@ -0,0 +1,209 @@
1
+ import {
2
+ bleServerBegin,
3
+ bleAdvertiseStart,
4
+ bleAdvertiseStop,
5
+ bleAddService,
6
+ bleAddChar,
7
+ bleOnRead,
8
+ bleOnWrite,
9
+ bleOnConnect,
10
+ bleOnDisconnect,
11
+ bleNotify,
12
+ bleIsConnected,
13
+ bleClientCount,
14
+ bleSetName,
15
+ bleUntilConnected,
16
+ bleUntilConnectedStart,
17
+ bleSetTxPower,
18
+ bleStatus,
19
+ } from './emit.js';
20
+ import { callback } from './callback.js';
21
+
22
+ /** Characteristic value encoding — drives both TS callback types and C++ marshalling. */
23
+ export enum BleValueType {
24
+ Uint8 = 'uint8',
25
+ Uint16 = 'uint16',
26
+ Uint32 = 'uint32',
27
+ Int8 = 'int8',
28
+ Int16 = 'int16',
29
+ Int32 = 'int32',
30
+ Float32 = 'float32',
31
+ Utf8 = 'utf8',
32
+ Boolean = 'boolean',
33
+ Bytes = 'bytes',
34
+ }
35
+
36
+ /** GATT characteristic permission flags. Combine with `|`. */
37
+ export enum BlePerm {
38
+ Read = 1,
39
+ Write = 2,
40
+ Notify = 4,
41
+ }
42
+
43
+ /** BLE peripheral status (mirrored by the runtime shim). */
44
+ export enum BleStatus {
45
+ Idle = 0,
46
+ Initializing = 1,
47
+ Advertising = 2,
48
+ Connected = 3,
49
+ Error = 4,
50
+ }
51
+
52
+ export enum BleAdvertisingMode {
53
+ Connectable = 'connectable',
54
+ NonConnectable = 'non_connectable',
55
+ }
56
+
57
+ /** A well-known GATT characteristic entry in the catalog. */
58
+ export interface GattCharacteristicDef {
59
+ readonly uuid: string;
60
+ readonly type: BleValueType;
61
+ readonly read?: boolean;
62
+ readonly write?: boolean;
63
+ readonly notify?: boolean;
64
+ }
65
+
66
+ /**
67
+ * Standard GATT services/characteristics. Autocomplete walks the hierarchy:
68
+ * GATT.ENVIRONMENTAL. -> TEMPERATURE, HUMIDITY, ...
69
+ * Pass the .uuid, .type, and computed perms to BleServer.characteristic().
70
+ */
71
+ export const GATT = {
72
+ DEVICE_INFO: {
73
+ MANUFACTURER_NAME: { uuid: '2A29', type: BleValueType.Utf8, read: true },
74
+ MODEL_NUMBER: { uuid: '2A24', type: BleValueType.Utf8, read: true },
75
+ FIRMWARE_REVISION: { uuid: '2A26', type: BleValueType.Utf8, read: true },
76
+ },
77
+ ENVIRONMENTAL: {
78
+ TEMPERATURE: { uuid: '2A6E', type: BleValueType.Int16, read: true, notify: true },
79
+ HUMIDITY: { uuid: '2A6F', type: BleValueType.Uint16, read: true, notify: true },
80
+ PRESSURE: { uuid: '2A6D', type: BleValueType.Uint32, read: true, notify: true },
81
+ },
82
+ BATTERY: {
83
+ LEVEL: { uuid: '2A19', type: BleValueType.Uint8, read: true, notify: true },
84
+ },
85
+ } as const;
86
+
87
+ /** The value passed to/from callbacks — narrowed per characteristic by type. */
88
+ export type CharValue = number | string | boolean | Uint8Array;
89
+
90
+ /**
91
+ * BLE GATT peripheral control, lowered to native ESP-IDF NimBLE
92
+ * (`nimble_host` / `ble_gap` / `ble_gatts`) by framework-esp32.
93
+ *
94
+ * No `include()` calls here — NimBLE headers are framework-owned and added via
95
+ * forcedIncludes when the program uses ble.* ops.
96
+ *
97
+ * Transpiler note: method bodies pass parameters directly into semantic calls
98
+ * (no local consts / module counters) so the resolver can statically track every
99
+ * argument. The characteristic index is carried through the chain via
100
+ * `this._charCount` fieldValues, mirroring how HttpRequest carries _method/_url.
101
+ */
102
+ export class BleClass {
103
+ static readonly __instance_name = "Ble";
104
+
105
+ /** Begin building a GATT server with the given advertised device name. */
106
+ server(name: string): BleServer {
107
+ bleSetName(name);
108
+ return new BleServer(name, 0, 1);
109
+ }
110
+
111
+ /** Initialize NimBLE, register services, and start advertising. */
112
+ begin(): void {
113
+ bleServerBegin("TypeCAD");
114
+ bleAdvertiseStart();
115
+ }
116
+
117
+ advertise(): void { bleAdvertiseStart(); }
118
+ stopAdvertising(): void { bleAdvertiseStop(); }
119
+
120
+ /** Blocking at top level; cooperatively awaitable inside async functions. */
121
+ untilConnected(timeoutMs: number = 0): Promise<boolean> {
122
+ bleUntilConnected(timeoutMs);
123
+ return Promise.resolve(false);
124
+ }
125
+
126
+ untilConnectedStart(): void { bleUntilConnectedStart(); }
127
+ isConnected(): boolean { return bleIsConnected(); }
128
+ status(): BleStatus { return bleStatus() as BleStatus; }
129
+ clientCount(): number { return bleClientCount(); }
130
+ txPower(dbm: number): this { bleSetTxPower(dbm); return this; }
131
+ notify(index: number, value: number): void { bleNotify(index, value); }
132
+ }
133
+
134
+ /**
135
+ * Fluent GATT server builder. Returned by `Ble.server()`.
136
+ *
137
+ * Single-class fluent chain (like HttpRequest): characteristic() returns `this`,
138
+ * so onRead/onWrite/onSubscribe chain directly. The _charCount field tracks
139
+ * which characteristic slot the callbacks attach to.
140
+ *
141
+ * Field tracking (read by the transpiler resolver via ctor field assignment):
142
+ * _name — advertised device name
143
+ * _charCount — current characteristic index (the last characteristic() target)
144
+ * _svcCount — current service index
145
+ */
146
+ export class BleServer {
147
+ private _name: string;
148
+ private _charCount: number;
149
+ private _lastChar: number;
150
+ private _svcCount: number;
151
+
152
+ constructor(name: string, charCount: number, svcCount: number) {
153
+ this._name = name;
154
+ this._charCount = charCount;
155
+ this._lastChar = charCount;
156
+ this._svcCount = svcCount;
157
+ }
158
+
159
+ /** Add a characteristic by UUID, value type, and permissions.
160
+ * Combine permissions with `|`: `BlePerm.Read | BlePerm.Notify`.
161
+ * Returns this for chaining. */
162
+ characteristic(uuid: string, type: BleValueType, perms: number): this {
163
+ bleAddChar(this._charCount, uuid, type, perms, this._svcCount);
164
+ return this;
165
+ }
166
+
167
+ /** Begin a new service grouping. Subsequent characteristics attach to it. */
168
+ service(uuid: string): this {
169
+ bleAddService(uuid);
170
+ return this;
171
+ }
172
+
173
+ /** Register a read handler for the most recently added characteristic. */
174
+ onRead(handler: () => CharValue): this {
175
+ bleOnRead(this._lastChar, callback(handler));
176
+ return this;
177
+ }
178
+
179
+ /** Register a write handler for the most recently added characteristic. */
180
+ onWrite(handler: (value: number) => void): this {
181
+ bleOnWrite(this._lastChar, callback(handler));
182
+ return this;
183
+ }
184
+
185
+ /** Register a connect handler (called when a central connects). */
186
+ onConnect(handler: () => void): this {
187
+ bleOnConnect(callback(handler));
188
+ return this;
189
+ }
190
+
191
+ /** Register a disconnect handler (called when a central disconnects). */
192
+ onDisconnect(handler: () => void): this {
193
+ bleOnDisconnect(callback(handler));
194
+ return this;
195
+ }
196
+
197
+ /** Push a new value to subscribed clients on the most recently added characteristic. */
198
+ notify(value: number): void {
199
+ bleNotify(this._lastChar, value);
200
+ }
201
+
202
+ /** Initialize NimBLE, register services, and start advertising. */
203
+ begin(): void {
204
+ bleServerBegin(this._name);
205
+ bleAdvertiseStart();
206
+ }
207
+ }
208
+
209
+ export const Ble = new BleClass();
package/src/emit.ts CHANGED
@@ -30,6 +30,49 @@ export function gpioSetMode(pin: number | string, mode: string): void {}
30
30
  /** Write PWM duty cycle to a pin. */
31
31
  export function pwmWrite(pin: number | string, duty: number): void {}
32
32
 
33
+ // ---------------------------------------------------------------------------
34
+ // RMT — Remote Control Transceiver (addressable LEDs, IR, raw digital waveforms)
35
+ // ---------------------------------------------------------------------------
36
+ // rmtTxInit/rmtRxInit are POSITIONAL semantic primitives — the ergonomic
37
+ // opts-object form lives in hal/rmt.ts (which destructures and forwards). The
38
+ // resolver collapses object literals, so HALOpIR fields must be scalars; the
39
+ // rmt.ts wrapper bridges the ergonomic API to these positional calls.
40
+ //
41
+ // Pin params accept Pin | number | string so callers can pass a board alias
42
+ // like LED (a Pin object) directly; the transpiler resolves it to its number.
43
+ import type { Pin } from './gpio.js';
44
+ type RmtPin = Pin | number | string;
45
+
46
+ /** Positional semantic primitive. Args: pin, resolutionHz, bit0Hi, bit0Lo,
47
+ * bit1Hi, bit1Lo, msbFirst, queueDepth. Use rmtTxInit() from hal/rmt.ts. */
48
+ export function rmtTxInit(
49
+ pin: RmtPin,
50
+ resolutionHz: number,
51
+ bit0Hi: number, bit0Lo: number, bit1Hi: number, bit1Lo: number,
52
+ msbFirst: boolean, queueDepth: number,
53
+ ): void {}
54
+ /** Write bytes via the channel's bytes-encoder (timings fixed at init). */
55
+ export function rmtTxWriteBytes(pin: RmtPin, bytes: number[] | Uint8Array): void {}
56
+ /** Write raw RMT symbols — arbitrary [hiTicks, loTicks] pairs. */
57
+ export function rmtTxWriteSymbols(pin: RmtPin, symbols: [number, number][]): void {}
58
+ /** Block until the queued TX completes. */
59
+ export function rmtTxWaitDone(pin: RmtPin, timeoutMs?: number): void {}
60
+ /** Tear down the TX channel and release its slot. */
61
+ export function rmtTxDeinit(pin: RmtPin): void {}
62
+
63
+ /** Positional semantic primitive — use rmtRxInit() from hal/rmt.ts. */
64
+ export function rmtRxInit(pin: RmtPin, resolutionHz: number): void {}
65
+ /** Register a callback-by-name invoked when an RX burst completes. */
66
+ export function rmtRxOnReceived(pin: RmtPin, handler: string): void {}
67
+ /** Start receiving. */
68
+ export function rmtRxStart(pin: RmtPin): void {}
69
+ /** Stop receiving. */
70
+ export function rmtRxStop(pin: RmtPin): void {}
71
+ /** Blocking read — returns flattened symbols [d0,l0,d1,l1,…] in ticks. */
72
+ export function rmtRxRead(pin: RmtPin, maxCount: number): number[] { return []; }
73
+ /** Tear down the RX channel and release its slot. */
74
+ export function rmtRxDeinit(pin: RmtPin): void {}
75
+
33
76
  // ---------------------------------------------------------------------------
34
77
  // ADC — analog-to-digital conversion
35
78
  // ---------------------------------------------------------------------------
@@ -99,6 +142,15 @@ export function i2cRequestFrom(bus: string, address: number, quantity: number, s
99
142
  export function i2cAvailable(bus: string): number { return 0; }
100
143
  /** Read a byte from I2C. */
101
144
  export function i2cRead(bus: string): number { return 0; }
145
+ /**
146
+ * Drain `count` bytes requested from the I2C bus into a caller-provided buffer.
147
+ * Semantic primitive: lowers to the `i2c.read_buffer` HAL op. The `buffer`
148
+ * argument is emitted as a placeholder (`__HAL_READ_BUF__`) that the var-init
149
+ * transformer rewrites to the caller's own buffer variable, so bytes land in
150
+ * the `uint8_t data[N]` declared in user scope — NOT an internal temp that
151
+ * decays to a pointer on return. Keeps `data.length` / `data[i]` valid.
152
+ */
153
+ export function i2cReadBuffer(bus: string, count: number, buffer: number[] | Uint8Array): void {}
102
154
 
103
155
  // ---------------------------------------------------------------------------
104
156
  // SPI — serial peripheral interface
@@ -118,6 +170,14 @@ export function spiEndTx(bus: string): void {}
118
170
  export function spiCsLow(pin: number | string): void {}
119
171
  /** Set SPI chip-select pin HIGH. */
120
172
  export function spiCsHigh(pin: number | string): void {}
173
+ /**
174
+ * Read `count` bytes from the SPI bus into a caller-provided buffer by clocking
175
+ * dummy (0x00) transfers. Semantic primitive: lowers to the `spi.read_buffer`
176
+ * HAL op (per-byte `bus.transfer(0)` read loop). The `buffer` placeholder is
177
+ * rewritten to the caller's variable. Mirrors i2cReadBuffer. The caller is
178
+ * responsible for asserting/de-asserting chip-select around it.
179
+ */
180
+ export function spiReadBuffer(bus: string, count: number, buffer: number[] | Uint8Array): void {}
121
181
  /** Set SPI data mode. */
122
182
  export function spiSetMode(bus: string, mode: number): void {}
123
183
  /** Set SPI bit order. */
@@ -201,6 +261,104 @@ export function powerDeepSleep(ms: number): void {}
201
261
  export function powerLightSleep(): void {}
202
262
  /** Set the CPU frequency (MHz). */
203
263
  export function powerSetCpuFrequency(mhz: number): void {}
264
+ /** Enter deep sleep until `pin` reaches `level` (pin wakeup). Architecture-aware:
265
+ * ext0 on Xtensa (RTC pins), gpio-wakeup on RISC-V. */
266
+ export function powerDeepSleepPin(pin: number, level: number): void {}
267
+
268
+ // ---------------------------------------------------------------------------
269
+ // Preferences (NVS-backed key/value store)
270
+ // ---------------------------------------------------------------------------
271
+
272
+ export function preferencesBegin(namespace: string, readOnly: boolean): void {}
273
+ export function preferencesEnd(): void {}
274
+ export function preferencesClear(): void {}
275
+ export function preferencesRemove(key: string): void {}
276
+ export function preferencesPutInt(key: string, value: number): void {}
277
+ export function preferencesGetInt(key: string, defaultValue: number): number { return 0; }
278
+ export function preferencesPutUInt(key: string, value: number): void {}
279
+ export function preferencesGetUInt(key: string, defaultValue: number): number { return 0; }
280
+ export function preferencesPutBool(key: string, value: boolean): void {}
281
+ export function preferencesGetBool(key: string, defaultValue: boolean): boolean { return false; }
282
+ export function preferencesPutFloat(key: string, value: number): void {}
283
+ export function preferencesGetFloat(key: string, defaultValue: number): number { return 0; }
284
+ export function preferencesPutString(key: string, value: string): void {}
285
+ export function preferencesGetString(key: string, defaultValue: string): string { return ""; }
286
+
287
+ export function wifiConnect(ssid: string, password?: string, timeoutMs?: number): boolean { return false; }
288
+ export function wifiConnectStart(ssid: string, password?: string): void {}
289
+ export function wifiDisconnect(): void {}
290
+ export function wifiStatus(): number { return 0; }
291
+ export function wifiIsConnected(): boolean { return false; }
292
+ export function wifiLocalIp(): string { return ""; }
293
+ export function wifiRssi(): number { return 0; }
294
+ export function wifiMac(): string { return ""; }
295
+ export function wifiSetHostname(name: string): void {}
296
+ export function wifiSetStaticIp(ip: string, gateway: string, subnet: string, dns?: string): void {}
297
+ export function wifiSetAutoReconnect(enabled: boolean): void {}
298
+ export function wifiSetPowerSave(mode: string): void {}
299
+ export function wifiSetTxPower(dbm: number): void {}
300
+ export function wifiOnEvent(event: string, handler: string): void {}
301
+ export function wifiApStart(ssid: string, password?: string, channel?: number, hidden?: boolean, maxClients?: number): boolean { return false; }
302
+ export function wifiApStop(): void {}
303
+ export function wifiApClientCount(): number { return 0; }
304
+ export function wifiApIp(): string { return ""; }
305
+ export function wifiApSetChannel(channel: number): void {}
306
+ export function wifiApSetHidden(hidden: boolean): void {}
307
+ export function wifiApSetMaxClients(maxClients: number): void {}
308
+ export function wifiScan(): number { return 0; }
309
+ export function wifiScanStart(): void {}
310
+ export function wifiScanCount(): number { return 0; }
311
+ export function wifiScanSsid(index: number): string { return ""; }
312
+ export function wifiScanRssi(index: number): number { return 0; }
313
+ export function wifiScanEncryption(index: number): number { return 0; }
314
+ export function wifiScanChannel(index: number): number { return 0; }
315
+ export function wifiSaveCredentials(ssid: string, password: string): void {}
316
+ export function wifiConnectSaved(timeoutMs?: number): boolean { return false; }
317
+ export function wifiClearCredentials(): void {}
318
+ export function wifiWaitConnected(timeoutMs?: number): boolean { return false; }
319
+ export function wifiWaitDisconnected(): void {}
320
+
321
+ // ---------------------------------------------------------------------------
322
+ // HTTP client
323
+ // ---------------------------------------------------------------------------
324
+
325
+ export function httpBegin(method: string, url: string): void {}
326
+ export function httpReset(): void {}
327
+ export function httpSetHeader(name: string, value: string): void {}
328
+ export function httpSetTimeout(ms: number): void {}
329
+ export function httpSetMaxBody(bytes: number): void {}
330
+ export function httpSetBody(data: string, json?: boolean): void {}
331
+ export function httpSetInsecure(): void {}
332
+ export function httpSetCaCert(pem: string): void {}
333
+ export function httpSend(): boolean { return false; }
334
+ export function httpSendStart(): void {}
335
+ export function httpStatus(): number { return 0; }
336
+ export function httpOk(): boolean { return false; }
337
+ export function httpBody(): string { return ""; }
338
+ export function httpContentLength(): number { return 0; }
339
+ export function httpResponseHeader(name: string): string { return ""; }
340
+
341
+ // ---------------------------------------------------------------------------
342
+ // BLE (NimBLE GATT peripheral)
343
+ // ---------------------------------------------------------------------------
344
+
345
+ export function bleServerBegin(name: string): void {}
346
+ export function bleAdvertiseStart(): void {}
347
+ export function bleAdvertiseStop(): void {}
348
+ export function bleAddService(uuid: string): void {}
349
+ export function bleAddChar(index: number, uuid: string, type: string, perms: number, svcIndex: number): void {}
350
+ export function bleOnRead(index: number, handler: string): void {}
351
+ export function bleOnWrite(index: number, handler: string): void {}
352
+ export function bleOnConnect(handler: string): void {}
353
+ export function bleOnDisconnect(handler: string): void {}
354
+ export function bleNotify(index: number, value: number | string): void {}
355
+ export function bleIsConnected(): boolean { return false; }
356
+ export function bleClientCount(): number { return 0; }
357
+ export function bleSetName(name: string): void {}
358
+ export function bleUntilConnected(timeoutMs?: number): boolean { return false; }
359
+ export function bleUntilConnectedStart(): void {}
360
+ export function bleSetTxPower(dbm: number): void {}
361
+ export function bleStatus(): number { return 0; }
204
362
 
205
363
  // ---------------------------------------------------------------------------
206
364
  // Raw C++ escape hatch
@@ -208,3 +366,20 @@ export function powerSetCpuFrequency(mhz: number): void {}
208
366
 
209
367
  /** Emit raw C++ code (escape hatch for unsupported operations). */
210
368
  export function rawCpp(code: string): void {}
369
+
370
+ /**
371
+ * Emit raw C++ in expression context. Use when an IDF macro or constructor
372
+ * must produce a value (e.g. `WIFI_INIT_CONFIG_DEFAULT()` expands to a struct
373
+ * initializer; there's no TS-side way to construct it). The type parameter
374
+ * is purely a TS hint — the transpiler doesn't check it; it just emits the
375
+ * raw text in expression position.
376
+ *
377
+ * const cfg = rawCpp<wifi_init_config_t>('WIFI_INIT_CONFIG_DEFAULT()');
378
+ *
379
+ * lowers to:
380
+ *
381
+ * wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
382
+ */
383
+ export function rawCppExpr<T>(code: string): T {
384
+ return undefined as unknown as T;
385
+ }