Skip to content

Commit

Permalink
Merge branch 'main' into nm/struct-buffer-6
Browse files Browse the repository at this point in the history
  • Loading branch information
noahm committed Feb 2, 2025
2 parents 52b7f9f + 77f8f38 commit aefe7f1
Show file tree
Hide file tree
Showing 21 changed files with 1,897 additions and 1,702 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ jobs:
runs-on: ubuntu-latest
name: Vite Build
steps:
- uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5
- uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: 22
cache: "yarn"
Expand Down
16 changes: 8 additions & 8 deletions .github/workflows/status-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ jobs:
runs-on: ubuntu-latest
name: Biome Lint
steps:
- uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
- uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: 22
cache: "yarn"
Expand All @@ -18,8 +18,8 @@ jobs:
runs-on: ubuntu-latest
name: Typescript
steps:
- uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
- uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: 22
cache: "yarn"
Expand All @@ -29,8 +29,8 @@ jobs:
runs-on: ubuntu-latest
name: Tests
steps:
- uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
- uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: 22
cache: "yarn"
Expand All @@ -40,8 +40,8 @@ jobs:
runs-on: ubuntu-latest
name: Vite Build
steps:
- uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
- uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4
with:
node-version: 22
cache: "yarn"
Expand Down
2 changes: 1 addition & 1 deletion .mise.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
[tools]
node = "22.9"
node = "22.13"
925 changes: 0 additions & 925 deletions .yarn/releases/yarn-4.5.0.cjs

This file was deleted.

934 changes: 934 additions & 0 deletions .yarn/releases/yarn-4.6.0.cjs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
nodeLinker: node-modules

