forked from Dniel97/segatools
mu3: added lights hook
This commit is contained in:
parent
b77ce7b457
commit
9fe98b227b
@ -48,7 +48,7 @@ static_assert(sizeof(struct io4_report_in) == 0x40, "IO4 IN report size");
|
|||||||
struct io4_report_out {
|
struct io4_report_out {
|
||||||
uint8_t report_id;
|
uint8_t report_id;
|
||||||
uint8_t cmd;
|
uint8_t cmd;
|
||||||
uint8_t payload[62];
|
uint8_t payload[IO4_REPORT_OUT_PAYLOAD_LEN];
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(struct io4_report_out) == 0x40, "IO4 OUT report size");
|
static_assert(sizeof(struct io4_report_out) == 0x40, "IO4 OUT report size");
|
||||||
@ -223,7 +223,11 @@ static HRESULT io4_handle_write(struct irp *irp)
|
|||||||
return S_OK;
|
return S_OK;
|
||||||
|
|
||||||
case IO4_CMD_SET_GENERAL_OUTPUT:
|
case IO4_CMD_SET_GENERAL_OUTPUT:
|
||||||
dprintf("USB I/O: GPIO Out\n");
|
// dprintf("USB I/O: GPIO Out\n");
|
||||||
|
|
||||||
|
if (io4_ops->write_gpio != NULL) {
|
||||||
|
return io4_ops->write_gpio(out.payload, IO4_REPORT_OUT_PAYLOAD_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define IO4_REPORT_OUT_PAYLOAD_LEN 62
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
/* System buttons in button[0] */
|
/* System buttons in button[0] */
|
||||||
|
|
||||||
@ -24,6 +26,7 @@ struct io4_state {
|
|||||||
|
|
||||||
struct io4_ops {
|
struct io4_ops {
|
||||||
HRESULT (*poll)(void *ctx, struct io4_state *state);
|
HRESULT (*poll)(void *ctx, struct io4_state *state);
|
||||||
|
HRESULT (*write_gpio)(uint8_t* payload, size_t len);
|
||||||
};
|
};
|
||||||
|
|
||||||
HRESULT io4_hook_init(
|
HRESULT io4_hook_init(
|
||||||
|
@ -57,11 +57,11 @@ void chuni_io_config_load(
|
|||||||
filename);
|
filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg->led_output_pipe = GetPrivateProfileIntW(L"led", L"cabLedOutputPipe", 1, filename);
|
cfg->cab_led_output_pipe = GetPrivateProfileIntW(L"led", L"cabLedOutputPipe", 1, filename);
|
||||||
cfg->led_output_serial = GetPrivateProfileIntW(L"led", L"cabLedOutputSerial", 0, filename);
|
cfg->cab_led_output_serial = GetPrivateProfileIntW(L"led", L"cabLedOutputSerial", 0, filename);
|
||||||
|
|
||||||
cfg->slider_led_output_pipe = GetPrivateProfileIntW(L"led", L"controllerLedOutputPipe", 1, filename);
|
cfg->controller_led_output_pipe = GetPrivateProfileIntW(L"led", L"controllerLedOutputPipe", 1, filename);
|
||||||
cfg->slider_led_output_serial = GetPrivateProfileIntW(L"led", L"controllerLedOutputSerial", 0, filename);
|
cfg->controller_led_output_serial = GetPrivateProfileIntW(L"led", L"controllerLedOutputSerial", 0, filename);
|
||||||
|
|
||||||
cfg->led_serial_baud = GetPrivateProfileIntW(L"led", L"serialBaud", 921600, filename);
|
cfg->led_serial_baud = GetPrivateProfileIntW(L"led", L"serialBaud", 921600, filename);
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ void chuni_io_config_load(
|
|||||||
L"serialPort",
|
L"serialPort",
|
||||||
L"COM5",
|
L"COM5",
|
||||||
port_input,
|
port_input,
|
||||||
6,
|
_countof(port_input),
|
||||||
filename);
|
filename);
|
||||||
|
|
||||||
// Sanitize the output path. If it's a serial COM port, it needs to be prefixed
|
// Sanitize the output path. If it's a serial COM port, it needs to be prefixed
|
||||||
|
@ -12,16 +12,15 @@ struct chuni_io_config {
|
|||||||
uint8_t vk_cell[32];
|
uint8_t vk_cell[32];
|
||||||
|
|
||||||
// Which ways to output LED information are enabled
|
// Which ways to output LED information are enabled
|
||||||
bool led_output_pipe;
|
bool cab_led_output_pipe;
|
||||||
bool led_output_serial;
|
bool cab_led_output_serial;
|
||||||
|
|
||||||
bool slider_led_output_pipe;
|
bool controller_led_output_pipe;
|
||||||
bool slider_led_output_serial;
|
bool controller_led_output_serial;
|
||||||
|
|
||||||
// The name of a COM port to output LED data on, in serial mode
|
// The name of a COM port to output LED data on, in serial mode
|
||||||
wchar_t led_serial_port[12];
|
wchar_t led_serial_port[12];
|
||||||
int32_t led_serial_baud;
|
int32_t led_serial_baud;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void chuni_io_config_load(
|
void chuni_io_config_load(
|
||||||
|
@ -48,15 +48,15 @@ HRESULT led_output_init(struct chuni_io_config* const cfg)
|
|||||||
led_escaped_buf[i].data_len = chuni_led_board_data_lens[i];
|
led_escaped_buf[i].data_len = chuni_led_board_data_lens[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
any_outputs_enabled = config->led_output_pipe || config->slider_led_output_pipe
|
any_outputs_enabled = config->cab_led_output_pipe || config->controller_led_output_pipe
|
||||||
|| config->led_output_serial || config->slider_led_output_serial;
|
|| config->cab_led_output_serial || config->controller_led_output_serial;
|
||||||
|
|
||||||
if (config->led_output_pipe || config->slider_led_output_pipe)
|
if (config->cab_led_output_pipe || config->controller_led_output_pipe)
|
||||||
{
|
{
|
||||||
led_pipe_init(); // don't really care about errors here tbh
|
led_pipe_init(); // don't really care about errors here tbh
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config->led_output_serial || config->slider_led_output_serial)
|
if (config->cab_led_output_serial || config->controller_led_output_serial)
|
||||||
{
|
{
|
||||||
led_serial_init(config->led_serial_port, config->led_serial_baud);
|
led_serial_init(config->led_serial_port, config->led_serial_baud);
|
||||||
}
|
}
|
||||||
@ -106,13 +106,13 @@ void led_output_update(uint8_t board, const byte* rgb)
|
|||||||
|
|
||||||
if (board < 2)
|
if (board < 2)
|
||||||
{
|
{
|
||||||
// billboard
|
// billboard (cab)
|
||||||
if (config->led_output_pipe)
|
if (config->cab_led_output_pipe)
|
||||||
{
|
{
|
||||||
led_pipe_update(escaped_data);
|
led_pipe_update(escaped_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config->led_output_serial)
|
if (config->cab_led_output_serial)
|
||||||
{
|
{
|
||||||
led_serial_update(escaped_data);
|
led_serial_update(escaped_data);
|
||||||
}
|
}
|
||||||
@ -120,12 +120,12 @@ void led_output_update(uint8_t board, const byte* rgb)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// slider
|
// slider
|
||||||
if (config->slider_led_output_pipe)
|
if (config->controller_led_output_pipe)
|
||||||
{
|
{
|
||||||
led_pipe_update(escaped_data);
|
led_pipe_update(escaped_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config->slider_led_output_serial)
|
if (config->controller_led_output_serial)
|
||||||
{
|
{
|
||||||
led_serial_update(escaped_data);
|
led_serial_update(escaped_data);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
Credits:
|
Credits:
|
||||||
somewhatlurker, skogaby
|
somewhatlurker, skogaby
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
28
dist/chuni/segatools.ini
vendored
28
dist/chuni/segatools.ini
vendored
@ -63,20 +63,6 @@ framed=1
|
|||||||
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
|
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
|
||||||
monitor=0
|
monitor=0
|
||||||
|
|
||||||
; -----------------------------------------------------------------------------
|
|
||||||
; Custom IO settings
|
|
||||||
; -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
[aimeio]
|
|
||||||
; To use a custom card reader IO DLL enter its path here.
|
|
||||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
|
||||||
path=
|
|
||||||
|
|
||||||
[chuniio]
|
|
||||||
; To use a custom Chunithm IO DLL enter its path here.
|
|
||||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
|
||||||
path=
|
|
||||||
|
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
; LED settings
|
; LED settings
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
@ -122,6 +108,20 @@ controllerLedOutputSerial=0
|
|||||||
; [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers
|
; [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers
|
||||||
|
|
||||||
|
|
||||||
|
; -----------------------------------------------------------------------------
|
||||||
|
; Custom IO settings
|
||||||
|
; -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
[aimeio]
|
||||||
|
; To use a custom card reader IO DLL enter its path here.
|
||||||
|
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||||
|
path=
|
||||||
|
|
||||||
|
[chuniio]
|
||||||
|
; To use a custom Chunithm IO DLL enter its path here.
|
||||||
|
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||||
|
path=
|
||||||
|
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
; Input settings
|
; Input settings
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
|
38
dist/chusan/segatools.ini
vendored
38
dist/chusan/segatools.ini
vendored
@ -88,25 +88,6 @@ framed=0
|
|||||||
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
|
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
|
||||||
monitor=0
|
monitor=0
|
||||||
|
|
||||||
; -----------------------------------------------------------------------------
|
|
||||||
; Custom IO settings
|
|
||||||
; -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
[aimeio]
|
|
||||||
; To use a custom card reader IO DLL (x64) enter its path here.
|
|
||||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
|
||||||
path=
|
|
||||||
|
|
||||||
[chuniio]
|
|
||||||
; Uncomment this if you have custom chuniio implementation comprised of a single 32bit DLL.
|
|
||||||
; (will use chu2to3 engine internally)
|
|
||||||
;path=
|
|
||||||
|
|
||||||
; Uncomment both of these if you have custom chuniio implementation comprised of two DLLs.
|
|
||||||
; x86 chuniio to path32, x64 to path64. Both are necessary.
|
|
||||||
;path32=
|
|
||||||
;path64=
|
|
||||||
|
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
; LED settings
|
; LED settings
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
@ -152,6 +133,25 @@ controllerLedOutputSerial=0
|
|||||||
; [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers
|
; [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers
|
||||||
|
|
||||||
|
|
||||||
|
; -----------------------------------------------------------------------------
|
||||||
|
; Custom IO settings
|
||||||
|
; -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
[aimeio]
|
||||||
|
; To use a custom card reader IO DLL (x64) enter its path here.
|
||||||
|
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||||
|
path=
|
||||||
|
|
||||||
|
[chuniio]
|
||||||
|
; Uncomment this if you have custom chuniio implementation comprised of a single 32bit DLL.
|
||||||
|
; (will use chu2to3 engine internally)
|
||||||
|
;path=
|
||||||
|
|
||||||
|
; Uncomment both of these if you have custom chuniio implementation comprised of two DLLs.
|
||||||
|
; x86 chuniio to path32, x64 to path64. Both are necessary.
|
||||||
|
;path32=
|
||||||
|
;path64=
|
||||||
|
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
; Input settings
|
; Input settings
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
|
48
dist/mu3/segatools.ini
vendored
48
dist/mu3/segatools.ini
vendored
@ -80,6 +80,54 @@ enable=1
|
|||||||
; modding frameworks such as BepInEx.
|
; modding frameworks such as BepInEx.
|
||||||
targetAssembly=
|
targetAssembly=
|
||||||
|
|
||||||
|
; -----------------------------------------------------------------------------
|
||||||
|
; LED settings
|
||||||
|
; -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
[led15093]
|
||||||
|
; Enable emulation of the 15093-06 controlled lights, which handle the air tower
|
||||||
|
; RGBs and the rear LED panel (billboard) on the cabinet.
|
||||||
|
enable=1
|
||||||
|
|
||||||
|
[led]
|
||||||
|
; Output billboard LED strip data to a named pipe called "\\.\pipe\ongeki_led"
|
||||||
|
cabLedOutputPipe=1
|
||||||
|
; Output billboard LED strip data to serial
|
||||||
|
cabLedOutputSerial=0
|
||||||
|
|
||||||
|
; Output slider LED data to the named pipe
|
||||||
|
controllerLedOutputPipe=1
|
||||||
|
; Output slider LED data to the serial port
|
||||||
|
controllerLedOutputSerial=0
|
||||||
|
|
||||||
|
; Serial port to send data to if using serial output. Default is COM5.
|
||||||
|
;serialPort=COM5
|
||||||
|
; Baud rate for serial data
|
||||||
|
;serialBaud=921600
|
||||||
|
|
||||||
|
; Data output a sequence of bytes, with JVS-like framing.
|
||||||
|
; Each "packet" starts with 0xE0 as a sync. To avoid E0 appearing elsewhere,
|
||||||
|
; 0xD0 is used as an escape character -- if you receive D0 in the output, ignore
|
||||||
|
; it and use the next sent byte plus one instead.
|
||||||
|
;
|
||||||
|
; After the sync is one byte for the board number that was updated, followed by
|
||||||
|
; the red, green and blue values for each LED.
|
||||||
|
;
|
||||||
|
; Board 0 has 61 LEDs:
|
||||||
|
; [0]-[1]: left side button
|
||||||
|
; [2]-[8]: left pillar lower LEDs
|
||||||
|
; [9]-[17]: left pillar center LEDs
|
||||||
|
; [18]-[24]: left pillar upper LEDs
|
||||||
|
; [25]-[35]: billboard LEDs
|
||||||
|
; [36]-[42]: right pillar upper LEDs
|
||||||
|
; [43]-[51]: right pillar center LEDs
|
||||||
|
; [52]-[58]: right pillar lower LEDs
|
||||||
|
; [59]-[60]: right side button
|
||||||
|
;
|
||||||
|
; Board 1 has 6 LEDs:
|
||||||
|
; [0]-[5]: 3 left and 3 right controller buttons
|
||||||
|
;
|
||||||
|
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
; Custom IO settings
|
; Custom IO settings
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
|
@ -9,6 +9,7 @@ enum {
|
|||||||
JVS_CMD_READ_SWITCHES = 0x20,
|
JVS_CMD_READ_SWITCHES = 0x20,
|
||||||
JVS_CMD_READ_COIN = 0x21,
|
JVS_CMD_READ_COIN = 0x21,
|
||||||
JVS_CMD_READ_ANALOGS = 0x22,
|
JVS_CMD_READ_ANALOGS = 0x22,
|
||||||
|
JVS_CMD_READ_ROTARYS = 0x23,
|
||||||
JVS_CMD_WRITE_GPIO = 0x32,
|
JVS_CMD_WRITE_GPIO = 0x32,
|
||||||
JVS_CMD_RESET = 0xF0,
|
JVS_CMD_RESET = 0xF0,
|
||||||
JVS_CMD_ASSIGN_ADDR = 0xF1,
|
JVS_CMD_ASSIGN_ADDR = 0xF1,
|
||||||
@ -32,6 +33,11 @@ struct jvs_req_read_analogs {
|
|||||||
uint8_t nanalogs;
|
uint8_t nanalogs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct jvs_req_read_rotarys {
|
||||||
|
uint8_t cmd;
|
||||||
|
uint8_t nrotarys;
|
||||||
|
};
|
||||||
|
|
||||||
struct jvs_req_reset {
|
struct jvs_req_reset {
|
||||||
uint8_t cmd;
|
uint8_t cmd;
|
||||||
uint8_t unknown;
|
uint8_t unknown;
|
||||||
|
@ -11,10 +11,13 @@
|
|||||||
#include "util/dprintf.h"
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
static HRESULT mu3_io4_poll(void *ctx, struct io4_state *state);
|
static HRESULT mu3_io4_poll(void *ctx, struct io4_state *state);
|
||||||
|
static HRESULT mu3_io4_write_gpio(uint8_t* payload, size_t len);
|
||||||
|
|
||||||
static uint16_t coins;
|
static uint16_t coins;
|
||||||
|
|
||||||
static const struct io4_ops mu3_io4_ops = {
|
static const struct io4_ops mu3_io4_ops = {
|
||||||
.poll = mu3_io4_poll,
|
.poll = mu3_io4_poll,
|
||||||
|
.write_gpio = mu3_io4_write_gpio,
|
||||||
};
|
};
|
||||||
|
|
||||||
HRESULT mu3_io4_hook_init(const struct io4_config *cfg)
|
HRESULT mu3_io4_hook_init(const struct io4_config *cfg)
|
||||||
@ -124,3 +127,46 @@ static HRESULT mu3_io4_poll(void *ctx, struct io4_state *state)
|
|||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HRESULT mu3_io4_write_gpio(uint8_t* payload, size_t len)
|
||||||
|
{
|
||||||
|
// Just fast fail if there aren't enough bytes in the payload
|
||||||
|
if (len < 3)
|
||||||
|
return S_OK;
|
||||||
|
|
||||||
|
// This command is used for lights in Ongeki, but it only contains button lights,
|
||||||
|
// and only in the first 3 bytes of the payload; everything else is padding to
|
||||||
|
// make the payload 62 bytes. The rest of the cabinet lights and the side button
|
||||||
|
// lights are handled separately, by the 15093 lights controller.
|
||||||
|
uint32_t lights_data = (uint32_t) ((uint8_t)(payload[0]) << 24 |
|
||||||
|
(uint8_t)(payload[1]) << 16 |
|
||||||
|
(uint8_t)(payload[2]) << 8);
|
||||||
|
|
||||||
|
// Since Sega uses an odd ordering for the first part of the bitfield,
|
||||||
|
// let's normalize the data and just send over bytes for the receiver
|
||||||
|
// to interpret as RGB values.
|
||||||
|
uint8_t rgb_out[6 * 3] = {
|
||||||
|
lights_data & MU3_IO_LED_L1_R ? 0xFF : 0x00,
|
||||||
|
lights_data & MU3_IO_LED_L1_G ? 0xFF : 0x00,
|
||||||
|
lights_data & MU3_IO_LED_L1_B ? 0xFF : 0x00,
|
||||||
|
lights_data & MU3_IO_LED_L2_R ? 0xFF : 0x00,
|
||||||
|
lights_data & MU3_IO_LED_L2_G ? 0xFF : 0x00,
|
||||||
|
lights_data & MU3_IO_LED_L2_B ? 0xFF : 0x00,
|
||||||
|
lights_data & MU3_IO_LED_L3_R ? 0xFF : 0x00,
|
||||||
|
lights_data & MU3_IO_LED_L3_G ? 0xFF : 0x00,
|
||||||
|
lights_data & MU3_IO_LED_L3_B ? 0xFF : 0x00,
|
||||||
|
lights_data & MU3_IO_LED_R1_R ? 0xFF : 0x00,
|
||||||
|
lights_data & MU3_IO_LED_R1_G ? 0xFF : 0x00,
|
||||||
|
lights_data & MU3_IO_LED_R1_B ? 0xFF : 0x00,
|
||||||
|
lights_data & MU3_IO_LED_R2_R ? 0xFF : 0x00,
|
||||||
|
lights_data & MU3_IO_LED_R2_G ? 0xFF : 0x00,
|
||||||
|
lights_data & MU3_IO_LED_R2_B ? 0xFF : 0x00,
|
||||||
|
lights_data & MU3_IO_LED_R3_R ? 0xFF : 0x00,
|
||||||
|
lights_data & MU3_IO_LED_R3_G ? 0xFF : 0x00,
|
||||||
|
lights_data & MU3_IO_LED_R3_B ? 0xFF : 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
mu3_io_led_set_colors(1, rgb_out);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
@ -14,6 +14,8 @@ void mu3_io_config_load(
|
|||||||
assert(cfg != NULL);
|
assert(cfg != NULL);
|
||||||
assert(filename != NULL);
|
assert(filename != NULL);
|
||||||
|
|
||||||
|
wchar_t output_path_input[6];
|
||||||
|
|
||||||
cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", VK_F1, filename);
|
cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", VK_F1, filename);
|
||||||
cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", VK_F2, filename);
|
cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", VK_F2, filename);
|
||||||
cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", VK_F3, filename);
|
cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", VK_F3, filename);
|
||||||
@ -30,4 +32,25 @@ void mu3_io_config_load(
|
|||||||
cfg->vk_right_3 = GetPrivateProfileIntW(L"io4", L"right3", 'L', filename);
|
cfg->vk_right_3 = GetPrivateProfileIntW(L"io4", L"right3", 'L', filename);
|
||||||
cfg->vk_left_menu = GetPrivateProfileIntW(L"io4", L"leftMenu", 'U', filename);
|
cfg->vk_left_menu = GetPrivateProfileIntW(L"io4", L"leftMenu", 'U', filename);
|
||||||
cfg->vk_right_menu = GetPrivateProfileIntW(L"io4", L"rightMenu", 'O', filename);
|
cfg->vk_right_menu = GetPrivateProfileIntW(L"io4", L"rightMenu", 'O', filename);
|
||||||
|
|
||||||
|
cfg->cab_led_output_pipe = GetPrivateProfileIntW(L"led", L"cabLedOutputPipe", 1, filename);
|
||||||
|
cfg->cab_led_output_serial = GetPrivateProfileIntW(L"led", L"cabLedOutputSerial", 0, filename);
|
||||||
|
|
||||||
|
cfg->controller_led_output_pipe = GetPrivateProfileIntW(L"led", L"controllerLedOutputPipe", 1, filename);
|
||||||
|
cfg->controller_led_output_serial = GetPrivateProfileIntW(L"led", L"controllerLedOutputSerial", 0, filename);
|
||||||
|
|
||||||
|
cfg->led_serial_baud = GetPrivateProfileIntW(L"led", L"serialBaud", 921600, filename);
|
||||||
|
|
||||||
|
GetPrivateProfileStringW(
|
||||||
|
L"led",
|
||||||
|
L"serialPort",
|
||||||
|
L"COM5",
|
||||||
|
output_path_input,
|
||||||
|
_countof(output_path_input),
|
||||||
|
filename);
|
||||||
|
|
||||||
|
// Sanitize the output path. If it's a serial COM port, it needs to be prefixed
|
||||||
|
// with `\\.\`.
|
||||||
|
wcsncpy(cfg->led_serial_port, L"\\\\.\\", 4);
|
||||||
|
wcsncat_s(cfg->led_serial_port, MAX_PATH, output_path_input, MAX_PATH);
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,17 @@ struct mu3_io_config {
|
|||||||
uint8_t vk_right_3;
|
uint8_t vk_right_3;
|
||||||
uint8_t vk_left_menu;
|
uint8_t vk_left_menu;
|
||||||
uint8_t vk_right_menu;
|
uint8_t vk_right_menu;
|
||||||
|
|
||||||
|
// Which ways to output LED information are enabled
|
||||||
|
bool cab_led_output_pipe;
|
||||||
|
bool cab_led_output_serial;
|
||||||
|
|
||||||
|
bool controller_led_output_pipe;
|
||||||
|
bool controller_led_output_serial;
|
||||||
|
|
||||||
|
// The name of a COM port to output LED data on, in serial mode
|
||||||
|
wchar_t led_serial_port[12];
|
||||||
|
int32_t led_serial_baud;
|
||||||
};
|
};
|
||||||
|
|
||||||
void mu3_io_config_load(
|
void mu3_io_config_load(
|
||||||
|
23
mu3io/leddata.h
Normal file
23
mu3io/leddata.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define LED_PACKET_FRAMING 0xE0
|
||||||
|
#define LED_PACKET_ESCAPE 0xD0
|
||||||
|
#define LED_NUM_MAX 66
|
||||||
|
#define LED_BOARDS_TOTAL 2
|
||||||
|
#define LED_OUTPUT_HEADER_SIZE 2
|
||||||
|
#define LED_OUTPUT_DATA_SIZE_MAX LED_NUM_MAX * 3 * 2 // max if every byte's escaped
|
||||||
|
#define LED_OUTPUT_TOTAL_SIZE_MAX LED_OUTPUT_HEADER_SIZE + LED_OUTPUT_DATA_SIZE_MAX
|
||||||
|
|
||||||
|
// This struct is used to send data related to the button and cab LEDs
|
||||||
|
struct _ongeki_led_data_buf_t {
|
||||||
|
byte framing; // Sync byte
|
||||||
|
uint8_t board; // LED output the data is for (0: cab, 1: control deck)
|
||||||
|
byte data[LED_OUTPUT_DATA_SIZE_MAX]; // Buffer for LEDs
|
||||||
|
byte data_len; // How many bytes to output from the buffer
|
||||||
|
};
|
||||||
|
|
||||||
|
static byte ongeki_led_board_data_lens[LED_BOARDS_TOTAL] = {9*3, 6*3};
|
130
mu3io/ledoutput.c
Normal file
130
mu3io/ledoutput.c
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <process.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "mu3io/config.h"
|
||||||
|
#include "mu3io/leddata.h"
|
||||||
|
#include "mu3io/ledoutput.h"
|
||||||
|
#include "mu3io/pipeimpl.h"
|
||||||
|
#include "mu3io/serialimpl.h"
|
||||||
|
|
||||||
|
static struct _ongeki_led_data_buf_t mu3_led_unescaped_buf[LED_BOARDS_TOTAL];
|
||||||
|
static struct _ongeki_led_data_buf_t mu3_led_escaped_buf[LED_BOARDS_TOTAL];
|
||||||
|
|
||||||
|
static bool mu3_led_output_is_init = false;
|
||||||
|
static struct mu3_io_config* mu3_io_config;
|
||||||
|
static bool mu3_led_any_outputs_enabled;
|
||||||
|
|
||||||
|
HANDLE mu3_led_init_mutex;
|
||||||
|
|
||||||
|
HRESULT mu3_led_output_init(struct mu3_io_config* const cfg)
|
||||||
|
{
|
||||||
|
DWORD dwWaitResult = WaitForSingleObject(mu3_led_init_mutex, INFINITE);
|
||||||
|
if (dwWaitResult == WAIT_FAILED)
|
||||||
|
{
|
||||||
|
return HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
}
|
||||||
|
else if (dwWaitResult != WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mu3_led_output_is_init)
|
||||||
|
{
|
||||||
|
mu3_io_config = cfg;
|
||||||
|
|
||||||
|
// Setup the framing bytes for the packets
|
||||||
|
for (int i = 0; i < LED_BOARDS_TOTAL; i++) {
|
||||||
|
mu3_led_unescaped_buf[i].framing = LED_PACKET_FRAMING;
|
||||||
|
mu3_led_unescaped_buf[i].board = i;
|
||||||
|
mu3_led_unescaped_buf[i].data_len = ongeki_led_board_data_lens[i];
|
||||||
|
|
||||||
|
mu3_led_escaped_buf[i].framing = LED_PACKET_FRAMING;
|
||||||
|
mu3_led_escaped_buf[i].board = i;
|
||||||
|
mu3_led_escaped_buf[i].data_len = ongeki_led_board_data_lens[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
mu3_led_any_outputs_enabled = mu3_io_config->cab_led_output_pipe || mu3_io_config->controller_led_output_pipe
|
||||||
|
|| mu3_io_config->cab_led_output_serial || mu3_io_config->controller_led_output_serial;
|
||||||
|
|
||||||
|
if (mu3_io_config->cab_led_output_pipe || mu3_io_config->controller_led_output_pipe)
|
||||||
|
{
|
||||||
|
mu3_led_pipe_init(); // don't really care about errors here tbh
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mu3_io_config->cab_led_output_serial || mu3_io_config->controller_led_output_serial)
|
||||||
|
{
|
||||||
|
mu3_led_serial_init(mu3_io_config->led_serial_port, mu3_io_config->led_serial_baud);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mu3_led_output_is_init = true;
|
||||||
|
|
||||||
|
ReleaseMutex(mu3_led_init_mutex);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct _ongeki_led_data_buf_t* escape_led_data(struct _ongeki_led_data_buf_t* unescaped)
|
||||||
|
{
|
||||||
|
struct _ongeki_led_data_buf_t* out_struct = &mu3_led_escaped_buf[unescaped->board];
|
||||||
|
|
||||||
|
byte* in_buf = unescaped->data;
|
||||||
|
byte* out_buf = out_struct->data;
|
||||||
|
int i = 0;
|
||||||
|
int o = 0;
|
||||||
|
|
||||||
|
while (i < unescaped->data_len)
|
||||||
|
{
|
||||||
|
byte b = in_buf[i++];
|
||||||
|
if (b == LED_PACKET_FRAMING || b == LED_PACKET_ESCAPE)
|
||||||
|
{
|
||||||
|
out_buf[o++] = LED_PACKET_ESCAPE;
|
||||||
|
b--;
|
||||||
|
}
|
||||||
|
out_buf[o++] = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_struct->data_len = o;
|
||||||
|
|
||||||
|
return out_struct;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mu3_led_output_update(int board, const byte* rgb)
|
||||||
|
{
|
||||||
|
if (board < 0 || board > 1 || !mu3_led_any_outputs_enabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(mu3_led_unescaped_buf[board].data, rgb, mu3_led_unescaped_buf[board].data_len);
|
||||||
|
struct _ongeki_led_data_buf_t* escaped_data = escape_led_data(&mu3_led_unescaped_buf[board]);
|
||||||
|
|
||||||
|
if (board == 0)
|
||||||
|
{
|
||||||
|
// cab
|
||||||
|
if (mu3_io_config->cab_led_output_pipe)
|
||||||
|
{
|
||||||
|
mu3_led_pipe_update(escaped_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mu3_io_config->cab_led_output_serial)
|
||||||
|
{
|
||||||
|
mu3_led_serial_update(escaped_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// slider
|
||||||
|
if (mu3_io_config->controller_led_output_pipe)
|
||||||
|
{
|
||||||
|
mu3_led_pipe_update(escaped_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mu3_io_config->controller_led_output_serial)
|
||||||
|
{
|
||||||
|
mu3_led_serial_update(escaped_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
mu3io/ledoutput.h
Normal file
20
mu3io/ledoutput.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
LED output functions
|
||||||
|
|
||||||
|
Credits:
|
||||||
|
somewhatlurker, skogaby
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "mu3io/config.h"
|
||||||
|
|
||||||
|
extern HANDLE mu3_led_init_mutex;
|
||||||
|
|
||||||
|
HRESULT mu3_led_output_init(struct mu3_io_config* const cfg);
|
||||||
|
void mu3_led_output_update(int board, const byte* rgb);
|
@ -8,9 +8,16 @@ mu3io_lib = static_library(
|
|||||||
xinput_lib,
|
xinput_lib,
|
||||||
],
|
],
|
||||||
sources : [
|
sources : [
|
||||||
'mu3io.c',
|
|
||||||
'mu3io.h',
|
|
||||||
'config.c',
|
'config.c',
|
||||||
'config.h',
|
'config.h',
|
||||||
|
'leddata.h',
|
||||||
|
'ledoutput.c',
|
||||||
|
'ledoutput.h',
|
||||||
|
'mu3io.c',
|
||||||
|
'mu3io.h',
|
||||||
|
'pipeimpl.c',
|
||||||
|
'pipeimpl.h',
|
||||||
|
'serialimpl.c',
|
||||||
|
'serialimpl.h'
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#include "mu3io/mu3io.h"
|
#include "mu3io/mu3io.h"
|
||||||
#include "mu3io/config.h"
|
#include "mu3io/config.h"
|
||||||
|
#include "mu3io/ledoutput.h"
|
||||||
|
|
||||||
#include "util/dprintf.h"
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
static uint8_t mu3_opbtn;
|
static uint8_t mu3_opbtn;
|
||||||
@ -32,7 +34,17 @@ HRESULT mu3_io_init(void)
|
|||||||
dprintf("XInput: Mouse lever emulation : %i\n", mu3_io_cfg.use_mouse);
|
dprintf("XInput: Mouse lever emulation : %i\n", mu3_io_cfg.use_mouse);
|
||||||
dprintf("XInput: --- End configuration ---\n");
|
dprintf("XInput: --- End configuration ---\n");
|
||||||
|
|
||||||
return S_OK;
|
mu3_led_init_mutex = CreateMutex(
|
||||||
|
NULL, // default security attributes
|
||||||
|
FALSE, // initially not owned
|
||||||
|
NULL); // unnamed mutex
|
||||||
|
|
||||||
|
if (mu3_led_init_mutex == NULL)
|
||||||
|
{
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mu3_led_output_init(&mu3_io_cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT mu3_io_poll(void)
|
HRESULT mu3_io_poll(void)
|
||||||
@ -203,5 +215,5 @@ HRESULT mu3_io_led_init(void)
|
|||||||
|
|
||||||
void mu3_io_led_set_colors(uint8_t board, uint8_t *rgb)
|
void mu3_io_led_set_colors(uint8_t board, uint8_t *rgb)
|
||||||
{
|
{
|
||||||
return;
|
mu3_led_output_update(board, rgb);
|
||||||
}
|
}
|
||||||
|
160
mu3io/pipeimpl.c
Normal file
160
mu3io/pipeimpl.c
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <process.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "mu3io/leddata.h"
|
||||||
|
#include "mu3io/pipeimpl.h"
|
||||||
|
|
||||||
|
static bool mu3_pipe_update[LED_BOARDS_TOTAL];
|
||||||
|
|
||||||
|
// incoming data is copied into these to ensure it isn't written during output
|
||||||
|
static struct _ongeki_led_data_buf_t mu3_pipe_write_buf[LED_BOARDS_TOTAL];
|
||||||
|
static HANDLE mu3_pipe_write_mutex;
|
||||||
|
|
||||||
|
static HRESULT mu3_pipe_create(LPHANDLE hPipe, LPCWSTR lpszPipename, DWORD dwBufSize)
|
||||||
|
{
|
||||||
|
*hPipe = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
|
*hPipe = CreateNamedPipeW(
|
||||||
|
lpszPipename, // pipe name
|
||||||
|
PIPE_ACCESS_OUTBOUND, // read/write access
|
||||||
|
PIPE_TYPE_BYTE | // byte type pipe
|
||||||
|
PIPE_WAIT, // blocking mode
|
||||||
|
PIPE_UNLIMITED_INSTANCES, // max. instances
|
||||||
|
dwBufSize, // output buffer size
|
||||||
|
0, // input buffer size
|
||||||
|
0, // client time-out
|
||||||
|
NULL); // default security attribute
|
||||||
|
|
||||||
|
if (*hPipe == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT mu3_pipe_write(HANDLE hPipe, LPCVOID lpBuffer, DWORD dwSize)
|
||||||
|
{
|
||||||
|
DWORD cbWritten = 0;
|
||||||
|
|
||||||
|
bool fSuccess = WriteFile(
|
||||||
|
hPipe,
|
||||||
|
lpBuffer,
|
||||||
|
dwSize,
|
||||||
|
&cbWritten,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!fSuccess || cbWritten != dwSize)
|
||||||
|
{
|
||||||
|
DWORD last_err = GetLastError();
|
||||||
|
return (last_err == ERROR_BROKEN_PIPE) ? E_ABORT : E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int __stdcall mu3_io_led_pipe_thread_proc(void *ctx)
|
||||||
|
{
|
||||||
|
HANDLE hPipe;
|
||||||
|
LPCWSTR lpszPipename = L"\\\\.\\pipe\\ongeki_led";
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
hPipe = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
|
if (mu3_pipe_create(&hPipe, lpszPipename, LED_OUTPUT_TOTAL_SIZE_MAX) != S_OK)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for a connection to the pipe
|
||||||
|
bool fConnected = ConnectNamedPipe(hPipe, NULL) ?
|
||||||
|
true : (GetLastError() == ERROR_PIPE_CONNECTED);
|
||||||
|
|
||||||
|
while (fConnected)
|
||||||
|
{
|
||||||
|
if (WaitForSingleObject(mu3_pipe_write_mutex, INFINITE) != WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < LED_BOARDS_TOTAL; i++) {
|
||||||
|
if (mu3_pipe_update[i])
|
||||||
|
{
|
||||||
|
HRESULT result = mu3_pipe_write(
|
||||||
|
hPipe,
|
||||||
|
&mu3_pipe_write_buf[i],
|
||||||
|
LED_OUTPUT_HEADER_SIZE + mu3_pipe_write_buf[i].data_len);
|
||||||
|
|
||||||
|
if (result != S_OK)
|
||||||
|
{
|
||||||
|
//if (result == E_ABORT)
|
||||||
|
//{
|
||||||
|
fConnected = false;
|
||||||
|
//}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mu3_pipe_update[i] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReleaseMutex(mu3_pipe_write_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
FlushFileBuffers(hPipe);
|
||||||
|
DisconnectNamedPipe(hPipe);
|
||||||
|
CloseHandle(hPipe);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT mu3_led_pipe_init()
|
||||||
|
{
|
||||||
|
mu3_pipe_write_mutex = CreateMutex(
|
||||||
|
NULL, // default security attributes
|
||||||
|
FALSE, // initially not owned
|
||||||
|
NULL); // unnamed mutex
|
||||||
|
|
||||||
|
if (mu3_pipe_write_mutex == NULL)
|
||||||
|
{
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear out update bools
|
||||||
|
for (int i = 0; i < LED_BOARDS_TOTAL; i++) {
|
||||||
|
mu3_pipe_update[i] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_beginthreadex(
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
mu3_io_led_pipe_thread_proc,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mu3_led_pipe_update(struct _ongeki_led_data_buf_t* data)
|
||||||
|
{
|
||||||
|
if (data->board > 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WaitForSingleObject(mu3_pipe_write_mutex, INFINITE) != WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&mu3_pipe_write_buf[data->board], data, sizeof(struct _ongeki_led_data_buf_t));
|
||||||
|
mu3_pipe_update[data->board] = true;
|
||||||
|
|
||||||
|
ReleaseMutex(mu3_pipe_write_mutex);
|
||||||
|
}
|
15
mu3io/pipeimpl.h
Normal file
15
mu3io/pipeimpl.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
Pipe implementation for chuniio
|
||||||
|
|
||||||
|
Credits:
|
||||||
|
somewhatlurker, skogaby
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include "mu3io/leddata.h"
|
||||||
|
|
||||||
|
HRESULT mu3_led_pipe_init();
|
||||||
|
void mu3_led_pipe_update(struct _ongeki_led_data_buf_t* data);
|
88
mu3io/serialimpl.c
Normal file
88
mu3io/serialimpl.c
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <process.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "mu3io/leddata.h"
|
||||||
|
#include "mu3io/serialimpl.h"
|
||||||
|
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
|
static HANDLE mu3_serial_port;
|
||||||
|
|
||||||
|
HRESULT mu3_led_serial_init(wchar_t led_com[12], DWORD baud)
|
||||||
|
{
|
||||||
|
// Setup the serial communications
|
||||||
|
BOOL status;
|
||||||
|
|
||||||
|
mu3_serial_port = CreateFileW(led_com,
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (mu3_serial_port == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
dprintf("Ongeki Serial LEDs: Failed to open COM port (attempted on %S)\n", led_com);
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DCB dcb_serial_params = { 0 };
|
||||||
|
dcb_serial_params.DCBlength = sizeof(dcb_serial_params);
|
||||||
|
status = GetCommState(mu3_serial_port, &dcb_serial_params);
|
||||||
|
|
||||||
|
dcb_serial_params.BaudRate = baud;
|
||||||
|
dcb_serial_params.ByteSize = 8;
|
||||||
|
dcb_serial_params.StopBits = ONESTOPBIT;
|
||||||
|
dcb_serial_params.Parity = NOPARITY;
|
||||||
|
SetCommState(mu3_serial_port, &dcb_serial_params);
|
||||||
|
|
||||||
|
COMMTIMEOUTS timeouts = { 0 };
|
||||||
|
timeouts.ReadIntervalTimeout = 50;
|
||||||
|
timeouts.ReadTotalTimeoutConstant = 50;
|
||||||
|
timeouts.ReadTotalTimeoutMultiplier = 10;
|
||||||
|
timeouts.WriteTotalTimeoutConstant = 50;
|
||||||
|
timeouts.WriteTotalTimeoutMultiplier = 10;
|
||||||
|
|
||||||
|
SetCommTimeouts(mu3_serial_port, &timeouts);
|
||||||
|
|
||||||
|
if (!status)
|
||||||
|
{
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mu3_led_serial_update(struct _ongeki_led_data_buf_t* data)
|
||||||
|
{
|
||||||
|
if (data->board > 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mu3_serial_port != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
DWORD bytes_written = 0;
|
||||||
|
|
||||||
|
BOOL status = WriteFile(
|
||||||
|
mu3_serial_port,
|
||||||
|
data,
|
||||||
|
LED_OUTPUT_HEADER_SIZE + data->data_len,
|
||||||
|
&bytes_written,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!status)
|
||||||
|
{
|
||||||
|
DWORD last_err = GetLastError();
|
||||||
|
dprintf("Ongeki Serial LEDs: Serial port write failed -- %d\n", (int) last_err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dprintf("Ongeki Serial LEDs: Invalid serial port handle\n");
|
||||||
|
}
|
||||||
|
}
|
15
mu3io/serialimpl.h
Normal file
15
mu3io/serialimpl.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
Serial LED implementation for chuniio
|
||||||
|
|
||||||
|
Credits:
|
||||||
|
somewhatlurker, skogaby
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include "mu3io/leddata.h"
|
||||||
|
|
||||||
|
HRESULT mu3_led_serial_init(wchar_t led_com[12], DWORD baud);
|
||||||
|
void mu3_led_serial_update(struct _ongeki_led_data_buf_t* data);
|
Loading…
Reference in New Issue
Block a user