@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,63 @@
1
+ // ---------------------------------------------------------------------------
2
+ // I2CTarget — the thin Zephyr-shaped I2C device
3
+ //
4
+ // One address on a bus, Zephyr's register verbs verbatim: writeReg/readReg
5
+ // are i2c_reg_write_byte / i2c_reg_read_byte, updateReg is the native
6
+ // read-modify-write (i2c_reg_update_byte — mask and all, no read-back race),
7
+ // and write() is i2c_write. No begin/end transaction dance, no Wire
8
+ // vocabulary — the controller device handle and the per-call address are all
9
+ // Zephyr needs.
10
+ //
11
+ // `bus` is the board's bus instance export (I2C0/I2C1); the address is the
12
+ // 7-bit form (0x44). The optional bus `hz` applies once (i2c_configure,
13
+ // guarded) — Zephyr's own I2C_SPEED_SET mapping.
14
+ // ----------------------------------------------------------------------------
15
+
16
+ import { i2cRegWrite, i2cRegRead, i2cRegUpdate, i2cDevWrite } from './emit.js';
17
+
18
+ export class I2CTarget {
19
+ private readonly _bus: string;
20
+ private readonly _address: number;
21
+ private readonly _hz: number;
22
+
23
+ /** Construct a device handle. `bus` is the bus instance (I2C0, I2C1, …);
24
+ * `address` is the 7-bit I2C address; `hz` optionally sets the bus speed
25
+ * once at first use (100k/400k/1M map to Zephyr's I2C_SPEED_* tiers). */
26
+ constructor(bus: string, address: number, opts?: { hz?: number }) {
27
+ this._bus = bus;
28
+ this._address = address;
29
+ this._hz = opts?.hz ?? 0;
30
+ }
31
+
32
+ /** Write one register byte (i2c_reg_write_byte). */
33
+ writeReg(reg: number, value: number): void {
34
+ i2cRegWrite(this._bus, this._address, this._hz, reg, value);
35
+ }
36
+
37
+ /** Read one register byte (i2c_reg_read_byte). */
38
+ readReg(reg: number): number {
39
+ return i2cRegRead(this._bus, this._address, this._hz, reg);
40
+ }
41
+
42
+ /** Read-modify-write one register field (i2c_reg_update_byte): the bits in
43
+ * `mask` are replaced by `value`. Atomic on the wire — no read-back race. */
44
+ updateReg(reg: number, mask: number, value: number): void {
45
+ i2cRegUpdate(this._bus, this._address, this._hz, reg, mask, value);
46
+ }
47
+
48
+ /** Write raw bytes (i2c_write) — commands and data with no register
49
+ * convention. */
50
+ write(data: number[] | Uint8Array): void {
51
+ i2cDevWrite(this._bus, this._address, this._hz, data);
52
+ }
53
+
54
+ /** The 7-bit I2C address this target addresses. Exposed so I2CTarget
55
+ * structurally satisfies the @typecad/simulator II2CDeviceAccessor
56
+ * contract (`readonly address`), letting the same driver function be
57
+ * typed against the contract and accept either a real board device or a
58
+ * simulated one. The transpiler strips HAL class bodies to IR, so this
59
+ * getter carries no runtime cost in the generated C++. */
60
+ get address(): number {
61
+ return this._address;
62
+ }
63
+ }
package/src/i2c.ts CHANGED
@@ -1,167 +1,29 @@
1
- import { i2cBegin, i2cEnd, i2cSetClock, i2cBeginTx, i2cWrite, i2cWriteBuffer, i2cEndTx, i2cRequestFrom, i2cAvailable, i2cRead, i2cReadBuffer, rawCpp } from './emit.js';
2
- import { include } from './include.js';
3
-
4
- export class I2CDevice {
5
- private _bus: string;
6
- private _address: number;
7
-
8
- constructor(bus: string, address: number) {
9
- this._bus = bus;
10
- this._address = address;
11
- }
12
-
13
- /** The 7-bit I2C address this accessor targets. Exposed so I2CDevice
14
- * structurally satisfies the @typecad/simulator II2CDeviceAccessor contract
15
- * (which declares `readonly address`), letting the same driver function be
16
- * typed against the contract and accept either a real board device or a
17
- * simulated one. The transpiler strips HAL class bodies to IR, so this
18
- * getter carries no runtime cost in the generated C++. */
19
- get address(): number {
20
- return this._address;
21
- }
22
-
23
- writeByte(register: number, value: number): void {
24
- include("<Wire.h>");
25
- i2cBeginTx(this._bus, this._address);
26
- i2cWrite(this._bus, register);
27
- i2cWrite(this._bus, value);
28
- i2cEndTx(this._bus, true);
29
- }
30
-
31
- readByte(register: number): number {
32
- include("<Wire.h>");
33
- i2cBeginTx(this._bus, this._address);
34
- i2cWrite(this._bus, register);
35
- i2cEndTx(this._bus, false);
36
- i2cRequestFrom(this._bus, this._address, 1);
37
- return i2cRead(this._bus);
38
- }
39
-
40
- writeBytes(register: number, data: number[] | Uint8Array): void {
41
- include("<Wire.h>");
42
- i2cBeginTx(this._bus, this._address);
43
- i2cWrite(this._bus, register);
44
- i2cWriteBuffer(this._bus, data);
45
- i2cEndTx(this._bus, true);
46
- }
47
-
48
- readBytes(register: number, count: number): Uint8Array {
49
- include("<Wire.h>");
50
- i2cBeginTx(this._bus, this._address);
51
- i2cWrite(this._bus, register);
52
- i2cEndTx(this._bus, false);
53
- i2cRequestFrom(this._bus, this._address, count, true);
54
- // Drain the requested bytes into the caller's buffer (declared by the
55
- // Uint8Array return marker as `uint8_t data[count]`). Using the semantic
56
- // primitive — NOT rawCpp — keeps the buffer in user scope so it survives
57
- // the return (no decayed pointer) and `data.length` / `data[i]` work.
58
- i2cReadBuffer(this._bus, count, new Uint8Array(count));
59
- return new Uint8Array(count);
60
- }
61
- }
62
-
63
- export class I2CBus {
64
- static readonly __includes = ["<Wire.h>"];
65
- private _bus: string;
66
-
67
- constructor(bus: string) {
68
- this._bus = bus;
69
- }
70
-
71
- device(address: number): I2CDevice {
72
- return new I2CDevice(this._bus, address);
73
- }
74
-
75
- begin(): this {
76
- include("<Wire.h>");
77
- i2cBegin(this._bus);
78
- return this;
79
- }
80
-
81
- beginSlave(address: number): void {
82
- i2cBegin(this._bus, address);
83
- }
84
-
85
- end(): void {
86
- i2cEnd(this._bus);
87
- }
88
-
89
- setClock(hz: number): void {
90
- i2cSetClock(this._bus, hz);
91
- }
92
-
93
- /** Recover a locked I2C bus by clocking SCL until the stuck slave releases SDA.
94
- *
95
- * NOTE: This references the board-defined `SCL` pin macro. All current MCU
96
- * packages (atmega328p, esp32, esp32c3, esp32c6, esp32s3) export SCL, so
97
- * this works in practice. A fully portable version would resolve the SCL
98
- * pin number via a board constant (e.g. peripherals.i2c.0.sclPin), but that
99
- * requires adding resolved numeric pin fields to the board-constants
100
- * pipeline — deferred for now. */
101
- recover(): void {
102
- include("<Wire.h>");
103
- rawCpp(`pinMode(SCL, OUTPUT);`);
104
- rawCpp(`for (int i = 0; i < 16; i++) {`);
105
- rawCpp(` digitalWrite(SCL, LOW);`);
106
- rawCpp(` delayMicroseconds(10);`);
107
- rawCpp(` digitalWrite(SCL, HIGH);`);
108
- rawCpp(` delayMicroseconds(10);`);
109
- rawCpp(`}`);
110
- rawCpp(`${this._bus}.begin();`);
111
- }
112
-
113
- take(): this | null {
114
- include("<Wire.h>");
115
- return this;
116
- }
117
-
118
- release(): void {
119
- // No-op for standard Arduino.
120
- }
121
-
122
- writeByte(address: number, register: number, value: number): void {
123
- i2cBeginTx(this._bus, address);
124
- i2cWrite(this._bus, register);
125
- i2cWrite(this._bus, value);
126
- i2cEndTx(this._bus, true);
127
- }
128
-
129
- readByte(address: number, register: number): number {
130
- i2cBeginTx(this._bus, address);
131
- i2cWrite(this._bus, register);
132
- i2cEndTx(this._bus, false);
133
- i2cRequestFrom(this._bus, address, 1);
134
- return i2cRead(this._bus);
135
- }
136
-
137
- // Low-level Wire API pass-through methods
138
- beginTransmission(address: number): void {
139
- i2cBeginTx(this._bus, address);
140
- }
141
-
142
- write(data: number | number[] | Uint8Array): void {
143
- i2cWrite(this._bus, data);
144
- }
145
-
146
- endTransmission(stop?: boolean): number {
147
- return i2cEndTx(this._bus, stop ?? true);
148
- }
149
-
150
- requestFrom(address: number, quantity: number, stop?: boolean): number {
151
- return i2cRequestFrom(this._bus, address, quantity, stop ?? true);
152
- }
153
-
154
- available(): number {
155
- return i2cAvailable(this._bus);
156
- }
157
-
158
- read(): number {
159
- return i2cRead(this._bus);
160
- }
161
- }
162
-
163
-
164
- /** Map TypeCAD I2C instance number to Arduino C++ object name. I2C0→Wire, I2C1→Wire1 */
165
- export function i2cName(instance: number): string {
166
- return instance === 0 ? "Wire" : `Wire${instance}`;
167
- }
1
+ // ---------------------------------------------------------------------------
2
+ // I2C controller selector (legacy Wire API removed)
3
+ //
4
+ // The bus singletons (I2C0/I2C1…) are CONTROLLER SELECTORS; device(address)
5
+ // hands back the FUNCTIONAL I2CTarget directly — register verbs callable with
6
+ // no further construction (`I2C0.device(0x44).writeReg(...)`) and the same
7
+ // fact-carrier `new Sensor(SENSOR.x, I2C0.device(0x44))` consumes. Explicit
8
+ // construction `new I2CTarget(I2C0, 0x44)` is equivalent. The former
9
+ // begin/endTransmission/requestFrom Wire reconstruction was removed with the
10
+ // legacy Arduino surface; the standalone I2CDevice fact-carrier was absorbed
11
+ // by I2CTarget (same facts, plus the verbs).
12
+ // ----------------------------------------------------------------------------
13
+
14
+ import { I2CTarget } from './i2c-target.js';
15
+
16
+ export class I2CBus {
17
+ private _bus: string;
18
+
19
+ constructor(bus: string) {
20
+ this._bus = bus;
21
+ }
22
+
23
+ /** The functional device target at `address` on this controller —
24
+ * register verbs callable directly, and the fact-carrier `new Sensor(...)`
25
+ * accepts. Equivalent to `new I2CTarget(this, address)`. */
26
+ device(address: number): I2CTarget {
27
+ return new I2CTarget(this._bus, address);
28
+ }
29
+ }
package/src/index.ts CHANGED
@@ -4,65 +4,51 @@
4
4
  // status enums, capability guards, PinCapabilityFlags, IToneAttachment, ...)
