diff --git a/sdk/commands/config.ts b/sdk/commands/config.ts index 687c1e5..c3c9b4b 100644 --- a/sdk/commands/config.ts +++ b/sdk/commands/config.ts @@ -1,5 +1,5 @@ import { StructBuffer, bits, uint8_t, uint16_t, sbytes } from "@nmann/struct-buffer"; -import { EnabledSensors } from "./enabled-sensors.ts"; +import { enabledSensors_t } from "./enabled-sensors.ts"; import { Panel } from "../api.ts"; import { padData } from "../utils.ts"; @@ -9,7 +9,7 @@ export type Decoded = Re * Each panel has various thresholds that are used based on * if it's a LoadCell or FSR panel. */ -const packed_panel_settings_t = new StructBuffer("packed_panel_settings_t", { +const packed_panel_settings_t = new StructBuffer({ /** * Load Cell Thresholds */ @@ -56,7 +56,7 @@ const flags_t = bits(uint8_t, { /** * Just an RGB struct for named access */ -const rgb_t = new StructBuffer("rbg_t", { +const rgb_t = new StructBuffer({ r: uint8_t, g: uint8_t, b: uint8_t, @@ -69,7 +69,7 @@ const rgb_t = new StructBuffer("rbg_t", { * The order and packing of this struct corresponds to the configuration packet sent to * the master controller, so it must not be changed. */ -export const smx_config_t = new StructBuffer("smx_config_t", { +export const smx_config_t = new StructBuffer({ /** * The firmware version of the master controller. Where supported (version 2 and up), this * will always read back the firmware version. This will default to 0xFF on version 1. @@ -120,7 +120,7 @@ export const smx_config_t = new StructBuffer("smx_config_t", { * Which sensors on each panel to enable. This can be used to disable sensors that * we know aren't populated. */ - enabledSensors: new EnabledSensors(), + enabledSensors: enabledSensors_t, /** * How long the master controller will wait for a lights command before assuming @@ -233,7 +233,7 @@ const NEW_CONFIG_INIT = [ "00".repeat(49), ]; -const smx_old_config_t = new StructBuffer("smx_old_config_t", { +const smx_old_config_t = new StructBuffer({ unused1: uint8_t[6], masterDebounceMilliseconds: uint16_t, @@ -262,7 +262,7 @@ const smx_old_config_t = new StructBuffer("smx_old_config_t", { panelThreshold1Low: uint8_t, panelThreshold1High: uint8_t, - enabledSensors: new EnabledSensors(), + enabledSensors: enabledSensors_t, autoLightsTimeout: uint8_t, @@ -361,7 +361,7 @@ export class SMXConfig { console.log("CONFIG RAW DATA: ", data.toString()); if (this.firmwareVersion >= 5) { - this.config = smx_config_t.decode(data.slice(2, -1), true); + this.config = smx_config_t.decode(data.slice(2, -1), { littleEndian: true }); } else { this.oldConfigSize = data[1]; console.log("Reading Old Config"); @@ -370,21 +370,21 @@ export class SMXConfig { // handle very old stage's smaller config data by padding // it out to the full size of the `smx_old_config_t` struct const paddedData = padData(slicedData, smx_old_config_t.byteLength); - this.oldConfig = smx_old_config_t.decode(paddedData, true); + this.oldConfig = smx_old_config_t.decode(paddedData, { littleEndian: true }); this.config = this.convertOldToNew(this.oldConfig); } } encode(): Uint8Array { if (this.firmwareVersion >= 5) { - return new Uint8Array(smx_config_t.encode(this.config, true).buffer); + return new Uint8Array(smx_config_t.encode(this.config, { littleEndian: true }).buffer); } if (!this.oldConfig) throw new ReferenceError("Can not encode old config as it is null"); console.log("Writing Old Config"); this.convertNewToOld(); - const encodedConfig = smx_old_config_t.encode(this.oldConfig, true); + const encodedConfig = smx_old_config_t.encode(this.oldConfig, { littleEndian: true }); // If the old config data is less than 128 Bytes, only send the first 128 bytes if (this.oldConfigSize && this.oldConfigSize <= 128) { return new Uint8Array(encodedConfig.buffer.slice(0, 128)); @@ -470,7 +470,7 @@ export class SMXConfig { */ private convertOldToNew(oldConfig: Decoded): Decoded { console.log("old config: ", oldConfig); - const newConfig = smx_config_t.decode(sbytes(NEW_CONFIG_INIT.join("")), false); + const newConfig = smx_config_t.decode(sbytes(NEW_CONFIG_INIT.join("")), { littleEndian: false }); newConfig.debounceNodelayMilliseconds = oldConfig.masterDebounceMilliseconds; diff --git a/sdk/commands/data_info.ts b/sdk/commands/data_info.ts index de4e3b2..04cce3f 100644 --- a/sdk/commands/data_info.ts +++ b/sdk/commands/data_info.ts @@ -1,6 +1,6 @@ import { StructBuffer, char, uint8_t, uint16_t } from "@nmann/struct-buffer"; -const data_info_packet_t = new StructBuffer("data_info_packet_t", { +const data_info_packet_t = new StructBuffer({ /** Always 'I' */ cmd: char, // Not Used @@ -28,7 +28,7 @@ export class SMXDeviceInfo { } #decode(data: Uint8Array) { - const info_packet = data_info_packet_t.decode(data, true); + const info_packet = data_info_packet_t.decode(data, { littleEndian: true }); this.player = Number.parseInt(String.fromCharCode(info_packet.player)) + 1; this.serial = info_packet.serial.map((x) => `00${x.toString(16).toUpperCase()}`.slice(-2)).join(""); diff --git a/sdk/commands/enabled-sensors.test.ts b/sdk/commands/enabled-sensors.test.ts index a0029c6..e37cc3f 100644 --- a/sdk/commands/enabled-sensors.test.ts +++ b/sdk/commands/enabled-sensors.test.ts @@ -1,11 +1,11 @@ import { sbytes, sview } from "@nmann/struct-buffer"; import { expect, test, describe } from "vitest"; -import { twoEnabledSensors_t, EnabledSensors } from "./enabled-sensors"; +import { twoEnabledSensors_t, enabledSensors_t } from "./enabled-sensors"; import { SENSOR_COUNT } from "../api"; describe("twoEnabledSensors_t", () => { test("encode", () => { - expect(twoEnabledSensors_t.decode(sbytes("F0"), false)).toEqual({ + expect(twoEnabledSensors_t.decode(sbytes("F0"), { littleEndian: false })).toEqual({ left0: true, right0: true, up0: true, @@ -29,8 +29,6 @@ describe("twoEnabledSensors_t", () => { }); }); -const enabledSensors = new EnabledSensors(); - const decodedData = [ Array(SENSOR_COUNT).fill(false), Array(SENSOR_COUNT).fill(true), @@ -46,9 +44,9 @@ const decodedData = [ const encodedData = "0f 0f ff 0f 00"; test("decode", () => { - expect(enabledSensors.decode(sbytes(encodedData))).toEqual(decodedData); + expect(enabledSensors_t.decode(sbytes(encodedData))).toEqual(decodedData); }); test("encode", () => { - expect(sview(enabledSensors.encode(decodedData))).toEqual(encodedData); + expect(sview(enabledSensors_t.encode(decodedData))).toEqual(encodedData); }); diff --git a/sdk/commands/enabled-sensors.ts b/sdk/commands/enabled-sensors.ts index 43b3465..ebf144f 100644 --- a/sdk/commands/enabled-sensors.ts +++ b/sdk/commands/enabled-sensors.ts @@ -1,4 +1,4 @@ -import { StructBuffer, bits, createDataView, uint8_t } from "@nmann/struct-buffer"; +import { Inject, bits, uint8_t } from "@nmann/struct-buffer"; import { SENSOR_COUNT, FsrSensor } from "../api"; type Decoded = ReturnType; @@ -39,51 +39,34 @@ function joinTwoSensors( }; } -export class EnabledSensors extends StructBuffer< - // biome-ignore lint/complexity/noBannedTypes: - {}, - Array>, - Array> -> { - constructor() { - super("EnabledSensors", {}); - } +const BYTE_LENGTH = 5; - override get count() { - return 5; // always 5 items (5 twoDisabledSensors_t) - } - - override get isList() { - return true; - } - - override get byteLength() { - return 5; - } - - override decode(view: DataView, littleEndian = false, offset = 0): Array> { - const decoded = twoEnabledSensors_t[this.count] - .decode(view, littleEndian, offset) - .flatMap>(splitTwoSensors); +/** very simple custom type that conveniently packs and unpacks */ +export const enabledSensors_t = new Inject>, Array>>( + // decode + (view, offset) => { + const decoded = twoEnabledSensors_t[BYTE_LENGTH].decode(view, { offset }).flatMap>(splitTwoSensors); // decoded now has a trailing entry for the 4 bits of padding on the end of data // so we slice to just the desired data - return decoded.slice(0, 9); - } + const value = decoded.slice(0, 9); - override encode(obj: Array>, littleEndian = false, offset = 0, view?: DataView): DataView { - if (obj.length !== 9) { + return { + size: BYTE_LENGTH, + value, + }; + }, + // encode + (values) => { + if (values.length !== 9) { throw new TypeError("DisabledSensors only encodes sets of 9"); } - const v = createDataView(this.count, view); const joined: Array> = []; - for (let i = 0; i < this.count; i++) { + for (let i = 0; i < BYTE_LENGTH; i++) { const aIdx = i * 2; const bIdx = aIdx + 1; - joined.push(joinTwoSensors(obj[aIdx], bIdx < obj.length ? obj[bIdx] : undefined)); + joined.push(joinTwoSensors(values[aIdx], bIdx < values.length ? values[bIdx] : undefined)); } - twoEnabledSensors_t[this.count].encode(joined, littleEndian, offset, v); - - return v; - } -} + return twoEnabledSensors_t[BYTE_LENGTH].encode(joined); + }, +); diff --git a/sdk/commands/sensor_test.ts b/sdk/commands/sensor_test.ts index db096ef..f6aa663 100644 --- a/sdk/commands/sensor_test.ts +++ b/sdk/commands/sensor_test.ts @@ -76,7 +76,7 @@ const dips_t = bitFields(uint8_t, { * * These values are then used to create the `SMXPanelTestData` for each panel. */ -const detail_data_t = new StructBuffer("detail_data_t", { +const detail_data_t = new StructBuffer({ sig_bad: sig_bad_t, sensors: int16_t[4], dips: dips_t, @@ -205,8 +205,8 @@ export class SMXSensorTestData { /** * Convert the data from 8-Bit Little Endian Bytes to 16-Bit Integers */ - const sensor_data_t = new StructBuffer("sensor_data_t", { data: uint16_t[size] }); - const decoded_data = sensor_data_t.decode(data.slice(preamble), true); + const sensor_data_t = new StructBuffer({ data: uint16_t[size] }); + const decoded_data = sensor_data_t.decode(data.slice(preamble), { littleEndian: true }); // Cycle through each panel and grab the data for (let panel = 0; panel < PANEL_COUNT; panel++) { @@ -231,7 +231,7 @@ export class SMXSensorTestData { } // Generate an SMXPanelTestData object for each panel - this.panels.push(new SMXPanelTestData(detail_data_t.decode(out_bytes, true), data_mode, isFsr)); + this.panels.push(new SMXPanelTestData(detail_data_t.decode(out_bytes, { littleEndian: true }), data_mode, isFsr)); } } } diff --git a/sdk/smx.ts b/sdk/smx.ts index 962029d..390afff 100644 --- a/sdk/smx.ts +++ b/sdk/smx.ts @@ -33,7 +33,7 @@ class SMXEvents { // Panel Input State (If a panel is active or not) this.inputState$ = rawReport$ .filter((e) => e.reportId === HID_REPORT_INPUT_STATE) - .map((e) => StageInputs.decode(e.data, true)); + .map((e) => StageInputs.decode(e.data, { littleEndian: true })); // All other reports (command responses) const report$ = rawReport$