@mikrojs/native 0.20.1 → 0.21.0-next.20260913195055

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 (56) hide show
  1. package/CMakeLists.txt +3 -1
  2. package/cmake/mikrojs_bytecode.cmake +1 -1
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.js +1 -1
  5. package/dist/runtime/result/native-result.node-shim.js.map +1 -1
  6. package/dist/runtime/result/types.d.ts +5 -5
  7. package/dist/runtime/result/types.d.ts.map +1 -1
  8. package/dist/types.d.ts +1 -1
  9. package/dist/types.d.ts.map +1 -1
  10. package/include/mikrojs/mikrojs.h +26 -2
  11. package/include/mikrojs/ota_env.h +8 -6
  12. package/include/mikrojs/ota_policy.h +16 -0
  13. package/include/mikrojs/private.h +13 -0
  14. package/include/mikrojs/utils.h +24 -0
  15. package/package.json +10 -10
  16. package/prebuilds/darwin-arm64/mikrojs.napi.node +0 -0
  17. package/prebuilds/linux-arm64/mikrojs.napi.node +0 -0
  18. package/prebuilds/linux-x64/mikrojs.napi.node +0 -0
  19. package/runtime/gpio/types.ts +116 -0
  20. package/runtime/i2c/types.ts +25 -31
  21. package/runtime/i2s/types.ts +23 -12
  22. package/runtime/internal.d.ts +1 -174
  23. package/runtime/kv/shared.ts +13 -11
  24. package/runtime/neopixel/types.ts +24 -6
  25. package/runtime/observable/native-observable.node-shim.ts +73 -37
  26. package/runtime/observable/native-operators.node-shim.ts +417 -0
  27. package/runtime/observable/observable.ts +76 -1
  28. package/runtime/observable/operators.ts +156 -89
  29. package/runtime/observable/types.ts +61 -6
  30. package/runtime/pwm/types.ts +31 -11
  31. package/runtime/result/native-result.node-shim.ts +1 -1
  32. package/runtime/result/types.ts +5 -5
  33. package/runtime/sleep/types.ts +10 -8
  34. package/runtime/spi/types.ts +16 -14
  35. package/runtime/uart/types.ts +27 -15
  36. package/src/gpio_claim.cpp +63 -0
  37. package/src/mik_abort.cpp +1 -2
  38. package/src/mik_console.cpp +192 -115
  39. package/src/mik_http_client.cpp +3 -14
  40. package/src/mik_inspect.cpp +86 -9
  41. package/src/mik_observable.cpp +1028 -80
  42. package/src/mik_ota_client.cpp +5 -2
  43. package/src/mik_ota_policy.cpp +65 -18
  44. package/src/mik_result.cpp +10 -9
  45. package/src/mikrojs.cpp +26 -13
  46. package/src/modules.cpp +17 -6
  47. package/src/timers.cpp +6 -2
  48. package/src/utils.cpp +106 -0
  49. package/runtime/i2c/i2c.ts +0 -35
  50. package/runtime/i2s/i2s.ts +0 -46
  51. package/runtime/neopixel/neopixel.ts +0 -38
  52. package/runtime/pin/pin.ts +0 -51
  53. package/runtime/pin/types.ts +0 -49
  54. package/runtime/pwm/pwm.ts +0 -32
  55. package/runtime/spi/spi.ts +0 -31
  56. package/runtime/uart/uart.ts +0 -52
@@ -1,6 +1,7 @@
1
- /* Operators for `Observable.pipe(...)`. Each is a factory returning a
2
- * function `(source) => Observable`. Composition is pure pipe — no method
3
- * chaining on Observable itself.
1
+ /* Operators for `Observable.pipe(...)`, declared here and implemented in C
2
+ * (mik_observable.cpp, module `mikro/observable/operators`). Each is a
3
+ * factory returning a function `(source) => Observable`. Composition is pure
4
+ * pipe: no method chaining on Observable itself.
4
5
  *
5
6
  * M0 scope: operators apply to non-fallible streams (`Err = never`). For
6
7
  * fallible streams (`Observable<Ok, Err>` with Err != never), corresponding
@@ -14,97 +15,163 @@
14
15
  * See `.claude/plans/observable.md` for the full design.
15
16
  */
16
17
 
17
- import {Observable as NativeObservable} from 'native:mikro/observable'
18
+ import type {Observable} from './types.js'
18
19
 