5
5
  // now live in @typecad/simulator. Import them from there.
6
6
  export type { DigitalValue, AnalogValue } from './types.js';
7
- export { PinMode, InterruptMode } from './types.js';
8
- export type { IPinGroup, PinGroupMember } from './types.js';
9
- export { createPinGroup } from './types.js';
7
+ export { PinMode } from './types.js';
10
8
 
11
9
  export type { InterruptHandler } from './types.js';
12
10
 
13
11
  export type { ArchitectureIdentifier } from './types.js';
14
12
 
15
- // Protocol-shape types (re-exported downstream by @typecad/framework-arduino)
16
- export type { I2CAddress } from './types.js';
17
- export type { SPIBitOrder, SPIMode, SPISettings } from './types.js';
13
+ export type { SerialValue } from './types.js';
18
14
 
19
15
  export { include } from './include.js';
20
16
  export { board } from './board.js';
21
17
  export { callback } from './callback.js';
22
18
  export { rawCpp, rawCppExpr, boardResolve } from './emit.js';
23
- export { HIGH, LOW, OUTPUT, INPUT, INPUT_PULLUP, INPUT_PULLDOWN, OUTPUT_OPEN_DRAIN, ANALOG, LED_BUILTIN, LSBFIRST, MSBFIRST, WDTO_15MS, WDTO_30MS, WDTO_60MS, WDTO_120MS, WDTO_250MS, WDTO_500MS, WDTO_1S, WDTO_2S, WDTO_4S, WDTO_8S } from './constants.js';
24
- export { delay, millis, micros, delayMicroseconds, map, constrain, TimingClass, Timing } from './timing.js';
25
- export { freeHeap, setInterval, setTimeout, clearInterval, clearTimeout } from './timing.js';
26
- export { abs, min, max, NumClass, Num, MapChain, ConstrainChain } from './math.js';
27
- export { Pulse, pulseIn, pulseInLong } from './pulse.js';
28
- export { Shift, shiftIn, shiftOut } from './shift.js';
19
+ export { TimeClass, Time } from './time.js';
20
+ export { abs, min, max, NumClass, Num } from './math.js';
21
+
29
22
  export { Random } from './random.js';
