diff --git a/sdk/commands/config.ts b/sdk/commands/config.ts index 231b54d..1a2c566 100644 --- a/sdk/commands/config.ts +++ b/sdk/commands/config.ts @@ -3,17 +3,6 @@ import { EnabledSensors } from "./enabled-sensors.ts"; export type Decoded = ReturnType; -/** - * Each FSR panel has 4 sensors. Make read/write easier by - * making them a struct - */ -const packed_sensor_t = new StructBuffer("packed_sensor_t", { - up: uint8_t, - right: uint8_t, - down: uint8_t, - left: uint8_t, -}); - /** * Each panel has various thresholds that are used based on * if it's a LoadCell or FSR panel. @@ -27,9 +16,10 @@ const packed_panel_settings_t = new StructBuffer("packed_panel_settings_t", { /** * FSR Thresholds + * 4 Sensors per threshold */ - fsrLowThreshold: packed_sensor_t, - fsrHighThreshold: packed_sensor_t, + fsrLowThreshold: uint8_t[4], + fsrHighThreshold: uint8_t[4], /** * TODO: Not sure what these are for @@ -44,22 +34,6 @@ const packed_panel_settings_t = new StructBuffer("packed_panel_settings_t", { reserved: uint16_t, }); -/** - * Just an intermediate struct so you can more easily dig into - * each panels sensors - */ -const panel_settings_t = new StructBuffer("panel_settings_t", { - up_left: packed_panel_settings_t, - up: packed_panel_settings_t, - up_right: packed_panel_settings_t, - left: packed_panel_settings_t, - center: packed_panel_settings_t, - right: packed_panel_settings_t, - down_left: packed_panel_settings_t, - down: packed_panel_settings_t, - down_right: packed_panel_settings_t, -}); - /** * Flags for Panel Config stored in a uint8_t */ @@ -86,22 +60,6 @@ const rgb_t = new StructBuffer("rbg_t", { b: uint8_t, }); -/** - * Just an intermediate struct so you can more easily dig into - * each panels step color RGB values - */ -const step_colors_t = new StructBuffer("step_colors_t", { - up_left: rgb_t, - up: rgb_t, - up_right: rgb_t, - left: rgb_t, - center: rgb_t, - right: rgb_t, - down_left: rgb_t, - down: rgb_t, - down_right: rgb_t, -}); - /** * The configuration for a connected controller. This can be retrieved with SMX_GetConfig * and modified with SMX_SetConfig. @@ -172,14 +130,18 @@ export const smx_config_t = new StructBuffer("smx_config_t", { /** * The color to use for each panel when auto-lighting in master mode. This doesn't * apply when the pads are in autonomous lighting mode (no master), since they don't - * store any configuration by themselves. These colors should be scaled to the 0-170 - * range. + * store any configuration by themselves. + * + * These colors are scaled to the 0-170 range. + * + * TODO: We can unscale them to 0-255 when reading, but then we would need to scale them back + * when writing. */ - stepColor: step_colors_t, + stepColor: rgb_t[9], /** * The default color to set the platform (underside) LED strips to. - * RGB values from 0-255 + * RGB values from 0-255 */ platformStripColor: rgb_t, @@ -210,7 +172,7 @@ export const smx_config_t = new StructBuffer("smx_config_t", { * * Setting a value to 0xFF disables that threshold. */ - panelSettings: panel_settings_t, + panelSettings: packed_panel_settings_t[9], /** * This is an internal tunable and should be left unchanged. @@ -226,61 +188,24 @@ export const smx_config_t = new StructBuffer("smx_config_t", { padding: uint8_t[49], }); -/** - * Class to represent all 4 sensors on a panel. - */ -class Panel { - up = false; - right = false; - down = false; - left = false; - - /** - * Convert the first 4 Least Significant Bits to represent all 4 sensors on a panel - * TODO: Determine if this ordering is actually correct - */ - constructor(byte: number) { - this.up = byte & 0x08 ? true : false; - this.right = byte & 0x04 ? true : false; - this.down = byte & 0x02 ? true : false; - this.left = byte & 0x01 ? true : false; - } - - /** - * Convert a panels 4 sensors back into a 4-bit LSB byte - * TODO: Determine if this ordering is actually correct - */ - toByte(): number { - return (this.up ? 1 << 3 : 0) + (this.right ? 1 << 2 : 0) + (this.down ? 1 << 1 : 0) + (this.left ? 1 : 0); - } -} - /** * The configuration for a connected SMX Stage. */ export class SMXConfig { - private data: Array; public config: Decoded; /** * Take in the data array and decode it into this. */ constructor(data: Array) { - this.data = data; - this.config = smx_config_t.decode(this.data.slice(2, -1), true); + this.config = smx_config_t.decode(data.slice(2, -1), true); } /** * TODO: Make this private again later, and maybe make a function called * "write_to_stage" or something? Depends on how we want to handle writing/reading */ - encode(): DataView | null { - if (!this.config) { - return null; - } - - const encoded_data = smx_config_t.encode(this.config, true); - - return encoded_data; + encode(): DataView { + return smx_config_t.encode(this.config, true); } } diff --git a/sdk/commands/data_info.ts b/sdk/commands/data_info.ts index 9f86335..beff915 100644 --- a/sdk/commands/data_info.ts +++ b/sdk/commands/data_info.ts @@ -5,7 +5,7 @@ const data_info_packet_t = new StructBuffer("data_info_packet_t", { cmd: char, // Not Used packet_size: uint8_t, - /** '0' for P1, '1' for P2 (Note these are the characters '0' and '1', not the numbers 0 and 1) */ + // '0' for P1, '1' for P2 (Note these are the characters '0' and '1', not the numbers 0 and 1) player: char, // Unused and Unknown unused2: char, diff --git a/sdk/commands/enabled-sensors.test.ts b/sdk/commands/enabled-sensors.test.ts index 82552d8..a0029c6 100644 --- a/sdk/commands/enabled-sensors.test.ts +++ b/sdk/commands/enabled-sensors.test.ts @@ -1,28 +1,30 @@ import { sbytes, sview } from "@nmann/struct-buffer"; import { expect, test, describe } from "vitest"; import { twoEnabledSensors_t, EnabledSensors } from "./enabled-sensors"; +import { SENSOR_COUNT } from "../api"; describe("twoEnabledSensors_t", () => { test("encode", () => { expect(twoEnabledSensors_t.decode(sbytes("F0"), false)).toEqual({ - up0: true, + left0: true, right0: true, + up0: true, down0: true, - left0: true, - up1: false, + left1: false, right1: false, + up1: false, down1: false, - left1: false, }); + expect(twoEnabledSensors_t.decode(sbytes("0F"))).toEqual({ - up0: false, + left0: false, right0: false, + up0: false, down0: false, - left0: false, - up1: true, + left1: true, right1: true, + up1: true, down1: true, - left1: true, }); }); }); @@ -30,60 +32,15 @@ describe("twoEnabledSensors_t", () => { const enabledSensors = new EnabledSensors(); const decodedData = [ - { - down: false, - left: false, - right: false, - up: false, - }, - { - down: true, - left: true, - right: true, - up: true, - }, - { - down: false, - left: false, - right: false, - up: false, - }, - { - down: true, - left: true, - right: true, - up: true, - }, - { - down: true, - left: true, - right: true, - up: true, - }, - { - down: true, - left: true, - right: true, - up: true, - }, - { - down: false, - left: false, - right: false, - up: false, - }, - { - down: true, - left: true, - right: true, - up: true, - }, - { - down: false, - left: false, - right: false, - up: false, - }, + Array(SENSOR_COUNT).fill(false), + Array(SENSOR_COUNT).fill(true), + Array(SENSOR_COUNT).fill(false), + Array(SENSOR_COUNT).fill(true), + Array(SENSOR_COUNT).fill(true), + Array(SENSOR_COUNT).fill(true), + Array(SENSOR_COUNT).fill(false), + Array(SENSOR_COUNT).fill(true), + Array(SENSOR_COUNT).fill(false), ]; const encodedData = "0f 0f ff 0f 00"; @@ -93,6 +50,5 @@ test("decode", () => { }); test("encode", () => { - // this currently fails for reasons I don't quite understand. probably endianness or something - expect(sview(enabledSensors.encode(decodedData, false))).toEqual(encodedData); + expect(sview(enabledSensors.encode(decodedData))).toEqual(encodedData); }); diff --git a/sdk/commands/enabled-sensors.ts b/sdk/commands/enabled-sensors.ts index faac4f6..5f40cb2 100644 --- a/sdk/commands/enabled-sensors.ts +++ b/sdk/commands/enabled-sensors.ts @@ -1,73 +1,52 @@ import { StructBuffer, bits, createDataView, uint8_t } from "@nmann/struct-buffer"; +import { SENSOR_COUNT, Sensor } from "../api"; type Decoded = ReturnType; -interface EnabeledSensorSet { - up: boolean; - right: boolean; - down: boolean; - left: boolean; -} - /** sensors enabled, with two panels packed into a single byte */ export const twoEnabledSensors_t = bits(uint8_t, { - up0: 7, + left0: 7, right0: 6, - down0: 5, - left0: 4, - up1: 3, + up0: 5, + down0: 4, + left1: 3, right1: 2, - down1: 1, - left1: 0, + up1: 1, + down1: 0, }); /** splits packed */ -function splitTwoSensors(decoded: Decoded): EnabeledSensorSet[] { +function splitTwoSensors(decoded: Decoded): Array> { return [ - { - up: decoded.up0, - right: decoded.right0, - down: decoded.down0, - left: decoded.left0, - }, - { - up: decoded.up1, - right: decoded.right1, - down: decoded.down1, - left: decoded.left1, - }, + [decoded.left0, decoded.right0, decoded.up0, decoded.down0], + [decoded.left1, decoded.right1, decoded.up1, decoded.down1], ]; } function joinTwoSensors( - sensorA: EnabeledSensorSet, - sensorB: EnabeledSensorSet = { - up: false, - right: false, - down: false, - left: false, - }, + sensorA: Array, + sensorB: Array = Array(SENSOR_COUNT).fill(false), ): Decoded { return { - up0: sensorA.up, - right0: sensorA.right, - down0: sensorA.down, - left0: sensorA.left, - up1: sensorB.up, - right1: sensorB.right, - down1: sensorB.down, - left1: sensorB.left, + left0: sensorA[Sensor.Left], + right0: sensorA[Sensor.Right], + up0: sensorA[Sensor.Up], + down0: sensorA[Sensor.Down], + left1: sensorB[Sensor.Left], + right1: sensorB[Sensor.Right], + up1: sensorB[Sensor.Up], + down1: sensorB[Sensor.Down], }; } export class EnabledSensors extends StructBuffer< // biome-ignore lint/complexity/noBannedTypes: {}, - EnabeledSensorSet[], - EnabeledSensorSet[] + Array>, + Array> > { constructor() { - super("DisabledSensors", {}); + super("EnabledSensors", {}); } override get count() { @@ -78,16 +57,21 @@ export class EnabledSensors extends StructBuffer< return true; } - override decode(view: DataView, littleEndian = false, offset = 0): EnabeledSensorSet[] { + 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); + .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); } - override encode(obj: EnabeledSensorSet[], littleEndian = false, offset = 0, view?: DataView): DataView { + override encode(obj: Array>, littleEndian = false, offset = 0, view?: DataView): DataView { if (obj.length !== 9) { throw new TypeError("DisabledSensors only encodes sets of 9"); } diff --git a/sdk/index.ts b/sdk/index.ts index 9fb09a0..27a684d 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -32,14 +32,19 @@ export async function getStageConfig(dev: HIDDevice) { const encoded_config = smxconfig.encode(); if (encoded_config) { const buf = new Uint8Array(encoded_config.buffer); - console.log("Same Thing:", response.slice(2, -1).toString() === buf.toString()); + console.log("Config Encodes Correctly:", response.slice(2, -1).toString() === buf.toString()); } + + console.log(smxconfig); return smxconfig; } export async function getSensorTestData(dev: HIDDevice) { await send_data(dev, [API_COMMAND.GET_SENSOR_TEST_DATA, SensorTestMode.CalibratedValues], true); const response = await process_packets(dev, API_COMMAND.GET_SENSOR_TEST_DATA, true); + if (response.length === 0) { + return null; + } return new SMXSensorTestData(response); } diff --git a/sdk/packet.ts b/sdk/packet.ts index 88ee1f4..19f2dc3 100644 --- a/sdk/packet.ts +++ b/sdk/packet.ts @@ -112,8 +112,8 @@ export async function send_data(dev: HIDDevice, data: Array, debug = fal export async function process_packets(dev: HIDDevice, responseType: number, debug = false): Promise> { let current_packet: Array = []; - let seenFirstPacket = false; + let readingPacket = false; while (true) { const data = await nextReportCommand(dev); @@ -123,7 +123,28 @@ export async function process_packets(dev: HIDDevice, responseType: number, debu continue; } - if (handle_packet(new Uint8Array(data.buffer), current_packet)) { + // Create the data buffer here so we can check for start flags and ACKs + const data_buffer = new Uint8Array(data.buffer); + + // If we see an ACK Command just ignore it and restart + if (data_buffer[0] === ACK_COMMAND) { + readingPacket = false; + seenFirstPacket = false; + current_packet = []; + continue; + } + + // Wait until we see a packet start flag so we don't grab a + // packet half way through + if (!readingPacket) { + if (data_buffer[0] & PACKET_FLAG_START_OF_COMMAND) { + readingPacket = true; + } else { + continue; + } + } + + if (handle_packet(data_buffer, current_packet)) { break; } @@ -136,6 +157,12 @@ export async function process_packets(dev: HIDDevice, responseType: number, debu current_packet = []; } } + + // If we've gotten here and our current packet is empty, that means + // we flushed it at some point. Restart + if (current_packet.length === 0) { + readingPacket = false; + } } // TODO: Handle Acknowledgements diff --git a/ui/state.ts b/ui/state.ts index b465913..8fb9512 100644 --- a/ui/state.ts +++ b/ui/state.ts @@ -8,7 +8,7 @@ export const uiState = createStore(); /** backing atom of all known devices */ export const devices$ = atom>({}); -export const displayTestData$ = atom(true); +export const displayTestData$ = atom(false); /** current p1 pad, derived from devices$ above */ export const p1Dev$ = atom(