hidapi: snek & stac support
This commit is contained in:
@@ -180,12 +180,16 @@ list(APPEND SMDATA_ARCH_LIGHTS_SRC "arch/Lights/LightsDriver.cpp"
|
|||||||
"arch/Lights/LightsDriver_Export.cpp"
|
"arch/Lights/LightsDriver_Export.cpp"
|
||||||
"arch/Lights/LightsDriver_SextetStream.cpp"
|
"arch/Lights/LightsDriver_SextetStream.cpp"
|
||||||
"arch/Lights/LightsDriver_SystemMessage.cpp"
|
"arch/Lights/LightsDriver_SystemMessage.cpp"
|
||||||
|
"arch/Lights/LightsDriver_stac.cpp"
|
||||||
|
"arch/Lights/LightsDriver_snek.cpp"
|
||||||
"arch/Lights/LightsDriver_HidBlueDot.cpp")
|
"arch/Lights/LightsDriver_HidBlueDot.cpp")
|
||||||
list(APPEND SMDATA_ARCH_LIGHTS_HPP "arch/Lights/LightsDriver.h"
|
list(APPEND SMDATA_ARCH_LIGHTS_HPP "arch/Lights/LightsDriver.h"
|
||||||
"arch/Lights/LightsDriver_Export.h"
|
"arch/Lights/LightsDriver_Export.h"
|
||||||
"arch/Lights/LightsDriver_SextetStream.h"
|
"arch/Lights/LightsDriver_SextetStream.h"
|
||||||
"arch/Lights/LightsDriver_SystemMessage.h"
|
"arch/Lights/LightsDriver_SystemMessage.h"
|
||||||
"arch/Lights/SextetUtils.h"
|
"arch/Lights/SextetUtils.h"
|
||||||
|
"arch/Lights/LightsDriver_stac.h"
|
||||||
|
"arch/Lights/LightsDriver_snek.h"
|
||||||
"arch/Lights/LightsDriver_HidBlueDot.h")
|
"arch/Lights/LightsDriver_HidBlueDot.h")
|
||||||
|
|
||||||
# TODO: Confirm if Apple can use the export.
|
# TODO: Confirm if Apple can use the export.
|
||||||
@@ -214,7 +218,6 @@ if(NOT APPLE)
|
|||||||
"arch/Lights/LightsDriver_Linux_PIUIO_Leds.cpp"
|
"arch/Lights/LightsDriver_Linux_PIUIO_Leds.cpp"
|
||||||
"arch/Lights/LightsDriver_Linux_PIUIOBTN_Leds.cpp"
|
"arch/Lights/LightsDriver_Linux_PIUIOBTN_Leds.cpp"
|
||||||
"arch/Lights/LightsDriver_Linux_ITGIO.cpp"
|
"arch/Lights/LightsDriver_Linux_ITGIO.cpp"
|
||||||
"arch/Lights/LightsDriver_Linux_stac.cpp"
|
|
||||||
"arch/Lights/LightsDriver_LinuxPacDrive.cpp"
|
"arch/Lights/LightsDriver_LinuxPacDrive.cpp"
|
||||||
"arch/Lights/LightsDriver_LinuxWeedTech.cpp")
|
"arch/Lights/LightsDriver_LinuxWeedTech.cpp")
|
||||||
list(APPEND SMDATA_ARCH_LIGHTS_HPP
|
list(APPEND SMDATA_ARCH_LIGHTS_HPP
|
||||||
@@ -223,7 +226,6 @@ if(NOT APPLE)
|
|||||||
"arch/Lights/LightsDriver_Linux_PIUIO_Leds.h"
|
"arch/Lights/LightsDriver_Linux_PIUIO_Leds.h"
|
||||||
"arch/Lights/LightsDriver_Linux_PIUIOBTN_Leds.h"
|
"arch/Lights/LightsDriver_Linux_PIUIOBTN_Leds.h"
|
||||||
"arch/Lights/LightsDriver_Linux_ITGIO.h"
|
"arch/Lights/LightsDriver_Linux_ITGIO.h"
|
||||||
"arch/Lights/LightsDriver_Linux_stac.h"
|
|
||||||
"arch/Lights/LightsDriver_LinuxPacDrive.h"
|
"arch/Lights/LightsDriver_LinuxPacDrive.h"
|
||||||
"arch/Lights/LightsDriver_LinuxWeedTech.h")
|
"arch/Lights/LightsDriver_LinuxWeedTech.h")
|
||||||
if(WITH_MINIMAID)
|
if(WITH_MINIMAID)
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.
|
||||||
|
*/
|
||||||
@@ -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
|
#ifndef LightsDriver_stac_H
|
||||||
#define LightsDriver_Linux_stac_H
|
#define LightsDriver_stac_H
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* -------------------------- NOTE --------------------------
|
* -------------------------- 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}=="eb5b", OWNER="dance", GROUP="dance", MODE="0660"
|
||||||
* SUBSYSTEMS=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="eb5a", 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 --------------------------
|
* -------------------------- NOTE --------------------------
|
||||||
*/
|
*/
|
||||||
@@ -23,17 +23,20 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "hidapi.h"
|
#include "hidapi.h"
|
||||||
|
|
||||||
//static information about the device(s) in question.
|
// static information about the device(s) in question.
|
||||||
#define STAC_VID "04d8"
|
#define STAC_VID 0x04d8
|
||||||
#define STAC_PID_P1 "ea4b"
|
#define STAC_PID_P1 0xea4b
|
||||||
#define STAC_PID_P2 "ea4a"
|
#define STAC_PID_P2 0xea4a
|
||||||
#define STAC_NUMOF_LIGHTS 5
|
#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_HIDREPORT_SIZE (STAC_NUMOF_LIGHTS + 1)
|
||||||
#define STAC_REPORT_ID 0x01
|
#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
|
enum StacLightIndex
|
||||||
{
|
{
|
||||||
STAC_LIGHTINDEX_BTN1 = 0,
|
STAC_LIGHTINDEX_BTN1 = 0,
|
||||||
@@ -44,19 +47,20 @@ enum StacLightIndex
|
|||||||
STAC_LIGHTINDEX_MAX
|
STAC_LIGHTINDEX_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
class LightsDriver_Linux_stac : public LightsDriver
|
class LightsDriver_stac : public LightsDriver
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
hid_device* handle[2];
|
hid_device *handle[STAC_MAX_NUMBER] = {nullptr};
|
||||||
|
|
||||||
bool stateChanged = false;
|
bool stateChanged[STAC_MAX_NUMBER] = {false};
|
||||||
uint8_t outputBuffer[2][STAC_HIDREPORT_SIZE];
|
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);
|
void SetBuffer(int index, bool lightState, GameController ctrlNum);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LightsDriver_Linux_stac();
|
LightsDriver_stac();
|
||||||
virtual ~LightsDriver_Linux_stac();
|
virtual ~LightsDriver_stac();
|
||||||
|
|
||||||
virtual void Set(const LightsState *ls);
|
virtual void Set(const LightsState *ls);
|
||||||
};
|
};
|
||||||
@@ -64,7 +68,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (c) 2021 StepMania team
|
* (c) 2025 din
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
Reference in New Issue
Block a user