forked from Dniel97/segatools
idac: 837-15070 board implementation
This commit is contained in:
parent
4e58d3b9a2
commit
7e5e0f132e
81
board/led15070-cmd.h
Normal file
81
board/led15070-cmd.h
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "board/led15070-frame.h"
|
||||||
|
|
||||||
|
/* Command IDs */
|
||||||
|
|
||||||
|
enum {
|
||||||
|
LED_15070_CMD_RESET = 0x10,
|
||||||
|
LED_15070_CMD_SET_INPUT = 0x28, // No known use case
|
||||||
|
LED_15070_CMD_SET_NORMAL_12BIT = 0x30, // TODO
|
||||||
|
LED_15070_CMD_SET_NORMAL_8BIT = 0x31,
|
||||||
|
LED_15070_CMD_SET_MULTI_FLASH_8BIT = 0x32,
|
||||||
|
LED_15070_CMD_SET_MULTI_FADE_8BIT = 0x33,
|
||||||
|
LED_15070_CMD_SET_PALETTE_7_NORMAL_LED = 0x34, // No known use case
|
||||||
|
LED_15070_CMD_SET_PALETTE_6_FLASH_LED = 0x35, // No known use case
|
||||||
|
LED_15070_CMD_SET_15DC_OUT = 0x36, // No known use case
|
||||||
|
LED_15070_CMD_SET_15GS_OUT = 0x37, // No known use case
|
||||||
|
LED_15070_CMD_SET_PSC_MAX = 0x38, // No known use case
|
||||||
|
LED_15070_CMD_SET_FET_OUTPUT = 0x39,
|
||||||
|
LED_15070_CMD_SET_GS_PALETTE = 0x3A,
|
||||||
|
LED_15070_CMD_DC_UPDATE = 0x3B,
|
||||||
|
LED_15070_CMD_GS_UPDATE = 0x3C,
|
||||||
|
LED_15070_CMD_ROTATE = 0x3E, // No known use case, wtf is this?
|
||||||
|
LED_15070_CMD_SET_DC_DATA = 0x3F,
|
||||||
|
LED_15070_CMD_EEPROM_WRITE = 0x7B,
|
||||||
|
LED_15070_CMD_EEPROM_READ = 0x7C,
|
||||||
|
LED_15070_CMD_ACK_ON = 0x7D,
|
||||||
|
LED_15070_CMD_ACK_OFF = 0x7E,
|
||||||
|
LED_15070_CMD_BOARD_INFO = 0xF0,
|
||||||
|
LED_15070_CMD_BOARD_STATUS = 0xF1,
|
||||||
|
LED_15070_CMD_FW_SUM = 0xF2,
|
||||||
|
LED_15070_CMD_PROTOCOL_VER = 0xF3,
|
||||||
|
LED_15070_CMD_TO_BOOT_MODE = 0xFD,
|
||||||
|
LED_15070_CMD_FW_UPDATE = 0xFE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Response codes */
|
||||||
|
|
||||||
|
enum {
|
||||||
|
LED_15070_STATUS_OK = 0x01,
|
||||||
|
LED_15070_STATUS_SUM_ERR = 0x02,
|
||||||
|
LED_15070_STATUS_PARITY_ERR = 0x03,
|
||||||
|
LED_15070_STATUS_FRAMING_ERR = 0x04,
|
||||||
|
LED_15070_STATUS_OVERRUN_ERR = 0x05,
|
||||||
|
LED_15070_STATUS_BUFFER_OVERFLOW = 0x06,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
LED_15070_REPORT_OK = 0x01,
|
||||||
|
LED_15070_REPORT_WAIT = 0x02,
|
||||||
|
LED_15070_REPORT_ERR1 = 0x03,
|
||||||
|
LED_15070_REPORT_ERR2 = 0x04,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Request data structures */
|
||||||
|
|
||||||
|
struct led15070_req_any {
|
||||||
|
struct led15070_hdr hdr;
|
||||||
|
uint8_t cmd;
|
||||||
|
uint8_t payload[256];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Response data structures */
|
||||||
|
|
||||||
|
struct led15070_resp_any {
|
||||||
|
struct led15070_hdr hdr;
|
||||||
|
uint8_t status;
|
||||||
|
uint8_t cmd;
|
||||||
|
uint8_t report;
|
||||||
|
uint8_t data[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct led15070_resp_board_info {
|
||||||
|
struct led15070_hdr hdr;
|
||||||
|
uint8_t status;
|
||||||
|
uint8_t cmd;
|
||||||
|
uint8_t report;
|
||||||
|
char board_num[8];
|
||||||
|
uint8_t endcode; // Always 0xFF
|
||||||
|
uint8_t fw_ver;
|
||||||
|
};
|
194
board/led15070-frame.c
Normal file
194
board/led15070-frame.c
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "board/led15070-frame.h"
|
||||||
|
|
||||||
|
#include "hook/iobuf.h"
|
||||||
|
|
||||||
|
static void led15070_frame_sync(struct iobuf *src);
|
||||||
|
static HRESULT led15070_frame_accept(const struct iobuf *dest);
|
||||||
|
static HRESULT led15070_frame_encode_byte(struct iobuf *dest, uint8_t byte);
|
||||||
|
|
||||||
|
/* Frame structure:
|
||||||
|
|
||||||
|
[0] Sync byte (0xE0)
|
||||||
|
[1] Destination address
|
||||||
|
[2] Source Address
|
||||||
|
[3] Length of data/payload
|
||||||
|
[4] Data/payload
|
||||||
|
For requests (host to board):
|
||||||
|
[0] Command
|
||||||
|
... Payload
|
||||||
|
For responses (board to host):
|
||||||
|
[0] Status
|
||||||
|
[1] Command
|
||||||
|
[2] Report
|
||||||
|
... Payload
|
||||||
|
[n] Checksum: Sum of all prior bytes (excluding sync byte)
|
||||||
|
|
||||||
|
Byte stuffing:
|
||||||
|
|
||||||
|
0xD0 is an escape byte. Un-escape the subsequent byte by adding 1. */
|
||||||
|
|
||||||
|
static void led15070_frame_sync(struct iobuf *src)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0 ; i < src->pos && src->bytes[i] != 0xE0 ; i++);
|
||||||
|
|
||||||
|
src->pos -= i;
|
||||||
|
memmove(&src->bytes[0], &src->bytes[i], i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT led15070_frame_accept(const struct iobuf *dest)
|
||||||
|
{
|
||||||
|
uint8_t checksum;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (dest->pos < 3 || dest->pos != dest->bytes[3] + 5) {
|
||||||
|
return S_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
checksum = 0;
|
||||||
|
|
||||||
|
for (i = 1 ; i < dest->pos - 1 ; i++) {
|
||||||
|
checksum += dest->bytes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
//dprintf("LED checksum %02x, expected %02x\n", checksum, dest->bytes[dest->pos - 1]);
|
||||||
|
|
||||||
|
if (checksum != dest->bytes[dest->pos - 1]) {
|
||||||
|
return HRESULT_FROM_WIN32(ERROR_CRC);
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT led15070_frame_decode(struct iobuf *dest, struct iobuf *src)
|
||||||
|
{
|
||||||
|
uint8_t byte;
|
||||||
|
bool escape;
|
||||||
|
size_t i;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
assert(dest != NULL);
|
||||||
|
assert(dest->bytes != NULL || dest->nbytes == 0);
|
||||||
|
assert(dest->pos <= dest->nbytes);
|
||||||
|
assert(src != NULL);
|
||||||
|
assert(src->bytes != NULL || src->nbytes == 0);
|
||||||
|
assert(src->pos <= src->nbytes);
|
||||||
|
|
||||||
|
led15070_frame_sync(src);
|
||||||
|
|
||||||
|
dest->pos = 0;
|
||||||
|
escape = false;
|
||||||
|
|
||||||
|
for (i = 0, hr = S_FALSE ; i < src->pos && hr == S_FALSE ; i++) {
|
||||||
|
/* Step the FSM to unstuff another byte */
|
||||||
|
|
||||||
|
byte = src->bytes[i];
|
||||||
|
|
||||||
|
if (dest->pos >= dest->nbytes) {
|
||||||
|
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||||
|
} else if (i == 0) {
|
||||||
|
dest->bytes[dest->pos++] = byte;
|
||||||
|
} else if (byte == 0xE0) {
|
||||||
|
hr = E_FAIL;
|
||||||
|
} else if (byte == 0xD0) {
|
||||||
|
if (escape) {
|
||||||
|
hr = E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
escape = true;
|
||||||
|
} else if (escape) {
|
||||||
|
dest->bytes[dest->pos++] = byte + 1;
|
||||||
|
escape = false;
|
||||||
|
} else {
|
||||||
|
dest->bytes[dest->pos++] = byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to accept the packet we've built up so far */
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
hr = led15070_frame_accept(dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle FSM terminal state */
|
||||||
|
|
||||||
|
if (hr != S_FALSE) {
|
||||||
|
/* Frame was either accepted or rejected, remove it from src */
|
||||||
|
memmove(&src->bytes[0], &src->bytes[i], src->pos - i);
|
||||||
|
src->pos -= i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT led15070_frame_encode(
|
||||||
|
struct iobuf *dest,
|
||||||
|
const void *ptr,
|
||||||
|
size_t nbytes)
|
||||||
|
{
|
||||||
|
const uint8_t *src;
|
||||||
|
uint8_t checksum;
|
||||||
|
uint8_t byte;
|
||||||
|
size_t i;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
assert(dest != NULL);
|
||||||
|
assert(dest->bytes != NULL || dest->nbytes == 0);
|
||||||
|
assert(dest->pos <= dest->nbytes);
|
||||||
|
assert(ptr != NULL);
|
||||||
|
|
||||||
|
src = ptr;
|
||||||
|
|
||||||
|
assert(nbytes >= 3 && src[0] == 0xE0 && src[3] + 4 == nbytes);
|
||||||
|
|
||||||
|
if (dest->pos >= dest->nbytes) {
|
||||||
|
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
dest->bytes[dest->pos++] = 0xE0;
|
||||||
|
checksum = 0;
|
||||||
|
// dprintf("%02x ", 0xe0);
|
||||||
|
|
||||||
|
for (i = 1 ; i < nbytes ; i++) {
|
||||||
|
byte = src[i];
|
||||||
|
checksum += byte;
|
||||||
|
// dprintf("%02x ", byte);
|
||||||
|
|
||||||
|
hr = led15070_frame_encode_byte(dest, byte);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// dprintf("%02x \n", checksum);
|
||||||
|
|
||||||
|
return led15070_frame_encode_byte(dest, checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT led15070_frame_encode_byte(struct iobuf *dest, uint8_t byte)
|
||||||
|
{
|
||||||
|
if (byte == 0xE0 || byte == 0xD0) {
|
||||||
|
if (dest->pos + 2 > dest->nbytes) {
|
||||||
|
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
dest->bytes[dest->pos++] = 0xD0;
|
||||||
|
dest->bytes[dest->pos++] = byte - 1;
|
||||||
|
} else {
|
||||||
|
if (dest->pos + 1 > dest->nbytes) {
|
||||||
|
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
dest->bytes[dest->pos++] = byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
26
board/led15070-frame.h
Normal file
26
board/led15070-frame.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "hook/iobuf.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
LED_15070_FRAME_SYNC = 0xE0,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct led15070_hdr {
|
||||||
|
uint8_t sync;
|
||||||
|
uint8_t dest_adr;
|
||||||
|
uint8_t src_adr;
|
||||||
|
uint8_t nbytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
HRESULT led15070_frame_decode(struct iobuf *dest, struct iobuf *src);
|
||||||
|
|
||||||
|
HRESULT led15070_frame_encode(
|
||||||
|
struct iobuf *dest,
|
||||||
|
const void *ptr,
|
||||||
|
size_t nbytes);
|
1250
board/led15070.c
Normal file
1250
board/led15070.c
Normal file
File diff suppressed because it is too large
Load Diff
29
board/led15070.h
Normal file
29
board/led15070.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct led15070_config {
|
||||||
|
bool enable;
|
||||||
|
unsigned int port_no;
|
||||||
|
char board_number[8];
|
||||||
|
uint8_t fw_ver;
|
||||||
|
uint16_t fw_sum;
|
||||||
|
wchar_t eeprom_path[MAX_PATH];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef HRESULT (*io_led_init_t)(void);
|
||||||
|
typedef void (*io_led_set_fet_output_t)(const uint8_t *rgb);
|
||||||
|
typedef void (*io_led_dc_update_t)(const uint8_t *rgb);
|
||||||
|
typedef void (*io_led_gs_update_t)(const uint8_t *rgb);
|
||||||
|
|
||||||
|
HRESULT led15070_hook_init(
|
||||||
|
const struct led15070_config *cfg,
|
||||||
|
io_led_init_t _led_init,
|
||||||
|
io_led_set_fet_output_t _led_set_fet_output,
|
||||||
|
io_led_dc_update_t _led_dc_update,
|
||||||
|
io_led_gs_update_t _led_gs_update,
|
||||||
|
unsigned int first_port,
|
||||||
|
unsigned int num_boards);
|
@ -25,6 +25,11 @@ board_lib = static_library(
|
|||||||
'led15093-frame.h',
|
'led15093-frame.h',
|
||||||
'led15093.c',
|
'led15093.c',
|
||||||
'led15093.h',
|
'led15093.h',
|
||||||
|
'led15070-cmd.h',
|
||||||
|
'led15070-frame.c',
|
||||||
|
'led15070-frame.h',
|
||||||
|
'led15070.c',
|
||||||
|
'led15070.h',
|
||||||
'sg-cmd.c',
|
'sg-cmd.c',
|
||||||
'sg-cmd.h',
|
'sg-cmd.h',
|
||||||
'sg-frame.c',
|
'sg-frame.c',
|
||||||
|
9
dist/idac/segatools.ini
vendored
9
dist/idac/segatools.ini
vendored
@ -75,6 +75,15 @@ dipsw3=0
|
|||||||
dipsw4=0
|
dipsw4=0
|
||||||
dipsw5=0
|
dipsw5=0
|
||||||
|
|
||||||
|
; -----------------------------------------------------------------------------
|
||||||
|
; LED settings
|
||||||
|
; -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
[led15070]
|
||||||
|
; Enable emulation of the 15070-02 controlled lights, which handle the cabinet
|
||||||
|
; and seat LEDs.
|
||||||
|
enable=1
|
||||||
|
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
; Custom IO settings
|
; Custom IO settings
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
|
@ -13,6 +13,43 @@
|
|||||||
#include "platform/config.h"
|
#include "platform/config.h"
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
|
|
||||||
|
|
||||||
|
void led15070_config_load(struct led15070_config *cfg, const wchar_t *filename)
|
||||||
|
{
|
||||||
|
assert(cfg != NULL);
|
||||||
|
assert(filename != NULL);
|
||||||
|
|
||||||
|
wchar_t tmpstr[16];
|
||||||
|
|
||||||
|
cfg->enable = GetPrivateProfileIntW(L"led15070", L"enable", 1, filename);
|
||||||
|
cfg->port_no = GetPrivateProfileIntW(L"led15070", L"portNo", 0, filename);
|
||||||
|
cfg->fw_ver = GetPrivateProfileIntW(L"led15070", L"fwVer", 0x90, filename);
|
||||||
|
/* TODO: Unknown, no firmware file available */
|
||||||
|
cfg->fw_sum = GetPrivateProfileIntW(L"led15070", L"fwSum", 0x0000, filename);
|
||||||
|
|
||||||
|
GetPrivateProfileStringW(
|
||||||
|
L"led15070",
|
||||||
|
L"boardNumber",
|
||||||
|
L"15070-02",
|
||||||
|
tmpstr,
|
||||||
|
_countof(tmpstr),
|
||||||
|
filename);
|
||||||
|
|
||||||
|
size_t n = wcstombs(cfg->board_number, tmpstr, sizeof(cfg->board_number));
|
||||||
|
for (int i = n; i < sizeof(cfg->board_number); i++)
|
||||||
|
{
|
||||||
|
cfg->board_number[i] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
GetPrivateProfileStringW(
|
||||||
|
L"led15070",
|
||||||
|
L"eepromPath",
|
||||||
|
L"DEVICE",
|
||||||
|
cfg->eeprom_path,
|
||||||
|
_countof(cfg->eeprom_path),
|
||||||
|
filename);
|
||||||
|
}
|
||||||
|
|
||||||
void idac_dll_config_load(
|
void idac_dll_config_load(
|
||||||
struct idac_dll_config *cfg,
|
struct idac_dll_config *cfg,
|
||||||
const wchar_t *filename)
|
const wchar_t *filename)
|
||||||
@ -42,6 +79,7 @@ void idac_hook_config_load(
|
|||||||
zinput_config_load(&cfg->zinput, filename);
|
zinput_config_load(&cfg->zinput, filename);
|
||||||
dvd_config_load(&cfg->dvd, filename);
|
dvd_config_load(&cfg->dvd, filename);
|
||||||
io4_config_load(&cfg->io4, filename);
|
io4_config_load(&cfg->io4, filename);
|
||||||
|
led15070_config_load(&cfg->led15070, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename)
|
void zinput_config_load(struct zinput_config *cfg, const wchar_t *filename)
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "board/config.h"
|
#include "board/config.h"
|
||||||
|
#include "board/led15070.h"
|
||||||
|
|
||||||
#include "hooklib/dvd.h"
|
#include "hooklib/dvd.h"
|
||||||
|
|
||||||
@ -19,6 +20,7 @@ struct idac_hook_config {
|
|||||||
struct io4_config io4;
|
struct io4_config io4;
|
||||||
struct idac_dll_config dll;
|
struct idac_dll_config dll;
|
||||||
struct zinput_config zinput;
|
struct zinput_config zinput;
|
||||||
|
struct led15070_config led15070;
|
||||||
};
|
};
|
||||||
|
|
||||||
void idac_dll_config_load(
|
void idac_dll_config_load(
|
||||||
|
@ -67,24 +67,31 @@ static DWORD CALLBACK idac_pre_startup(void)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = sg_reader_hook_init(&idac_hook_cfg.aime, 3, 3, idac_hook_mod);
|
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = idac_dll_init(&idac_hook_cfg.dll, idac_hook_mod);
|
hr = idac_dll_init(&idac_hook_cfg.dll, idac_hook_mod);
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hr = sg_reader_hook_init(&idac_hook_cfg.aime, 3, 3, idac_hook_mod);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
hr = idac_io4_hook_init(&idac_hook_cfg.io4);
|
hr = idac_io4_hook_init(&idac_hook_cfg.io4);
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hr = led15070_hook_init(&idac_hook_cfg.led15070, idac_dll.led_init,
|
||||||
|
idac_dll.led_set_fet_output, NULL, idac_dll.led_gs_update, 2, 1);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize debug helpers */
|
/* Initialize debug helpers */
|
||||||
|
|
||||||
spike_hook_init(L".\\segatools.ini");
|
spike_hook_init(L".\\segatools.ini");
|
||||||
|
@ -24,6 +24,18 @@ const struct dll_bind_sym idac_dll_syms[] = {
|
|||||||
}, {
|
}, {
|
||||||
.sym = "idac_io_get_analogs",
|
.sym = "idac_io_get_analogs",
|
||||||
.off = offsetof(struct idac_dll, get_analogs),
|
.off = offsetof(struct idac_dll, get_analogs),
|
||||||
|
}, {
|
||||||
|
.sym = "idac_io_led_init",
|
||||||
|
.off = offsetof(struct idac_dll, led_init),
|
||||||
|
}, {
|
||||||
|
.sym = "idac_io_led_set_fet_output",
|
||||||
|
.off = offsetof(struct idac_dll, led_set_fet_output),
|
||||||
|
}, {
|
||||||
|
.sym = "idac_io_led_gs_update",
|
||||||
|
.off = offsetof(struct idac_dll, led_gs_update),
|
||||||
|
}, {
|
||||||
|
.sym = "idac_io_led_set_leds",
|
||||||
|
.off = offsetof(struct idac_dll, led_set_leds),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,6 +11,10 @@ struct idac_dll {
|
|||||||
void (*get_gamebtns)(uint8_t *gamebtn);
|
void (*get_gamebtns)(uint8_t *gamebtn);
|
||||||
void (*get_shifter)(uint8_t *gear);
|
void (*get_shifter)(uint8_t *gear);
|
||||||
void (*get_analogs)(struct idac_io_analog_state *out);
|
void (*get_analogs)(struct idac_io_analog_state *out);
|
||||||
|
HRESULT (*led_init)(void);
|
||||||
|
void (*led_set_fet_output)(const uint8_t *rgb);
|
||||||
|
void (*led_gs_update)(const uint8_t *rgb);
|
||||||
|
void (*led_set_leds)(const uint8_t *rgb);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct idac_dll_config {
|
struct idac_dll_config {
|
||||||
|
@ -17,3 +17,7 @@ EXPORTS
|
|||||||
idac_io_get_gamebtns
|
idac_io_get_gamebtns
|
||||||
idac_io_get_shifter
|
idac_io_get_shifter
|
||||||
idac_io_get_analogs
|
idac_io_get_analogs
|
||||||
|
idac_io_led_init
|
||||||
|
idac_io_led_set_fet_output
|
||||||
|
idac_io_led_gs_update
|
||||||
|
idac_io_led_set_leds
|
||||||
|
@ -11,10 +11,12 @@
|
|||||||
#include "util/dprintf.h"
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
static HRESULT idac_io4_poll(void *ctx, struct io4_state *state);
|
static HRESULT idac_io4_poll(void *ctx, struct io4_state *state);
|
||||||
|
static HRESULT idac_io4_write_gpio(uint8_t* payload, size_t len);
|
||||||
static uint16_t coins;
|
static uint16_t coins;
|
||||||
|
|
||||||
static const struct io4_ops idac_io4_ops = {
|
static const struct io4_ops idac_io4_ops = {
|
||||||
.poll = idac_io4_poll,
|
.poll = idac_io4_poll,
|
||||||
|
.write_gpio = idac_io4_write_gpio
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint16_t idac_gear_signals[] = {
|
static const uint16_t idac_gear_signals[] = {
|
||||||
@ -128,3 +130,34 @@ static HRESULT idac_io4_poll(void *ctx, struct io4_state *state)
|
|||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HRESULT idac_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 IDAC, 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 15070 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 ON/OFF values.
|
||||||
|
uint8_t rgb_out[6] = {
|
||||||
|
lights_data & IDAC_IO_LED_START ? 0xFF : 0x00,
|
||||||
|
lights_data & IDAC_IO_LED_VIEW_CHANGE ? 0xFF : 0x00,
|
||||||
|
lights_data & IDAC_IO_LED_UP ? 0xFF : 0x00,
|
||||||
|
lights_data & IDAC_IO_LED_DOWN ? 0xFF : 0x00,
|
||||||
|
lights_data & IDAC_IO_LED_RIGHT ? 0xFF : 0x00,
|
||||||
|
lights_data & IDAC_IO_LED_LEFT ? 0xFF : 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
idac_dll.led_set_leds(rgb_out);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
@ -19,7 +19,7 @@ static bool idac_io_coin;
|
|||||||
|
|
||||||
uint16_t idac_io_get_api_version(void)
|
uint16_t idac_io_get_api_version(void)
|
||||||
{
|
{
|
||||||
return 0x0100;
|
return 0x0101;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT idac_io_init(void)
|
HRESULT idac_io_init(void)
|
||||||
@ -118,3 +118,44 @@ void idac_io_get_analogs(struct idac_io_analog_state *out)
|
|||||||
out->accel = tmp.accel;
|
out->accel = tmp.accel;
|
||||||
out->brake = tmp.brake;
|
out->brake = tmp.brake;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HRESULT idac_io_led_init(void)
|
||||||
|
{
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void idac_io_led_set_fet_output(const uint8_t *rgb)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
dprintf("IDAC LED: LEFT SEAT LED: %02X\n", rgb[0]);
|
||||||
|
dprintf("IDAC LED: RIGHT SEAT LED: %02X\n", rgb[1]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void idac_io_led_gs_update(const uint8_t *rgb)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
for (int i = 0; i < 9; i++) {
|
||||||
|
dprintf("IDAC LED: LED %d: %02X %02X %02X Speed: %02X\n",
|
||||||
|
i, rgb[i * 4], rgb[i * 4 + 1], rgb[i * 4 + 2], rgb[i * 4 + 3]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void idac_io_led_set_leds(const uint8_t *rgb)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
dprintf("IDAC LED: START: %02X\n", rgb[0]);
|
||||||
|
dprintf("IDAC LED: VIEW CHANGE: %02X\n", rgb[1]);
|
||||||
|
dprintf("IDAC LED: UP: %02X\n", rgb[2]);
|
||||||
|
dprintf("IDAC LED: DOWN: %02X\n", rgb[3]);
|
||||||
|
dprintf("IDAC LED: RIGHT: %02X\n", rgb[4]);
|
||||||
|
dprintf("IDAC LED: LEFT: %02X\n", rgb[5]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
@ -6,3 +6,7 @@ EXPORTS
|
|||||||
idac_io_get_gamebtns
|
idac_io_get_gamebtns
|
||||||
idac_io_get_shifter
|
idac_io_get_shifter
|
||||||
idac_io_get_analogs
|
idac_io_get_analogs
|
||||||
|
idac_io_led_init
|
||||||
|
idac_io_led_set_fet_output
|
||||||
|
idac_io_led_gs_update
|
||||||
|
idac_io_led_set_leds
|
||||||
|
@ -19,6 +19,17 @@ enum {
|
|||||||
IDAC_IO_GAMEBTN_VIEW_CHANGE = 0x20,
|
IDAC_IO_GAMEBTN_VIEW_CHANGE = 0x20,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/* These are the bitmasks to use when checking which
|
||||||
|
lights are triggered on incoming IO4 GPIO writes. */
|
||||||
|
IDAC_IO_LED_START = 1 << 31,
|
||||||
|
IDAC_IO_LED_VIEW_CHANGE = 1 << 30,
|
||||||
|
IDAC_IO_LED_UP = 1 << 25,
|
||||||
|
IDAC_IO_LED_DOWN = 1 << 24,
|
||||||
|
IDAC_IO_LED_LEFT = 1 << 23,
|
||||||
|
IDAC_IO_LED_RIGHT = 1 << 22,
|
||||||
|
};
|
||||||
|
|
||||||
struct idac_io_analog_state {
|
struct idac_io_analog_state {
|
||||||
/* Current steering wheel position, where zero is the centered position.
|
/* Current steering wheel position, where zero is the centered position.
|
||||||
|
|
||||||
@ -92,4 +103,60 @@ void idac_io_get_analogs(struct idac_io_analog_state *out);
|
|||||||
|
|
||||||
Minimum API version: 0x0100 */
|
Minimum API version: 0x0100 */
|
||||||
|
|
||||||
void idac_io_get_shifter(uint8_t *gear);
|
void idac_io_get_shifter(uint8_t *gear);
|
||||||
|
|
||||||
|
/* Initialize LED emulation. This function will be called before any
|
||||||
|
other idac_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.
|
||||||
|
|
||||||
|
Minimum API version: 0x0101 */
|
||||||
|
|
||||||
|
HRESULT idac_io_led_init(void);
|
||||||
|
|
||||||
|
/* Update the FET outputs. rgb is a pointer to an array up to 3 bytes.
|
||||||
|
|
||||||
|
The following bits are used to control the FET outputs:
|
||||||
|
[0]: LEFT SEAT LED
|
||||||
|
[1]: RIGHT SEAT LED
|
||||||
|
|
||||||
|
The LED is truned on when the byte is 255 and turned off when the byte is 0.
|
||||||
|
|
||||||
|
Minimum API version: 0x0101 */
|
||||||
|
|
||||||
|
void idac_io_led_set_fet_output(const uint8_t *rgb);
|
||||||
|
|
||||||
|
/* Update the RGB LEDs. rgb is a pointer to an array up to 32 * 4 = 128 bytes.
|
||||||
|
|
||||||
|
The LEDs are laid out as follows:
|
||||||
|
[0]: LEFT UP LED
|
||||||
|
[1-2]: LEFT CENTER LED
|
||||||
|
[3]: LEFT DOWN LED
|
||||||
|
[5]: RIGHT UP LED
|
||||||
|
[6-7]: RIGHT CENTER LED
|
||||||
|
[8]: RIGHT DOWN LED
|
||||||
|
|
||||||
|
Each rgb value is comprised for 4 bytes in the order of R, G, B, Speed.
|
||||||
|
Speed is a value from 0 to 255, where 0 is the fastest speed and 255 is the slowest.
|
||||||
|
|
||||||
|
Minimum API version: 0x0101 */
|
||||||
|
|
||||||
|
void idac_io_led_gs_update(const uint8_t *rgb);
|
||||||
|
|
||||||
|
/* Update the cabinet button LEDs. rgb is a pointer to an array up to 6 bytes.
|
||||||
|
|
||||||
|
The LEDs are laid out as follows:
|
||||||
|
[0]: START LED
|
||||||
|
[1]: VIEW CHANGE LED
|
||||||
|
[2]: UP LED
|
||||||
|
[3]: DOWN LED
|
||||||
|
[4]: RIGHT LED
|
||||||
|
[5]: LEFT LED
|
||||||
|
|
||||||
|
The LED is turned on when the byte is 255 and turned off when the byte is 0.
|
||||||
|
|
||||||
|
Minimum API version: 0x0101 */
|
||||||
|
|
||||||
|
void idac_io_led_set_leds(const uint8_t *rgb);
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
/*
|
||||||
|
"Initial D ARCADE STAGE Zero" (idz) hook
|
||||||
|
|
||||||
|
Devices
|
||||||
|
|
||||||
|
JVS: 837-15257 "Type 4" I/O Board
|
||||||
|
COM1: 838-15069 MOTOR DRIVE BD RS232/422 Board
|
||||||
|
COM10: 837-15286 "Gen 2" Aime Reader
|
||||||
|
COM11: 837-15070-02 IC BD LED Controller Board
|
||||||
|
*/
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user