30
- export { randomSeed, random } from './random.js';
31
- export { noInterrupts, interrupts, attachInterrupt, detachInterrupt } from './interrupts.js';
32
- export { Pin, OutputPin, InputPin, ToneChain } from './gpio.js';
33
- export { I2CBus, I2CDevice, i2cName } from './i2c.js';
34
- export { SPIBus, SPIDevice, spiName } from './spi.js';
35
- export { SerialPort, serialName } from './uart.js';
36
- export { createHALInstances } from './utils.js';
23
+ export { Pin } from './gpio.js';
24
+ export { GPIO } from './gpio-pin.js';
25
+ export { shiftOut, shiftIn } from './shift-pin.js';
26
+ export { PWM } from './pwm-pin.js';
27
+ export { ADC } from './adc-pin.js';
28
+ export { DAC } from './dac-pin.js';
29
+ export { Watchdog } from './watchdog.js';
30
+ export { Counter } from './counter.js';
31
+ export { I2CTarget } from './i2c-target.js';
32
+ export { SPITarget } from './spi-target.js';
33
+ export { UART } from './uart-port.js';
34
+ export { Thread } from './thread.js';
35
+ export { I2CBus } from './i2c.js';
36
+ export { Sensor } from './sensor.js';
37
+ export { SENSOR, CHAN, SENSOR_PART_INFO } from './sensor-catalog.generated.js';
38
+ export { ZEPHYR_ADC_GAINS, ZEPHYR_ADC_REFERENCES, ZEPHYR_GPIO_FLAGS, ZEPHYR_GPIO_INTS } from './zephyr-tokens.generated.js';
39
+ export type { SensorToken, SensorChannelName, SensorPartInfo } from './sensor-catalog.generated.js';
40
+ export { SPIBus } from './spi.js';
41
+ export { USBConsole } from './usb.js';
37
42
  // Register-mapped struct decorators (compile-time markers, erased by transpiler)
