forked from Dniel97/segatools
chuni/chusan: added LED output to DLLs (will break most DLLs)
Credits: somewhatlurker, skogaby https://dev.s-ul.net/skogaby/segatools/-/blob/ongeki-15093/
This commit is contained in:
parent
ed042176d7
commit
8ebdf67d6e
@ -103,11 +103,16 @@ static uint16_t led15093_fw_sum;
|
|||||||
static uint8_t led15093_board_adr = 1;
|
static uint8_t led15093_board_adr = 1;
|
||||||
static uint8_t led15093_host_adr = 1;
|
static uint8_t led15093_host_adr = 1;
|
||||||
|
|
||||||
HRESULT led15093_hook_init(const struct led15093_config *cfg, unsigned int first_port,
|
static io_led_init_t led_init;
|
||||||
unsigned int num_boards, uint8_t board_adr, uint8_t host_adr)
|
static io_led_set_leds_t set_leds;
|
||||||
|
|
||||||
|
HRESULT led15093_hook_init(const struct led15093_config *cfg, io_led_init_t _led_init,
|
||||||
|
io_led_set_leds_t _set_leds, unsigned int first_port, unsigned int num_boards, uint8_t board_adr, uint8_t host_adr)
|
||||||
{
|
{
|
||||||
|
|
||||||
assert(cfg != NULL);
|
assert(cfg != NULL);
|
||||||
|
assert(_led_init != NULL);
|
||||||
|
assert(_set_leds != NULL);
|
||||||
|
|
||||||
if (!cfg->enable) {
|
if (!cfg->enable) {
|
||||||
return S_FALSE;
|
return S_FALSE;
|
||||||
@ -117,6 +122,8 @@ HRESULT led15093_hook_init(const struct led15093_config *cfg, unsigned int first
|
|||||||
first_port = cfg->port_no;
|
first_port = cfg->port_no;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
led_init = _led_init;
|
||||||
|
set_leds = _set_leds;
|
||||||
led15093_board_adr = board_adr;
|
led15093_board_adr = board_adr;
|
||||||
led15093_host_adr = host_adr;
|
led15093_host_adr = host_adr;
|
||||||
|
|
||||||
@ -207,9 +214,9 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp)
|
|||||||
|
|
||||||
if (!v->started) {
|
if (!v->started) {
|
||||||
dprintf("LED 15093: Starting LED backend\n");
|
dprintf("LED 15093: Starting LED backend\n");
|
||||||
// hr = fgo_dll.led_init();
|
hr = led_init();
|
||||||
hr = S_OK;
|
|
||||||
|
|
||||||
|
// hr = S_OK;
|
||||||
v->started = true;
|
v->started = true;
|
||||||
v->start_hr = hr;
|
v->start_hr = hr;
|
||||||
|
|
||||||
@ -229,6 +236,19 @@ static HRESULT led15093_handle_irp_locked(int board, struct irp *irp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if (irp->op == IRP_OP_OPEN) {
|
||||||
|
dprintf("LED 15093: Starting backend DLL\n");
|
||||||
|
int res = led_init();
|
||||||
|
|
||||||
|
if (res != 0) {
|
||||||
|
dprintf("LED 15093: Backend error, LED board disconnected: "
|
||||||
|
"%d\n",
|
||||||
|
res);
|
||||||
|
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hr = uart_handle_irp(boarduart, irp);
|
hr = uart_handle_irp(boarduart, irp);
|
||||||
|
|
||||||
@ -624,6 +644,9 @@ static HRESULT led15093_req_set_led(int board, const struct led15093_req_set_led
|
|||||||
|
|
||||||
memcpy(v->led, req->data, req->hdr.nbytes - 1);
|
memcpy(v->led, req->data, req->hdr.nbytes - 1);
|
||||||
|
|
||||||
|
// Return the current LED data, remove const qualifier
|
||||||
|
set_leds(board, (uint8_t *) req->data);
|
||||||
|
|
||||||
if (!v->enable_response)
|
if (!v->enable_response)
|
||||||
return S_OK;
|
return S_OK;
|
||||||
|
|
||||||
|
@ -16,6 +16,9 @@ struct led15093_config {
|
|||||||
uint16_t fw_sum;
|
uint16_t fw_sum;
|
||||||
};
|
};
|
||||||
|
|
||||||
HRESULT led15093_hook_init(const struct led15093_config *cfg, unsigned int first_port,
|
typedef int (*io_led_init_t)();
|
||||||
unsigned int num_boards, uint8_t board_adr, uint8_t host_adr);
|
typedef void (*io_led_set_leds_t)(uint8_t board, uint8_t *rgb);
|
||||||
|
|
||||||
|
HRESULT led15093_hook_init(const struct led15093_config *cfg, io_led_init_t _led_init,
|
||||||
|
io_led_set_leds_t _set_leds, unsigned int first_port, unsigned int num_boards, uint8_t board_adr, uint8_t host_adr);
|
||||||
|
|
||||||
|
@ -30,6 +30,12 @@ const struct dll_bind_sym chuni_dll_syms[] = {
|
|||||||
}, {
|
}, {
|
||||||
.sym = "chuni_io_slider_set_leds",
|
.sym = "chuni_io_slider_set_leds",
|
||||||
.off = offsetof(struct chuni_dll, slider_set_leds),
|
.off = offsetof(struct chuni_dll, slider_set_leds),
|
||||||
|
}, {
|
||||||
|
.sym = "chuni_io_led_init",
|
||||||
|
.off = offsetof(struct chuni_dll, led_init),
|
||||||
|
}, {
|
||||||
|
.sym = "chuni_io_led_set_colors",
|
||||||
|
.off = offsetof(struct chuni_dll, led_set_leds),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ struct chuni_dll {
|
|||||||
void (*slider_start)(chuni_io_slider_callback_t callback);
|
void (*slider_start)(chuni_io_slider_callback_t callback);
|
||||||
void (*slider_stop)(void);
|
void (*slider_stop)(void);
|
||||||
void (*slider_set_leds)(const uint8_t *rgb);
|
void (*slider_set_leds)(const uint8_t *rgb);
|
||||||
|
int (*led_init)();
|
||||||
|
void (*led_set_leds)(uint8_t board, uint8_t *rgb);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct chuni_dll_config {
|
struct chuni_dll_config {
|
||||||
|
@ -20,3 +20,5 @@ EXPORTS
|
|||||||
chuni_io_slider_set_leds
|
chuni_io_slider_set_leds
|
||||||
chuni_io_slider_start
|
chuni_io_slider_start
|
||||||
chuni_io_slider_stop
|
chuni_io_slider_stop
|
||||||
|
chuni_io_led_init
|
||||||
|
chuni_io_led_set_colors
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "amex/amex.h"
|
#include "amex/amex.h"
|
||||||
|
|
||||||
|
#include "board/led15093.h"
|
||||||
#include "board/sg-reader.h"
|
#include "board/sg-reader.h"
|
||||||
|
|
||||||
#include "chunihook/config.h"
|
#include "chunihook/config.h"
|
||||||
@ -96,7 +97,8 @@ static DWORD CALLBACK chuni_pre_startup(void)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = led15093_hook_init(&chuni_hook_cfg.led15093, 10, 2, 2, 1);
|
hr = led15093_hook_init(&chuni_hook_cfg.led15093,
|
||||||
|
chuni_dll.led_init, chuni_dll.led_set_leds, 10, 2, 2, 1);
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "chuniio/chuniio.h"
|
#include "chuniio/chuniio.h"
|
||||||
#include "chuniio/config.h"
|
#include "chuniio/config.h"
|
||||||
|
#include "chuniio/ledoutput.h"
|
||||||
|
|
||||||
#include "util/dprintf.h"
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
@ -18,7 +19,6 @@ static uint8_t chuni_io_hand_pos;
|
|||||||
static HANDLE chuni_io_slider_thread;
|
static HANDLE chuni_io_slider_thread;
|
||||||
static bool chuni_io_slider_stop_flag;
|
static bool chuni_io_slider_stop_flag;
|
||||||
static struct chuni_io_config chuni_io_cfg;
|
static struct chuni_io_config chuni_io_cfg;
|
||||||
static HANDLE chuni_io_slider_led_port;
|
|
||||||
|
|
||||||
uint16_t chuni_io_get_api_version(void)
|
uint16_t chuni_io_get_api_version(void)
|
||||||
{
|
{
|
||||||
@ -28,7 +28,17 @@ uint16_t chuni_io_get_api_version(void)
|
|||||||
HRESULT chuni_io_jvs_init(void)
|
HRESULT chuni_io_jvs_init(void)
|
||||||
{
|
{
|
||||||
chuni_io_config_load(&chuni_io_cfg, L".\\segatools.ini");
|
chuni_io_config_load(&chuni_io_cfg, L".\\segatools.ini");
|
||||||
|
|
||||||
|
led_init_mutex = CreateMutex(
|
||||||
|
NULL, // default security attributes
|
||||||
|
FALSE, // initially not owned
|
||||||
|
NULL); // unnamed mutex
|
||||||
|
|
||||||
|
if (led_init_mutex == NULL)
|
||||||
|
{
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +103,7 @@ void chuni_io_jvs_poll(uint8_t *opbtn, uint8_t *beams)
|
|||||||
|
|
||||||
HRESULT chuni_io_slider_init(void)
|
HRESULT chuni_io_slider_init(void)
|
||||||
{
|
{
|
||||||
return S_OK;
|
return led_output_init(&chuni_io_cfg); // because of slider LEDs
|
||||||
}
|
}
|
||||||
|
|
||||||
void chuni_io_slider_start(chuni_io_slider_callback_t callback)
|
void chuni_io_slider_start(chuni_io_slider_callback_t callback)
|
||||||
@ -111,39 +121,6 @@ void chuni_io_slider_start(chuni_io_slider_callback_t callback)
|
|||||||
callback,
|
callback,
|
||||||
0,
|
0,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
chuni_io_slider_led_port = CreateFileW(chuni_io_cfg.led_com,
|
|
||||||
GENERIC_READ | GENERIC_WRITE,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
OPEN_EXISTING,
|
|
||||||
0,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (chuni_io_slider_led_port == INVALID_HANDLE_VALUE)
|
|
||||||
dprintf("Chunithm LEDs: Failed to open COM port (Attempted on %S)\n", chuni_io_cfg.led_com);
|
|
||||||
else
|
|
||||||
dprintf("Chunithm LEDs: COM Port Success!\n");
|
|
||||||
|
|
||||||
DCB dcb_serial_params = { 0 };
|
|
||||||
dcb_serial_params.DCBlength = sizeof(dcb_serial_params);
|
|
||||||
status = GetCommState(chuni_io_slider_led_port, &dcb_serial_params);
|
|
||||||
|
|
||||||
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
|
|
||||||
SetCommState(chuni_io_slider_led_port, &dcb_serial_params);
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
SetCommTimeouts(chuni_io_slider_led_port, &timeouts);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void chuni_io_slider_stop(void)
|
void chuni_io_slider_stop(void)
|
||||||
@ -158,34 +135,11 @@ void chuni_io_slider_stop(void)
|
|||||||
CloseHandle(chuni_io_slider_thread);
|
CloseHandle(chuni_io_slider_thread);
|
||||||
chuni_io_slider_thread = NULL;
|
chuni_io_slider_thread = NULL;
|
||||||
chuni_io_slider_stop_flag = false;
|
chuni_io_slider_stop_flag = false;
|
||||||
|
|
||||||
dprintf("Chunithm LEDs: Closing COM port\n");
|
|
||||||
CloseHandle(chuni_io_slider_led_port);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void chuni_io_slider_set_leds(const uint8_t *rgb)
|
void chuni_io_slider_set_leds(const uint8_t *rgb)
|
||||||
{
|
{
|
||||||
if (chuni_io_slider_led_port != INVALID_HANDLE_VALUE)
|
led_output_update(2, rgb);
|
||||||
{
|
|
||||||
char led_buffer[100];
|
|
||||||
DWORD bytes_to_write; // No of bytes to write into the port
|
|
||||||
DWORD bytes_written = 0; // No of bytes written to the port
|
|
||||||
bytes_to_write = sizeof(led_buffer);
|
|
||||||
BOOL status;
|
|
||||||
|
|
||||||
led_buffer[0] = 0xAA;
|
|
||||||
led_buffer[1] = 0xAA;
|
|
||||||
memcpy(led_buffer+2, rgb, sizeof(uint8_t) * 96);
|
|
||||||
led_buffer[98] = 0xDD;
|
|
||||||
led_buffer[99] = 0xDD;
|
|
||||||
|
|
||||||
status = WriteFile(chuni_io_slider_led_port, // Handle to the Serial port
|
|
||||||
led_buffer, // Data to be written to the port
|
|
||||||
bytes_to_write, //No of bytes to write
|
|
||||||
&bytes_written, //Bytes written
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx)
|
static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx)
|
||||||
@ -211,3 +165,13 @@ static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int chuni_io_led_init()
|
||||||
|
{
|
||||||
|
return led_output_init(&chuni_io_cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void chuni_io_led_set_colors(uint8_t board, uint8_t *rgb)
|
||||||
|
{
|
||||||
|
led_output_update(board, rgb);
|
||||||
|
}
|
||||||
|
@ -145,3 +145,21 @@ void chuni_io_slider_stop(void);
|
|||||||
Minimum API version: 0x0100 */
|
Minimum API version: 0x0100 */
|
||||||
|
|
||||||
void chuni_io_slider_set_leds(const uint8_t *rgb);
|
void chuni_io_slider_set_leds(const uint8_t *rgb);
|
||||||
|
|
||||||
|
/* Initialize LED emulation. This function will be called before any
|
||||||
|
other chuni_io_led_*() function calls.
|
||||||
|
|
||||||
|
All subsequent calls may originate from arbitrary threads and some may
|
||||||
|
overlap with each other. Ensuring synchronization inside your IO DLL is
|
||||||
|
your responsibility. */
|
||||||
|
|
||||||
|
int chuni_io_led_init();
|
||||||
|
|
||||||
|
/* Update the RGB LEDs. rgb is a pointer to an array of 66 * 3 = 198
|
||||||
|
bytes. The majority of these are for the marquee display, but the final
|
||||||
|
LEDs are for the side partitions.
|
||||||
|
|
||||||
|
Chunithm uses two chains/boards. One is on the left side and one on the
|
||||||
|
right side of the cab. Exact layout is TBD. */
|
||||||
|
|
||||||
|
void chuni_io_led_set_colors(uint8_t board, uint8_t *rgb);
|
||||||
|
@ -57,7 +57,24 @@ void chuni_io_config_load(
|
|||||||
filename);
|
filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
GetPrivateProfileStringW(L"slider", L"ledport", L"COM5", port_input, 6, filename);
|
cfg->led_output_pipe = GetPrivateProfileIntW(L"led", L"cabLedOutputPipe", 1, filename);
|
||||||
wcsncpy(cfg->led_com, L"\\\\.\\", 4);
|
cfg->led_output_serial = GetPrivateProfileIntW(L"led", L"cabLedOutputSerial", 0, filename);
|
||||||
wcsncat_s(cfg->led_com, 11, port_input, 6);
|
|
||||||
|
cfg->slider_led_output_pipe = GetPrivateProfileIntW(L"led", L"controllerLedOutputPipe", 1, filename);
|
||||||
|
cfg->slider_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",
|
||||||
|
port_input,
|
||||||
|
6,
|
||||||
|
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, 11, port_input, 6);
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,18 @@ struct chuni_io_config {
|
|||||||
uint8_t vk_ir_emu;
|
uint8_t vk_ir_emu;
|
||||||
uint8_t vk_ir[6];
|
uint8_t vk_ir[6];
|
||||||
uint8_t vk_cell[32];
|
uint8_t vk_cell[32];
|
||||||
wchar_t led_com[12];
|
|
||||||
|
// Which ways to output LED information are enabled
|
||||||
|
bool led_output_pipe;
|
||||||
|
bool led_output_serial;
|
||||||
|
|
||||||
|
bool slider_led_output_pipe;
|
||||||
|
bool slider_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 chuni_io_config_load(
|
void chuni_io_config_load(
|
||||||
|
22
chuniio/leddata.h
Normal file
22
chuniio/leddata.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#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 3
|
||||||
|
#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 slider and billboard LEDs
|
||||||
|
struct _chuni_led_data_buf_t {
|
||||||
|
byte framing; // Sync byte
|
||||||
|
uint8_t board; // LED output the data is for (0-1: billboard, 2: slider)
|
||||||
|
byte data[LED_OUTPUT_DATA_SIZE_MAX]; // Buffer for LEDs
|
||||||
|
byte data_len; // How many bytes to output from the buffer
|
||||||
|
};
|
||||||
|
|
||||||
|
static byte chuni_led_board_data_lens[LED_BOARDS_TOTAL] = {53*3, 63*3, 31*3};
|
133
chuniio/ledoutput.c
Normal file
133
chuniio/ledoutput.c
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <process.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "chuniio/config.h"
|
||||||
|
#include "chuniio/leddata.h"
|
||||||
|
#include "chuniio/ledoutput.h"
|
||||||
|
#include "chuniio/pipeimpl.h"
|
||||||
|
#include "chuniio/serialimpl.h"
|
||||||
|
|
||||||
|
static struct _chuni_led_data_buf_t led_unescaped_buf[LED_BOARDS_TOTAL];
|
||||||
|
static struct _chuni_led_data_buf_t led_escaped_buf[LED_BOARDS_TOTAL];
|
||||||
|
|
||||||
|
static bool led_output_is_init = false;
|
||||||
|
static struct chuni_io_config* config;
|
||||||
|
static bool any_outputs_enabled;
|
||||||
|
|
||||||
|
HANDLE led_init_mutex;
|
||||||
|
|
||||||
|
int led_output_init(struct chuni_io_config* const cfg)
|
||||||
|
{
|
||||||
|
DWORD dwWaitResult = WaitForSingleObject(led_init_mutex, INFINITE);
|
||||||
|
if (dwWaitResult == WAIT_FAILED)
|
||||||
|
{
|
||||||
|
// return HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (dwWaitResult != WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
// return E_FAIL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!led_output_is_init)
|
||||||
|
{
|
||||||
|
config = cfg;
|
||||||
|
|
||||||
|
// Setup the framing bytes for the packets
|
||||||
|
for (int i = 0; i < LED_BOARDS_TOTAL; i++) {
|
||||||
|
led_unescaped_buf[i].framing = LED_PACKET_FRAMING;
|
||||||
|
led_unescaped_buf[i].board = i;
|
||||||
|
led_unescaped_buf[i].data_len = chuni_led_board_data_lens[i];
|
||||||
|
|
||||||
|
led_escaped_buf[i].framing = LED_PACKET_FRAMING;
|
||||||
|
led_escaped_buf[i].board = 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
|
||||||
|
|| config->led_output_serial || config->slider_led_output_serial;
|
||||||
|
|
||||||
|
if (config->led_output_pipe || config->slider_led_output_pipe)
|
||||||
|
{
|
||||||
|
led_pipe_init(); // don't really care about errors here tbh
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->led_output_serial || config->slider_led_output_serial)
|
||||||
|
{
|
||||||
|
led_serial_init(config->led_serial_port, config->led_serial_baud);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
led_output_is_init = true;
|
||||||
|
|
||||||
|
ReleaseMutex(led_init_mutex);
|
||||||
|
// return S_OK;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct _chuni_led_data_buf_t* escape_led_data(struct _chuni_led_data_buf_t* unescaped)
|
||||||
|
{
|
||||||
|
struct _chuni_led_data_buf_t* out_struct = &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 led_output_update(uint8_t board, const byte* rgb)
|
||||||
|
{
|
||||||
|
if (board < 0 || board > 2 || !any_outputs_enabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(led_unescaped_buf[board].data, rgb, led_unescaped_buf[board].data_len);
|
||||||
|
struct _chuni_led_data_buf_t* escaped_data = escape_led_data(&led_unescaped_buf[board]);
|
||||||
|
|
||||||
|
if (board < 2)
|
||||||
|
{
|
||||||
|
// billboard
|
||||||
|
if (config->led_output_pipe)
|
||||||
|
{
|
||||||
|
led_pipe_update(escaped_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->led_output_serial)
|
||||||
|
{
|
||||||
|
led_serial_update(escaped_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// slider
|
||||||
|
if (config->slider_led_output_pipe)
|
||||||
|
{
|
||||||
|
led_pipe_update(escaped_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->slider_led_output_serial)
|
||||||
|
{
|
||||||
|
led_serial_update(escaped_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
chuniio/ledoutput.h
Normal file
19
chuniio/ledoutput.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
LED output functions
|
||||||
|
|
||||||
|
Credits:
|
||||||
|
somewhatlurker, skogaby
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "chuniio/config.h"
|
||||||
|
|
||||||
|
extern HANDLE led_init_mutex;
|
||||||
|
int led_output_init(struct chuni_io_config* const cfg);
|
||||||
|
void led_output_update(uint8_t board, const byte* rgb);
|
@ -9,5 +9,12 @@ chuniio_lib = static_library(
|
|||||||
'chuniio.h',
|
'chuniio.h',
|
||||||
'config.c',
|
'config.c',
|
||||||
'config.h',
|
'config.h',
|
||||||
|
'leddata.h',
|
||||||
|
'ledoutput.c',
|
||||||
|
'ledoutput.h',
|
||||||
|
'pipeimpl.c',
|
||||||
|
'pipeimpl.h',
|
||||||
|
'serialimpl.c',
|
||||||
|
'serialimpl.h'
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
160
chuniio/pipeimpl.c
Normal file
160
chuniio/pipeimpl.c
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <process.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "chuniio/leddata.h"
|
||||||
|
#include "chuniio/pipeimpl.h"
|
||||||
|
|
||||||
|
static bool pipe_update[LED_BOARDS_TOTAL];
|
||||||
|
|
||||||
|
// incoming data is copied into these to ensure it isn't written during output
|
||||||
|
static struct _chuni_led_data_buf_t pipe_write_buf[LED_BOARDS_TOTAL];
|
||||||
|
static HANDLE pipe_write_mutex;
|
||||||
|
|
||||||
|
static HRESULT 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 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 chuni_io_led_pipe_thread_proc(void *ctx)
|
||||||
|
{
|
||||||
|
HANDLE hPipe;
|
||||||
|
LPCWSTR lpszPipename = L"\\\\.\\pipe\\chuni_led";
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
hPipe = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
|
if (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(pipe_write_mutex, INFINITE) != WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < LED_BOARDS_TOTAL; i++) {
|
||||||
|
if (pipe_update[i])
|
||||||
|
{
|
||||||
|
HRESULT result = pipe_write(
|
||||||
|
hPipe,
|
||||||
|
&pipe_write_buf[i],
|
||||||
|
LED_OUTPUT_HEADER_SIZE + pipe_write_buf[i].data_len);
|
||||||
|
|
||||||
|
if (result != S_OK)
|
||||||
|
{
|
||||||
|
//if (result == E_ABORT)
|
||||||
|
//{
|
||||||
|
fConnected = false;
|
||||||
|
//}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pipe_update[i] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReleaseMutex(pipe_write_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
FlushFileBuffers(hPipe);
|
||||||
|
DisconnectNamedPipe(hPipe);
|
||||||
|
CloseHandle(hPipe);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT led_pipe_init()
|
||||||
|
{
|
||||||
|
pipe_write_mutex = CreateMutex(
|
||||||
|
NULL, // default security attributes
|
||||||
|
FALSE, // initially not owned
|
||||||
|
NULL); // unnamed mutex
|
||||||
|
|
||||||
|
if (pipe_write_mutex == NULL)
|
||||||
|
{
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear out update bools
|
||||||
|
for (int i = 0; i < LED_BOARDS_TOTAL; i++) {
|
||||||
|
pipe_update[i] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_beginthreadex(
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
chuni_io_led_pipe_thread_proc,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void led_pipe_update(struct _chuni_led_data_buf_t* data)
|
||||||
|
{
|
||||||
|
if (data->board > 2)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WaitForSingleObject(pipe_write_mutex, INFINITE) != WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&pipe_write_buf[data->board], data, sizeof(struct _chuni_led_data_buf_t));
|
||||||
|
pipe_update[data->board] = true;
|
||||||
|
|
||||||
|
ReleaseMutex(pipe_write_mutex);
|
||||||
|
}
|
14
chuniio/pipeimpl.h
Normal file
14
chuniio/pipeimpl.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
Pipe implementation for chuniio
|
||||||
|
|
||||||
|
Credits:
|
||||||
|
somewhatlurker, skogaby
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include "chuniio/leddata.h"
|
||||||
|
|
||||||
|
HRESULT led_pipe_init();
|
||||||
|
void led_pipe_update(struct _chuni_led_data_buf_t* data);
|
99
chuniio/serialimpl.c
Normal file
99
chuniio/serialimpl.c
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <process.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "chuniio/leddata.h"
|
||||||
|
#include "chuniio/serialimpl.h"
|
||||||
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
|
static HANDLE serial_port;
|
||||||
|
static HANDLE serial_write_mutex;
|
||||||
|
|
||||||
|
HRESULT led_serial_init(wchar_t led_com[12], DWORD baud)
|
||||||
|
{
|
||||||
|
// Setup the serial communications
|
||||||
|
BOOL status;
|
||||||
|
|
||||||
|
serial_port = CreateFileW(led_com,
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (serial_port == INVALID_HANDLE_VALUE)
|
||||||
|
dprintf("Chunithm Serial LEDs: Failed to open COM port (Attempted on %S)\n", led_com);
|
||||||
|
else
|
||||||
|
dprintf("Chunithm Serial LEDs: COM port success!\n");
|
||||||
|
|
||||||
|
DCB dcb_serial_params = { 0 };
|
||||||
|
dcb_serial_params.DCBlength = sizeof(dcb_serial_params);
|
||||||
|
status = GetCommState(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(serial_port, &dcb_serial_params);
|
||||||
|
|
||||||
|
COMMTIMEOUTS timeouts = { 0 };
|
||||||
|
timeouts.ReadIntervalTimeout = 50;
|
||||||
|
timeouts.ReadTotalTimeoutConstant = 50;
|
||||||
|
timeouts.ReadTotalTimeoutMultiplier = 10;
|
||||||
|
timeouts.WriteTotalTimeoutConstant = 50;
|
||||||
|
timeouts.WriteTotalTimeoutMultiplier = 10;
|
||||||
|
|
||||||
|
SetCommTimeouts(serial_port, &timeouts);
|
||||||
|
|
||||||
|
if (!status)
|
||||||
|
{
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
serial_write_mutex = CreateMutex(
|
||||||
|
NULL, // default security attributes
|
||||||
|
FALSE, // initially not owned
|
||||||
|
NULL); // unnamed mutex
|
||||||
|
|
||||||
|
if (serial_write_mutex == NULL)
|
||||||
|
{
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void led_serial_update(struct _chuni_led_data_buf_t* data)
|
||||||
|
{
|
||||||
|
if (data->board > 2)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WaitForSingleObject(serial_write_mutex, INFINITE) != WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL status = true;
|
||||||
|
DWORD bytes_written = 0;
|
||||||
|
|
||||||
|
if (serial_port != INVALID_HANDLE_VALUE) {
|
||||||
|
status = WriteFile(
|
||||||
|
serial_port,
|
||||||
|
data,
|
||||||
|
LED_OUTPUT_HEADER_SIZE + data->data_len,
|
||||||
|
&bytes_written,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!status) {
|
||||||
|
DWORD last_err = GetLastError();
|
||||||
|
// dprintf("Chunithm Serial LEDs: Serial port write failed -- %d\n", last_err);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReleaseMutex(serial_write_mutex);
|
||||||
|
}
|
15
chuniio/serialimpl.h
Normal file
15
chuniio/serialimpl.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
Serial LED implementation for chuniio
|
||||||
|
|
||||||
|
Credits:
|
||||||
|
somewhatlurker, skogaby
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include "chuniio/leddata.h"
|
||||||
|
|
||||||
|
HRESULT led_serial_init(wchar_t led_com[12], DWORD baud);
|
||||||
|
void led_serial_update(struct _chuni_led_data_buf_t* data);
|
@ -30,6 +30,12 @@ const struct dll_bind_sym chuni_dll_syms[] = {
|
|||||||
}, {
|
}, {
|
||||||
.sym = "chuni_io_slider_set_leds",
|
.sym = "chuni_io_slider_set_leds",
|
||||||
.off = offsetof(struct chuni_dll, slider_set_leds),
|
.off = offsetof(struct chuni_dll, slider_set_leds),
|
||||||
|
}, {
|
||||||
|
.sym = "chuni_io_led_init",
|
||||||
|
.off = offsetof(struct chuni_dll, led_init),
|
||||||
|
}, {
|
||||||
|
.sym = "chuni_io_led_set_colors",
|
||||||
|
.off = offsetof(struct chuni_dll, led_set_leds),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ struct chuni_dll {
|
|||||||
void (*slider_start)(chuni_io_slider_callback_t callback);
|
void (*slider_start)(chuni_io_slider_callback_t callback);
|
||||||
void (*slider_stop)(void);
|
void (*slider_stop)(void);
|
||||||
void (*slider_set_leds)(const uint8_t *rgb);
|
void (*slider_set_leds)(const uint8_t *rgb);
|
||||||
|
int (*led_init)();
|
||||||
|
void (*led_set_leds)(uint8_t board, uint8_t *rgb);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct chuni_dll_config {
|
struct chuni_dll_config {
|
||||||
|
@ -20,3 +20,5 @@ EXPORTS
|
|||||||
chuni_io_slider_set_leds
|
chuni_io_slider_set_leds
|
||||||
chuni_io_slider_start
|
chuni_io_slider_start
|
||||||
chuni_io_slider_stop
|
chuni_io_slider_stop
|
||||||
|
chuni_io_led_init
|
||||||
|
chuni_io_led_set_colors
|
||||||
|
@ -129,7 +129,8 @@ static DWORD CALLBACK chusan_pre_startup(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = led15093_hook_init(&chusan_hook_cfg.led15093, first_port, 2, 2, 1);
|
hr = led15093_hook_init(&chusan_hook_cfg.led15093,
|
||||||
|
chuni_dll.led_init, chuni_dll.led_set_leds, first_port, 2, 2, 1);
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
struct led1509306_config {
|
|
||||||
bool enable;
|
|
||||||
bool cvt_port;
|
|
||||||
char board_number[8];
|
|
||||||
char chip_number[5];
|
|
||||||
uint8_t fw_ver;
|
|
||||||
uint16_t fw_sum;
|
|
||||||
};
|
|
||||||
|
|
||||||
HRESULT led1509306_hook_init(const struct led1509306_config *cfg);
|
|
71
dist/chuni/segatools.ini
vendored
71
dist/chuni/segatools.ini
vendored
@ -38,15 +38,52 @@ monitor=0
|
|||||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||||
path=
|
path=
|
||||||
|
|
||||||
[led15093]
|
|
||||||
; 837-15093-06 LED strip emulation setting.
|
|
||||||
enable=1
|
|
||||||
|
|
||||||
[chuniio]
|
[chuniio]
|
||||||
; To use a custom Chunithm IO DLL enter its path here.
|
; To use a custom Chunithm IO DLL enter its path here.
|
||||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||||
path=
|
path=
|
||||||
|
|
||||||
|
[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\chuni_ledstrip"
|
||||||
|
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 53 LEDs:
|
||||||
|
; [0]-[49]: snakes through left half of billboard (first column starts at top)
|
||||||
|
; [50]-[52]: left side partition LEDs
|
||||||
|
;
|
||||||
|
; Board 1 has 63 LEDs:
|
||||||
|
; [0]-[59]: right half of billboard (first column starts at bottom)
|
||||||
|
; [60]-[62]: right side partition LEDs
|
||||||
|
;
|
||||||
|
; Board 2 is the slider and has 31 LEDs:
|
||||||
|
; [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers
|
||||||
|
|
||||||
|
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
; Input settings
|
; Input settings
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
@ -66,6 +103,20 @@ test=0x31
|
|||||||
service=0x32
|
service=0x32
|
||||||
; Keyboard button to increment coin counter. Default is the 3 key.
|
; Keyboard button to increment coin counter. Default is the 3 key.
|
||||||
coin=0x33
|
coin=0x33
|
||||||
|
; Set to 0 for enable separate ir control. Deafult is space key.
|
||||||
|
ir=0x20
|
||||||
|
|
||||||
|
[ir]
|
||||||
|
; Uncomment and complete the following sequence of settings to configure a
|
||||||
|
; custom ir-cappable controller if you have one.
|
||||||
|
;ir6=0x53
|
||||||
|
; ... etc ...
|
||||||
|
;ir1=0x53
|
||||||
|
|
||||||
|
[slider]
|
||||||
|
; Enable slider emulation. If you have real AC slider, set this to 0.
|
||||||
|
; Slider serial port must be COM1.
|
||||||
|
;enable=1
|
||||||
|
|
||||||
; Key bindings for each of the 32 touch cells. The default key map, depicted
|
; Key bindings for each of the 32 touch cells. The default key map, depicted
|
||||||
; in left-to-right order, is as follows:
|
; in left-to-right order, is as follows:
|
||||||
@ -77,12 +128,8 @@ coin=0x33
|
|||||||
;
|
;
|
||||||
; Uncomment and complete the following sequence of settings to configure a
|
; Uncomment and complete the following sequence of settings to configure a
|
||||||
; custom high-precision touch strip controller if you have one.
|
; custom high-precision touch strip controller if you have one.
|
||||||
[slider]
|
;cell1=0x53
|
||||||
;cell32=0x53
|
;cell2=0x53
|
||||||
;cell31=0x53
|
|
||||||
;cell30=0x53
|
|
||||||
; ... etc ...
|
; ... etc ...
|
||||||
|
;cell31=0x53
|
||||||
; Enable slider LED serial output. This follows OpeNITHM Serial LED Protocol.
|
;cell32=0x53
|
||||||
; eg. COM5
|
|
||||||
;ledport=
|
|
||||||
|
45
dist/chusan/segatools.ini
vendored
45
dist/chusan/segatools.ini
vendored
@ -63,16 +63,53 @@ 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
|
||||||
|
|
||||||
[led15093]
|
|
||||||
; 837-15093-06 LED strip emulation setting.
|
|
||||||
enable=1
|
|
||||||
|
|
||||||
[chuniio]
|
[chuniio]
|
||||||
; Uncomment this if you have custom chuniio implementation.
|
; Uncomment this if you have custom chuniio implementation.
|
||||||
; x86 chuniio to path32, x64 to path64. Both are necessary.
|
; x86 chuniio to path32, x64 to path64. Both are necessary.
|
||||||
;path32=
|
;path32=
|
||||||
;path64=
|
;path64=
|
||||||
|
|
||||||
|
[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\chuni_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 53 LEDs:
|
||||||
|
; [0]-[49]: snakes through left half of billboard (first column starts at top)
|
||||||
|
; [50]-[52]: left side partition LEDs
|
||||||
|
;
|
||||||
|
; Board 1 has 63 LEDs:
|
||||||
|
; [0]-[59]: right half of billboard (first column starts at bottom)
|
||||||
|
; [60]-[62]: right side partition LEDs
|
||||||
|
;
|
||||||
|
; Board 2 is the slider and has 31 LEDs:
|
||||||
|
; [0]-[31]: slider LEDs right to left BRG, alternating between keys and dividers
|
||||||
|
|
||||||
|
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
; Input settings
|
; Input settings
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "board/io4.h"
|
#include "board/io4.h"
|
||||||
|
#include "board/led15093.h"
|
||||||
#include "board/sg-reader.h"
|
#include "board/sg-reader.h"
|
||||||
#include "board/vfd.h"
|
#include "board/vfd.h"
|
||||||
|
|
||||||
@ -96,7 +97,8 @@ static DWORD CALLBACK fgo_pre_startup(void)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = led15093_hook_init(&fgo_hook_cfg.led15093, 17, 1, 1, 2);
|
hr = led15093_hook_init(&fgo_hook_cfg.led15093,
|
||||||
|
fgo_dll.led_init, fgo_dll.led_set_leds, 17, 1, 1, 2);
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -24,6 +24,12 @@ const struct dll_bind_sym fgo_dll_syms[] = {
|
|||||||
}, {
|
}, {
|
||||||
.sym = "fgo_io_get_analogs",
|
.sym = "fgo_io_get_analogs",
|
||||||
.off = offsetof(struct fgo_dll, get_analogs),
|
.off = offsetof(struct fgo_dll, get_analogs),
|
||||||
|
}, {
|
||||||
|
.sym = "fgo_io_led_init",
|
||||||
|
.off = offsetof(struct fgo_dll, led_init),
|
||||||
|
}, {
|
||||||
|
.sym = "fgo_io_led_set_leds",
|
||||||
|
.off = offsetof(struct fgo_dll, led_set_leds),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,6 +11,8 @@ struct fgo_dll {
|
|||||||
void (*get_opbtns)(uint8_t *opbtn);
|
void (*get_opbtns)(uint8_t *opbtn);
|
||||||
void (*get_gamebtns)(uint8_t *gamebtn);
|
void (*get_gamebtns)(uint8_t *gamebtn);
|
||||||
void (*get_analogs)(int16_t *stick_x, int16_t *stick_y);
|
void (*get_analogs)(int16_t *stick_x, int16_t *stick_y);
|
||||||
|
int (*led_init)();
|
||||||
|
void (*led_set_leds)(uint8_t board, uint8_t *rgb);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fgo_dll_config {
|
struct fgo_dll_config {
|
||||||
|
@ -17,6 +17,8 @@ EXPORTS
|
|||||||
fgo_io_get_opbtns
|
fgo_io_get_opbtns
|
||||||
fgo_io_init
|
fgo_io_init
|
||||||
fgo_io_poll
|
fgo_io_poll
|
||||||
|
fgo_io_led_init
|
||||||
|
fgo_io_led_set_leds
|
||||||
fwdlusb_open
|
fwdlusb_open
|
||||||
fwdlusb_close
|
fwdlusb_close
|
||||||
fwdlusb_listupPrinter
|
fwdlusb_listupPrinter
|
||||||
|
@ -139,3 +139,13 @@ void fgo_io_get_analogs(int16_t *stick_x, int16_t *stick_y)
|
|||||||
*stick_y = fgo_stick_y;
|
*stick_y = fgo_stick_y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fgo_io_led_init()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fgo_io_led_set_leds(uint8_t board, uint8_t *rgb)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
@ -69,3 +69,18 @@ void fgo_io_get_gamebtns(uint8_t *btn);
|
|||||||
Minimum API version: 0x0100 */
|
Minimum API version: 0x0100 */
|
||||||
|
|
||||||
void fgo_io_get_analogs(int16_t *stick_x, int16_t *stick_y);
|
void fgo_io_get_analogs(int16_t *stick_x, int16_t *stick_y);
|
||||||
|
|
||||||
|
/* Initialize LED emulation. This function will be called before any
|
||||||
|
other fgo_io_led_*() function calls.
|
||||||
|
|
||||||
|
All subsequent calls may originate from arbitrary threads and some may
|
||||||
|
overlap with each other. Ensuring synchronization inside your IO DLL is
|
||||||
|
your responsibility. */
|
||||||
|
|
||||||
|
int fgo_io_led_init();
|
||||||
|
|
||||||
|
/* Update the RGB LEDs.
|
||||||
|
|
||||||
|
Exact layout is TBD. */
|
||||||
|
|
||||||
|
void fgo_io_led_set_leds(uint8_t board, uint8_t *rgb);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "board/config.h"
|
#include "board/config.h"
|
||||||
#include "board/led15093.h"
|
// #include "board/led15093.h"
|
||||||
|
|
||||||
#include "gfxhook/gfx.h"
|
#include "gfxhook/gfx.h"
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ struct mu3_hook_config {
|
|||||||
struct dvd_config dvd;
|
struct dvd_config dvd;
|
||||||
struct io4_config io4;
|
struct io4_config io4;
|
||||||
struct gfx_config gfx;
|
struct gfx_config gfx;
|
||||||
struct led15093_config led15093;
|
// struct led15093_config led15093;
|
||||||
struct mu3_dll_config dll;
|
struct mu3_dll_config dll;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,11 +61,14 @@ static DWORD CALLBACK mu3_pre_startup(void)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Does not work, Unity moment
|
||||||
hr = led15093_hook_init(&mu3_hook_cfg.led15093, 3, 1, 1, 2);
|
hr = led15093_hook_init(&mu3_hook_cfg.led15093, 3, 1, 1, 2);
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
hr = sg_reader_hook_init(&mu3_hook_cfg.aime, 1, 1, mu3_hook_mod);
|
hr = sg_reader_hook_init(&mu3_hook_cfg.aime, 1, 1, mu3_hook_mod);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user