Skip to content

Commit

Permalink
Merge pull request #7 from noahm/disabled-sensors-custom
Browse files Browse the repository at this point in the history
Disabled sensors custom field
  • Loading branch information
noahm authored Apr 1, 2024
2 parents f6a0618 + 2972b66 commit 239b203
Show file tree
Hide file tree
Showing 9 changed files with 776 additions and 49 deletions.
23 changes: 14 additions & 9 deletions .github/workflows/status-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ jobs:
node-version: 20
cache: "yarn"
- run: yarn --immutable

- name: Biome Lint/Format
run: yarn lint:ci
- run: yarn lint:ci
tsc:
runs-on: ubuntu-latest
name: Typescript
Expand All @@ -26,9 +24,18 @@ jobs:
node-version: 20
cache: "yarn"
- run: yarn --immutable

- name: Typescript
run: yarn typecheck
- run: yarn typecheck
test:
runs-on: ubuntu-latest
name: Tests
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: "yarn"
- run: yarn --immutable
- run: yarn test
build:
runs-on: ubuntu-latest
name: Vite Build
Expand All @@ -39,7 +46,5 @@ jobs:
node-version: 20
cache: "yarn"
- run: yarn --immutable

- name: Vite Build
run: yarn build
- run: yarn build

1 change: 0 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
},
"typescript.preferences.preferTypeOnlyAutoImports": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit",
"source.fixAll": "explicit"
}
}
2 changes: 1 addition & 1 deletion biome.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://biomejs.dev/schemas/1.6.2/schema.json",
"organizeImports": {
"enabled": true
"enabled": false
},
"linter": {
"enabled": true,
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"lint": "biome check sdk ui",
"lint:ci": "biome ci sdk ui",
"preview": "vite preview",
"test": "vitest",
"typecheck": "tsc"
},
"keywords": [
Expand All @@ -33,7 +34,8 @@
"@types/w3c-web-hid": "1.0.6",
"@vitejs/plugin-react": "^4.2.1",
"typescript": "^5.4.3",
"vite": "^5.2.6"
"vite": "^5.2.6",
"vitest": "^1.4.0"
},
"packageManager": "yarn@4.1.1"
}
35 changes: 5 additions & 30 deletions sdk/commands/config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { StructBuffer, bits, uint8_t, uint16_t } from "@nmann/struct-buffer";
import type { EachPanel } from "./inputs.ts";
import { EnabledSensors } from "./enabled-sensors.ts";

export type DecodedStruct<SB extends StructBuffer> = ReturnType<SB["decode"]>;
export type Decoded<Struct extends { decode(...args: unknown[]): unknown }> = ReturnType<Struct["decode"]>;

/**
* Each FSR panel has 4 sensors. Make read/write easier by
Expand Down Expand Up @@ -158,10 +158,9 @@ 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. This is packed, with four sensors per byte:
* enabledSensors[0] & 1 is the first sensor on the first panel, and so on.
* we know aren't populated.
*/
enabledSensors: uint8_t[5],
enabledSensors: new EnabledSensors(),

