Skip to content

Commit 199740f

Browse files
Typecheck jshal.js. (#60)
It's most practical for it to remain JS as it's splatted into the Emscripten build but it's too easy to break right now. Fixes radio receive.
1 parent 4d83adb commit 199740f

File tree

3 files changed

+128
-36
lines changed

3 files changed

+128
-36
lines changed

src/board/index.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ export class Board {
8787
* Defined during start().
8888
*/
8989
private modulePromise: Promise<ModuleWrapper> | undefined;
90+
/**
91+
* Defined by start but async.
92+
*/
93+
private module: ModuleWrapper | undefined;
9094
/**
9195
* If undefined, then when main finishes we stay stopped.
9296
* Otherwise we perform the action then clear this field.
@@ -316,12 +320,13 @@ export class Board {
316320
}
317321

318322
private async start() {
319-
if (this.modulePromise) {
323+
if (this.modulePromise || this.module) {
320324
throw new Error("Module already exists!");
321325
}
322326

323327
this.modulePromise = this.createModule();
324328
const module = await this.modulePromise;
329+
this.module = module;
325330
let panicCode: number | undefined;
326331
try {
327332
this.displayRunningState();
@@ -346,6 +351,7 @@ export class Board {
346351
// Called by the HAL for normal shutdown but not in error scenarios.
347352
this.stopComponents();
348353
this.modulePromise = undefined;
354+
this.module = undefined;
349355

350356
if (panicCode !== undefined) {
351357
this.displayPanic(panicCode);
@@ -371,9 +377,11 @@ export class Board {
371377
this.displayStoppedState();
372378
}
373379
if (this.modulePromise) {
380+
// Avoid this.module as we might still be creating it (async).
374381
const module = await this.modulePromise;
375382
module.requestStop();
376383
this.modulePromise = undefined;
384+
this.module = undefined;
377385
// Ctrl-C, Ctrl-D to interrupt the main loop.
378386
this.writeSerialInput("\x03\x04");
379387
}
@@ -543,6 +551,13 @@ export class Board {
543551
}
544552
}
545553

554+
writeRadioRxBuffer(packet: Uint8Array): number {
555+
if (!this.module) {
556+
throw new Error("Must be running");
557+
}
558+
return this.module.writeRadioRxBuffer(packet);
559+
}
560+
546561
initialize() {
547562
this.epoch = new Date().getTime();
548563
this.serialInputBuffer.length = 0;

src/jshal.d.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { EmscriptenModule } from "./board/wasm";
2+
3+
global {
4+
// In reality this is a local variable as jshal.js is splatted into the generated code.
5+
declare const Module: EmscriptenModule;
6+
declare const LibraryManager: {
7+
library: any;
8+
};
9+
10+
// Just what we need. There are lots more Emscripten helpers available.
11+
declare function UTF8ToString(ptr: number, len?: number);
12+
declare function stringToUTF8(s: string, buf: number, len: number);
13+
declare function lengthBytesUTF8(s: string);
14+
declare function mergeInto(library: any, functions: Record<string, function>);
15+
}

src/jshal.js

Lines changed: 97 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
* THE SOFTWARE.
2525
*/
2626

27+
// @ts-check
28+
/// <reference path="./jshal.d.ts" />
29+
2730
mergeInto(LibraryManager.library, {
2831
mp_js_hal_init: async function () {
2932
Module.board.initialize();
@@ -41,20 +44,32 @@ mergeInto(LibraryManager.library, {
4144
return Module.board.readSerialInput();
4245
},
4346

44-
mp_js_hal_stdout_tx_strn: function (ptr, len) {
47+
mp_js_hal_stdout_tx_strn: function (
48+
/** @type {number} */ ptr,
49+
/** @type {number} */ len
50+
) {
4551
Module.board.writeSerialOutput(UTF8ToString(ptr, len));
4652
},
4753

48-
mp_js_hal_filesystem_find: function (name, len) {
54+
mp_js_hal_filesystem_find: function (
55+
/** @type {number} */ name,
56+
/** @type {number} */ len
57+
) {
4958
return Module.fs.find(UTF8ToString(name, len));
5059
},
5160

52-
mp_js_hal_filesystem_create: function (name, len) {
61+
mp_js_hal_filesystem_create: function (
62+
/** @type {number} */ name,
63+
/** @type {number} */ len
64+
) {
5365
const filename = UTF8ToString(name, len);
5466
return Module.fs.create(filename);
5567
},
5668

57-
mp_js_hal_filesystem_name: function (idx, buf) {
69+
mp_js_hal_filesystem_name: function (
70+
/** @type {number} */ idx,
71+
/** @type {number} */ buf
72+
) {
5873
const name = Module.fs.name(idx);
5974
if (name === undefined) {
6075
return -1;
@@ -64,52 +79,66 @@ mergeInto(LibraryManager.library, {
6479
return len;
6580
},
6681

67-
mp_js_hal_filesystem_size: function (idx) {
82+
mp_js_hal_filesystem_size: function (/** @type {number} */ idx) {
6883
return Module.fs.size(idx);
6984
},
7085

71-
mp_js_hal_filesystem_remove: function (idx) {
86+
mp_js_hal_filesystem_remove: function (/** @type {number} */ idx) {
7287
return Module.fs.remove(idx);
7388
},
7489

75-
mp_js_hal_filesystem_readbyte: function (idx, offset) {
90+
mp_js_hal_filesystem_readbyte: function (
91+
/** @type {number} */ idx,
92+
/** @type {number} */ offset
93+
) {
7694
return Module.fs.readbyte(idx, offset);
7795
},
7896

79-
mp_js_hal_filesystem_write: function (idx, buf, len) {
80-
const data = new Uint8Array(HEAP8.buffer, buf, len);
97+
mp_js_hal_filesystem_write: function (
98+
/** @type {number} */ idx,
99+
/** @type {number} */ buf,
100+
/** @type {number} */ len
101+
) {
102+
const data = new Uint8Array(Module.HEAPU8.buffer, buf, len);
81103
return Module.fs.write(idx, data);
82104
},
83105

84106
mp_js_hal_reset: function () {
85107
Module.board.throwReset();
86108
},
87109

88-
mp_js_hal_panic: function (code) {
110+
mp_js_hal_panic: function (/** @type {number} */ code) {
89111
Module.board.throwPanic(code);
90112
},
91113

92114
mp_js_hal_temperature: function () {
93115
return Module.board.temperature.value;
94116
},
95117

96-
mp_js_hal_button_get_presses: function (button) {
118+
mp_js_hal_button_get_presses: function (/** @type {number} */ button) {
97119
return Module.board.buttons[button].getAndClearPresses();
98120
},
99121

100-
mp_js_hal_button_is_pressed: function (button) {
122+
mp_js_hal_button_is_pressed: function (/** @type {number} */ button) {
101123
return Module.board.buttons[button].isPressed();
102124
},
103125

104-
mp_js_hal_pin_is_touched: function (pin) {
126+
mp_js_hal_pin_is_touched: function (/** @type {number} */ pin) {
105127
return Module.board.pins[pin].isTouched();
106128
},
107129

108-
mp_js_hal_display_get_pixel: function (x, y) {
130+
mp_js_hal_display_get_pixel: function (
131+
/** @type {number} */ x,
132+
/** @type {number} */ y
133+
) {
109134
return Module.board.display.getPixel(x, y);
110135
},
111136

112-
mp_js_hal_display_set_pixel: function (x, y, value) {
137+
mp_js_hal_display_set_pixel: function (
138+
/** @type {number} */ x,
139+
/** @type {number} */ y,
140+
/** @type {number} */ value
141+
) {
113142
Module.board.display.setPixel(x, y, value);
114143
},
115144

@@ -139,7 +168,7 @@ mergeInto(LibraryManager.library, {
139168
);
140169
},
141170

142-
mp_js_hal_accelerometer_set_range: function (r) {
171+
mp_js_hal_accelerometer_set_range: function (/** @type {number} */ r) {
143172
Module.board.accelerometer.setRange(r);
144173
},
145174

@@ -163,51 +192,68 @@ mergeInto(LibraryManager.library, {
163192
return Module.board.compass.state.compassHeading.value;
164193
},
165194

166-
mp_js_hal_audio_set_volume: function (value) {
195+
mp_js_hal_audio_set_volume: function (/** @type {number} */ value) {
167196
Module.board.audio.setVolume(value);
168197
},
169198

170-
mp_js_hal_audio_init: function (sample_rate) {
199+
mp_js_hal_audio_init: function (/** @type {number} */ sample_rate) {
200+
// @ts-expect-error
171201
Module.board.audio.default.init(sample_rate);
172202
},
173203

174-
mp_js_hal_audio_write_data: function (buf, num_samples) {
204+
mp_js_hal_audio_write_data: function (
205+
/** @type {number} */ buf,
206+
/** @type {number} */ num_samples
207+
) {
208+
// @ts-expect-error
175209
Module.board.audio.default.writeData(
176210
Module.conversions.convertAudioBuffer(
177211
Module.HEAPU8,
178212
buf,
213+
// @ts-expect-error
179214
Module.board.audio.default.createBuffer(num_samples)
180215
)
181216
);
182217
},
183218

184-
mp_js_hal_audio_speech_init: function (sample_rate) {
219+
mp_js_hal_audio_speech_init: function (/** @type {number} */ sample_rate) {
220+
// @ts-expect-error
185221
Module.board.audio.speech.init(sample_rate);
186222
},
187223

188-
mp_js_hal_audio_speech_write_data: function (buf, num_samples) {
224+
mp_js_hal_audio_speech_write_data: function (
225+
/** @type {number} */ buf,
226+
/** @type {number} */ num_samples
227+
) {
228+
// @ts-expect-error
189229
Module.board.audio.speech.writeData(
190230
Module.conversions.convertAudioBuffer(
191231
Module.HEAPU8,
192232
buf,
233+
// @ts-expect-error
193234
Module.board.audio.speech.createBuffer(num_samples)
194235
)
195236
);
196237
},
197238

198-
mp_js_hal_audio_period_us: function (period_us) {
239+
mp_js_hal_audio_period_us: function (/** @type {number} */ period_us) {
199240
Module.board.audio.setPeriodUs(period_us);
200241
},
201242

202-
mp_js_hal_audio_amplitude_u10: function (amplitude_u10) {
243+
mp_js_hal_audio_amplitude_u10: function (
244+
/** @type {number} */ amplitude_u10
245+
) {
203246
Module.board.audio.setAmplitudeU10(amplitude_u10);
204247
},
205248

206249
mp_js_hal_microphone_init: function () {
207250
Module.board.microphone.microphoneOn();
208251
},
209252

210-
mp_js_hal_microphone_set_threshold: function (kind, value) {
253+
mp_js_hal_microphone_set_threshold: function (
254+
/** @type {number} */ kind,
255+
/** @type {number} */ value
256+
) {
211257
Module.board.microphone.setThreshold(
212258
Module.conversions.convertSoundThresholdNumberToString(kind),
213259
value
@@ -218,7 +264,7 @@ mergeInto(LibraryManager.library, {
218264
return Module.board.microphone.soundLevel.value;
219265
},
220266

221-
mp_js_hal_audio_play_expression: function (expr) {
267+
mp_js_hal_audio_play_expression: function (/** @type {any} */ expr) {
222268
return Module.board.audio.playSoundExpression(UTF8ToString(expr));
223269
},
224270

@@ -230,29 +276,42 @@ mergeInto(LibraryManager.library, {
230276
return Module.board.audio.isSoundExpressionActive();
231277
},
232278

233-
mp_js_radio_enable: function (group, max_payload, queue) {
279+
mp_js_radio_enable: function (
280+
/** @type {number} */ group,
281+
/** @type {number} */ max_payload,
282+
/** @type {number} */ queue
283+
) {
234284
Module.board.radio.enable({ group, maxPayload: max_payload, queue });
235285
},
236286

237287
mp_js_radio_disable: function () {
238288
Module.board.radio.disable();
239289
},
240290

241-
mp_js_radio_update_config: function (group, max_payload, queue) {
291+
mp_js_radio_update_config: function (
292+
/** @type {number} */ group,
293+
/** @type {number} */ max_payload,
294+
/** @type {number} */ queue
295+
) {
242296
Module.board.radio.updateConfig({ group, maxPayload: max_payload, queue });
243297
},
244298

245-
mp_js_radio_send: function (buf, len, buf2, len2) {
299+
mp_js_radio_send: function (
300+
/** @type {number} */ buf,
301+
/** @type {number} */ len,
302+
/** @type {number} */ buf2,
303+
/** @type {number} */ len2
304+
) {
246305
const data = new Uint8Array(len + len2);
247-
data.set(HEAPU8.slice(buf, buf + len));
248-
data.set(HEAPU8.slice(buf2, buf2 + len2), len);
306+
data.set(Module.HEAPU8.slice(buf, buf + len));
307+
data.set(Module.HEAPU8.slice(buf2, buf2 + len2), len);
249308
Module.board.radio.send(data);
250309
},
251310

252311
mp_js_radio_peek: function () {
253312
const packet = Module.board.radio.peek();
254313
if (packet) {
255-
return Module.board.module.writeRadioRxBuffer(packet);
314+
return Module.board.writeRadioRxBuffer(packet);
256315
}
257316
return null;
258317
},
@@ -261,16 +320,16 @@ mergeInto(LibraryManager.library, {
261320
Module.board.radio.pop();
262321
},
263322

264-
mp_js_hal_log_delete: function (full_erase) {
323+
mp_js_hal_log_delete: function (/** @type {boolean} */ full_erase) {
265324
// We don't have a notion of non-full erase.
266325
Module.board.dataLogging.delete();
267326
},
268327

269-
mp_js_hal_log_set_mirroring: function (serial) {
328+
mp_js_hal_log_set_mirroring: function (/** @type {boolean} */ serial) {
270329
Module.board.dataLogging.setMirroring(serial);
271330
},
272331

273-
mp_js_hal_log_set_timestamp: function (period) {
332+
mp_js_hal_log_set_timestamp: function (/** @type {number} */ period) {
274333
Module.board.dataLogging.setTimestamp(period);
275334
},
276335

@@ -282,7 +341,10 @@ mergeInto(LibraryManager.library, {
282341
return Module.board.dataLogging.endRow();
283342
},
284343

285-
mp_js_hal_log_data: function (key, value) {
344+
mp_js_hal_log_data: function (
345+
/** @type {number} */ key,
346+
/** @type {number} */ value
347+
) {
286348
return Module.board.dataLogging.logData(
287349
UTF8ToString(key),
288350
UTF8ToString(value)

0 commit comments

Comments
 (0)