19
- import type {Observable as ObservableT} from './types.js'
20
-
21
- /* `native:mikro/observable` resolves only inside the runtime build; outside
22
- * (twoslash, host typecheck without internal.d.ts) it falls back to `any`,
23
- * which collapses pipe/operator inference at use sites. Pin the type to the
24
- * declared class in `./types.ts` so consumers always see the typed shape. */
25
- const Observable = NativeObservable as unknown as typeof ObservableT
26
- type Observable<Ok, Err = never> = ObservableT<Ok, Err>
20
+ type Op<A, B> = (source: Observable<A>) => Observable<B>
27
21
 
28
22
  /* Map values through a transform. A throw inside `fn` panics. */
29
- export const map =
30
- <A, B>(fn: (value: A) => B) =>
31
- (source: Observable<A>): Observable<B> =>
32
- new Observable<B>((sub) => {
33
- const upstream = source.subscribe({
34
- next: (value) => sub.next(fn(value)),
35
- complete: () => sub.complete(),
36
- })
37
- sub.addTeardown(() => upstream.unsubscribe())
38
- })
39
-
40
- /* Pass through values matching `predicate`. A throw inside it panics. */
41
- export const filter =
42
- <A>(predicate: (value: A) => boolean) =>
43
- (source: Observable<A>): Observable<A> =>
44
- new Observable<A>((sub) => {
45
- const upstream = source.subscribe({
46
- next: (value) => {
47
- if (predicate(value)) sub.next(value)
48
- },
49
- complete: () => sub.complete(),
50
- })
51
- sub.addTeardown(() => upstream.unsubscribe())
52
- })
23
+ export declare function map<A, B>(fn: (value: A) => B): Op<A, B>
24
+
25
+ /* Pass through values matching `predicate`; a type guard narrows the output.
26
+ * A throw inside it panics. */
27
+ export declare function filter<A, B extends A>(predicate: (value: A) => value is B): Op<A, B>
28
+ export declare function filter<A>(predicate: (value: A) => boolean): Op<A, A>
29
+
30
+ /* Run `fn` on each value, then pass it through unchanged. A throw inside
31
+ * `fn` panics. */
32
+ export declare function tap<A>(fn: (value: A) => void): Op<A, A>
53
33
 
54
34
  /* Take at most `count` values, then complete. count <= 0 completes immediately. */
55
- export const take =
56
- (count: number) =>
57
- <A>(source: Observable<A>): Observable<A> =>
58
- new Observable<A>((sub) => {
59
- if (count <= 0) {
60
- sub.complete()
61
- return
62
- }
63
- let remaining = count
64
- const upstream = source.subscribe({
65
- next: (value) => {
66
- if (remaining <= 0) return
67
- remaining--
68
- sub.next(value)
69
- if (remaining === 0) sub.complete()
70
- },
71
- complete: () => sub.complete(),
72
- })
73
- sub.addTeardown(() => upstream.unsubscribe())
74
- })
75
-
76
- /* Stop emitting when `notifier` emits its first value. Notifier completing
77
- * without emitting is NOT a trigger — primary keeps going. */
78
- export const takeUntil =
79
- (notifier: Observable<unknown, unknown>) =>
80
- <A>(source: Observable<A>): Observable<A> =>
81
- new Observable<A>((sub) => {
82
- const upstream = source.subscribe({
83
- next: (value) => sub.next(value),
84
- complete: () => sub.complete(),
85
- })
86
- const notifierSub = notifier.subscribe({
87
- next: () => sub.complete(),
88
- })
89
- sub.addTeardown(() => {
90
- notifierSub.unsubscribe()
91
- upstream.unsubscribe()
92
- })
93
- })
35
+ export declare function take(count: number): <A>(source: Observable<A>) => Observable<A>
36
+
37
+ /* Drop the first `count` values, then pass the rest through. */
38
+ export declare function skip(count: number): <A>(source: Observable<A>) => Observable<A>
39
+
40
+ /* Fold values into an accumulator, emitting each intermediate result. */
41
+ export declare function scan<A, B>(fn: (acc: B, value: A) => B, seed: B): Op<A, B>
42
+
43
+ /* Drop values equal (by ===, or `equals`) to the previous one. */
44
+ export declare function distinctUntilChanged<A>(equals?: (a: A, b: A) => boolean): Op<A, A>
45
+
46
+ /* Emit `value` on subscribe, then pass the source through. */
47
+ export declare function startWith<A>(value: A): Op<A, A>
94
48
 