/**
* How long the master controller will wait for a lights command before assuming
Expand Down Expand Up @@ -261,29 +260,14 @@ class Panel {
*/
export class SMXConfig {
private data: Array<number>;
public config: DecodedStruct<typeof smx_config_t>;
public decodedEnabledSensors: EachPanel<Panel>;
public config: Decoded<typeof smx_config_t>;

/**
* Take in the data array and decode it into this.
*/
constructor(data: Array<number>) {
this.data = data;

this.config = smx_config_t.decode(this.data.slice(2, -1), true);

// Do some data massaging to make `enabledSensors` easier to modify
this.decodedEnabledSensors = {
up_left: new Panel(this.config.enabledSensors[0] >> 4),
up: new Panel(this.config.enabledSensors[0] & 0xf),
up_right: new Panel(this.config.enabledSensors[1] >> 4),
left: new Panel(this.config.enabledSensors[1] & 0xf),
center: new Panel(this.config.enabledSensors[2] >> 4),
right: new Panel(this.config.enabledSensors[2] & 0xf),
down_left: new Panel(this.config.enabledSensors[3] >> 4),
down: new Panel(this.config.enabledSensors[3] & 0xf),
down_right: new Panel(this.config.enabledSensors[4] >> 4),
};
}

/**
Expand All @@ -295,15 +279,6 @@ export class SMXConfig {
return null;
}

// Do some data massaging to convert `enabledSensors` back to its c equivalent
const tmp_enabledSensors = [
(this.decodedEnabledSensors.up_left.toByte() << 4) + this.decodedEnabledSensors.up.toByte(),
(this.decodedEnabledSensors.up_right.toByte() << 4) + this.decodedEnabledSensors.left.toByte(),
(this.decodedEnabledSensors.center.toByte() << 4) + this.decodedEnabledSensors.right.toByte(),
(this.decodedEnabledSensors.down_left.toByte() << 4) + this.decodedEnabledSensors.down.toByte(),
this.decodedEnabledSensors.down_right.toByte() << 4,
];
this.config.enabledSensors = tmp_enabledSensors;
const encoded_data = smx_config_t.encode(this.config, true);

return encoded_data;
Expand Down
98 changes: 98 additions & 0 deletions sdk/commands/enabled-sensors.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { sbytes, sview } from "@nmann/struct-buffer";
import { expect, test, describe } from "vitest";
import { twoEnabledSensors_t, EnabledSensors } from "./enabled-sensors";

describe("twoEnabledSensors_t", () => {
test("encode", () => {
expect(twoEnabledSensors_t.decode(sbytes("F0"), false)).toEqual({
up0: true,
right0: true,
down0: true,
left0: true,
up1: false,
right1: false,
down1: false,
left1: false,
});
expect(twoEnabledSensors_t.decode(sbytes("0F"))).toEqual({
up0: false,
right0: false,
down0: false,
left0: false,
up1: true,
right1: true,
down1: true,
left1: true,
});
});
});

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,
},
];

const encodedData = "0f 0f ff 0f 00";

test("decode", () => {
expect(enabledSensors.decode(sbytes(encodedData))).toEqual(decodedData);
});

test("encode", () => {
// this currently fails for reasons I don't quite understand. probably endianness or something
expect(sview(enabledSensors.encode(decodedData, false))).toEqual(encodedData);
});
105 changes: 105 additions & 0 deletions sdk/commands/enabled-sensors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { StructBuffer, bits, createDataView, uint8_t } from "@nmann/struct-buffer";

type Decoded<Struct extends { decode(...args: unknown[]): unknown }> = ReturnType<Struct["decode"]>;

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,
right0: 6,
down0: 5,
left0: 4,
up1: 3,
right1: 2,
down1: 1,
left1: 0,
});

/** splits packed */
function splitTwoSensors(decoded: Decoded<typeof twoEnabledSensors_t>): EnabeledSensorSet[] {
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,
},
];
}

function joinTwoSensors(
sensorA: EnabeledSensorSet,
sensorB: EnabeledSensorSet = {
up: false,
right: false,
down: false,
left: false,
},
): Decoded<typeof twoEnabledSensors_t> {
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,
};
}

export class EnabledSensors extends StructBuffer<
// biome-ignore lint/complexity/noBannedTypes: <explanation>
{},
EnabeledSensorSet[],
EnabeledSensorSet[]
> {
constructor() {
super("DisabledSensors", {});
}

override get count() {
return 5; // always 5 items (5 twoDisabledSensors_t)
}

override get isList() {
return true;
}

override decode(view: DataView, littleEndian = false, offset = 0): EnabeledSensorSet[] {
const decoded = twoEnabledSensors_t[this.count]
.decode(view, littleEndian, offset)
.flatMap<EnabeledSensorSet>(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 {
if (obj.length !== 9) {
throw new TypeError("DisabledSensors only encodes sets of 9");
}
const v = createDataView(this.count, view);
const joined: Array<Decoded<typeof twoEnabledSensors_t>> = [];
for (let i = 0; i < this.count; i++) {
const aIdx = i * 2;
const bIdx = aIdx + 1;
joined.push(joinTwoSensors(obj[aIdx], bIdx < obj.length ? obj[bIdx] : undefined));
}
twoEnabledSensors_t[this.count].encode(joined, littleEndian, offset, v);

return v;
}
}
4 changes: 2 additions & 2 deletions sdk/commands/sensor_test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { StructBuffer, bitFields, bits, bool, int16_t, uint16_t, uint8_t } from "@nmann/struct-buffer";
import { API_COMMAND, char2byte } from "../api";
import type { DecodedStruct } from "./config";
import type { Decoded } from "./config";
import type { EachPanel, EachSensor } from "./inputs";

/**
Expand Down Expand Up @@ -97,7 +97,7 @@ export class SMXPanelTestData {
left: false,
};

constructor(data: DecodedStruct<typeof detail_data_t>) {
constructor(data: Decoded<typeof detail_data_t>) {
/**
* Check the header. this is always `false true false` or `0 1 0` to identify it as a response,
* and not as random steps from the player.
Expand Down
Loading

0 comments on commit 239b203

Please sign in to comment.