hidapi: snek & stac support

This commit is contained in:
din
2025-03-17 22:22:02 -05:00
committed by teejusb
parent d3f985fbee
commit 1e62bec650
6 changed files with 415 additions and 141 deletions
+6 -4
View File
@@ -180,13 +180,17 @@ list(APPEND SMDATA_ARCH_LIGHTS_SRC "arch/Lights/LightsDriver.cpp"
"arch/Lights/LightsDriver_Export.cpp"
"arch/Lights/LightsDriver_SextetStream.cpp"
"arch/Lights/LightsDriver_SystemMessage.cpp"
"arch/Lights/LightsDriver_HidBlueDot.cpp")
"arch/Lights/LightsDriver_stac.cpp"
"arch/Lights/LightsDriver_snek.cpp"
"arch/Lights/LightsDriver_HidBlueDot.cpp")
list(APPEND SMDATA_ARCH_LIGHTS_HPP "arch/Lights/LightsDriver.h"
"arch/Lights/LightsDriver_Export.h"
"arch/Lights/LightsDriver_SextetStream.h"
"arch/Lights/LightsDriver_SystemMessage.h"
"arch/Lights/SextetUtils.h"
"arch/Lights/LightsDriver_HidBlueDot.h")
"arch/Lights/LightsDriver_stac.h"
"arch/Lights/LightsDriver_snek.h"
"arch/Lights/LightsDriver_HidBlueDot.h")
# TODO: Confirm if Apple can use the export.
if(NOT APPLE)
@@ -214,7 +218,6 @@ if(NOT APPLE)
"arch/Lights/LightsDriver_Linux_PIUIO_Leds.cpp"
"arch/Lights/LightsDriver_Linux_PIUIOBTN_Leds.cpp"
"arch/Lights/LightsDriver_Linux_ITGIO.cpp"
"arch/Lights/LightsDriver_Linux_stac.cpp"
"arch/Lights/LightsDriver_LinuxPacDrive.cpp"
"arch/Lights/LightsDriver_LinuxWeedTech.cpp")
list(APPEND SMDATA_ARCH_LIGHTS_HPP
@@ -223,7 +226,6 @@ if(NOT APPLE)
"arch/Lights/LightsDriver_Linux_PIUIO_Leds.h"
"arch/Lights/LightsDriver_Linux_PIUIOBTN_Leds.h"
"arch/Lights/LightsDriver_Linux_ITGIO.h"
"arch/Lights/LightsDriver_Linux_stac.h"
"arch/Lights/LightsDriver_LinuxPacDrive.h"
"arch/Lights/LightsDriver_LinuxWeedTech.h")
if(WITH_MINIMAID)
-111
View File
@@ -1,111 +0,0 @@
#include "global.h"
#include "LightsDriver_Linux_stac.h"
#include "GameState.h"
#include "Game.h"
#include "RageLog.h"
#include <cerrno>
#include <cstdint>
#include <cstdio>
#if defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#if defined(HAVE_FCNTL_H)
#include <fcntl.h>
#endif
#include <libudev.h>
#include <fcntl.h>
#include <linux/hidraw.h>
#include <sys/ioctl.h>
REGISTER_LIGHTS_DRIVER_CLASS2(stac, Linux_stac);
LightsDriver_Linux_stac::LightsDriver_Linux_stac()
{
memset(outputBuffer[GameController_1], 0x00, STAC_HIDREPORT_SIZE);
memset(outputBuffer[GameController_2], 0x00, STAC_HIDREPORT_SIZE);
// Open the device using the VID, PID,
// and optionally the Serial number.
handleP1 = hid_open(STAC_VID, STAC_PID_P1, NULL);
handleP2 = hid_open(STAC_VID, STAC_PID_P2, NULL);
if (!handleP1) {
LOG->Warn("Stac P1 device not found.");
hid_exit();
return;
}
}
LightsDriver_Linux_stac::~LightsDriver_Linux_stac()
{
if(handleP1)
hid_close(handleP1);
if (handleP2)
hid_close(handleP2);
// Finalize the hidapi library
hid_exit();
}
void LightsDriver_Linux_stac::SetBuffer(int index, bool lightState, GameController ctrlNum)
{
//the first byte is the report ID, so we offset it here to adjust.
uint8_t index_offset = index + 1;
//each index in the array represents a single light,
//the light will turn on for any value that isn't 0x00
uint8_t val = lightState ? 0xFF : 0x00;
//ensure the index is valid and the light value has changed.
if (index_offset < STAC_HIDREPORT_SIZE && outputBuffer[ctrlNum][index_offset] != val)
{
outputBuffer[ctrlNum][index_offset] = val;
//signal the loop to push the new buffer to the device.
stateChanged = true;
}
}
void LightsDriver_Linux_stac::HandleState(const LightsState *ls, GameController ctrlNum)
{
if (!handle[ctrlNum])
return;
//check to see which game we are running as it can change during gameplay.
const InputScheme *pInput = &GAMESTATE->GetCurrentGame()->m_InputScheme;
RString sInputName = pInput->m_szName;
if (sInputName.EqualsNoCase("dance"))
{
SetBuffer(STAC_LIGHTINDEX_BTN1, ls->m_bGameButtonLights[ctrlNum][DANCE_BUTTON_UP], ctrlNum);
SetBuffer(STAC_LIGHTINDEX_BTN2, ls->m_bGameButtonLights[ctrlNum][DANCE_BUTTON_DOWN], ctrlNum);
SetBuffer(STAC_LIGHTINDEX_BTN3, ls->m_bGameButtonLights[ctrlNum][DANCE_BUTTON_LEFT], ctrlNum);
SetBuffer(STAC_LIGHTINDEX_BTN4, ls->m_bGameButtonLights[ctrlNum][DANCE_BUTTON_RIGHT], ctrlNum);
}
else if (sInputName.EqualsNoCase("pump"))
{
SetBuffer(STAC_LIGHTINDEX_BTN1, ls->m_bGameButtonLights[ctrlNum][PUMP_BUTTON_UPLEFT], ctrlNum);
SetBuffer(STAC_LIGHTINDEX_BTN2, ls->m_bGameButtonLights[ctrlNum][PUMP_BUTTON_UPRIGHT], ctrlNum);
SetBuffer(STAC_LIGHTINDEX_BTN3, ls->m_bGameButtonLights[ctrlNum][PUMP_BUTTON_CENTER], ctrlNum);
SetBuffer(STAC_LIGHTINDEX_BTN4, ls->m_bGameButtonLights[ctrlNum][PUMP_BUTTON_DOWNLEFT], ctrlNum);
SetBuffer(STAC_LIGHTINDEX_BTN5, ls->m_bGameButtonLights[ctrlNum][PUMP_BUTTON_DOWNRIGHT], ctrlNum);
}
if (!stateChanged)
return;
hid_write(handle[ctrlNum], (unsigned char*)&outputBuffer[ctrlNum], STAC_HIDREPORT_SIZE);
stateChanged = false;
}
void LightsDriver_Linux_stac::Set(const LightsState *ls)
{
HandleState(ls, GameController_1);
HandleState(ls, GameController_2);
}
+112
View File
@@ -0,0 +1,112 @@
#include "global.h"
#include "RageLog.h"
#include "LightsDriver_snek.h"
#include "GameState.h"
#include "Game.h"
REGISTER_LIGHTS_DRIVER_CLASS(snek);
LightsDriver_snek::LightsDriver_snek()
{
struct hid_device_info *devs, *cur_dev;
memset(outputBuffer, 0x00, SNEK_HIDREPORT_SIZE);
// Enumerate through the snek device to find the lighting interface.
devs = hid_enumerate(SNEK_VID, SNEK_PID);
cur_dev = devs;
if (devs && cur_dev)
{
// Look for the desired interface number for lighting.
while (cur_dev)
{
if (cur_dev->vendor_id == SNEK_VID &&
cur_dev->product_id == SNEK_PID &&
cur_dev->interface_number == SNEK_LIGHTING_INTERFACENUM)
{
// Open the device via its path (only way to get interface)
handle = hid_open_path(cur_dev->path);
break;
}
cur_dev = cur_dev->next;
}
}
if (!handle)
{
LOG->Warn("snek board lighting not found.");
}
}
LightsDriver_snek::~LightsDriver_snek()
{
if (handle)
{
hid_close(handle);
}
// Finalize the hidapi library
hid_exit();
}
void LightsDriver_snek::SetBuffer(int index, bool lightState)
{
// the first byte is the report ID, so we offset it here to adjust.
uint8_t index_offset = index + 1;
// each index in the array represents a single light,
// the light will turn on for any value that isn't 0x00
uint8_t val = lightState ? 0xFF : 0x00;
// ensure report ID is set.
outputBuffer[0] = SNEK_REPORT_ID;
// ensure the index is valid and the light value has changed.
if (index_offset < SNEK_HIDREPORT_SIZE && outputBuffer[index_offset] != val)
{
outputBuffer[index_offset] = val;
// signal the loop to push the new buffer to the device.
stateChanged = true;
}
}
void LightsDriver_snek::Set(const LightsState *ls)
{
// do not make a message for a non-connected device.
if (!handle)
{
return;
}
SetBuffer(SNEK_INDEX_DANCE_M_UL, ls->m_bCabinetLights[LIGHT_MARQUEE_UP_LEFT]);
SetBuffer(SNEK_INDEX_DANCE_M_UR, ls->m_bCabinetLights[LIGHT_MARQUEE_UP_RIGHT]);
SetBuffer(SNEK_INDEX_DANCE_M_LL, ls->m_bCabinetLights[LIGHT_MARQUEE_LR_LEFT]);
SetBuffer(SNEK_INDEX_DANCE_M_LR, ls->m_bCabinetLights[LIGHT_MARQUEE_LR_RIGHT]);
SetBuffer(SNEK_INDEX_DANCE_P1_START, ls->m_bGameButtonLights[GameController_1][GAME_BUTTON_START]);
SetBuffer(SNEK_INDEX_DANCE_P2_START, ls->m_bGameButtonLights[GameController_2][GAME_BUTTON_START]);
SetBuffer(SNEK_INDEX_DANCE_NEON, ls->m_bCabinetLights[LIGHT_BASS_LEFT] || ls->m_bCabinetLights[LIGHT_BASS_RIGHT]);
SetBuffer(SNEK_INDEX_DANCE_P1_UP, ls->m_bGameButtonLights[GameController_1][DANCE_BUTTON_UP]);
SetBuffer(SNEK_INDEX_DANCE_P1_DOWN, ls->m_bGameButtonLights[GameController_1][DANCE_BUTTON_DOWN]);
SetBuffer(SNEK_INDEX_DANCE_P1_LEFT, ls->m_bGameButtonLights[GameController_1][DANCE_BUTTON_LEFT]);
SetBuffer(SNEK_INDEX_DANCE_P1_RIGHT, ls->m_bGameButtonLights[GameController_1][DANCE_BUTTON_RIGHT]);
SetBuffer(SNEK_INDEX_DANCE_P2_UP, ls->m_bGameButtonLights[GameController_2][DANCE_BUTTON_UP]);
SetBuffer(SNEK_INDEX_DANCE_P2_DOWN, ls->m_bGameButtonLights[GameController_2][DANCE_BUTTON_DOWN]);
SetBuffer(SNEK_INDEX_DANCE_P2_LEFT, ls->m_bGameButtonLights[GameController_2][DANCE_BUTTON_LEFT]);
SetBuffer(SNEK_INDEX_DANCE_P2_RIGHT, ls->m_bGameButtonLights[GameController_2][DANCE_BUTTON_RIGHT]);
// only push on changes.
if (stateChanged)
{
// TODO: Check for error/reconnect.
hid_write(handle, (unsigned char *)&outputBuffer, SNEK_HIDREPORT_SIZE);
stateChanged = false;
}
}
+140
View File
@@ -0,0 +1,140 @@
/* LightsDriver_snek: Control lights for the snek board by icedragon.io using hidapi */
#ifndef LightsDriver_snek_H
#define LightsDriver_snek_H
/*
* -------------------------- NOTE --------------------------
*
* This driver needs user read/write access to the icedragon.io snek board.
* This can be achieved by using a udev rule like this:
*
* SUBSYSTEMS=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="10a8", OWNER="dance", GROUP="dance", MODE="0660"
*
* Refer to your distribution's documentation on how to properly apply a udev rule.
*
* -------------------------- NOTE --------------------------
*/
#include "arch/Lights/LightsDriver.h"
#include <cstdint>
#include "hidapi.h"
// static information about the device in question.
#define SNEK_VID 0x2e8a
#define SNEK_PID 0x10a8
#define SNEK_NUMOF_LIGHTS 32
// the first byte of the buffer is a static report id.
#define SNEK_HIDREPORT_SIZE (SNEK_NUMOF_LIGHTS + 1)
#define SNEK_REPORT_ID 0x01
#define SNEK_LIGHTING_INTERFACENUM 0x02
// all indicies contain their respective 573 pinouts
enum SnekLightIndex
{
SNEK_LIGHTINDEX_CN10_FL1 = 0,
SNEK_LIGHTINDEX_CN10_FL2,
SNEK_LIGHTINDEX_CN10_FL3,
SNEK_LIGHTINDEX_CN10_FL4,
SNEK_LIGHTINDEX_CN10_FL5,
SNEK_LIGHTINDEX_CN10_FL6,
SNEK_LIGHTINDEX_CN10_FL7,
SNEK_LIGHTINDEX_CN10_FL8,
SNEK_LIGHTINDEX_CN13_FL1,
SNEK_LIGHTINDEX_CN13_FL2,
SNEK_LIGHTINDEX_CN13_FL3,
SNEK_LIGHTINDEX_CN13_FL4,
SNEK_LIGHTINDEX_CN14_FL1,
SNEK_LIGHTINDEX_CN14_FL2,
SNEK_LIGHTINDEX_CN14_FL3,
SNEK_LIGHTINDEX_CN14_FL4,
SNEK_LIGHTINDEX_CN12_FL1,
SNEK_LIGHTINDEX_CN12_FL2,
SNEK_LIGHTINDEX_CN12_FL3,
SNEK_LIGHTINDEX_CN12_FL4,
SNEK_LIGHTINDEX_CN12_FL5,
SNEK_LIGHTINDEX_CN12_FL6,
SNEK_LIGHTINDEX_CN12_FL7,
SNEK_LIGHTINDEX_CN12_FL8,
SNEK_LIGHTINDEX_CN11_FL1,
SNEK_LIGHTINDEX_CN11_FL2,
SNEK_LIGHTINDEX_CN11_FL3,
SNEK_LIGHTINDEX_CN11_FL4,
SNEK_LIGHTINDEX_CN11_FL5,
SNEK_LIGHTINDEX_CN11_FL6,
SNEK_LIGHTINDEX_CN11_FL7,
SNEK_LIGHTINDEX_CN11_FL8,
SNEK_LIGHTINDEX_MAX
};
// helper defines for dance mode.
#define SNEK_INDEX_DANCE_P1_START SNEK_LIGHTINDEX_CN10_FL3
#define SNEK_INDEX_DANCE_P2_START SNEK_LIGHTINDEX_CN10_FL4
#define SNEK_INDEX_DANCE_M_LR SNEK_LIGHTINDEX_CN10_FL5
#define SNEK_INDEX_DANCE_M_UR SNEK_LIGHTINDEX_CN10_FL6
#define SNEK_INDEX_DANCE_M_LL SNEK_LIGHTINDEX_CN10_FL7
#define SNEK_INDEX_DANCE_M_UL SNEK_LIGHTINDEX_CN10_FL8
#define SNEK_INDEX_DANCE_NEON SNEK_LIGHTINDEX_CN13_FL1
#define SNEK_INDEX_DANCE_P1_UP SNEK_LIGHTINDEX_CN12_FL1
#define SNEK_INDEX_DANCE_P1_DOWN SNEK_LIGHTINDEX_CN12_FL2
#define SNEK_INDEX_DANCE_P1_LEFT SNEK_LIGHTINDEX_CN12_FL3
#define SNEK_INDEX_DANCE_P1_RIGHT SNEK_LIGHTINDEX_CN12_FL4
#define SNEK_INDEX_DANCE_P2_UP SNEK_LIGHTINDEX_CN11_FL1
#define SNEK_INDEX_DANCE_P2_DOWN SNEK_LIGHTINDEX_CN11_FL2
#define SNEK_INDEX_DANCE_P2_LEFT SNEK_LIGHTINDEX_CN11_FL3
#define SNEK_INDEX_DANCE_P2_RIGHT SNEK_LIGHTINDEX_CN11_FL4
class LightsDriver_snek : public LightsDriver
{
private:
hid_device *handle = nullptr;
bool stateChanged = false;
uint8_t outputBuffer[SNEK_HIDREPORT_SIZE] = {0};
void SetBuffer(int index, bool lightState);
public:
LightsDriver_snek();
virtual ~LightsDriver_snek();
virtual void Set(const LightsState *ls);
};
#endif
/*
* (c) 2025 din
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+127
View File
@@ -0,0 +1,127 @@
#include "global.h"
#include "RageLog.h"
#include "LightsDriver_stac.h"
#include "GameState.h"
#include "Game.h"
REGISTER_LIGHTS_DRIVER_CLASS(stac);
LightsDriver_stac::LightsDriver_stac()
{
struct hid_device_info *devs, *cur_dev;
memset(outputBuffer[GameController_1], 0x00, STAC_HIDREPORT_SIZE);
memset(outputBuffer[GameController_2], 0x00, STAC_HIDREPORT_SIZE);
// Enumerate through to find the lighting interface.
devs = hid_enumerate(STAC_VID, 0);
cur_dev = devs;
if (devs && cur_dev)
{
while (cur_dev)
{
if (cur_dev->vendor_id == STAC_VID &&
cur_dev->interface_number == STAC_LIGHTING_INTERFACE)
{
if (cur_dev->product_id == STAC_PID_P1)
{
handle[0] = hid_open_path(cur_dev->path);
}
else if (cur_dev->product_id == STAC_PID_P2)
{
handle[1] = hid_open_path(cur_dev->path);
}
}
cur_dev = cur_dev->next;
}
}
if (!handle[0])
{
LOG->Warn("stac P1 device not found.");
}
if (!handle[1])
{
LOG->Warn("stac P2 device not found.");
}
}
LightsDriver_stac::~LightsDriver_stac()
{
for (int i = 0; i < STAC_MAX_NUMBER; i++)
{
if (handle[i])
{
hid_close(handle[i]);
}
}
// Finalize the hidapi library
hid_exit();
}
void LightsDriver_stac::SetBuffer(int index, bool lightState, GameController ctrlNum)
{
// the first byte is the report ID, so we offset it here to adjust.
uint8_t index_offset = index + 1;
// each index in the array represents a single light,
// the light will turn on for any value that isn't 0x00
uint8_t val = lightState ? 0xFF : 0x00;
// ensure report ID is set.
outputBuffer[ctrlNum][0] = STAC_REPORT_ID;
// ensure the index is valid and the light value has changed.
if (index_offset < STAC_HIDREPORT_SIZE && outputBuffer[ctrlNum][index_offset] != val)
{
outputBuffer[ctrlNum][index_offset] = val;
// signal the loop to push the new buffer to the device.
stateChanged[ctrlNum] = true;
}
}
void LightsDriver_stac::HandleState(const LightsState *ls, GameController ctrlNum)
{
// do not create a message for an disconnected device.
if (!handle[ctrlNum])
return;
// check to see which game we are running as it can change during gameplay.
const InputScheme *pInput = &GAMESTATE->GetCurrentGame()->m_InputScheme;
RString sInputName = pInput->m_szName;
if (sInputName.EqualsNoCase("dance"))
{
SetBuffer(STAC_LIGHTINDEX_BTN1, ls->m_bGameButtonLights[ctrlNum][DANCE_BUTTON_UP], ctrlNum);
SetBuffer(STAC_LIGHTINDEX_BTN2, ls->m_bGameButtonLights[ctrlNum][DANCE_BUTTON_DOWN], ctrlNum);
SetBuffer(STAC_LIGHTINDEX_BTN3, ls->m_bGameButtonLights[ctrlNum][DANCE_BUTTON_LEFT], ctrlNum);
SetBuffer(STAC_LIGHTINDEX_BTN4, ls->m_bGameButtonLights[ctrlNum][DANCE_BUTTON_RIGHT], ctrlNum);
}
else if (sInputName.EqualsNoCase("pump"))
{
SetBuffer(STAC_LIGHTINDEX_BTN1, ls->m_bGameButtonLights[ctrlNum][PUMP_BUTTON_UPLEFT], ctrlNum);
SetBuffer(STAC_LIGHTINDEX_BTN2, ls->m_bGameButtonLights[ctrlNum][PUMP_BUTTON_UPRIGHT], ctrlNum);
SetBuffer(STAC_LIGHTINDEX_BTN3, ls->m_bGameButtonLights[ctrlNum][PUMP_BUTTON_CENTER], ctrlNum);
SetBuffer(STAC_LIGHTINDEX_BTN4, ls->m_bGameButtonLights[ctrlNum][PUMP_BUTTON_DOWNLEFT], ctrlNum);
SetBuffer(STAC_LIGHTINDEX_BTN5, ls->m_bGameButtonLights[ctrlNum][PUMP_BUTTON_DOWNRIGHT], ctrlNum);
}
// only push changes.
if (stateChanged[ctrlNum])
{
// TODO: Check for error/reconnect.
hid_write(handle[ctrlNum], (unsigned char *)&outputBuffer[ctrlNum], STAC_HIDREPORT_SIZE);
stateChanged[ctrlNum] = false;
}
}
void LightsDriver_stac::Set(const LightsState *ls)
{
HandleState(ls, GameController_1);
HandleState(ls, GameController_2);
}
@@ -1,7 +1,7 @@
/* LightsDriver_Linux_stac: Control lights for the stac by icedragon.io via direct hidraw writes. */
/* LightsDriver_stac: Control lights for the stac by icedragon.io using hidapi */
#ifndef LightsDriver_Linux_stac_H
#define LightsDriver_Linux_stac_H
#ifndef LightsDriver_stac_H
#define LightsDriver_stac_H
/*
* -------------------------- NOTE --------------------------
@@ -13,7 +13,7 @@
* SUBSYSTEMS=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="eb5b", OWNER="dance", GROUP="dance", MODE="0660"
* SUBSYSTEMS=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="eb5a", OWNER="dance", GROUP="dance", MODE="0660"
*
* Refer to your distrobution's documentation on how to properly apply a udev rule.
* Refer to your distribution's documentation on how to properly apply a udev rule.
*
* -------------------------- NOTE --------------------------
*/
@@ -23,48 +23,52 @@
#include <cstdint>
#include "hidapi.h"
//static information about the device(s) in question.
#define STAC_VID "04d8"
#define STAC_PID_P1 "ea4b"
#define STAC_PID_P2 "ea4a"
// static information about the device(s) in question.
#define STAC_VID 0x04d8
#define STAC_PID_P1 0xea4b
#define STAC_PID_P2 0xea4a
#define STAC_NUMOF_LIGHTS 5
//the first byte of the buffer is a static report id.
// the first byte of the buffer is a static report id.
#define STAC_HIDREPORT_SIZE (STAC_NUMOF_LIGHTS + 1)
#define STAC_REPORT_ID 0x01
#define STAC_LIGHTING_INTERFACE 0x01
// total number of supported devices.
#define STAC_MAX_NUMBER 2
//all indicies contain their respective 573 pinouts
enum StacLightIndex
{
STAC_LIGHTINDEX_BTN1 = 0,
STAC_LIGHTINDEX_BTN2 = 1,
STAC_LIGHTINDEX_BTN3 = 2,
STAC_LIGHTINDEX_BTN4 = 3,
STAC_LIGHTINDEX_BTN5 = 4,
STAC_LIGHTINDEX_MAX
STAC_LIGHTINDEX_BTN1 = 0,
STAC_LIGHTINDEX_BTN2 = 1,
STAC_LIGHTINDEX_BTN3 = 2,
STAC_LIGHTINDEX_BTN4 = 3,
STAC_LIGHTINDEX_BTN5 = 4,
STAC_LIGHTINDEX_MAX
};
class LightsDriver_Linux_stac : public LightsDriver
class LightsDriver_stac : public LightsDriver
{
private:
hid_device* handle[2];
hid_device *handle[STAC_MAX_NUMBER] = {nullptr};
bool stateChanged = false;
uint8_t outputBuffer[2][STAC_HIDREPORT_SIZE];
bool stateChanged[STAC_MAX_NUMBER] = {false};
uint8_t outputBuffer[STAC_MAX_NUMBER][STAC_HIDREPORT_SIZE] = {0};
void HandleState(const LightsState *ls, StacDevice *dev, GameController ctrlNum);
void HandleState(const LightsState *ls, GameController ctrlNum);
void SetBuffer(int index, bool lightState, GameController ctrlNum);
public:
LightsDriver_Linux_stac();
virtual ~LightsDriver_Linux_stac();
virtual void Set(const LightsState *ls);
public:
LightsDriver_stac();
virtual ~LightsDriver_stac();
virtual void Set(const LightsState *ls);
};
#endif
/*
* (c) 2021 StepMania team
* (c) 2025 din
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a