95
49
  /* Run `fn` when the subscription ends for any reason (unsubscribe or
96
50
  * natural completion). A throw inside `fn` panics; the remaining teardowns
97
- * still run. RxJS naming. */
98
- export const finalize =
99
- (fn: () => void) =>
100
- <A>(source: Observable<A>): Observable<A> =>
101
- new Observable<A>((sub) => {
102
- const upstream = source.subscribe({
103
- next: (value) => sub.next(value),
104
- complete: () => sub.complete(),
105
- })
106
- sub.addTeardown(() => {
107
- upstream.unsubscribe()
108
- fn()
109
- })
110
- })
51
+ * still run. */
52
+ export declare function finalize(fn: () => void): <A>(source: Observable<A>) => Observable<A>
53
+
54
+ /* Stop when `until` fires. An Observable ends the stream when it emits a
55
+ * value (completing alone does not); a predicate ends it at the first value
56
+ * it accepts, delivered too unless `inclusive` is false. */
57
+ export declare function takeUntil(
58
+ notifier: Observable<unknown, unknown>,
59
+ ): <A>(source: Observable<A>) => Observable<A>
60
+ export declare function takeUntil<A>(
61
+ predicate: (value: A) => boolean,
62
+ options?: {inclusive?: boolean},
63
+ ): Op<A, A>
64
+
65
+ /* Interleave the source with `others`; completes when all of them have. */
66
+ export declare function mergeWith<A, B>(...others: Array<Observable<B>>): Op<A, A | B>
67
+
68
+ /* Pair each source value with the latest value of `other`. Source values
69
+ * arriving before `other` has emitted are dropped. */
70
+ export declare function withLatestFrom<A, B>(other: Observable<B>): Op<A, [A, B]>
71
+
72
+ /* Emit the latest values of all sources whenever any of them emits, once
73
+ * every source has emitted. Completes when all sources have, or as soon as
74
+ * one completes without a value (no tuple can ever form). */
75
+ export declare function combineLatest<T extends readonly unknown[]>(sources: {
76
+ [K in keyof T]: Observable<T[K]>
77
+ }): Observable<T>
78
+
79
+ /* Compose operators left to right into one operator, for reuse across
80
+ * streams or as a `state()` pipeline. */
81
+ export declare function pipe<A>(): Op<A, A>
82
+ export declare function pipe<A, B>(op1: Op<A, B>): Op<A, B>
83
+ export declare function pipe<A, B, C>(op1: Op<A, B>, op2: Op<B, C>): Op<A, C>
84
+ export declare function pipe<A, B, C, D>(op1: Op<A, B>, op2: Op<B, C>, op3: Op<C, D>): Op<A, D>
85
+ export declare function pipe<A, B, C, D, E>(
86
+ op1: Op<A, B>,
87
+ op2: Op<B, C>,
88
+ op3: Op<C, D>,
89
+ op4: Op<D, E>,
90
+ ): Op<A, E>
91
+ export declare function pipe<A, B, C, D, E, F>(
92
+ op1: Op<A, B>,
93
+ op2: Op<B, C>,
94
+ op3: Op<C, D>,
95
+ op4: Op<D, E>,
96
+ op5: Op<E, F>,
97
+ ): Op<A, F>
98
+ export declare function pipe<A, B, C, D, E, F, G>(
99
+ op1: Op<A, B>,
100
+ op2: Op<B, C>,
101
+ op3: Op<C, D>,
102
+ op4: Op<D, E>,
103
+ op5: Op<E, F>,
104
+ op6: Op<F, G>,
105
+ ): Op<A, G>
106
+ export declare function pipe<A, B, C, D, E, F, G, H>(
107
+ op1: Op<A, B>,
108
+ op2: Op<B, C>,
109
+ op3: Op<C, D>,
110
+ op4: Op<D, E>,
111
+ op5: Op<E, F>,
112
+ op6: Op<F, G>,
113
+ op7: Op<G, H>,
114
+ ): Op<A, H>
115
+ export declare function pipe<A, B, C, D, E, F, G, H, I>(
116
+ op1: Op<A, B>,
117
+ op2: Op<B, C>,
118
+ op3: Op<C, D>,
119
+ op4: Op<D, E>,
120
+ op5: Op<E, F>,
121
+ op6: Op<F, G>,
122
+ op7: Op<G, H>,
123
+ op8: Op<H, I>,
124
+ ): Op<A, I>
125
+ export declare function pipe<A, B, C, D, E, F, G, H, I, J>(
126
+ op1: Op<A, B>,
127
+ op2: Op<B, C>,
128
+ op3: Op<C, D>,
129
+ op4: Op<D, E>,
130
+ op5: Op<E, F>,
131
+ op6: Op<F, G>,
132
+ op7: Op<G, H>,
133
+ op8: Op<H, I>,
134
+ op9: Op<I, J>,
135
+ ): Op<A, J>
136
+ /* Longer chains still compose; type them by hand from the result. */
137
+ export declare function pipe<A, B, C, D, E, F, G, H, I, J>(
138
+ op1: Op<A, B>,
139
+ op2: Op<B, C>,
140
+ op3: Op<C, D>,
141
+ op4: Op<D, E>,
142
+ op5: Op<E, F>,
143
+ op6: Op<F, G>,
144
+ op7: Op<G, H>,
145
+ op8: Op<H, I>,
146
+ op9: Op<I, J>,
147
+ ...ops: Array<Op<any, any>>
148
+ ): Op<A, unknown>
149
+
150
+ /* Map each value to an inner stream and pass on the latest inner stream's
151
+ * values; a new value unsubscribes the previous inner stream. Completes once
152
+ * the source and the last inner stream have both completed. */
153
+ export declare function switchMap<A, B>(project: (value: A) => Observable<B>): Op<A, B>
154
+
155
+ /* Emit 0 after `delayMs`, then complete; with `periodMs`, keep counting up
156
+ * every period instead. */
157
+ export declare function timer(delayMs: number, periodMs?: number): Observable<number>
158
+
159
+ /* Which edge of a burst an operator emits on. */
160
+ export type EdgeOptions = {leading?: boolean; trailing?: boolean}
161
+
162
+ /* Emit a value only once `ms` have passed without another one. `trailing`
163
+ * (default) emits the last value of a burst when it ends; `leading` emits the
164
+ * first one at once. A pending trailing value is flushed on complete. */
165
+ export declare function debounceTime(
166
+ ms: number,
167
+ options?: EdgeOptions,
168
+ ): <A>(source: Observable<A>) => Observable<A>
169
+
170
+ /* Emit one value per `ms` window and drop the rest. `leading` (default)
171
+ * emits the value that opens a window; `trailing` emits the last dropped one
172
+ * when the window ends, which opens the next window. A pending trailing
173
+ * value is flushed on complete. */
174
+ export declare function throttleTime(
175
+ ms: number,
176
+ options?: EdgeOptions,
177
+ ): <A>(source: Observable<A>) => Observable<A>
@@ -20,7 +20,8 @@ export interface Subscriber<Ok, Err = never> {
20
20
  readonly closed: boolean
21
21
  }
