Skip to content

Typecheck jshal.js. #60

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion src/board/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ export class Board {
* Defined during start().
*/
private modulePromise: Promise<ModuleWrapper> | undefined;
/**
* Defined by start but async.
*/
private module: ModuleWrapper | undefined;
/**
* If undefined, then when main finishes we stay stopped.
* Otherwise we perform the action then clear this field.
Expand Down Expand Up @@ -316,12 +320,13 @@ export class Board {
}

private async start() {
if (this.modulePromise) {
if (this.modulePromise || this.module) {
throw new Error("Module already exists!");
}

this.modulePromise = this.createModule();
const module = await this.modulePromise;
this.module = module;
let panicCode: number | undefined;
try {
this.displayRunningState();
Expand All @@ -346,6 +351,7 @@ export class Board {
// Called by the HAL for normal shutdown but not in error scenarios.
this.stopComponents();
this.modulePromise = undefined;
this.module = undefined;

if (panicCode !== undefined) {
this.displayPanic(panicCode);
Expand All @@ -371,9 +377,11 @@ export class Board {
this.displayStoppedState();
}
if (this.modulePromise) {
// Avoid this.module as we might still be creating it (async).
const module = await this.modulePromise;
module.requestStop();
this.modulePromise = undefined;
this.module = undefined;
// Ctrl-C, Ctrl-D to interrupt the main loop.
this.writeSerialInput("\x03\x04");
}
Expand Down Expand Up @@ -543,6 +551,13 @@ export class Board {
}
}

writeRadioRxBuffer(packet: Uint8Array): number {
if (!this.module) {
throw new Error("Must be running");
}
return this.module.writeRadioRxBuffer(packet);
}

initialize() {
this.epoch = new Date().getTime();
this.serialInputBuffer.length = 0;
Expand Down
15 changes: 15 additions & 0 deletions src/jshal.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { EmscriptenModule } from "./board/wasm";

global {
// In reality this is a local variable as jshal.js is splatted into the generated code.
declare const Module: EmscriptenModule;
declare const LibraryManager: {
library: any;
};

// Just what we need. There are lots more Emscripten helpers available.
declare function UTF8ToString(ptr: number, len?: number);
declare function stringToUTF8(s: string, buf: number, len: number);
declare function lengthBytesUTF8(s: string);
declare function mergeInto(library: any, functions: Record<string, function>);
}
132 changes: 97 additions & 35 deletions src/jshal.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
* THE SOFTWARE.
*/

// @ts-check
/// <reference path="./jshal.d.ts" />

mergeInto(LibraryManager.library, {
mp_js_hal_init: async function () {
Module.board.initialize();
Expand All @@ -41,20 +44,32 @@ mergeInto(LibraryManager.library, {
return Module.board.readSerialInput();
},

mp_js_hal_stdout_tx_strn: function (ptr, len) {
mp_js_hal_stdout_tx_strn: function (
/** @type {number} */ ptr,
/** @type {number} */ len
) {
Module.board.writeSerialOutput(UTF8ToString(ptr, len));
},

mp_js_hal_filesystem_find: function (name, len) {
mp_js_hal_filesystem_find: function (
/** @type {number} */ name,
/** @type {number} */ len
) {
return Module.fs.find(UTF8ToString(name, len));
},

mp_js_hal_filesystem_create: function (name, len) {
mp_js_hal_filesystem_create: function (
/** @type {number} */ name,
/** @type {number} */ len
) {
const filename = UTF8ToString(name, len);
return Module.fs.create(filename);
},

mp_js_hal_filesystem_name: function (idx, buf) {
mp_js_hal_filesystem_name: function (
/** @type {number} */ idx,
/** @type {number} */ buf
) {
const name = Module.fs.name(idx);
if (name === undefined) {
return -1;
Expand All @@ -64,52 +79,66 @@ mergeInto(LibraryManager.library, {
return len;
},

mp_js_hal_filesystem_size: function (idx) {
mp_js_hal_filesystem_size: function (/** @type {number} */ idx) {
return Module.fs.size(idx);
},

mp_js_hal_filesystem_remove: function (idx) {
mp_js_hal_filesystem_remove: function (/** @type {number} */ idx) {
return Module.fs.remove(idx);
},

mp_js_hal_filesystem_readbyte: function (idx, offset) {
mp_js_hal_filesystem_readbyte: function (
/** @type {number} */ idx,
/** @type {number} */ offset
) {
return Module.fs.readbyte(idx, offset);
},

mp_js_hal_filesystem_write: function (idx, buf, len) {
const data = new Uint8Array(HEAP8.buffer, buf, len);
mp_js_hal_filesystem_write: function (
/** @type {number} */ idx,
/** @type {number} */ buf,
/** @type {number} */ len
) {
const data = new Uint8Array(Module.HEAPU8.buffer, buf, len);
return Module.fs.write(idx, data);
},

mp_js_hal_reset: function () {
Module.board.throwReset();
},

mp_js_hal_panic: function (code) {
mp_js_hal_panic: function (/** @type {number} */ code) {
Module.board.throwPanic(code);
},

mp_js_hal_temperature: function () {
return Module.board.temperature.value;
},

mp_js_hal_button_get_presses: function (button) {
mp_js_hal_button_get_presses: function (/** @type {number} */ button) {
return Module.board.buttons[button].getAndClearPresses();
},

mp_js_hal_button_is_pressed: function (button) {
mp_js_hal_button_is_pressed: function (/** @type {number} */ button) {
return Module.board.buttons[button].isPressed();
},

mp_js_hal_pin_is_touched: function (pin) {
mp_js_hal_pin_is_touched: function (/** @type {number} */ pin) {
return Module.board.pins[pin].isTouched();
},

mp_js_hal_display_get_pixel: function (x, y) {
mp_js_hal_display_get_pixel: function (
/** @type {number} */ x,
/** @type {number} */ y
) {
return Module.board.display.getPixel(x, y);
},

mp_js_hal_display_set_pixel: function (x, y, value) {
mp_js_hal_display_set_pixel: function (
/** @type {number} */ x,
/** @type {number} */ y,
/** @type {number} */ value
) {
Module.board.display.setPixel(x, y, value);
},

Expand Down Expand Up @@ -139,7 +168,7 @@ mergeInto(LibraryManager.library, {
);
},

mp_js_hal_accelerometer_set_range: function (r) {
mp_js_hal_accelerometer_set_range: function (/** @type {number} */ r) {
Module.board.accelerometer.setRange(r);
},

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

mp_js_hal_audio_set_volume: function (value) {
mp_js_hal_audio_set_volume: function (/** @type {number} */ value) {
Module.board.audio.setVolume(value);
},

mp_js_hal_audio_init: function (sample_rate) {
mp_js_hal_audio_init: function (/** @type {number} */ sample_rate) {
// @ts-expect-error
Module.board.audio.default.init(sample_rate);
},

mp_js_hal_audio_write_data: function (buf, num_samples) {
mp_js_hal_audio_write_data: function (
/** @type {number} */ buf,
/** @type {number} */ num_samples
) {
// @ts-expect-error
Module.board.audio.default.writeData(
Module.conversions.convertAudioBuffer(
Module.HEAPU8,
buf,
// @ts-expect-error
Module.board.audio.default.createBuffer(num_samples)
)
);
},

mp_js_hal_audio_speech_init: function (sample_rate) {
mp_js_hal_audio_speech_init: function (/** @type {number} */ sample_rate) {
// @ts-expect-error
Module.board.audio.speech.init(sample_rate);
},

mp_js_hal_audio_speech_write_data: function (buf, num_samples) {
mp_js_hal_audio_speech_write_data: function (
/** @type {number} */ buf,
/** @type {number} */ num_samples
) {
// @ts-expect-error
Module.board.audio.speech.writeData(
Module.conversions.convertAudioBuffer(
Module.HEAPU8,
buf,
// @ts-expect-error
Module.board.audio.speech.createBuffer(num_samples)
)
);
},

mp_js_hal_audio_period_us: function (period_us) {
mp_js_hal_audio_period_us: function (/** @type {number} */ period_us) {
Module.board.audio.setPeriodUs(period_us);
},

mp_js_hal_audio_amplitude_u10: function (amplitude_u10) {
mp_js_hal_audio_amplitude_u10: function (
/** @type {number} */ amplitude_u10
) {
Module.board.audio.setAmplitudeU10(amplitude_u10);
},

mp_js_hal_microphone_init: function () {
Module.board.microphone.microphoneOn();
},

mp_js_hal_microphone_set_threshold: function (kind, value) {
mp_js_hal_microphone_set_threshold: function (
/** @type {number} */ kind,
/** @type {number} */ value
) {
Module.board.microphone.setThreshold(
Module.conversions.convertSoundThresholdNumberToString(kind),
value
Expand All @@ -218,7 +264,7 @@ mergeInto(LibraryManager.library, {
return Module.board.microphone.soundLevel.value;
},

mp_js_hal_audio_play_expression: function (expr) {
mp_js_hal_audio_play_expression: function (/** @type {any} */ expr) {
return Module.board.audio.playSoundExpression(UTF8ToString(expr));
},

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

mp_js_radio_enable: function (group, max_payload, queue) {
mp_js_radio_enable: function (
/** @type {number} */ group,
/** @type {number} */ max_payload,
/** @type {number} */ queue
) {
Module.board.radio.enable({ group, maxPayload: max_payload, queue });
},

mp_js_radio_disable: function () {
Module.board.radio.disable();
},

mp_js_radio_update_config: function (group, max_payload, queue) {
mp_js_radio_update_config: function (
/** @type {number} */ group,
/** @type {number} */ max_payload,
/** @type {number} */ queue
) {
Module.board.radio.updateConfig({ group, maxPayload: max_payload, queue });
},

mp_js_radio_send: function (buf, len, buf2, len2) {
mp_js_radio_send: function (
/** @type {number} */ buf,
/** @type {number} */ len,
/** @type {number} */ buf2,
/** @type {number} */ len2
) {
const data = new Uint8Array(len + len2);
data.set(HEAPU8.slice(buf, buf + len));
data.set(HEAPU8.slice(buf2, buf2 + len2), len);
data.set(Module.HEAPU8.slice(buf, buf + len));
data.set(Module.HEAPU8.slice(buf2, buf2 + len2), len);
Module.board.radio.send(data);
},

mp_js_radio_peek: function () {
const packet = Module.board.radio.peek();
if (packet) {
return Module.board.module.writeRadioRxBuffer(packet);
return Module.board.writeRadioRxBuffer(packet);
}
return null;
},
Expand All @@ -261,16 +320,16 @@ mergeInto(LibraryManager.library, {
Module.board.radio.pop();
},

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

mp_js_hal_log_set_mirroring: function (serial) {
mp_js_hal_log_set_mirroring: function (/** @type {boolean} */ serial) {
Module.board.dataLogging.setMirroring(serial);
},

mp_js_hal_log_set_timestamp: function (period) {
mp_js_hal_log_set_timestamp: function (/** @type {number} */ period) {
Module.board.dataLogging.setTimestamp(period);
},

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

mp_js_hal_log_data: function (key, value) {
mp_js_hal_log_data: function (
/** @type {number} */ key,
/** @type {number} */ value
) {
return Module.board.dataLogging.logData(
UTF8ToString(key),
UTF8ToString(value)
Expand Down