38
43
  export type { Bit, Bits } from './register.js';
39
44
  export { register, bits } from './register.js';
40
- export { EEPROMClass, EEPROM } from './eeprom.js';
41
- export { WDTClass, WDT } from './wdt.js';
42
- export { ADCClass, ADC } from './adc.js';
43
- export { DACClass, DAC } from './dac.js';
44
- export { PreferencesClass, Preferences } from './preferences.js';
45
- export { HardwareTimer, Timer0, Timer1, Timer2 } from './timer.js';
46
- export { FSClass, FS } from './fs.js';
47
- export { fsBegin, fsReadText, fsWriteText, fsExists, fsRemove } from './fs.js';
48
- export { MdnsClass, MDNS } from './mdns.js';
49
- export { mdnsStart, mdnsSetHostname, mdnsAddService, mdnsAnnounce, mdnsStop } from './mdns.js';
50
- export { MqttClass, MQTT } from './mqtt.js';
51
- export { mqttConnect, mqttOnMessage, mqttSubscribe, mqttPublish, mqttConnected, mqttDisconnect } from './mqtt.js';
52
- export { OtaClass, OTA } from './ota.js';
53
- export { otaFromUrl, otaBegin, otaWrite, otaApply } from './ota.js';
54
- export { TemperatureClass, Temperature } from './temperature.js';
55
- export { tempRead } from './temperature.js';
56
- export { hwtimerSetFrequency, hwtimerOnOverflow, hwtimerStart, hwtimerStop } from './timer.js';
57
- export { CapacitiveClass, Capacitive } from './capacitive.js';
58
- export { capacitiveRead } from './capacitive.js';
59
- export { PowerClass, Power } from './power.js';
45
+ export { Store } from './preferences.js';
46
+ export { File } from './fs.js';
47
+ export { Mqtt } from './mqtt.js';
48
+
60
49
  export { AsyncClass, Async } from './async.js';