yarnPath: .yarn/releases/yarn-4.5.0.cjs
yarnPath: .yarn/releases/yarn-4.6.0.cjs
19 changes: 9 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,19 @@
"baconjs": "patch:baconjs@npm%3A3.0.17#~/.yarn/patches/baconjs-npm-3.0.17-1a95474784.patch",
"classnames": "^2.5.1",
"jotai": "^2.9.3",
"logrocket": "^9.0.0",
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@biomejs/biome": "1.9.3",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@biomejs/biome": "1.9.4",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"@types/w3c-web-hid": "1.0.6",
"@vitejs/plugin-react": "^4.3.1",
"@vitejs/plugin-react": "^4.3.4",
"typescript": "^5.5.4",
"vite": "^5.4.2",
"vite": "^6.0.7",
"vite-plugin-mkcert": "^1.17.6",
"vitest": "^2.0.5"
"vitest": "^2.1.8"
},
"packageManager": "yarn@4.5.0"
"packageManager": "yarn@4.6.0"
}
13 changes: 8 additions & 5 deletions sdk/commands/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ const packed_panel_settings_t = new StructBuffer({
loadCellHighThreshold: uint8_t,

/**
* FSR Thresholds
* 4 Sensors per threshold
* Activation threshold when pressing.
* 4 values, one for each sensor on this panel.
*/
fsrLowThreshold: uint8_t[4],
/**
* Release threshold when lifting.
* 4 values, one for each sensor on this panel.
*/
fsrHighThreshold: uint8_t[4],

/**
Expand Down Expand Up @@ -357,14 +361,13 @@ export class SMXConfig {
*/
constructor(data: Uint8Array, firmwareVersion: number) {
this.firmwareVersion = firmwareVersion;
console.log("Config Firmware Version: ", this.firmwareVersion);
console.log("CONFIG RAW DATA: ", data.toString());
console.debug("CONFIG RAW DATA: ", data.toString());

if (this.firmwareVersion >= 5) {
this.config = smx_config_t.decode(data.slice(2, -1), { littleEndian: true });
} else {
this.oldConfigSize = data[1];
console.log("Reading Old Config");
console.debug("Reading Old Config");

const slicedData = data.slice(2, -1);
// handle very old stage's smaller config data by padding
Expand Down
2 changes: 1 addition & 1 deletion sdk/commands/data_info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class SMXDeviceInfo {
player = 0;

constructor(data: Uint8Array) {
console.log("DEVICEINFO RAW DATA: ", data.toString());
console.debug("DEVICEINFO RAW DATA: ", data.toString());
this.#decode(data);
}

Expand Down
2 changes: 1 addition & 1 deletion sdk/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ export {
SENSOR_COUNT,
PANEL_COUNT,
} from "./api.js";
export { type PanelName, type EachPanel } from "./commands/inputs.js";
export type { PanelName, EachPanel } from "./commands/inputs.js";
export { SensorTestMode, type SMXPanelTestData, type SMXSensorTestData } from "./commands/sensor_test.js";
export { SMXStage } from "./smx.js";
2 changes: 1 addition & 1 deletion sdk/packet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export async function send_data(dev: HIDDevice, data: Uint8Array, debug = false)
// Send each packet
for (const packet of packets) {
if (debug) {
console.log("OUTGOING RAW PACKET: ", packet.toString());
console.debug("OUTGOING RAW PACKET: ", packet.toString());
}
await dev.sendReport(HID_REPORT_OUTPUT, packet);
}
Expand Down
12 changes: 5 additions & 7 deletions sdk/smx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ class SMXEvents {
.filter((e) => e.type === "host_cmd_finished")
.map((e) => e.type === "host_cmd_finished");

finishedCommand$.log("Cmd Finished");

const okSend$ = finishedCommand$.startWith(true);

// Main USB Output
Expand Down Expand Up @@ -101,7 +99,7 @@ export class SMXStage {

// write outgoing events to the device
this.events.eventsToSend$.onValue(async (value) => {
this.debug && console.log("writing to HID");
this.debug && console.debug("writing to HID");
await send_data(this.dev, value, this.debug);
});

Expand Down Expand Up @@ -241,9 +239,9 @@ export class SMXStage {
const encoded_config = this._config.encode();
if (encoded_config) {
this.debug &&
console.log("Config Encodes Correctly: ", data.slice(2, -1).toString() === encoded_config.toString());
console.debug("Config Encodes Correctly: ", data.slice(2, -1).toString() === encoded_config.toString());
}
this.debug && console.log("Got Config: ", this.config);
this.debug && console.info("Got Config: ", this.config);

return this._config;
}
Expand All @@ -252,15 +250,15 @@ export class SMXStage {
// biome-ignore lint/style/noNonNullAssertion: config should very much be defined here
this.test = new SMXSensorTestData(data, this.test_mode, this.config!.flags.PlatformFlags_FSR);

this.debug && console.log("Got Test: ", this.test);
this.debug && console.debug("Got Test: ", this.test);

return this.test;
}

private handleDeviceInfo(data: Uint8Array): SMXDeviceInfo {
this.info = new SMXDeviceInfo(data);

this.debug && console.log("Got Info: ", this.info);
this.debug && console.debug("Got Info: ", this.info);

return this.info;
}
Expand Down
12 changes: 6 additions & 6 deletions sdk/state-machines/collate-packets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,18 @@ export type Packet = { type: "host_cmd_finished" } | DataPacket | AckPacket;
export const collatePackets: StateF<DataView, PacketHandlingState, Packet> = (state, event) => {
// TODO: This whole function could maybe just use a bit more comments
if (!Bacon.hasValue(event)) {
console.log("No Event Value");
console.debug("No Event Value");
return [state, []];
}

let currentPacket = state.currentPacket;
const data = new Uint8Array(event.value.buffer);

console.log("INCOMING RAW PACKET: ", data.toString());
console.debug("INCOMING RAW PACKET: ", data.toString());

// Return if packet is empty
if (data.length <= PACKET_PREAMBLE_SIZE) {
console.log("Empty Packet");
console.debug("Empty Packet");
return [state, []];
}
const cmd = data[0];
Expand All @@ -46,12 +46,12 @@ export const collatePackets: StateF<DataView, PacketHandlingState, Packet> = (st
// we ignore the packet if we didn't request it, since it might be requested
// for a different program.
// TODO: Handle this? Not sure there's anything to handle here tbh
console.log("Found Packet Flag Device Info");
console.debug("Found Packet Flag Device Info");
}

if (PACKET_PREAMBLE_SIZE + byte_len > data.length) {
// TODO: Can this even happen???
console.log("Communication Error: Oversized Packet (ignored)");
console.warn("Communication Error: Oversized Packet (ignored)");
return [state, []];
}

Expand All @@ -71,7 +71,7 @@ export const collatePackets: StateF<DataView, PacketHandlingState, Packet> = (st
* This shouldn't happen, so warn about it and recover by clearing the junk in the buffer.
* TODO: Again, does this actually happen???!?
*/
console.log(
console.warn(
"Got PACKET_FLAG_OF_START_COMMAND, but we had ${current_packet.length} bytes in the buffer. Dropping it and continuing.",
);
currentPacket = new Uint8Array(0);
Expand Down
3 changes: 0 additions & 3 deletions ui/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import * as Bacon from "baconjs";
import { Provider } from "jotai";
import LogRocket from "logrocket";
import { createRoot } from "react-dom/client";

import { uiState } from "./state.ts";
import { UI } from "./ui.tsx";

LogRocket.init("rgozwj/smx-config-web");

Bacon.fromEvent(document, "DOMContentLoaded").onValue(async () => {
const rootEl = document.getElementById("root");
if (!rootEl) return;
Expand Down
12 changes: 11 additions & 1 deletion ui/pad-coms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,17 @@ export async function promptSelectDevice() {

export async function open_smx_device(dev: HIDDevice, autoSelect = false) {
if (!dev.opened) {
await dev.open();
try {
await dev.open();
} catch (e) {
console.error(e);
uiState.set(nextStatusTextLine$, "failed to open device; more details in the browser console.");
uiState.set(
nextStatusTextLine$,
"if you are using linux, permissions to talk to a stage are still an unsolved puzzle.",
);
return;
}
}

const stage = new SMXStage(dev);
Expand Down
39 changes: 39 additions & 0 deletions ui/stage/config.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useAtomValue, type Atom } from "jotai";
import type { SMXStage } from "../../sdk";
import { useConfig } from "./hooks";

export function ConfigValues(props: { stageAtom: Atom<SMXStage | undefined> }) {
const stage = useAtomValue(props.stageAtom);
const config = useConfig(stage);

const ranges = config?.enabledSensors.flatMap((panel, idx) => {
if (!panel.some((sensor) => sensor)) {
return []; // skip panels will all disabled sensors
}

const { fsrHighThreshold: highs, fsrLowThreshold: lows } = config.panelSettings[idx];

return {
idx,
lows,
highs,
};
});

if (!ranges) {
return null;
}

return (
<>
<h3>Sensitivity settings</h3>
<ul>
{ranges.map((range) => (
<li key={range.idx}>
Panel {range.idx + 1}: {range.lows[0]} - {range.highs[0]}
</li>
))}
</ul>
</>
);
}
67 changes: 67 additions & 0 deletions ui/stage/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { useAtomValue } from "jotai";
import { useState, useEffect, useRef } from "react";
import { type SMXStage, type SMXSensorTestData, SensorTestMode } from "../../sdk";
import { displayTestData$ } from "../state";

// UI Update Rate in Milliseconds
const UI_UPDATE_RATE = 50;

export function useInputState(stage: SMXStage | undefined) {
const readTestData = useAtomValue(displayTestData$);
const [panelStates, setPanelStates] = useState<Array<boolean> | null>();
useEffect(() => {
return stage?.inputState$.throttle(UI_UPDATE_RATE).onValue(setPanelStates);
}, [stage]);
return panelStates;
}

export function useTestData(stage: SMXStage | undefined) {
const testDataMode = useAtomValue(displayTestData$);
const [testData, setTestData] = useState<SMXSensorTestData | null>(null);

// request updates on an interval
useEffect(() => {
if (!stage || !testDataMode) {
return;
}
let testMode = SensorTestMode.UncalibratedValues;
switch (testDataMode) {
case "calibrated":
testMode = SensorTestMode.CalibratedValues;
break;
case "noise":
testMode = SensorTestMode.Noise;
break;
case "tare":
testMode = SensorTestMode.Tare;
}
const handle = setInterval(() => stage.updateTestData(testMode), UI_UPDATE_RATE);
return () => clearInterval(handle);
}, [stage, testDataMode]);

// ingest responses and display in UI
useEffect(() => {
return stage?.testDataResponse$.onValue(setTestData);
}, [stage]);

return testData;
}

export function useConfig(stage: SMXStage | undefined) {
const stageRef = useRef(stage);
const [configData, setConfig] = useState(stage?.config);

useEffect(() => {
if (stageRef.current !== stage) {
// detected the stage has changed, so keep the config in sync
setConfig(stage?.config);
stageRef.current = stage;
}
}, [stage]);

useEffect(() => {
return stage?.configResponse$.onValue((config) => setConfig(config.config));
}, [stage]);

return configData;
}
Loading

0 comments on commit aefe7f1

Please sign in to comment.