From e81e867ee8ed017b1232913b1e264858c2e8a80f Mon Sep 17 00:00:00 2001 From: skogaby Date: Sun, 19 Jul 2020 03:29:40 -0500 Subject: [PATCH 1/4] Add a lights driver that outputs the sextet lights protocol over a serial connection, instead of to a pipe. Also refactor the sextet lights driver to use a common utility file that the serial driver takes advantage of as well. --- src/CMakeData-arch.cmake | 3 + src/Makefile.am | 5 +- src/arch/Lights/LightsDriver_SextetStream.cpp | 136 +------------- src/arch/Lights/LightsDriver_Win32Serial.cpp | 110 ++++++++++++ src/arch/Lights/LightsDriver_Win32Serial.h | 48 +++++ src/arch/Lights/SextetUtils.h | 167 ++++++++++++++++++ 6 files changed, 333 insertions(+), 136 deletions(-) create mode 100644 src/arch/Lights/LightsDriver_Win32Serial.cpp create mode 100644 src/arch/Lights/LightsDriver_Win32Serial.h create mode 100644 src/arch/Lights/SextetUtils.h diff --git a/src/CMakeData-arch.cmake b/src/CMakeData-arch.cmake index 6d6ccd4a12..39996d7d84 100644 --- a/src/CMakeData-arch.cmake +++ b/src/CMakeData-arch.cmake @@ -206,6 +206,7 @@ list(APPEND SMDATA_ARCH_LIGHTS_HPP "arch/Lights/LightsDriver.h" list(APPEND SMDATA_ARCH_LIGHTS_SRC "arch/Lights/LightsDriver_SextetStream.cpp") list(APPEND SMDATA_ARCH_LIGHTS_HPP "arch/Lights/LightsDriver_SextetStream.h") +list(APPEND SMDATA_ARCH_LIGHTS_HPP "arch/Lights/SextetUtils.h") # TODO: Confirm if Apple can use the export. if(NOT APPLE) @@ -214,10 +215,12 @@ if(NOT APPLE) if(WIN32) list(APPEND SMDATA_ARCH_LIGHTS_SRC + "arch/Lights/LightsDriver_Win32Serial.cpp" "arch/Lights/LightsDriver_Win32Parallel.cpp" "arch/Lights/LightsDriver_PacDrive.cpp") list(APPEND SMDATA_ARCH_LIGHTS_HPP "arch/Lights/LightsDriver_Win32Parallel.h" + "arch/Lights/LightsDriver_Win32Serial.h" "arch/Lights/LightsDriver_PacDrive.cpp") if(WITH_MINIMAID) list(APPEND SMDATA_ARCH_LIGHTS_SRC diff --git a/src/Makefile.am b/src/Makefile.am index 9bcb849c06..c028c3407c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -244,7 +244,8 @@ InputHandler += arch/InputHandler/InputHandler_MonkeyKeyboard.cpp arch/InputHand Lights += arch/Lights/LightsDriver_Export.cpp arch/Lights/LightsDriver_Export.h \ arch/Lights/LightsDriver_SystemMessage.cpp arch/Lights/LightsDriver_SystemMessage.h \ - arch/Lights/LightsDriver_SextetStream.cpp arch/Lights/LightsDriver_SextetStream.h + arch/Lights/LightsDriver_SextetStream.cpp arch/Lights/LightsDriver_SextetStream.h \ + arch/Lights/SextetUtils.h LoadingWindow += arch/LoadingWindow/LoadingWindow_Null.h @@ -395,6 +396,8 @@ if WINDOWS arch/InputHandler/InputHandler_Win32_Pump.cpp arch/InputHandler/InputHandler_Win32_Pump.h \ arch/InputHandler/InputHandler_Win32_RTIO.cpp arch/InputHandler/InputHandler_Win32_RTIO.h + Lights += arch/Lights/LightsDriver_Win32Serial.cpp arch/Lights/LightsDriver_Win32Serial.h + Sound += arch/Sound/RageSoundDriver_DSound_Software.cpp arch/Sound/RageSoundDriver_DSound_Software.h \ arch/Sound/DSoundHelpers.cpp arch/Sound/DSoundHelpers.h \ arch/Sound/RageSoundDriver_WaveOut.cpp arch/Sound/RageSoundDriver_WaveOut.h diff --git a/src/arch/Lights/LightsDriver_SextetStream.cpp b/src/arch/Lights/LightsDriver_SextetStream.cpp index 26d1e5e787..e1be922fd4 100644 --- a/src/arch/Lights/LightsDriver_SextetStream.cpp +++ b/src/arch/Lights/LightsDriver_SextetStream.cpp @@ -3,146 +3,12 @@ #include "PrefsManager.h" #include "RageLog.h" #include "RageUtil.h" +#include "SextetUtils.h" #include using namespace std; -// Number of printable characters used to encode lights -static const size_t CABINET_SEXTET_COUNT = 1; -static const size_t CONTROLLER_SEXTET_COUNT = 6; - -// Number of bytes to contain the full pack and a trailing LF -static const size_t FULL_SEXTET_COUNT = CABINET_SEXTET_COUNT + (NUM_GameController * CONTROLLER_SEXTET_COUNT) + 1; - - -// Serialization routines - -// Encodes the low 6 bits of a byte as a printable, non-space ASCII -// character (i.e., within the range 0x21-0x7E) such that the low 6 bits of -// the character are the same as the input. -inline uint8_t printableSextet(uint8_t data) -{ - // Maps the 6-bit value into the range 0x30-0x6F, wrapped in such a way - // that the low 6 bits of the result are the same as the data (so - // decoding is trivial). - // - // 00nnnn -> 0100nnnn (0x4n) - // 01nnnn -> 0101nnnn (0x5n) - // 10nnnn -> 0110nnnn (0x6n) - // 11nnnn -> 0011nnnn (0x3n) - - // Put another way, the top 4 bits H of the output are determined from - // the top two bits T of the input like so: - // H = ((T + 1) mod 4) + 3 - - return ((data + (uint8_t)0x10) & (uint8_t)0x3F) + (uint8_t)0x30; -} - -// Packs 6 booleans into a 6-bit value -inline uint8_t packPlainSextet(bool b0, bool b1, bool b2, bool b3, bool b4, bool b5) -{ - return (uint8_t)( - (b0 ? 0x01 : 0) | - (b1 ? 0x02 : 0) | - (b2 ? 0x04 : 0) | - (b3 ? 0x08 : 0) | - (b4 ? 0x10 : 0) | - (b5 ? 0x20 : 0)); -} - -// Packs 6 booleans into a printable sextet -inline uint8_t packPrintableSextet(bool b0, bool b1, bool b2, bool b3, bool b4, bool b5) -{ - return printableSextet(packPlainSextet(b0, b1, b2, b3, b4, b5)); -} - -// Packs the cabinet lights into a printable sextet and adds it to a buffer -inline size_t packCabinetLights(const LightsState *ls, uint8_t* buffer) -{ - buffer[0] = packPrintableSextet( - ls->m_bCabinetLights[LIGHT_MARQUEE_UP_LEFT], - ls->m_bCabinetLights[LIGHT_MARQUEE_UP_RIGHT], - ls->m_bCabinetLights[LIGHT_MARQUEE_LR_LEFT], - ls->m_bCabinetLights[LIGHT_MARQUEE_LR_RIGHT], - ls->m_bCabinetLights[LIGHT_BASS_LEFT], - ls->m_bCabinetLights[LIGHT_BASS_RIGHT]); - return CABINET_SEXTET_COUNT; -} - -// Packs the button lights for a controller into 6 printable sextets and -// adds them to a buffer -inline size_t packControllerLights(const LightsState *ls, GameController gc, uint8_t* buffer) -{ - // Menu buttons - buffer[0] = packPrintableSextet( - ls->m_bGameButtonLights[gc][GAME_BUTTON_MENULEFT], - ls->m_bGameButtonLights[gc][GAME_BUTTON_MENURIGHT], - ls->m_bGameButtonLights[gc][GAME_BUTTON_MENUUP], - ls->m_bGameButtonLights[gc][GAME_BUTTON_MENUDOWN], - ls->m_bGameButtonLights[gc][GAME_BUTTON_START], - ls->m_bGameButtonLights[gc][GAME_BUTTON_SELECT]); - - // Other non-sensors - buffer[1] = packPrintableSextet( - ls->m_bGameButtonLights[gc][GAME_BUTTON_BACK], - ls->m_bGameButtonLights[gc][GAME_BUTTON_COIN], - ls->m_bGameButtonLights[gc][GAME_BUTTON_OPERATOR], - ls->m_bGameButtonLights[gc][GAME_BUTTON_EFFECT_UP], - ls->m_bGameButtonLights[gc][GAME_BUTTON_EFFECT_DOWN], - false); - - // Sensors - buffer[2] = packPrintableSextet( - ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_01], - ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_02], - ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_03], - ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_04], - ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_05], - ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_06]); - buffer[3] = packPrintableSextet( - ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_07], - ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_08], - ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_09], - ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_10], - ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_11], - ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_12]); - buffer[4] = packPrintableSextet( - ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_13], - ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_14], - ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_15], - ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_16], - ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_17], - ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_18]); - buffer[5] = packPrintableSextet( - ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_19], - false, - false, - false, - false, - false); - - return CONTROLLER_SEXTET_COUNT; -} - -inline size_t packLine(uint8_t * buffer, const LightsState* ls) -{ - size_t index = 0; - - index += packCabinetLights(ls, &(buffer[index])); - - FOREACH_ENUM(GameController, gc) - { - index += packControllerLights(ls, gc, &(buffer[index])); - } - - // Terminate with LF - buffer[index++] = 0xA; - - return index; -} - - // Private members/methods are kept out of the header using an opaque pointer `_impl`. // Google "pimpl idiom" for an explanation of what's going on and why it is (or might be) useful. diff --git a/src/arch/Lights/LightsDriver_Win32Serial.cpp b/src/arch/Lights/LightsDriver_Win32Serial.cpp new file mode 100644 index 0000000000..3f06a5b6d3 --- /dev/null +++ b/src/arch/Lights/LightsDriver_Win32Serial.cpp @@ -0,0 +1,110 @@ +#include "global.h" +#include "LightsDriver_Win32Serial.h" +#include "windows.h" +#include "RageUtil.h" + +REGISTER_LIGHTS_DRIVER_CLASS(Win32Serial); + +static Preference g_sLightsComPort("LightsComPort", "COM54"); + +HANDLE serialPort; + +LightsDriver_Win32Serial::LightsDriver_Win32Serial() +{ + // Ensure a non-match the first time + lastOutput[0] = 0; + + RString sComPort = g_sLightsComPort.Get(); + + serialPort = CreateFile(RString("\\\\.\\").append(sComPort).c_str(), + GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + 0, + NULL); + + if (serialPort == INVALID_HANDLE_VALUE) { + MessageBox(nullptr, "Could not find a device on the configured COM port.", "ERROR", MB_OK); + return; + } + + DCB dcb_serial_params = { 0 }; + dcb_serial_params.DCBlength = sizeof(dcb_serial_params); + + if (GetCommState(serialPort, &dcb_serial_params) == 0) { + MessageBox(nullptr, "Could not connect to a device on the configured COM port.", "ERROR", MB_OK); + return; + } + + dcb_serial_params.BaudRate = CBR_115200; // Setting BaudRate = 115200 + dcb_serial_params.ByteSize = 8; // Setting ByteSize = 8 + dcb_serial_params.StopBits = ONESTOPBIT;// Setting StopBits = 1 + dcb_serial_params.Parity = NOPARITY; // Setting Parity = None + + if (SetCommState(serialPort, &dcb_serial_params) == 0) { + MessageBox(nullptr, "Could not setup the device parameters on the configured COM port.", "ERROR", MB_OK); + return; + } + + COMMTIMEOUTS timeouts = { 0 }; + timeouts.ReadIntervalTimeout = 50; // in milliseconds + timeouts.ReadTotalTimeoutConstant = 50; // in milliseconds + timeouts.ReadTotalTimeoutMultiplier = 10; // in milliseconds + timeouts.WriteTotalTimeoutConstant = 50; // in milliseconds + timeouts.WriteTotalTimeoutMultiplier = 10; // in milliseconds + + if (SetCommTimeouts(serialPort, &timeouts) == 0) { + MessageBox(nullptr, "Could not set the device timeouts on the configured COM port.", "ERROR", MB_OK); + return; + } +} + +LightsDriver_Win32Serial::~LightsDriver_Win32Serial() +{ + CloseHandle(serialPort); +} + +void LightsDriver_Win32Serial::Set(const LightsState* ls) +{ + if (serialPort != INVALID_HANDLE_VALUE) { + uint8_t buffer[FULL_SEXTET_COUNT]; + + packLine(buffer, ls); + + // Only write if the message has changed since the last write. + if (memcmp(buffer, lastOutput, FULL_SEXTET_COUNT) != 0) + { + DWORD bytesWritten = 0; + WriteFile(serialPort, buffer, FULL_SEXTET_COUNT, &bytesWritten, NULL); + + // Remember last message + memcpy(lastOutput, buffer, FULL_SEXTET_COUNT); + } + } +} + +/* + * (c) 2020 Skogaby + * 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. + */ diff --git a/src/arch/Lights/LightsDriver_Win32Serial.h b/src/arch/Lights/LightsDriver_Win32Serial.h new file mode 100644 index 0000000000..427a4ec8ce --- /dev/null +++ b/src/arch/Lights/LightsDriver_Win32Serial.h @@ -0,0 +1,48 @@ +#ifndef LightsDriver_SextetStream_H +#define LightsDriver_SextetStream_H + +/* + * `LightsDriver_Win32Serial` (abstract): Streams the light data (in + * ASCII-safe sextets) to a pre-configure serial port. The protocol + * of the messages sent follows the same protocol as the SextetStream + * lights driver, but it sent to serial instead of a FIFO or pipe. + */ + +#include "LightsDriver.h" +#include "SextetUtils.h" + +class LightsDriver_Win32Serial : public LightsDriver +{ +protected: + uint8_t lastOutput[FULL_SEXTET_COUNT]; +public: + LightsDriver_Win32Serial(); + virtual ~LightsDriver_Win32Serial(); + + virtual void Set(const LightsState* ls); +}; + +#endif + +/* + * Copyright © 2020 Skogaby + * + * 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, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * 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. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ diff --git a/src/arch/Lights/SextetUtils.h b/src/arch/Lights/SextetUtils.h new file mode 100644 index 0000000000..42d7bf7ea1 --- /dev/null +++ b/src/arch/Lights/SextetUtils.h @@ -0,0 +1,167 @@ +#ifndef SextetUtils_H +#define SextetUtils_H + +#include "LightsDriver.h" + +/* + * Utility functions that both `LightsDriver_Win32Serial` and `LightsDriver_SextetStream` + * take advantage of, in order to encode the lights data into a common format. + */ + + // Number of printable characters used to encode lights +static const size_t CABINET_SEXTET_COUNT = 1; +static const size_t CONTROLLER_SEXTET_COUNT = 6; + +// Number of bytes to contain the full pack and a trailing LF +static const size_t FULL_SEXTET_COUNT = CABINET_SEXTET_COUNT + (NUM_GameController * CONTROLLER_SEXTET_COUNT) + 1; + +// Serialization routines + +// Encodes the low 6 bits of a byte as a printable, non-space ASCII +// character (i.e., within the range 0x21-0x7E) such that the low 6 bits of +// the character are the same as the input. +inline uint8_t printableSextet(uint8_t data) +{ + // Maps the 6-bit value into the range 0x30-0x6F, wrapped in such a way + // that the low 6 bits of the result are the same as the data (so + // decoding is trivial). + // + // 00nnnn -> 0100nnnn (0x4n) + // 01nnnn -> 0101nnnn (0x5n) + // 10nnnn -> 0110nnnn (0x6n) + // 11nnnn -> 0011nnnn (0x3n) + + // Put another way, the top 4 bits H of the output are determined from + // the top two bits T of the input like so: + // H = ((T + 1) mod 4) + 3 + + return ((data + (uint8_t)0x10) & (uint8_t)0x3F) + (uint8_t)0x30; +} + +// Packs 6 booleans into a 6-bit value +inline uint8_t packPlainSextet(bool b0, bool b1, bool b2, bool b3, bool b4, bool b5) +{ + return (uint8_t)( + (b0 ? 0x01 : 0) | + (b1 ? 0x02 : 0) | + (b2 ? 0x04 : 0) | + (b3 ? 0x08 : 0) | + (b4 ? 0x10 : 0) | + (b5 ? 0x20 : 0)); +} + +// Packs 6 booleans into a printable sextet +inline uint8_t packPrintableSextet(bool b0, bool b1, bool b2, bool b3, bool b4, bool b5) +{ + return printableSextet(packPlainSextet(b0, b1, b2, b3, b4, b5)); +} + +// Packs the cabinet lights into a printable sextet and adds it to a buffer +inline size_t packCabinetLights(const LightsState* ls, uint8_t* buffer) +{ + buffer[0] = packPrintableSextet( + ls->m_bCabinetLights[LIGHT_MARQUEE_UP_LEFT], + ls->m_bCabinetLights[LIGHT_MARQUEE_UP_RIGHT], + ls->m_bCabinetLights[LIGHT_MARQUEE_LR_LEFT], + ls->m_bCabinetLights[LIGHT_MARQUEE_LR_RIGHT], + ls->m_bCabinetLights[LIGHT_BASS_LEFT], + ls->m_bCabinetLights[LIGHT_BASS_RIGHT]); + return CABINET_SEXTET_COUNT; +} + +// Packs the button lights for a controller into 6 printable sextets and +// adds them to a buffer +inline size_t packControllerLights(const LightsState* ls, GameController gc, uint8_t* buffer) +{ + // Menu buttons + buffer[0] = packPrintableSextet( + ls->m_bGameButtonLights[gc][GAME_BUTTON_MENULEFT], + ls->m_bGameButtonLights[gc][GAME_BUTTON_MENURIGHT], + ls->m_bGameButtonLights[gc][GAME_BUTTON_MENUUP], + ls->m_bGameButtonLights[gc][GAME_BUTTON_MENUDOWN], + ls->m_bGameButtonLights[gc][GAME_BUTTON_START], + ls->m_bGameButtonLights[gc][GAME_BUTTON_SELECT]); + + // Other non-sensors + buffer[1] = packPrintableSextet( + ls->m_bGameButtonLights[gc][GAME_BUTTON_BACK], + ls->m_bGameButtonLights[gc][GAME_BUTTON_COIN], + ls->m_bGameButtonLights[gc][GAME_BUTTON_OPERATOR], + ls->m_bGameButtonLights[gc][GAME_BUTTON_EFFECT_UP], + ls->m_bGameButtonLights[gc][GAME_BUTTON_EFFECT_DOWN], + false); + + // Sensors + buffer[2] = packPrintableSextet( + ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_01], + ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_02], + ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_03], + ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_04], + ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_05], + ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_06]); + buffer[3] = packPrintableSextet( + ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_07], + ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_08], + ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_09], + ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_10], + ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_11], + ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_12]); + buffer[4] = packPrintableSextet( + ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_13], + ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_14], + ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_15], + ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_16], + ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_17], + ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_18]); + buffer[5] = packPrintableSextet( + ls->m_bGameButtonLights[gc][GAME_BUTTON_CUSTOM_19], + false, + false, + false, + false, + false); + + return CONTROLLER_SEXTET_COUNT; +} + +inline size_t packLine(uint8_t* buffer, const LightsState* ls) +{ + size_t index = 0; + + index += packCabinetLights(ls, &(buffer[index])); + + FOREACH_ENUM(GameController, gc) + { + index += packControllerLights(ls, gc, &(buffer[index])); + } + + // Terminate with LF + buffer[index++] = 0xA; + + return index; +} + +#endif + +/* + * Copyright © 2014 Peter S. May + * + * 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, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * 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. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ From 9b3f26d6722eeaa8dce8222b4c7cac675c186d6f Mon Sep 17 00:00:00 2001 From: Martin Natano Date: Mon, 23 Aug 2021 22:04:28 +0200 Subject: [PATCH 2/4] Increase Stats.xml file size limit to 100MB A lot of people have run into the previous ~10MB limit and increasing it to 100MB doesn't seem to break anything. I left a limit in place, so that excessively large Stats.xml files on a USB profile can't be used to make a cab run out of memory. (SM uses a multiple of the memory that is required for the file on disk.) --- src/Profile.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Profile.cpp b/src/Profile.cpp index 83875362a6..0f35e33244 100644 --- a/src/Profile.cpp +++ b/src/Profile.cpp @@ -49,11 +49,7 @@ static ThemeMetric UNLOCK_AUTH_STRING( "Profile", "UnlockAuthString" ); #define GUID_SIZE_BYTES 8 #define MAX_EDITABLE_INI_SIZE_BYTES 2*1024 // 2KB -#define MAX_PLAYER_STATS_XML_SIZE_BYTES \ - 400 /* Songs */ \ - * 5 /* Steps per Song */ \ - * 5 /* HighScores per Steps */ \ - * 1024 /* size in bytes of a HighScores XNode */ +#define MAX_PLAYER_STATS_XML_SIZE_BYTES 100*1024*1024 // 100MB const int DEFAULT_WEIGHT_POUNDS = 120; const float DEFAULT_BIRTH_YEAR= 1995; From baa5de4cd26ebf36cd288c8084f79b28e52843ce Mon Sep 17 00:00:00 2001 From: Martin Natano Date: Sun, 19 Sep 2021 22:07:31 +0200 Subject: [PATCH 3/4] Fix BinaryToHex() Previously the function stopped short on nul bytes ("\0") due to usage of the SArg() macro, which does not retrieve the length of the lua string. before the fix: `BinaryToHex("a\0b")` -> `"61"` after the fix: `BinaryToHex("a\0b")` -> `"610062"` --- src/RageUtil.cpp | 18 +++++++++++++++--- src/RageUtil.h | 2 +- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/RageUtil.cpp b/src/RageUtil.cpp index 51f054f1aa..6a821c45dd 100644 --- a/src/RageUtil.cpp +++ b/src/RageUtil.cpp @@ -225,11 +225,11 @@ bool IsHexVal( const RString &s ) return true; } -RString BinaryToHex( const void *pData_, int iNumBytes ) +RString BinaryToHex( const void *pData_, size_t iNumBytes ) { const unsigned char *pData = (const unsigned char *) pData_; RString s; - for( int i=0; i Date: Fri, 24 Sep 2021 14:41:56 -0700 Subject: [PATCH 4/4] Verify that PrefsTable[name] exists before indexing the pref. --- Themes/_fallback/Scripts/02 ThemePrefs.lua | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Themes/_fallback/Scripts/02 ThemePrefs.lua b/Themes/_fallback/Scripts/02 ThemePrefs.lua index 55bb07791c..2bc5b86cfb 100644 --- a/Themes/_fallback/Scripts/02 ThemePrefs.lua +++ b/Themes/_fallback/Scripts/02 ThemePrefs.lua @@ -62,11 +62,14 @@ end local function ResolveTable( pref ) -- check the section for this theme local name = GetThemeName() - local val = PrefsTable[name][pref] - - if val ~= nil then - --Trace( ("ResolveTable(%s): found in %s"):format(pref,name) ) - return PrefsTable[name] + local val = nil + + if PrefsTable[name] then + val = PrefsTable[name][pref] + if val ~= nil then + --Trace( ("ResolveTable(%s): found in %s"):format(pref,name) ) + return PrefsTable[name] + end end -- not in the current theme; check the fallback if it exists