22
22
 
23
- export type SubscribeCallback<Ok, Err> = (subscriber: Subscriber<Ok, Err>) => void
23
+ /* May return a teardown function, registered as if passed to addTeardown() last. */
24
+ export type SubscribeCallback<Ok, Err> = (subscriber: Subscriber<Ok, Err>) => void | (() => void)
24
25
 
25
26
  export interface Subscription {
26
27
  unsubscribe(): void
@@ -66,11 +67,49 @@ export declare class Observable<Ok, Err = never> {
66
67
  op5: OperatorFunction<D, Err, E, Err>,
67
68
  op6: OperatorFunction<E, Err, F, Err>,
68
69
  ): Observable<F, Err>
69
-
70
- static from<X, E>(p: Promise<Result<X, E>>): Observable<X, E>
71
- static from<T>(p: Promise<T>): Observable<T, never>
72
- static from<T>(it: Iterable<T>): Observable<T, never>
73
- static from<Ok, Err>(o: Observable<Ok, Err>): Observable<Ok, Err>
70
+ pipe<A, B, C, D, E, F, G>(
71
+ op1: OperatorFunction<Ok, Err, A, Err>,
72
+ op2: OperatorFunction<A, Err, B, Err>,
73
+ op3: OperatorFunction<B, Err, C, Err>,
74
+ op4: OperatorFunction<C, Err, D, Err>,
75
+ op5: OperatorFunction<D, Err, E, Err>,
76
+ op6: OperatorFunction<E, Err, F, Err>,
77
+ op7: OperatorFunction<F, Err, G, Err>,
78
+ ): Observable<G, Err>
79
+ pipe<A, B, C, D, E, F, G, H>(
80
+ op1: OperatorFunction<Ok, Err, A, Err>,
81
+ op2: OperatorFunction<A, Err, B, Err>,
82
+ op3: OperatorFunction<B, Err, C, Err>,
83
+ op4: OperatorFunction<C, Err, D, Err>,
84
+ op5: OperatorFunction<D, Err, E, Err>,
85
+ op6: OperatorFunction<E, Err, F, Err>,
86
+ op7: OperatorFunction<F, Err, G, Err>,
87
+ op8: OperatorFunction<G, Err, H, Err>,
88
+ ): Observable<H, Err>
89
+ pipe<A, B, C, D, E, F, G, H, I>(
90
+ op1: OperatorFunction<Ok, Err, A, Err>,
91
+ op2: OperatorFunction<A, Err, B, Err>,
92
+ op3: OperatorFunction<B, Err, C, Err>,
93
+ op4: OperatorFunction<C, Err, D, Err>,
94
+ op5: OperatorFunction<D, Err, E, Err>,
95
+ op6: OperatorFunction<E, Err, F, Err>,
96
+ op7: OperatorFunction<F, Err, G, Err>,
97
+ op8: OperatorFunction<G, Err, H, Err>,
98
+ op9: OperatorFunction<H, Err, I, Err>,
99
+ ): Observable<I, Err>
100
+ /* Longer chains still compose; type them by hand from the result. */
101
+ pipe<A, B, C, D, E, F, G, H, I>(
102
+ op1: OperatorFunction<Ok, Err, A, Err>,
103
+ op2: OperatorFunction<A, Err, B, Err>,
104
+ op3: OperatorFunction<B, Err, C, Err>,
105
+ op4: OperatorFunction<C, Err, D, Err>,
106
+ op5: OperatorFunction<D, Err, E, Err>,
107
+ op6: OperatorFunction<E, Err, F, Err>,
108
+ op7: OperatorFunction<F, Err, G, Err>,
109
+ op8: OperatorFunction<G, Err, H, Err>,
110
+ op9: OperatorFunction<H, Err, I, Err>,
111
+ ...ops: Array<OperatorFunction<any, any, any, any>>
112
+ ): Observable<unknown, Err>
74
113
 
75
114
  static withEmitters<Ok, Err = never>(): {
76
115
  observable: Observable<Ok, Err>
@@ -78,3 +117,19 @@ export declare class Observable<Ok, Err = never> {
78
117
  complete: () => void
79
118
  }
80
119
  }
120
+
121
+ /* A state container: values pushed through `next` run through `pipeline`,
122
+ * and the latest result is replayed to each new subscriber. */
123
+ export declare function state<In, Out>(
124
+ pipeline: (source: Observable<In>) => Observable<Out>,
125
+ ): readonly [value: Observable<Out>, set: (value: In) => void, complete: () => void]
126
+
127
+ /* Resolve with the first value, or undefined if the source completes without one. */
128
+ export declare function firstValueFrom<T>(source: Observable<T>): Promise<T | undefined>
129
+
130
+ /* Emit a promise's value, or an iterable's elements in order, then complete. */
131
+ export declare function from<T>(source: Promise<T>): Observable<T>
132
+ export declare function from<T>(source: Iterable<T>): Observable<T>
133
+
134
+ /* Emit the given values, then complete. */
135
+ export declare function of<T>(...values: T[]): Observable<T>
@@ -1,29 +1,49 @@
1
+ /* mikro/pwm, declared here and implemented in C (mik_pwm.cpp). */
2
+
3
+ import type {GpioInUse} from '../gpio/types.js'
1
4
  import type {Result} from '../result/types.js'
2
5
 
3
6
  export interface PwmOptions {
4
- /** Frequency in Hz */
7
+ /** Frequency in Hz, 1 to 40000000 */
5
8
  freq: number
6
9
  /** Initial duty cycle, 0.0–1.0. Defaults to 0. */
7
10
  duty?: number
8
11
  }
9
12
 
10
13
  export type PwmError =
14
+ | GpioInUse
15
+ | {name: 'InvalidGpio'; message: string}
16
+ | {name: 'InvalidParam'; message: string}
11
17
  | {name: 'NoChannel'; message: string}
12
18
  | {name: 'NoTimer'; message: string}
13
19
  | {name: 'ConfigFailed'; message: string}
14
- | {name: 'NotActive'}
15
20
  | {name: 'DutyFailed'; message: string}
16
21
  | {name: 'FreqFailed'; message: string}
17
22
  | {name: 'FadeFailed'; message: string}
18
23
 
19
- export declare class Pwm {
20
- constructor(pin: number, options: PwmOptions)
21
- /** Get or set duty cycle (0.0–1.0) */
22
- duty(value?: number): Result<number, PwmError>
23
- /** Get or set frequency in Hz */
24
- freq(value?: number): Result<number, PwmError>
25
- /** Hardware fade to target duty over duration. Returns promise with result. */
24
+ /**
25
+ * @public
26
+ */
27
+ export interface Pwm {
28
+ /** The current duty cycle (0.0–1.0) */
29
+ duty(): Result<number, PwmError>
30
+ /** Set the duty cycle (0.0–1.0) */
31
+ duty(value: number): Result<void, PwmError>
32
+ /** The current frequency in Hz */
33
+ freq(): Result<number, PwmError>
34
+ /** Set the frequency in Hz */
35
+ freq(value: number): Result<void, PwmError>
36
+ /** Hardware fade to a target duty over a duration. Resolves when the fade completes, or with
37
+ * `ok()` when `end()` stops it. */
26
38
  fade(targetDuty: number, durationMs: number): Promise<Result<void, PwmError>>
27
- /** Stop PWM and release the channel */
28
- end(): Result<void, PwmError>
39
+ /** Stops the output and releases the GPIO pin. Calling it again does nothing. Afterwards setters
40
+ * and `fade()` do nothing and getters return the last value; the first such call prints a
41
+ * warning. */
42
+ end(): void
29
43
  }
44
+
45
+ /**
46
+ * Claims a GPIO pin as a PWM output.
47
+ * @public
48
+ */
49
+ export declare function Pwm(gpio: number, options: PwmOptions): Result<Pwm, PwmError>
@@ -20,7 +20,7 @@ const proto = {
20
20
  orDefault(this: {ok: boolean; value?: unknown; error?: unknown}, defaultValue: unknown) {
21
21
  return this.ok ? this.value : defaultValue
22
22
  },
23
- orPanic(this: {ok: boolean; value?: unknown; error?: unknown}, message: string) {
23
+ orPanic(this: {ok: boolean; value?: unknown; error?: unknown}, message?: string) {
24
24
  if (this.ok) return this.value
25
25
  const panic = new Error(message)
26
26
  panic.name = 'PanicError'
@@ -1,5 +1,5 @@
1
1
  export declare class PanicError extends Error {
2
- constructor(message: string, options?: {cause?: unknown})
2
+ constructor(message?: string, options?: {cause?: unknown})
3
3
  }
4
4
 
5
5
  export interface OkResult<T> {
@@ -12,8 +12,8 @@ export interface OkResult<T> {
12
12
  match<A, B>(handlers: {ok: (value: T) => A; err: (error: never) => B}): A
13
13
  /** Get the value, or return the default if this is an Err. */
14
14
  orDefault<D>(defaultValue: D): T | D
15
- /** Get the value, or panic with the given message if this is an Err. */
16
- orPanic(message: string): T
15
+ /** Get the value, or panic if this is an Err. The error is included as cause. */
16
+ orPanic(message?: string): T
17
17
  }
18
18
 
19
19
  export interface ErrResult<E> {
@@ -26,8 +26,8 @@ export interface ErrResult<E> {
26
26
  match<A, B>(handlers: {ok: (value: never) => A; err: (error: E) => B}): B
27
27
  /** Return the default value since this is an Err. */
28
28
  orDefault<D>(defaultValue: D): D
29
- /** Always panics with the given message since this is an Err. The error is included as cause. */
30
- orPanic(message: string): never
29
+ /** Always panics since this is an Err. The error is included as cause. */
30
+ orPanic(message?: string): never
31
31
  }
32
32
 
33
33
  export type Result<T, E> = OkResult<T> | ErrResult<E>
@@ -1,13 +1,13 @@
1
1
  export type WakeupLevel = 'high' | 'low'
2
2
 
3
- /** A GPIO pin number that must be RTC-capable for deep-sleep wake.
3
+ /** A GPIO number that must be RTC-capable for deep-sleep wake.
4
4
  * Set varies per chip:
5
5
  * - ESP32-C6 / H2: 0–7 (LP_GPIO0–LP_GPIO7)
6
6
  * - ESP32-C3: 0–5
7
7
  * - ESP32-S2 / S3: 0–21 (LP_IO0–LP_IO21)
8
8
  * - ESP32: subset of 0–39 (see datasheet for RTC_GPIO mapping)
9
9
  *
10
- * Not statically validated — passing a non-RTC pin throws at runtime.
10
+ * Not statically validated: passing a non-RTC GPIO throws at runtime.
11
11
  */
12
12
  export type RtcGpio = number
13
13
 
@@ -16,9 +16,11 @@ export type LightWakeupSources = {
16
16
  /** Wake after this many milliseconds. Fractional values are allowed
17
17
  * (e.g. `0.01` = 10 µs). */
18
18
  timer?: number
19
- /** Wake when `pin` reaches `level`. Any GPIO works — no RTC-capable
20
- * constraint. */
21
- gpio?: {pin: number; level: WakeupLevel}
19
+ /** Wake when the GPIO numbered `gpio` reaches `level`. Any GPIO works; it
20
+ * does not need to be RTC-capable. Only one GPIO can wake the chip. */
21
+ gpio?: number
22
+ /** The level that wakes the chip. Required with `gpio`. */
23
+ level?: WakeupLevel
22
24
  }
23
25
 
24
26
  /** Sources that can wake the chip from deep sleep. */
@@ -27,8 +29,8 @@ export type DeepWakeupSources = {
27
29
  timer?: number
28
30
  /** Wake on a single RTC GPIO. ESP32 / S2 / S3 only — throws on
29
31
  * C3 / C6 / H2 (use `ext1` instead). */
30
- ext0?: {pin: RtcGpio; level: WakeupLevel}
31
- /** Wake when any of `pins` matches `mode`. Pins must be RTC-capable.
32
+ ext0?: {gpio: RtcGpio; level: WakeupLevel}
33
+ /** Wake when any of `gpios` matches `mode`. They must be RTC-capable.
32
34
  *
33
35
  * Caveat — original ESP32 chip only: the EXT1 hardware on the
34
36
  * original ESP32 cannot honor "any-low" with more than one pin (the
@@ -36,7 +38,7 @@ export type DeepWakeupSources = {
36
38
  * Multi-pin `{mode: 'any-low'}` throws on ESP32; single-pin works,
37
39
  * and `'any-high'` works for any pin count. Every newer chip
38
40
  * (C3, C5, C6, S2, S3, …) supports multi-pin `'any-low'` natively. */
39
- ext1?: {pins: RtcGpio[]; mode: 'any-low' | 'any-high'}
41
+ ext1?: {gpios: RtcGpio[]; mode: 'any-low' | 'any-high'}
40
42
  }
41
43
 
42
44
  /**
@@ -1,3 +1,6 @@
1
+ /* mikro/spi, declared here and implemented in C (mik_spi.cpp). */
2
+
3
+ import type {GpioInUse} from '../gpio/types.js'
1
4
  import type {Result} from '../result/types.js'
2
5
 
3
6
  /**
@@ -13,30 +16,29 @@ export interface SpiOptions {
13
16
  }
14
17
 
15
18
  export type SpiError =
19
+ | GpioInUse
20
+ | {name: 'InvalidGpio'; message: string}
21
+ | {name: 'InvalidParam'; message: string}
16
22
  | {name: 'BusInitFailed'; message: string}
17
23
  | {name: 'AddDeviceFailed'; message: string}
18
- | {name: 'NotStarted'}
19
- | {name: 'MissingPins'}
20
24
  | {name: 'TransferFailed'; message: string}
21
25
  | {name: 'WriteFailed'; message: string}
22
26
 
23
27
  /**
24
28
  * @public
25
29
  */
26
- export declare const Spi: {
27
- prototype: Spi
28
- new (hostNo: 1 | 2, options: SpiOptions): Spi
30
+ export interface Spi {
31
+ /** Full-duplex transfer: sends `data` and returns the bytes received at the same time. */
32
+ transfer(data: Uint8Array): Result<Uint8Array, SpiError>
33
+ /** Write-only transfer. */
34
+ write(data: Uint8Array): Result<void, SpiError>
35
+ /** Frees the bus and releases its GPIO pins. Calling it again does nothing. Afterwards `write()`
36
+ * does nothing and `transfer()` returns an empty array; the first such call prints a warning. */
37
+ end(): void
29
38
  }
30
39
 
31
40
  /**
41
+ * Claims the pins and starts an SPI bus on a host controller.
32
42
  * @public
33
43
  */
34
- export interface Spi {
35
- begin(): Result<void, SpiError>
36
-
37
- end(): Result<void, SpiError>
38
-
39
- transfer(data: Uint8Array): Result<Uint8Array, SpiError>
40
-
41
- write(data: Uint8Array): Result<void, SpiError>
42
- }
44
+ export declare function Spi(host: number, options: SpiOptions): Result<Spi, SpiError>
@@ -1,3 +1,6 @@
1
+ /* mikro/uart, declared here and implemented in C (mik_uart.cpp). */
2
+
3
+ import type {GpioInUse} from '../gpio/types.js'
1
4
  import type {Result} from '../result/types.js'
2
5
 
3
6
  /**
@@ -32,12 +35,13 @@ export interface UartRxOnlyOptions extends UartBaseOptions {
32
35
  }
33
36
 
34
37
  export type UartError =
38
+ | GpioInUse
39
+ | {name: 'InvalidGpio'; message: string}
40
+ | {name: 'InvalidParam'; message: string}
35
41
  | {name: 'DriverInstallFailed'; message: string}
36
42
  | {name: 'SetPinFailed'; message: string}
37
- | {name: 'InvalidParam'; message: string}
38
43
  | {name: 'WriteFailed'; message: string}
39
44
  | {name: 'ReadFailed'; message: string}
40
- | {name: 'NotStarted'}
41
45
  | {name: 'AlreadyReading'}
42
46
  | {name: 'NoRxPin'}
43
47
  | {name: 'NoTxPin'}
@@ -54,10 +58,8 @@ export interface UartTx {
54
58
  */
55
59
  export interface UartRx {
56
60
  /**
57
- * Open a Result-yielding async iterable of received chunks. Mid-stream
58
- * failures (driver fault, port closed mid-iteration) arrive as a single
59
- * terminal `err(UartError)` item rather than throwing — composes with
60
- * stream/* combinators and other Result-based APIs.
61
+ * Open a Result-yielding async iterable of received chunks. The iterable
62
+ * completes when `end()` is called.
61
63
  */
62
64
  read(): Result<AsyncIterable<Result<Uint8Array, UartError>>, UartError>
63
65
  }
@@ -65,17 +67,27 @@ export interface UartRx {
65
67
  /**
66
68
  * @public
67
69
  */
68
- export interface UartBase {
69
- begin(): Result<void, UartError>
70
- end(): Result<void, UartError>
70
+ export interface Uart {
71
+ /** Uninstalls the driver and releases the GPIO pins. Calling it again does nothing. An active
72
+ * `read()` iterable completes. Afterwards `write()` does nothing and `read()` returns an
73
+ * iterable that completes at once; the first such call prints a warning. */
74
+ end(): void
71
75
  }
72
76
 
73
77
  /**
78
+ * Claims the pins and installs the UART driver on a port. The methods available depend on which
79
+ * of `tx` and `rx` are given.
74
80
  * @public
75
81
  */
76
- export declare const Uart: {
77
- prototype: UartBase
78
- new (port: number, options: UartTxRxOptions): UartBase & UartTx & UartRx
79
- new (port: number, options: UartTxOnlyOptions): UartBase & UartTx
80
- new (port: number, options: UartRxOnlyOptions): UartBase & UartRx
81
- }
82
+ export declare function Uart(
83
+ port: number,
84
+ options: UartTxRxOptions,
85
+ ): Result<Uart & UartTx & UartRx, UartError>
86
+ export declare function Uart(
87
+ port: number,
88
+ options: UartTxOnlyOptions,
89
+ ): Result<Uart & UartTx, UartError>
90
+ export declare function Uart(
91
+ port: number,
92
+ options: UartRxOnlyOptions,
93
+ ): Result<Uart & UartRx, UartError>