61
- export { WiFiClass, WiFi, WiFiStatus, WiFiEncryption } from './wifi.js';
62
- export { HttpClass, Http, HttpRequest, HttpMethod } from './http.js';
63
- export {
64
- BleClass, Ble, BleServer,
65
- BleValueType, BlePerm, BleStatus, BleAdvertisingMode, GATT,
66
- } from './ble.js';
50
+ export { WiFi, Scan, WiFiAP } from './wifi.js';
51
+ export { Request } from './http.js';
52
+ export type { RequestOpts } from './http.js';
53
+ export { BLE, BleChain, BleValueType, BlePerm, GATT } from './ble.js';
67
54
  export type { GattCharacteristicDef, CharValue } from './ble.js';
68
- export { RmtChannel } from './rmt.js';
package/src/math.ts CHANGED
@@ -1,15 +1,12 @@
1
- export class MapChain {
2
- constructor(value: number) {}
3
- from(low: number, high: number): MapChain { return this; }
4
- to(low: number, high: number): number { return 0; }
5
- toPercent(): number { return 0; }
6
- toByte(): number { return 0; }
7
- }
8
-
9
- export class ConstrainChain {
10
- constructor(value: number) {}
11
- between(low: number, high: number): number { return 0; }
12
- }
1
+ // ---------------------------------------------------------------------------
2
+ // Num — numeric conveniences over the strategy polyfill.
3
+ //
4
+ // The fluent map/constrain chains (Num.map(x).from(a,b).to(c,d)) were dropped
5
+ // with the free map()/constrain() functions in the Zephyr-first cleanup —
6
+ // the remap/clamp arithmetic is a three-line helper in user code, and no
7
+ // backend honors it natively. abs/min/max stay (bare-call polyfills exist on
8
+ // every framework).
9
+ // ---------------------------------------------------------------------------
13
10
 
