Skip to content

Commit

Permalink
Add PanelTestMode suppport to smx class
Browse files Browse the repository at this point in the history
  • Loading branch information
fchorney committed May 16, 2024
1 parent 4f60aa1 commit 2801066
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 2 deletions.
9 changes: 9 additions & 0 deletions sdk/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,17 @@ export const API_COMMAND = {
GET_SENSOR_TEST_DATA: char2byte("y"),
SET_SERIAL_NUMBERS: char2byte("s"),
SET_PANEL_TEST_MODE: char2byte("t"),
SET_LIGHTS_OLD: char2byte("l"),
};

export enum PanelTestMode {
/** 48 represents the char "0" **/
Off = 48,
/** 49 represents the char "1" **/
PressureTest = 49,
};


export const SMX_USB_VENDOR_ID = 0x2341;
export const SMX_USB_PRODUCT_ID = 0x8037;
export const SMX_USB_PRODUCT_NAME = "StepManiaX";
Expand Down
99 changes: 97 additions & 2 deletions sdk/smx.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import * as Bacon from "baconjs";
import { collatePackets, type AckPacket, type DataPacket } from "./state-machines/collate-packets";
import { API_COMMAND, char2byte } from "./api";
import { API_COMMAND, PanelTestMode, char2byte } from "./api";
import { SMXConfig, type Decoded } from "./commands/config";
import { SMXDeviceInfo } from "./commands/data_info";
import { StageInputs } from "./commands/inputs";
import { HID_REPORT_INPUT, HID_REPORT_INPUT_STATE, send_data } from "./packet";
import { SMXSensorTestData, SensorTestMode } from "./commands/sensor_test";
import { RGB } from "./utils";
import { RGB, padData } from "./utils";

/**
* Class purely to set up in/out event stream "pipes" to properly throttle and sync input/output from a stage
Expand Down Expand Up @@ -82,6 +82,8 @@ export class SMXStage {
private test_mode: SensorTestMode = SensorTestMode.CalibratedValues;
private debug = true;
private _config: SMXConfig | null = null;
private panelTestMode = PanelTestMode.Off;
private testModeIntervalHandle: number | null = null;

public get config() {
return this._config?.config || null;
Expand Down Expand Up @@ -232,6 +234,99 @@ export class SMXStage {
this.events.output$.push(Uint8Array.of(API_COMMAND.GET_SENSOR_TEST_DATA, this.test_mode));
return this.testDataResponse$.firstToPromise();
}

/*
void SMX::SMXManager::UpdatePanelTestMode()
{
// If the test mode has changed, send the new test mode.
//
// When the test mode is enabled, send the test mode again periodically, or it'll time
// out on the master and be turned off. Don't repeat the PanelTestMode_Off command.
g_Lock.AssertLockedByCurrentThread();
uint32_t now = GetTickCount();
if(m_PanelTestMode == m_LastSentPanelTestMode &&
(m_PanelTestMode == PanelTestMode_Off || now - m_SentPanelTestModeAtTicks < 1000))
return;
// When we first send the test mode command (not for repeats), turn off lights.
if(m_LastSentPanelTestMode == PanelTestMode_Off)
{
// The 'l' command used to set lights, but it's now only used to turn lights off
// for cases like this.
string sData = "l";
sData.append(108, 0);
sData += "\n";
for(int iPad = 0; iPad < 2; ++iPad)
m_pDevices[iPad]->SendCommandLocked(sData);
}
m_SentPanelTestModeAtTicks = now;
m_LastSentPanelTestMode = m_PanelTestMode;
for(int iPad = 0; iPad < 2; ++iPad)
m_pDevices[iPad]->SendCommandLocked(ssprintf("t %c\n", m_PanelTestMode));
}
*/

setPanelTestMode(mode: PanelTestMode) {
// If we want to turn panel test mode off...
if (mode === PanelTestMode.Off) {
// We don't want to send the "Off" command multiple times, so only send it if
// it's currently activated
if (this.panelTestMode !== PanelTestMode.Off) {
if (this.testModeIntervalHandle !== null) {
clearInterval(this.testModeIntervalHandle);
this.testModeIntervalHandle = null;
}
// Turn off panel test mode, and send "Off" event
this.panelTestMode = mode;
this.events.output$.push(Uint8Array.of(API_COMMAND.SET_PANEL_TEST_MODE, mode));

// TODO: Do we need to do anything with this? Does this even need to be called to flush
// the queue?
this.events.ackReports$.firstToPromise();
}

// Either we're already off, or we sent the off command, so just return.
return;
}

// We only need to run this when the current mode is not the same as the requested mode
if (this.panelTestMode !== mode) {
this.panelTestMode = mode;

/**
* the 'l' command used to set lights, but it's now only used to turn lights off
* for cases like this
* Lights are always updated together (for some reason??)
* 2 pads * 9 panels * 25 lights each * 3 (RGB) = 1350
* The source code uses `108` and I'm really unsure why
*
* TODO: Does this even do anything?
*/
this.events.output$.push(
Uint8Array.of(API_COMMAND.SET_LIGHTS_OLD, ...padData([], 1350, 0), char2byte('\n'))
);

// TODO: Do we need to do anything with this? Does this even need to be called to flush
// the queue?
this.events.ackReports$.firstToPromise();

// Send the Panel Test Mode command
this.events.output$.push(Uint8Array.of(API_COMMAND.SET_PANEL_TEST_MODE, mode));

// TODO: Do we need to do anything with this? Does this even need to be called to flush
// the queue?
this.events.ackReports$.firstToPromise();

// The Panel Test Mode command needs to be resent every second
this.testModeIntervalHandle = setInterval(() => {
this.events.output$.push(Uint8Array.of(API_COMMAND.SET_PANEL_TEST_MODE, mode));

// TODO: Do I need to call this to consume the event?
this.events.ackReports$.firstToPromise();
}, 1000);
}
}

private handleConfig(data: Uint8Array): SMXConfig {
// biome-ignore lint/style/noNonNullAssertion: info should very much be defined here
Expand Down

0 comments on commit 2801066

Please sign in to comment.