14
11
  export class NumClass {
15
12
  // No __instance_name — Num methods must NOT be intercepted by the HAL
@@ -21,8 +18,6 @@ export class NumClass {
21
18
  abs(x: number): number { return 0; }
22
19
  min(a: number, b: number): number { return 0; }
23
20
  max(a: number, b: number): number { return 0; }
24
- constrain(value: number): ConstrainChain { return new ConstrainChain(value); }
25
- map(value: number): MapChain { return new MapChain(value); }
26
21
  }
27
22
 
28
23
  export const Num = new NumClass();
package/src/mqtt.ts CHANGED
@@ -1,26 +1,44 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Mqtt — the thin pub/sub client
3
+ //
4
+ // The broker URI and client id are CONSTRUCTION facts; the verbs map onto
5
+ // the Zephyr MQTT client (mqtt_connect / mqtt_publish / mqtt_subscribe,
6
+ // with a poll thread feeding mqtt_input/mqtt_live):
7
+ //
8
+ // connect() → establish the broker session (poll linked() after —
9
+ // the Zephyr client connects in its poll thread)
10
+ // onMessage(cb) → handler for every received PUBLISH on a subscribed
11
+ // topic — receives (topic, payload)
12
+ // subscribe(t) → subscribe to a topic filter ("sensors/#")
13
+ // publish(t, s) → publish a message
14
+ // linked() → the broker session is up
15
+ // disconnect() → disconnect and free the client
16
+ // ----------------------------------------------------------------------------
17
+
1
18
  import { callback } from './callback.js';
19
+ import {
20
+ mqttConnect, mqttOnMessage, mqttSubscribe, mqttPublish, mqttConnected, mqttDisconnect,
21
+ } from './emit.js';
22
+
23
+ export class Mqtt {
24
+ private readonly _uri: string;
25
+ private readonly _clientId: string;
26
+
27
+ /** Construct the client for a broker ("mqtt://broker.local" or
28
+ * "mqtts://..." for TLS). */
29
+ constructor(uri: string, opts: { clientId: string }) {
30
+ this._uri = uri;
31
+ this._clientId = opts.clientId;
32
+ }
2
33
 
3
- /**
4
- * MqttClass MQTT 3.1.1 pub/sub client (ESP-IDF esp_mqtt).
5
- *
6
- * Lowered to native MQTT HAL ops (mqtt.*): ESP-IDF's esp_mqtt_client_* API.
7
- * Covers the common IoT pub/sub path: connect to a broker, publish, subscribe
8
- * with an onMessage callback, and disconnect. The runtime shim owns the event
9
- * loop translation (ESP-IDF's MQTT event handler → the user's TS callback).
10
- *
11
- * Requires a network connection (WiFi) before connect().
12
- */
13
- export class MqttClass {
14
- static readonly __instance_name = "MQTT";
15
-
16
- /** Connect to a broker URI (e.g. "mqtt://broker.local" or "mqtts://..."). */
17
- connect(brokerUri: string, clientId: string): boolean {
18
- mqttConnect(brokerUri, clientId);
19
- return true;
34
+ /** Connect to the broker. Requires a network connection (WiFi) first.
35
+ * The Zephyr client completes the session in its poll thread — poll
36
+ * linked() afterwards. */
37
+ connect(): void {
38
+ mqttConnect(this._uri, this._clientId);
20
39
  }
21
40
 
22
- /** Set a handler invoked for every received PUBLISH on a subscribed topic.
23
- * The handler receives (topic, payload). */
41
+ /** Handler invoked for every received PUBLISH on a subscribed topic. */
24
42
  onMessage(handler: (topic: string, payload: string) => void): void {
25
43
  mqttOnMessage(callback(handler));
26
44
  }
@@ -35,8 +53,8 @@ export class MqttClass {
35
53
  mqttPublish(topic, data);
36
54
  }
37
55
 
38
- /** True if the client is currently connected to the broker. */
39
- connected(): boolean {
56
+ /** True while the broker session is up. */
57
+ linked(): boolean {
40
58
  return mqttConnected();
41
59
  }
42
60
 
@@ -45,13 +63,3 @@ export class MqttClass {
45
63
  mqttDisconnect();
46
64
  }
47
65
  }
48
-
49
- export const MQTT = new MqttClass();
50
-
51
- // ── Semantic primitives (resolved to mqtt.* HAL ops by the transpiler) ──
52
- export function mqttConnect(brokerUri: string, clientId: string): void {}
53
- export function mqttOnMessage(handler: string): void {}
54
- export function mqttSubscribe(topic: string): void {}
55
- export function mqttPublish(topic: string, data: string): void {}
56
- export function mqttConnected(): boolean { return false; }
57
- export function mqttDisconnect(): void {}
@@ -1,87 +1,78 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Store — the thin persistent key/value store
3
+ //
4
+ // The namespace is the CONSTRUCTION fact: `new Store('app')` rides every op
5
+ // as the settings subtree prefix (tc/app/<key> on Zephyr's settings/ZMS
6
+ // backend). There is no session to open or close — the backend loads once at
7
+ // boot and every verb maps 1:1 onto a settings write/read/delete:
8
+ //
9
+ // setInt/getInt, setFloat/getFloat, setBool/getBool,
10
+ // setString/getString — typed pairs; get takes a REQUIRED default (no
11
+ // hidden = 0 magic value)
12
+ // remove(key) → settings_delete
13
+ // clear() → delete every tc/<ns>/* key this app wrote
14
+ //
15
+ // Values survive re-flashing the application: they live in the board's
16
+ // storage partition, not the app image.
17
+ // ----------------------------------------------------------------------------
18
+
1
19
  import {
2
- preferencesBegin,
3
- preferencesEnd,
4
- preferencesClear,
5
- preferencesRemove,
6
- preferencesPutInt,
7
- preferencesGetInt,
8
- preferencesPutUInt,
9
- preferencesGetUInt,
10
- preferencesPutBool,
11
- preferencesGetBool,
12
- preferencesPutFloat,
13
- preferencesGetFloat,
14
- preferencesPutString,
15
- preferencesGetString,
20
+ preferencesPutInt, preferencesGetInt,
21
+ preferencesPutFloat, preferencesGetFloat,
22
+ preferencesPutBool, preferencesGetBool,
23
+ preferencesPutString, preferencesGetString,
24
+ preferencesRemove, preferencesClear,
16
25
  } from './emit.js';
17
26
 
18
- /**
19
- * Preferences — a persistent key/value store, lowered to native NVS
20
- * (nvs_flash / nvs_open / nvs_set_* / nvs_get_*) by framework-esp32.
21
- *
22
- * No include() calls here — NVS headers are framework-owned and added via
23
- * forcedIncludes when the program uses preferences.* ops. Method bodies pass
24
- * parameters directly into semantic calls so the resolver can statically track
25
- * every argument (matching the WiFi/HTTP HAL pattern).
26
- */
27
- export class PreferencesClass {
28
- static readonly __instance_name = "Preferences";
29
-
30
- begin(name: string, readOnly: boolean = false): void {
31
- preferencesBegin(name, readOnly);
32
- }
33
-
34
- end(): void {
35
- preferencesEnd();
36
- }
37
-
38
- clear(): void {
39
- preferencesClear();
40
- }
27
+ export class Store {
28
+ private readonly _ns: string;
41
29
 
42
- remove(key: string): void {
43
- preferencesRemove(key);
30
+ /** Construct the store for a namespace ('app' → settings subtree tc/app/). */
31
+ constructor(ns: string) {
32
+ this._ns = ns;
44
33
  }
45
34
 
46
- putInt(key: string, value: number): void {
47
- preferencesPutInt(key, value);
35
+ setInt(key: string, value: number): void {
36
+ preferencesPutInt(this._ns, key, value);
48
37
  }
49
38
 
50
- getInt(key: string, defaultValue: number = 0): number {
51
- return preferencesGetInt(key, defaultValue);
39
+ getInt(key: string, defaultValue: number): number {
40
+ return preferencesGetInt(this._ns, key, defaultValue);
52
41
  }
53
42
 
54
- putUInt(key: string, value: number): void {
55
- preferencesPutUInt(key, value);
43
+ setFloat(key: string, value: number): void {
44
+ preferencesPutFloat(this._ns, key, value);
56
45
  }
57
46
 
58
- getUInt(key: string, defaultValue: number = 0): number {
59
- return preferencesGetUInt(key, defaultValue);
47
+ getFloat(key: string, defaultValue: number): number {
48
+ return preferencesGetFloat(this._ns, key, defaultValue);
60
49
  }
61
50
 
62
- putBool(key: string, value: boolean): void {
63
- preferencesPutBool(key, value);
51
+ setBool(key: string, value: boolean): void {
52
+ preferencesPutBool(this._ns, key, value);
64
53
  }
65
54
 
66
- getBool(key: string, defaultValue: boolean = false): boolean {
67
- return preferencesGetBool(key, defaultValue);
55
+ getBool(key: string, defaultValue: boolean): boolean {
56
+ return preferencesGetBool(this._ns, key, defaultValue);
68
57
  }
69
58
 
70
- putFloat(key: string, value: number): void {
71
- preferencesPutFloat(key, value);
59
+ setString(key: string, value: string): void {
60
+ preferencesPutString(this._ns, key, value);
72
61
  }
73
62
 
74
- getFloat(key: string, defaultValue: number = 0): number {
75
- return preferencesGetFloat(key, defaultValue);
63
+ /** Read a string back. The value lands in the shim's ring buffer — copy
64
+ * what you need before the next get on the same key. */
65
+ getString(key: string, defaultValue: string): string {
66
+ return preferencesGetString(this._ns, key, defaultValue);
76
67
  }
77
68
 
78
- putString(key: string, value: string): void {
79
- preferencesPutString(key, value);
69
+ /** Delete one key (flash + cache). No-op when absent. */
70
+ remove(key: string): void {
71
+ preferencesRemove(this._ns, key);
80
72
  }
81
73
 
82
- getString(key: string, defaultValue: string = ""): string {
83
- return preferencesGetString(key, defaultValue);
74
+ /** Delete every key under this store's namespace. */
75
+ clear(): void {
76
+ preferencesClear(this._ns);
84
77
  }
85
78
  }
86
-
87
- export const Preferences = new PreferencesClass();