diff --git a/board/led15093-cmd.h b/board/led15093-cmd.h new file mode 100644 index 0000000..5648de6 --- /dev/null +++ b/board/led15093-cmd.h @@ -0,0 +1,222 @@ +#pragma once + +#include "board/led15093-frame.h" + +/* Command IDs */ + +enum { + LED_15093_CMD_RESET = 0x10, + LED_15093_CMD_SET_TIMEOUT = 0x11, + LED_15093_CMD_UNK1 = 0x12, + LED_15093_CMD_SET_DISABLE_RESPONSE = 0x14, + LED_15093_CMD_SET_ID = 0x18, + LED_15093_CMD_CLEAR_ID = 0x19, + LED_15093_CMD_SET_MAX_BRIGHT = 0x3F, // TODO + LED_15093_CMD_UPDATE_LED = 0x80, + LED_15093_CMD_SET_LED = 0x81, + LED_15093_CMD_SET_IMM_LED = 0x82, + LED_15093_CMD_SET_FADE_LED = 0x83, + LED_15093_CMD_SET_FADE_LEVEL = 0x84, + LED_15093_CMD_SET_FADE_SHIFT = 0x85, + LED_15093_CMD_SET_AUTO_SHIFT = 0x86, + LED_15093_CMD_GET_BOARD_INFO = 0xF0, + LED_15093_CMD_GET_BOARD_STATUS = 0xF1, + LED_15093_CMD_GET_FW_SUM = 0xF2, + LED_15093_CMD_GET_PROTOCOL_VER = 0xF3, + LED_15093_CMD_SET_BOOTMODE = 0xFD, + LED_15093_CMD_FW_UPDATE = 0xFE, +}; + +/* Response codes */ + +enum { + LED_15093_STATUS_OK = 0x01, + LED_15093_STATUS_ERR_SUM = 0x02, + LED_15093_STATUS_ERR_PARITY = 0x03, + LED_15093_STATUS_ERR_FRAMING = 0x04, + LED_15093_STATUS_ERR_OVERRUN = 0x05, + LED_15093_STATUS_ERR_BUFFER_OVERFLOW = 0x06, +}; + +enum { + LED_15093_REPORT_OK = 0x01, + LED_15093_REPORT_WAIT = 0x02, + LED_15093_REPORT_ERR1 = 0x03, + LED_15093_REPORT_ERR2 = 0x04, +}; + +/* Status bitmasks */ + +enum { + LED_15093_STATUS_UART_ERR_SUM = 0x01, + LED_15093_STATUS_UART_ERR_PARITY = 0x02, + LED_15093_STATUS_UART_ERR_FRAMING = 0x04, + LED_15093_STATUS_UART_ERR_OVERRUN = 0x08, + LED_15093_STATUS_UART_ERR_BUFFER_OVERFLOW = 0x10, +}; + +enum { + LED_15093_STATUS_BOARD_ERR_WDT = 0x01, + LED_15093_STATUS_BOARD_ERR_TIMEOUT = 0x02, + LED_15093_STATUS_BOARD_ERR_RESET = 0x04, + LED_15093_STATUS_BOARD_ERR_BOR = 0x08, +}; + +enum { + LED_15093_STATUS_CMD_ERR_BUSY = 0x01, + LED_15093_STATUS_CMD_ERR_UNKNOWN = 0x02, + LED_15093_STATUS_CMD_ERR_PARAM = 0x04, + LED_15093_STATUS_CMD_ERR_EXE = 0x08, +}; + +/* Status types for internal use */ + +enum { + LED_15093_STATUS_TYPE_BOARD = 1, + LED_15093_STATUS_TYPE_UART = 2, + LED_15093_STATUS_TYPE_CMD = 3, +}; + +/* Request data structures */ + +struct led15093_req_reset { + struct led15093_req_hdr hdr; + uint8_t cmd; + uint8_t r_type; +}; + +struct led15093_req_set_timeout { + struct led15093_req_hdr hdr; + uint8_t cmd; + uint8_t count; +}; + +struct led15093_req_set_disable_response { + struct led15093_req_hdr hdr; + uint8_t cmd; + bool sw; +}; + +struct led15093_req_set_id { + struct led15093_req_hdr hdr; + uint8_t cmd; + uint8_t id; +}; + +struct led15093_req_set_led { + struct led15093_req_hdr hdr; + uint8_t cmd; + uint8_t data[198]; +}; + +struct led15093_req_set_fade_level { + struct led15093_req_hdr hdr; + uint8_t cmd; + uint8_t depth; + uint8_t cycle; +}; + +struct led15093_req_set_fade_shift { + struct led15093_req_hdr hdr; + uint8_t cmd; + uint8_t target; +}; + +struct led15093_req_set_auto_shift { + struct led15093_req_hdr hdr; + uint8_t cmd; + uint8_t count; + uint8_t target; +}; + +struct led15093_req_get_board_status { + struct led15093_req_hdr hdr; + uint8_t cmd; + bool clear; +}; + +union led15093_req_any { + struct led15093_req_hdr hdr; + struct led15093_req_reset reset; + struct led15093_req_set_timeout set_timeout; + struct led15093_req_set_disable_response set_disable_response; + struct led15093_req_set_id set_id; + struct led15093_req_set_led set_led; + struct led15093_req_set_fade_level set_fade_level; + struct led15093_req_set_fade_shift set_fade_shift; + struct led15093_req_set_auto_shift set_auto_shift; + struct led15093_req_get_board_status get_board_status; + uint8_t payload[256]; +}; + +/* Response data structures */ + +struct led15093_resp_any { + struct led15093_resp_hdr hdr; + uint8_t status; + uint8_t cmd; + uint8_t report; + uint8_t data[32]; +}; + +struct led15093_resp_timeout { + struct led15093_resp_hdr hdr; + uint8_t status; + uint8_t cmd; + uint8_t report; + uint8_t count_upper; + uint8_t count_lower; +}; + +struct led15093_resp_fw_sum { + struct led15093_resp_hdr hdr; + uint8_t status; + uint8_t cmd; + uint8_t report; + uint8_t sum_upper; + uint8_t sum_lower; +}; + +struct led15093_resp_board_info_legacy { + struct led15093_resp_hdr hdr; + uint8_t status; + uint8_t cmd; + uint8_t report; + char board_num[8]; + uint8_t lf; // 0x0A (ASCII LF) + char chip_num[5]; + uint8_t endcode; // Always 0xFF + uint8_t fw_ver; +}; + +struct led15093_resp_board_info { + struct led15093_resp_hdr hdr; + uint8_t status; + uint8_t cmd; + uint8_t report; + char board_num[8]; + uint8_t lf; // 0x0A (ASCII LF) + char chip_num[5]; + uint8_t endcode; // Always 0xFF + uint8_t fw_ver; + uint8_t rx_buf; +}; + +struct led15093_resp_protocol_ver { + struct led15093_resp_hdr hdr; + uint8_t status; + uint8_t cmd; + uint8_t report; + uint8_t mode; + uint8_t major_ver; + uint8_t minor_ver; +}; + +struct led15093_resp_set_auto_shift { + struct led15093_resp_hdr hdr; + uint8_t status; + uint8_t cmd; + uint8_t report; + uint8_t count; + uint8_t target; +}; diff --git a/board/led1509306-frame.c b/board/led15093-frame.c similarity index 72% rename from board/led1509306-frame.c rename to board/led15093-frame.c index 8e11e8c..844f4bf 100644 --- a/board/led1509306-frame.c +++ b/board/led15093-frame.c @@ -5,13 +5,13 @@ #include #include -#include "board/led1509306-frame.h" +#include "board/led15093-frame.h" #include "hook/iobuf.h" -static void led1509306_frame_sync(struct iobuf *src); -static HRESULT led1509306_frame_accept(const struct iobuf *dest); -static HRESULT led1509306_frame_encode_byte(struct iobuf *dest, uint8_t byte); +static void led15093_frame_sync(struct iobuf *src); +static HRESULT led15093_frame_accept(const struct iobuf *dest); +static HRESULT led15093_frame_encode_byte(struct iobuf *dest, uint8_t byte); /* Frame structure: @@ -34,17 +34,17 @@ static HRESULT led1509306_frame_encode_byte(struct iobuf *dest, uint8_t byte); 0xD0 is an escape byte. Un-escape the subsequent byte by adding 1. */ -static void led1509306_frame_sync(struct iobuf *src) +static void led15093_frame_sync(struct iobuf *src) { size_t i; - for (i = 0 ; i < src->pos && src->bytes[i] != 0xE0 ; i++); + for (i = 0 ; i < src->pos && src->bytes[i] != LED_15093_FRAME_SYNC ; i++); src->pos -= i; memmove(&src->bytes[0], &src->bytes[i], i); } -static HRESULT led1509306_frame_accept(const struct iobuf *dest) +static HRESULT led15093_frame_accept(const struct iobuf *dest) { uint8_t checksum; size_t i; @@ -58,9 +58,9 @@ static HRESULT led1509306_frame_accept(const struct iobuf *dest) 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]); - + + // 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); } @@ -68,7 +68,7 @@ static HRESULT led1509306_frame_accept(const struct iobuf *dest) return S_OK; } -HRESULT led1509306_frame_decode(struct iobuf *dest, struct iobuf *src) +HRESULT led15093_frame_decode(struct iobuf *dest, struct iobuf *src) { uint8_t byte; bool escape; @@ -82,7 +82,7 @@ HRESULT led1509306_frame_decode(struct iobuf *dest, struct iobuf *src) assert(src->bytes != NULL || src->nbytes == 0); assert(src->pos <= src->nbytes); - led1509306_frame_sync(src); + led15093_frame_sync(src); dest->pos = 0; escape = false; @@ -96,9 +96,9 @@ HRESULT led1509306_frame_decode(struct iobuf *dest, struct iobuf *src) hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } else if (i == 0) { dest->bytes[dest->pos++] = byte; - } else if (byte == 0xE0) { + } else if (byte == LED_15093_FRAME_SYNC) { hr = E_FAIL; - } else if (byte == 0xD0) { + } else if (byte == LED_15093_FRAME_ESC) { if (escape) { hr = E_FAIL; } @@ -114,7 +114,7 @@ HRESULT led1509306_frame_decode(struct iobuf *dest, struct iobuf *src) /* Try to accept the packet we've built up so far */ if (SUCCEEDED(hr)) { - hr = led1509306_frame_accept(dest); + hr = led15093_frame_accept(dest); } } @@ -129,7 +129,7 @@ HRESULT led1509306_frame_decode(struct iobuf *dest, struct iobuf *src) return hr; } -HRESULT led1509306_frame_encode( +HRESULT led15093_frame_encode( struct iobuf *dest, const void *ptr, size_t nbytes) @@ -147,22 +147,24 @@ HRESULT led1509306_frame_encode( src = ptr; - assert(nbytes >= 3 && src[0] == 0xE0 && src[3] + 4 == nbytes); + assert(nbytes >= 3 && + src[0] == LED_15093_FRAME_SYNC && + src[3] + 4 == nbytes); if (dest->pos >= dest->nbytes) { return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } - dest->bytes[dest->pos++] = 0xE0; + dest->bytes[dest->pos++] = LED_15093_FRAME_SYNC; checksum = 0; - // dprintf("%02x ", 0xe0); + // dprintf("%02x ", LED_15093_FRAME_SYNC); for (i = 1 ; i < nbytes ; i++) { byte = src[i]; checksum += byte; // dprintf("%02x ", byte); - hr = led1509306_frame_encode_byte(dest, byte); + hr = led15093_frame_encode_byte(dest, byte); if (FAILED(hr)) { return hr; @@ -170,17 +172,17 @@ HRESULT led1509306_frame_encode( } // dprintf("%02x \n", checksum); - return led1509306_frame_encode_byte(dest, checksum); + return led15093_frame_encode_byte(dest, checksum); } -static HRESULT led1509306_frame_encode_byte(struct iobuf *dest, uint8_t byte) +static HRESULT led15093_frame_encode_byte(struct iobuf *dest, uint8_t byte) { - if (byte == 0xE0 || byte == 0xD0) { + if (byte == LED_15093_FRAME_SYNC || byte == LED_15093_FRAME_ESC) { if (dest->pos + 2 > dest->nbytes) { return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } - dest->bytes[dest->pos++] = 0xD0; + dest->bytes[dest->pos++] = LED_15093_FRAME_ESC; dest->bytes[dest->pos++] = byte - 1; } else { if (dest->pos + 1 > dest->nbytes) { diff --git a/board/led15093-frame.h b/board/led15093-frame.h new file mode 100644 index 0000000..2311eb6 --- /dev/null +++ b/board/led15093-frame.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include +#include + +#include "hook/iobuf.h" + +enum { + LED_15093_FRAME_SYNC = 0xE0, + LED_15093_FRAME_ESC = 0xD0, +}; + +struct led15093_req_hdr { + uint8_t sync; + uint8_t dest_adr; + uint8_t src_adr; + uint8_t nbytes; +}; + +struct led15093_resp_hdr { + uint8_t sync; + uint8_t dest_adr; + uint8_t src_adr; + uint8_t nbytes; +}; + +HRESULT led15093_frame_decode(struct iobuf *dest, struct iobuf *src); + +HRESULT led15093_frame_encode( + struct iobuf *dest, + const void *ptr, + size_t nbytes); diff --git a/board/led15093.c b/board/led15093.c new file mode 100644 index 0000000..c00e39f --- /dev/null +++ b/board/led15093.c @@ -0,0 +1,1112 @@ +/* + SEGA 837-15093-XX LED Controller Board emulator + + Supported variants: + + 837-15093 + 837-15093-01 + 837-15093-04 + 837-15093-05 + 837-15093-06 + + Credits: + 837-15093-XX LED Controller Board emulator (emihiok) + 837-15093-06 LED Controller Board emulator (somewhatlurker, skogaby) +*/ + +#include + +#include +#include +#include +#include +#include + +#include "board/led15093-cmd.h" +#include "board/led15093-frame.h" + +#include "board/led15093.h" + +#include "hook/iobuf.h" +#include "hook/iohook.h" + +#include "hooklib/uart.h" + +#include "util/dprintf.h" +#include "util/str.h" +#include "util/dump.h" + +#define led15093_nboards 2 +#define led15093_nnodes 1 + +#define led15093_led_count_max 66 + +typedef struct { + uint8_t boardadr; + uint8_t boardstatus[4]; + uint8_t fade_depth; + uint8_t fade_cycle; + uint8_t led[led15093_led_count_max][3]; + uint8_t led_bright[led15093_led_count_max][3]; + uint8_t led_count; + uint8_t status_code; + uint8_t report_code; + bool enable_bootloader; + bool enable_response; +} _led15093_per_node_vars; + +typedef struct { + CRITICAL_SECTION lock; + bool started; + HRESULT start_hr; + struct uart boarduart; + uint8_t written_bytes[520]; + uint8_t readable_bytes[520]; + _led15093_per_node_vars per_node_vars[led15093_nnodes]; +} _led15093_per_board_vars; + +_led15093_per_board_vars led15093_per_board_vars[led15093_nboards]; + +static HRESULT led15093_handle_irp(struct irp *irp); +static HRESULT led15093_handle_irp_locked(int board, struct irp *irp); + +static HRESULT led15093_req_dispatch(int board, const union led15093_req_any *req); +static HRESULT led15093_req_reset(int board, const struct led15093_req_reset *req); +static HRESULT led15093_req_set_timeout(int board, const struct led15093_req_set_timeout *req); +static HRESULT led15093_req_set_response(int board, const struct led15093_req_set_disable_response *req); +static HRESULT led15093_req_set_id(int board, const struct led15093_req_set_id *req); +static HRESULT led15093_req_clear_id(int board, const union led15093_req_any *req); +static HRESULT led15093_req_set_max_bright(int board, const struct led15093_req_set_led *req); +static HRESULT led15093_req_update_led(int board, const union led15093_req_any *req); +static HRESULT led15093_req_set_led(int board, const struct led15093_req_set_led *req); +static HRESULT led15093_req_set_imm_led(int board, const struct led15093_req_set_led *req); +static HRESULT led15093_req_set_fade_led(int board, const struct led15093_req_set_led *req); +static HRESULT led15093_req_set_fade_level(int board, const struct led15093_req_set_fade_level *req); +static HRESULT led15093_req_set_fade_shift(int board, const struct led15093_req_set_fade_shift *req); +static HRESULT led15093_req_set_auto_shift(int board, const struct led15093_req_set_auto_shift *req); +static HRESULT led15093_req_get_board_info(int board, const union led15093_req_any *req); +static HRESULT led15093_req_get_board_status(int board, const struct led15093_req_get_board_status *req); +static HRESULT led15093_req_get_fw_sum(int board, const union led15093_req_any *req); +static HRESULT led15093_req_get_protocol_ver(int board, const union led15093_req_any *req); +static HRESULT led15093_req_set_bootmode(int board, const union led15093_req_any *req); +static HRESULT led15093_req_fw_update(int board, const union led15093_req_any *req); + +static void led15093_set_status(int board, int id, uint8_t type, uint8_t status); +static void led15093_set_report(int board, int id, uint8_t report); +static void led15093_clear_status(int board, int id); +static void led15093_clear_report(int board, int id); + +static char led15093_board_num[8]; +static char led15093_chip_num[5]; +static char led15093_boot_chip_num[5]; +static uint8_t led15093_fw_ver; +static uint16_t led15093_fw_sum; +static uint8_t led15093_host_adr = 255; + +HRESULT led15093_hook_init( + const struct led15093_config *cfg, + unsigned int port_no_0, + unsigned int port_no_1) +{ + assert(cfg != NULL); + unsigned int port_no[2] = {port_no_0, port_no_1}; + + if (!cfg->enable) { + return S_FALSE; + } + + for (int i = 0; i < led15093_nboards; i++) { + if (cfg->port_no[i] != 0) { + port_no[i] = cfg->port_no[i]; + } + } + + memcpy(led15093_board_num, cfg->board_number, sizeof(led15093_board_num)); + memcpy(led15093_chip_num, cfg->chip_number, sizeof(led15093_chip_num)); + memcpy(led15093_boot_chip_num, cfg->boot_chip_number, sizeof(led15093_boot_chip_num)); + led15093_fw_ver = cfg->fw_ver; + led15093_fw_sum = cfg->fw_sum; + + for (int i = 0; i < led15093_nboards; i++) + { + _led15093_per_board_vars *vb = &led15093_per_board_vars[i]; + + InitializeCriticalSection(&vb->lock); + + if (port_no[i] == 0) { + continue; + } + + uart_init(&vb->boarduart, port_no[i]); + if (cfg->high_baudrate) { + vb->boarduart.baud.BaudRate = 460800; + } else { + vb->boarduart.baud.BaudRate = 115200; + } + vb->boarduart.written.bytes = vb->written_bytes; + vb->boarduart.written.nbytes = sizeof(vb->written_bytes); + vb->boarduart.readable.bytes = vb->readable_bytes; + vb->boarduart.readable.nbytes = sizeof(vb->readable_bytes); + + for (int j = 0; j < led15093_nnodes; j++) + { + _led15093_per_node_vars *vn = &vb->per_node_vars[j]; + + memset(vn->led, 0, sizeof(vn->led)); + memset(vn->led_bright, 0x3F, sizeof(vn->led_bright)); + vn->led_count = led15093_led_count_max; + vn->fade_depth = 32; + vn->fade_cycle = 8; + led15093_clear_status(i, 1 + j); + led15093_clear_report(i, 1 + j); + vn->boardstatus[3] = 1; // DIPSW1 ON + vn->boardadr = 1 + j; + vn->enable_bootloader = false; + vn->enable_response = true; + } + } + + dprintf("LED 15093: hook enabled.\n"); + + return iohook_push_handler(led15093_handle_irp); +} + +static HRESULT led15093_handle_irp(struct irp *irp) +{ + HRESULT hr; + + assert(irp != NULL); + + for (int i = 0; i < led15093_nboards; i++) + { + _led15093_per_board_vars *v = &led15093_per_board_vars[i]; + struct uart *boarduart = &v->boarduart; + + if (uart_match_irp(boarduart, irp)) + { + CRITICAL_SECTION lock = v->lock; + + EnterCriticalSection(&lock); + hr = led15093_handle_irp_locked(i, irp); + LeaveCriticalSection(&lock); + + return hr; + } + } + + return iohook_invoke_next(irp); +} + +static HRESULT led15093_handle_irp_locked(int board, struct irp *irp) +{ + union led15093_req_any req; + struct iobuf req_iobuf; + HRESULT hr; + + _led15093_per_board_vars *v = &led15093_per_board_vars[board]; + struct uart *boarduart = &led15093_per_board_vars[board].boarduart; + + /* + if (irp->op == IRP_OP_OPEN) { + // Unfortunately the LED board UART gets opened and closed repeatedly + + if (!v->started) { + dprintf("LED 15093: Starting LED backend\n"); + // hr = fgo_dll.led_init(); + hr = S_OK; + + v->started = true; + v->start_hr = hr; + + if (FAILED(hr)) { + dprintf("LED 15093: Backend error, LED board disconnected: " + "%x\n", + (int) hr); + + return hr; + } + } else { + hr = v->start_hr; + + if (FAILED(hr)) { + return hr; + } + } + } + */ + + hr = uart_handle_irp(boarduart, irp); + + if (FAILED(hr) || irp->op != IRP_OP_WRITE) { + return hr; + } + + for (;;) { +#if 0 + dprintf("TX Buffer:\n"); + dump_iobuf(&boarduart->written); +#endif + + req_iobuf.bytes = (byte*)&req; + req_iobuf.nbytes = sizeof(req.hdr) + sizeof(req.payload); + req_iobuf.pos = 0; + + hr = led15093_frame_decode(&req_iobuf, &boarduart->written); + + if (hr != S_OK) { + if (hr == HRESULT_FROM_WIN32(ERROR_CRC)) { + led15093_set_status( + board, + 2, + LED_15093_STATUS_TYPE_UART, + LED_15093_STATUS_UART_ERR_SUM); + } + + if (FAILED(hr)) { + dprintf("LED 15093: Deframe error: %x\n", (int) hr); + } + + return hr; + } + +#if 0 + dprintf("Deframe Buffer:\n"); + dump_iobuf(&req_iobuf); +#endif + + hr = led15093_req_dispatch(board, &req); + + if (FAILED(hr)) { + dprintf("LED 15093: Processing error: %x\n", (int) hr); + } + + /* TODO: We should wait for a get board status request with a clear flag, + instead of doing this here. */ + led15093_clear_status(board, req.hdr.dest_adr); + led15093_clear_report(board, req.hdr.dest_adr); + } +} + +static HRESULT led15093_req_dispatch(int board, const union led15093_req_any *req) +{ + switch (req->payload[4]) { + case LED_15093_CMD_RESET: + return led15093_req_reset(board, &req->reset); + + case LED_15093_CMD_SET_TIMEOUT: + return led15093_req_set_timeout(board, &req->set_timeout); + + case LED_15093_CMD_SET_DISABLE_RESPONSE: + return led15093_req_set_response(board, &req->set_disable_response); + + case LED_15093_CMD_SET_ID: + return led15093_req_set_id(board, &req->set_id); + + case LED_15093_CMD_CLEAR_ID: + return led15093_req_clear_id(board, req); + + case LED_15093_CMD_SET_MAX_BRIGHT: + return led15093_req_set_max_bright(board, &req->set_led); + + case LED_15093_CMD_UPDATE_LED: + return led15093_req_update_led(board, req); + + case LED_15093_CMD_SET_LED: + return led15093_req_set_led(board, &req->set_led); + + case LED_15093_CMD_SET_IMM_LED: + // case LED_15093_CMD_SET_IMM_LED_LEGACY: + return led15093_req_set_imm_led(board, &req->set_led); + + case LED_15093_CMD_SET_FADE_LED: + return led15093_req_set_fade_led(board, &req->set_led); + + case LED_15093_CMD_SET_FADE_LEVEL: + return led15093_req_set_fade_level(board, &req->set_fade_level); + + case LED_15093_CMD_SET_FADE_SHIFT: + return led15093_req_set_fade_shift(board, &req->set_fade_shift); + + case LED_15093_CMD_SET_AUTO_SHIFT: + return led15093_req_set_auto_shift(board, &req->set_auto_shift); + + case LED_15093_CMD_GET_BOARD_INFO: + return led15093_req_get_board_info(board, req); + + case LED_15093_CMD_GET_BOARD_STATUS: + return led15093_req_get_board_status(board, &req->get_board_status); + + case LED_15093_CMD_GET_FW_SUM: + return led15093_req_get_fw_sum(board, req); + + case LED_15093_CMD_GET_PROTOCOL_VER: + return led15093_req_get_protocol_ver(board, req); + + case LED_15093_CMD_SET_BOOTMODE: + return led15093_req_set_bootmode(board, req); + + case LED_15093_CMD_FW_UPDATE: + return led15093_req_fw_update(board, req); + + default: + dprintf("LED 15093: Unhandled command %02x\n", req->payload[4]); + led15093_set_report( + board, + req->hdr.dest_adr, + LED_15093_REPORT_ERR2); + + return S_OK; + } +} + +static HRESULT led15093_req_reset(int board, const struct led15093_req_reset *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Reset (board %d, node %d, type %02x)\n", + board, req->hdr.dest_adr, req->r_type); + + if (req->r_type != 0xd9) + dprintf("LED 15093: Warning -- Unknown reset type %02x\n", req->r_type); + + /* A dest_adr of 0 means that this message is addressed to all nodes */ + if (req->hdr.dest_adr == 0) { + for (int i = 0; i < led15093_nnodes; i++) { + led15093_per_board_vars[board].per_node_vars[i].enable_bootloader = false; + led15093_per_board_vars[board].per_node_vars[i].enable_response = true; + } + } else { + v->enable_bootloader = false; + v->enable_response = true; + } + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_RESET; + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_timeout(int board, const struct led15093_req_set_timeout *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Set timeout (board %u, count %u)\n", board, req->count); + + struct led15093_resp_timeout resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 2 + 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_SET_TIMEOUT; + resp.report = v->report_code; + + resp.count_upper = (req->count >> 8) & 0xff; + resp.count_lower = req->count & 0xff; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_response(int board, const struct led15093_req_set_disable_response *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + if (req->hdr.nbytes > 1) { + dprintf("LED 15093: Set LED response setting (board %d, node %d, SW %d)\n", + board, req->hdr.dest_adr, req->sw); + v->enable_response = !req->sw; + } else { + dprintf("LED 15093: Check LED response setting (board %d, node %d)\n", + board, req->hdr.dest_adr); + } + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 1 + 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_SET_DISABLE_RESPONSE; + resp.report = v->report_code; + + resp.data[0] = !v->enable_response; + + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_id(int board, const struct led15093_req_set_id *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Set ID (board %d, requested node ID %d)\n", + board, req->id); + + if (req->id == 0 || req->id > 8) { + dprintf("LED 15093: Error -- Invalid node ID requested: %d\n", + req->id); + led15093_set_status( + board, + v->boardadr, + LED_15093_STATUS_TYPE_CMD, + LED_15093_STATUS_CMD_ERR_PARAM); + + return HRESULT_FROM_WIN32(ERROR_BAD_UNIT); + } + + /* A dest_adr of 0 means that this message is addressed to any unassigned + node..? */ + if (req->hdr.dest_adr == 0) { + bool slot_found = false; + + for (int i = 0; i < led15093_nnodes && slot_found == false; i++) { + if (led15093_per_board_vars[board].per_node_vars[i].boardadr == 0) { + led15093_per_board_vars[board].per_node_vars[i].boardadr = req->id; + slot_found = true; + } + } + + if (!slot_found) { + dprintf("LED 15093: Warning -- Unable to assign requested node " + "%d, all slots full\n", req->hdr.dest_adr); + } + } else { + /* Overwrite current ID. Probably no use case for this but we do it + anyway */ + v->boardadr = req->id; + } + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_SET_ID; + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_clear_id(int board, const union led15093_req_any *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Clear ID (board %d, node %d)\n", + board, req->hdr.dest_adr); + + /* A dest_adr of 0 means that this message is addressed to all nodes */ + if (req->hdr.dest_adr == 0) { + for (int i = 0; i < led15093_nnodes; i++) { + led15093_per_board_vars[board].per_node_vars[i].boardadr = 0; + } + } else { + /* Overwrite current ID. Probably no use case for this but we do it + anyway */ + v->boardadr = 0; + } + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_CLEAR_ID; + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_max_bright(int board, const struct led15093_req_set_led *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Set maximum LED brightness (board %d, node %d)\n", + board, req->hdr.dest_adr); + + if ((req->hdr.nbytes - 1) > (v->led_count * 3)) { + dprintf("LED 15093: Error -- Invalid LED count\n"); + led15093_set_report(board, req->hdr.dest_adr, LED_15093_REPORT_ERR1); + + return E_INVALIDARG; + } + + /* 15093 equivalent of 15070's "set DC data". 63 (0x3F) is, again, the + default. */ + + memcpy(v->led_bright, req->data, req->hdr.nbytes - 1); + + // fgo_dll.led_gr_set_max_bright((const uint8_t*)&v->led_bright); + + if (!v->enable_response) + return S_OK; + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_SET_MAX_BRIGHT; + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + + +static HRESULT led15093_req_update_led(int board, const union led15093_req_any *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + // dprintf("LED 15093: Update LED (board %d, node %d)\n", + // board, req->hdr.dest_adr); + + // fgo_dll.led_gr_set_imm((const uint8_t*)&v->led); + + if (!v->enable_response) + return S_OK; + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_UPDATE_LED; + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_led(int board, const struct led15093_req_set_led *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + // dprintf("LED 15093: Set LED (board %d, node %d)\n", + // board, req->hdr.dest_adr); + + if ((req->hdr.nbytes - 1) > (v->led_count * 3)) { + dprintf("LED 15093: Error -- Invalid LED count\n"); + led15093_set_report(board, req->hdr.dest_adr, LED_15093_REPORT_ERR1); + + return E_INVALIDARG; + } + + memcpy(v->led, req->data, req->hdr.nbytes - 1); + + if (!v->enable_response) + return S_OK; + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_SET_LED; + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_imm_led(int board, const struct led15093_req_set_led *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + // dprintf("LED 15093: Set and immediately draw LED (board %d, node %d)\n", + // board, req->hdr.dest_adr); + + if ((req->hdr.nbytes - 1) > (v->led_count * 3)) { + dprintf("LED 15093: Error -- Invalid LED count\n"); + led15093_set_report(board, req->hdr.dest_adr, LED_15093_REPORT_ERR1); + + return E_INVALIDARG; + } + + memcpy(v->led, req->data, req->hdr.nbytes - 1); + + // fgo_dll.led_gr_set_imm((const uint8_t*)&v->led); + + if (!v->enable_response) + return S_OK; + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + if (req->cmd == LED_15093_CMD_SET_IMM_LED) { + resp.cmd = LED_15093_CMD_SET_IMM_LED; + } + // else { + // resp.cmd = LED_15093_CMD_SET_IMM_LED_LEGACY; + // } + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_fade_led(int board, const struct led15093_req_set_led *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + // dprintf("LED 15093: Set and fade LED (board %d, node %d)\n", + // board, req->hdr.dest_adr); + + if ((req->hdr.nbytes - 1) > (v->led_count * 3)) { + dprintf("LED 15093: Error -- Invalid LED count\n"); + led15093_set_report(board, req->hdr.dest_adr, LED_15093_REPORT_ERR1); + + return E_INVALIDARG; + } + + memcpy(v->led, req->data, req->hdr.nbytes - 1); + + // fgo_dll.led_gr_set_fade( + // (const uint8_t*)v->led, + // v->fade_depth, + // v->fade_cycle); + + if (!v->enable_response) + return S_OK; + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_SET_FADE_LED; + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_fade_level(int board, const struct led15093_req_set_fade_level *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Set fade level (board %d, node %d, depth %d, cycle %d)\n", + board, req->hdr.dest_adr, req->depth, req->cycle); + + v->fade_depth = req->depth; + v->fade_cycle = req->cycle; + + if (!v->enable_response) + return S_OK; + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_SET_FADE_LEVEL; + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_fade_shift(int board, const struct led15093_req_set_fade_shift *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + // dprintf("LED 15093: Set fade shift (board %d, node %d)\n", + // board, req->hdr.dest_adr); + + if (!v->enable_response) + return S_OK; + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_SET_FADE_SHIFT; + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_auto_shift(int board, const struct led15093_req_set_auto_shift *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Set auto shift (board %d, node %d)\n", + board, req->hdr.dest_adr); + + /* There's actually a lot of conflicting info about this command... It + seems they changed the arguments between the -04 and -05 board variants, + and also changed the command ID from 0x87 to 0x86. + + Fortunately, only the -05 variant actually uses this in any shipping + game, so we don't need to implement support for the legacy command + version. */ + + v->led_count = req->count; + + if (!v->enable_response) + return S_OK; + + struct led15093_resp_set_auto_shift resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 1 + 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_SET_AUTO_SHIFT; + resp.report = v->report_code; + + resp.count = v->led_count; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_get_board_info(int board, const union led15093_req_any *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Get board info (board %d, node %d)\n", + board, req->hdr.dest_adr); + + if (str_eq(led15093_board_num, "15093")) { + struct led15093_resp_board_info_legacy resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 7 + 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_GET_BOARD_INFO; + resp.report = v->report_code; + + memcpy(resp.board_num, led15093_board_num, sizeof(resp.board_num)); + resp.endcode = 0xff; + resp.fw_ver = led15093_fw_ver; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); + } else { + struct led15093_resp_board_info resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 18 + 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_GET_BOARD_INFO; + resp.report = v->report_code; + + memcpy(resp.board_num, led15093_board_num, sizeof(resp.board_num)); + resp.lf = 0x0a; + if (v->enable_bootloader) { + memcpy(resp.chip_num, led15093_boot_chip_num, sizeof(resp.chip_num)); + } else { + memcpy(resp.chip_num, led15093_chip_num, sizeof(resp.chip_num)); + } + resp.endcode = 0xff; + resp.fw_ver = led15093_fw_ver; + resp.rx_buf = 204; // Must be 204 regardless of active LED count + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); + } +} + +static HRESULT led15093_req_get_board_status(int board, const struct led15093_req_get_board_status *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Get board status (board %d, node %d, clear %d)\n", + board, req->hdr.dest_adr, req->clear); + + if (req->clear) { + led15093_clear_status(board, req->hdr.dest_adr); + } + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = (v->enable_bootloader) ? (3 + 3) : (4 + 3); + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_GET_BOARD_STATUS; + resp.report = v->report_code; + + if (v->enable_bootloader) { + resp.data[0] = v->boardstatus[0]; // Board flags + resp.data[1] = v->boardstatus[1]; // UART flags + resp.data[2] = v->boardstatus[2]; // Command flags + } else { + resp.data[0] = v->boardstatus[0]; // Board flags + resp.data[1] = v->boardstatus[1]; // UART flags + resp.data[2] = v->boardstatus[2]; // Command flags + resp.data[3] = v->boardstatus[3]; // DIPSW + } + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_get_fw_sum(int board, const union led15093_req_any *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Get firmware checksum (board %d, node %d)\n", + board, req->hdr.dest_adr); + + struct led15093_resp_fw_sum resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 2 + 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_GET_FW_SUM; + resp.report = v->report_code; + + resp.sum_upper = (led15093_fw_sum >> 8) & 0xff; + resp.sum_lower = led15093_fw_sum & 0xff; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_get_protocol_ver(int board, const union led15093_req_any *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Get protocol version (board %d, node %d)\n", + board, req->hdr.dest_adr); + + struct led15093_resp_protocol_ver resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3 + 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_GET_PROTOCOL_VER; + resp.report = v->report_code; + + if (v->enable_bootloader) { + resp.mode = 0; // BOOT mode + resp.major_ver = 1; + resp.minor_ver = 1; + } else { + resp.mode = 1; // APPLI mode + resp.major_ver = 1; + resp.minor_ver = 4; + } + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_set_bootmode(int board, const union led15093_req_any *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Set bootmode (board %d, node %d)\n", + board, req->hdr.dest_adr); + + v->enable_bootloader = true; + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 1 + 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_SET_BOOTMODE; + resp.report = v->report_code; + + resp.data[0] = 1; // IDK but this seems to fix test mode????? + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static HRESULT led15093_req_fw_update(int board, const union led15093_req_any *req) +{ + uint8_t id_idx = (req->hdr.dest_adr < 2) ? 0 : req->hdr.dest_adr - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + dprintf("LED 15093: Firmware update (UNIMPLEMENTED) (board %d, node %d)\n", + board, req->hdr.dest_adr); + + struct led15093_resp_any resp; + + memset(&resp, 0, sizeof(resp)); + resp.hdr.sync = LED_15093_FRAME_SYNC; + resp.hdr.dest_adr = led15093_host_adr; + resp.hdr.src_adr = v->boardadr; + resp.hdr.nbytes = 3; + + resp.status = v->status_code; + resp.cmd = LED_15093_CMD_FW_UPDATE; + resp.report = v->report_code; + + return led15093_frame_encode(&led15093_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); +} + +static void led15093_set_status(int board, int id, uint8_t type, uint8_t status) +{ + uint8_t id_idx = (id < 2) ? 0 : id - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + + if (type == LED_15093_STATUS_TYPE_BOARD) { + /* Set board flag */ + v->boardstatus[0] |= status; + } else if (type == LED_15093_STATUS_TYPE_UART) { + /* Set UART flag */ + v->boardstatus[1] |= status; + /* Set response status code */ + switch (status) { + case LED_15093_STATUS_UART_ERR_SUM: + v->status_code = LED_15093_STATUS_ERR_SUM; + break; + case LED_15093_STATUS_UART_ERR_PARITY: + v->status_code = LED_15093_STATUS_ERR_PARITY; + break; + case LED_15093_STATUS_UART_ERR_FRAMING: + v->status_code = LED_15093_STATUS_ERR_FRAMING; + break; + case LED_15093_STATUS_ERR_OVERRUN: + v->status_code = LED_15093_STATUS_ERR_OVERRUN; + break; + case LED_15093_STATUS_ERR_BUFFER_OVERFLOW: + v->status_code = LED_15093_STATUS_ERR_BUFFER_OVERFLOW; + break; + default: + break; + } + } else if (type == LED_15093_STATUS_TYPE_CMD) { + /* Set command flag */ + v->boardstatus[2] |= status; + } +} + +static void led15093_set_report(int board, int id, uint8_t report) +{ + uint8_t id_idx = (id < 2) ? 0 : id - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + v->report_code = report; +} + +static void led15093_clear_status(int board, int id) +{ + uint8_t id_idx = (id < 2) ? 0 : id - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + if (id == 0) + { + for (int i = 0; i < led15093_nnodes; i++) { + for (int j = 0; j < (_countof(v->boardstatus) - 1); j++) { + led15093_per_board_vars[board].per_node_vars[i].boardstatus[j] = 0; + } + + led15093_per_board_vars[board].per_node_vars[i].status_code = LED_15093_STATUS_OK; + } + } + else + { + v->boardstatus[0] = 0; // Board flags + v->boardstatus[1] = 0; // UART flags + v->boardstatus[2] = 0; // Command flags + + v->status_code = LED_15093_STATUS_OK; + } +} + +static void led15093_clear_report(int board, int id) +{ + if (id == 0) + { + for (int i = 0; i < led15093_nnodes; i++) { + led15093_per_board_vars[board].per_node_vars[i].report_code = LED_15093_REPORT_OK; + } + } + else + { + uint8_t id_idx = (id < 2) ? 0 : id - 2; + _led15093_per_node_vars *v = &led15093_per_board_vars[board].per_node_vars[id_idx]; + + v->report_code = LED_15093_STATUS_OK; + } +} diff --git a/board/led15093.h b/board/led15093.h new file mode 100644 index 0000000..ae4c27c --- /dev/null +++ b/board/led15093.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include +#include + +struct led15093_config { + bool enable; + bool high_baudrate; + unsigned int port_no[2]; + char board_number[8]; + char chip_number[5]; + char boot_chip_number[5]; + uint8_t fw_ver; + uint16_t fw_sum; +}; + +HRESULT led15093_hook_init( + const struct led15093_config *cfg, + unsigned int port_no_0, + unsigned int port_no_1); diff --git a/board/led1509306-cmd.h b/board/led1509306-cmd.h deleted file mode 100644 index 78019dc..0000000 --- a/board/led1509306-cmd.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include "board/led1509306-frame.h" - -enum { - LED_15093_06_CMD_RESET = 0x10, - LED_15093_06_CMD_SET_TIMEOUT = 0x11, - LED_15093_06_CMD_SET_DISABLE_RESPONSE = 0x14, - LED_15093_06_CMD_SET_LED = 0x82, - LED_15093_06_CMD_SET_LED_COUNT = 0x86, - LED_15093_06_CMD_BOARD_INFO = 0xF0, - LED_15093_06_CMD_BOARD_STATUS = 0xF1, - LED_15093_06_CMD_FW_SUM = 0xF2, - LED_15093_06_CMD_PROTOCOL_VER = 0xF3, - LED_15093_06_CMD_BOOTLOADER = 0xFD, -}; - -struct led1509306_req_any { - struct led1509306_hdr hdr; - uint8_t cmd; - uint8_t payload[256]; -}; - -struct led1509306_resp_any { - struct led1509306_hdr hdr; - uint8_t status; - uint8_t cmd; - uint8_t report; - uint8_t data[32]; -}; - -struct led1509306_resp_board_info { - struct led1509306_hdr hdr; - uint8_t status; - uint8_t cmd; - uint8_t report; - struct { - char board_num[8]; - uint8_t _0a; - char chip_num[5]; - uint8_t _ff; - uint8_t fw_ver; - // may be some more data after this that isn't checked - } data; -}; \ No newline at end of file diff --git a/board/led1509306-frame.h b/board/led1509306-frame.h deleted file mode 100644 index a39493e..0000000 --- a/board/led1509306-frame.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include - -#include -#include - -#include "hook/iobuf.h" - -enum { - LED_15093_06_FRAME_SYNC = 0xE0, -}; - -struct led1509306_hdr { - uint8_t sync; - uint8_t dest_adr; - uint8_t src_adr; - uint8_t nbytes; -}; - -HRESULT led1509306_frame_decode(struct iobuf *dest, struct iobuf *src); - -HRESULT led1509306_frame_encode( - struct iobuf *dest, - const void *ptr, - size_t nbytes); diff --git a/board/meson.build b/board/meson.build index df6ce92..b0dd300 100644 --- a/board/meson.build +++ b/board/meson.build @@ -20,9 +20,11 @@ board_lib = static_library( 'io3.h', 'io4.c', 'io4.h', - 'led1509306-cmd.h', - 'led1509306-frame.c', - 'led1509306-frame.h', + 'led15093-cmd.h', + 'led15093-frame.c', + 'led15093-frame.h', + 'led15093.c', + 'led15093.h', 'sg-cmd.c', 'sg-cmd.h', 'sg-frame.c', diff --git a/chunihook/config.c b/chunihook/config.c index afc7fae..92e99de 100644 --- a/chunihook/config.c +++ b/chunihook/config.c @@ -43,33 +43,65 @@ void slider_config_load(struct slider_config *cfg, const wchar_t *filename) cfg->enable = GetPrivateProfileIntW(L"slider", L"enable", 1, filename); } -void led1509306_config_load(struct led1509306_config *cfg, const wchar_t *filename) +void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) { assert(cfg != NULL); assert(filename != NULL); wchar_t tmpstr[16]; - + memset(cfg->board_number, ' ', sizeof(cfg->board_number)); memset(cfg->chip_number, ' ', sizeof(cfg->chip_number)); - - cfg->enable = GetPrivateProfileIntW(L"ledstrip", L"enable", 1, filename); - cfg->fw_ver = GetPrivateProfileIntW(L"ledstrip", L"fw_ver", 0x90, filename); - cfg->fw_sum = GetPrivateProfileIntW(L"ledstrip", L"fw_sum", 0xadf7, filename); - - GetPrivateProfileStringW(L"ledstrip", L"board_number", L"15093-06", tmpstr, _countof(tmpstr), filename); + memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number)); + + cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); + cfg->port_no[0] = GetPrivateProfileIntW(L"led15093", L"portNo0", 0, filename); + cfg->port_no[1] = GetPrivateProfileIntW(L"led15093", L"portNo1", 0, filename); + cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaudrate", 0, filename); + cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0x90, filename); + cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xadf7, filename); + + GetPrivateProfileStringW( + L"led15093", + L"boardNumber", + L"15093-06", + 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"ledstrip", L"chip_number", L"6710 ", tmpstr, _countof(tmpstr), filename); + + GetPrivateProfileStringW( + L"led15093", + L"chipNumber", + L"6710 ", + tmpstr, + _countof(tmpstr), + filename); + n = wcstombs(cfg->chip_number, tmpstr, sizeof(cfg->chip_number)); for (int i = n; i < sizeof(cfg->chip_number); i++) { cfg->chip_number[i] = ' '; - } + } + + GetPrivateProfileStringW( + L"led15093", + L"bootChipNumber", + L"6709 ", + tmpstr, + _countof(tmpstr), + filename); + + n = wcstombs(cfg->boot_chip_number, tmpstr, sizeof(cfg->boot_chip_number)); + for (int i = n; i < sizeof(cfg->boot_chip_number); i++) + { + cfg->boot_chip_number[i] = ' '; + } } void chuni_hook_config_load( @@ -87,5 +119,5 @@ void chuni_hook_config_load( gfx_config_load(&cfg->gfx, filename); chuni_dll_config_load(&cfg->dll, filename); slider_config_load(&cfg->slider, filename); - led1509306_config_load(&cfg->led1509306, filename); + led15093_config_load(&cfg->led15093, filename); } diff --git a/chunihook/config.h b/chunihook/config.h index d7a392b..8902b85 100644 --- a/chunihook/config.h +++ b/chunihook/config.h @@ -6,10 +6,10 @@ #include "amex/amex.h" #include "board/sg-reader.h" +#include "board/led15093.h" #include "chunihook/chuni-dll.h" #include "chunihook/slider.h" -#include "chunihook/led1509306.h" #include "gfxhook/gfx.h" @@ -22,7 +22,7 @@ struct chuni_hook_config { struct gfx_config gfx; struct chuni_dll_config dll; struct slider_config slider; - struct led1509306_config led1509306; + struct led15093_config led15093; }; void chuni_dll_config_load( diff --git a/chunihook/dllmain.c b/chunihook/dllmain.c index 5303378..bd68994 100644 --- a/chunihook/dllmain.c +++ b/chunihook/dllmain.c @@ -9,7 +9,6 @@ #include "chunihook/config.h" #include "chunihook/jvs.h" #include "chunihook/slider.h" -#include "chunihook/led1509306.h" #include "chuniio/chuniio.h" @@ -97,7 +96,7 @@ static DWORD CALLBACK chuni_pre_startup(void) goto fail; } - hr = led1509306_hook_init(&chuni_hook_cfg.led1509306); + hr = led15093_hook_init(&chuni_hook_cfg.led15093, 10, 11); if (FAILED(hr)) { goto fail; diff --git a/chunihook/led1509306.c b/chunihook/led1509306.c deleted file mode 100644 index 47fdd09..0000000 --- a/chunihook/led1509306.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - SEGA 837-15093-06 LED controller emulator - - Credits: - - somewhatlurker, skogaby -*/ - -#include - -#include -#include -#include -#include -#include - -#include "board/led1509306-cmd.h" -#include "board/led1509306-frame.h" - -#include "chunihook/led1509306.h" - -#include "hook/iobuf.h" -#include "hook/iohook.h" - -#include "hooklib/uart.h" - -#include "util/dprintf.h" -#include "util/dump.h" - -static HRESULT led1509306_handle_irp(struct irp *irp); -static HRESULT led1509306_handle_irp_locked(int board, struct irp *irp); - -static HRESULT led1509306_req_dispatch(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_reset(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_get_board_info(int board); -static HRESULT led1509306_req_get_fw_sum(int board); -static HRESULT led1509306_req_get_protocol_ver(int board); -static HRESULT led1509306_req_get_board_status(int board); -static HRESULT led1509306_req_set_led(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_set_disable_response(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_set_timeout(int board, const struct led1509306_req_any *req); - -static char led1509306_board_num[8]; -static char led1509306_chip_num[5]; -static uint8_t led1509306_fw_ver; -static uint16_t led1509306_fw_sum; -static uint8_t led1509306_board_adr = 2; -static uint8_t led1509306_host_adr = 1; - -#define led1509306_nboards 2 - -typedef struct { - CRITICAL_SECTION lock; - struct uart boarduart; - uint8_t written_bytes[520]; - uint8_t readable_bytes[520]; - bool enable_response; -} _led1509306_per_board_vars; - -_led1509306_per_board_vars led1509306_per_board_vars[led1509306_nboards]; - -HRESULT led1509306_hook_init(const struct led1509306_config *cfg) -{ - assert(cfg != NULL); - - if (!cfg->enable) { - return S_FALSE; - } - - memcpy(led1509306_board_num, cfg->board_number, sizeof(led1509306_board_num)); - memcpy(led1509306_chip_num, cfg->chip_number, sizeof(led1509306_chip_num)); - led1509306_fw_ver = cfg->fw_ver; - led1509306_fw_sum = cfg->fw_sum; - - for (int i = 0; i < led1509306_nboards; i++) - { - _led1509306_per_board_vars *v = &led1509306_per_board_vars[i]; - - InitializeCriticalSection(&v->lock); - - uart_init(&v->boarduart, 10 + i); - v->boarduart.written.bytes = v->written_bytes; - v->boarduart.written.nbytes = sizeof(v->written_bytes); - v->boarduart.readable.bytes = v->readable_bytes; - v->boarduart.readable.nbytes = sizeof(v->readable_bytes); - - v->enable_response = true; - } - - return iohook_push_handler(led1509306_handle_irp); -} - -static HRESULT led1509306_handle_irp(struct irp *irp) -{ - HRESULT hr; - - assert(irp != NULL); - - for (int i = 0; i < led1509306_nboards; i++) - { - _led1509306_per_board_vars *v = &led1509306_per_board_vars[i]; - struct uart *boarduart = &v->boarduart; - - if (uart_match_irp(boarduart, irp)) - { - CRITICAL_SECTION lock = v->lock; - - EnterCriticalSection(&lock); - hr = led1509306_handle_irp_locked(i, irp); - LeaveCriticalSection(&lock); - - return hr; - } - } - - return iohook_invoke_next(irp); -} - -static HRESULT led1509306_handle_irp_locked(int board, struct irp *irp) -{ - struct led1509306_req_any req; - struct iobuf req_iobuf; - HRESULT hr; - - struct uart *boarduart = &led1509306_per_board_vars[board].boarduart; - - hr = uart_handle_irp(boarduart, irp); - - if (FAILED(hr) || irp->op != IRP_OP_WRITE) { - return hr; - } - - for (;;) { -#if 0 - dprintf("TX Buffer:\n"); - dump_iobuf(&boarduart->written); -#endif - - req_iobuf.bytes = (byte*)&req; - req_iobuf.nbytes = sizeof(req.hdr) + sizeof(req.cmd) + sizeof(req.payload); - req_iobuf.pos = 0; - - hr = led1509306_frame_decode(&req_iobuf, &boarduart->written); - - if (hr != S_OK) { - if (FAILED(hr)) { - dprintf("Chunithm LED Strip: Deframe error: %x\n", (int) hr); - } - - return hr; - } - -#if 0 - dprintf("Deframe Buffer:\n"); - dump_iobuf(&req_iobuf); -#endif - - hr = led1509306_req_dispatch(board, &req); - - if (FAILED(hr)) { - dprintf("Chunithm LED Strip: Processing error: %x\n", (int) hr); - } - } -} - -static HRESULT led1509306_req_dispatch(int board, const struct led1509306_req_any *req) -{ - switch (req->cmd) { - case LED_15093_06_CMD_RESET: - return led1509306_req_reset(board, req); - - case LED_15093_06_CMD_BOARD_INFO: - return led1509306_req_get_board_info(board); - - case LED_15093_06_CMD_FW_SUM: - return led1509306_req_get_fw_sum(board); - - case LED_15093_06_CMD_PROTOCOL_VER: - return led1509306_req_get_protocol_ver(board); - - case LED_15093_06_CMD_BOARD_STATUS: - return led1509306_req_get_board_status(board); - - case LED_15093_06_CMD_SET_LED: - return led1509306_req_set_led(board, req); - - case LED_15093_06_CMD_SET_DISABLE_RESPONSE: - return led1509306_req_set_disable_response(board, req); - - case LED_15093_06_CMD_SET_TIMEOUT: - return led1509306_req_set_timeout(board, req); - - default: - dprintf("Chunithm LED Strip: Unhandled command %02x\n", req->cmd); - - return S_OK; - } -} - -static HRESULT led1509306_req_reset(int board, const struct led1509306_req_any *req) -{ - dprintf("Chunithm LED Strip: Reset (board %u, type %02x)\n", board, req->payload[0]); - - if (req->payload[0] != 0xd9) - dprintf("Chunithm LED Strip: Warning -- Unknown reset type %02x\n", req->payload[0]); - - led1509306_per_board_vars[board].enable_response = true; - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_RESET; - resp.report = 1; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_board_info(int board) -{ - dprintf("Chunithm LED Strip: Get board info (board %u)\n", board); - - struct led1509306_resp_board_info resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = sizeof(resp.data) + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_BOARD_INFO; - resp.report = 1; - - memcpy(resp.data.board_num, led1509306_board_num, sizeof(resp.data.board_num)); - resp.data._0a = 0x0a; - memcpy(resp.data.chip_num, led1509306_chip_num, sizeof(resp.data.chip_num)); - resp.data._ff = 0xff; - resp.data.fw_ver = led1509306_fw_ver; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_fw_sum(int board) -{ - dprintf("Chunithm LED Strip: Get firmware checksum (board %u)\n", board); - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 2 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_FW_SUM; - resp.report = 1; - - resp.data[0] = (led1509306_fw_sum >> 8) & 0xff; - resp.data[1] = led1509306_fw_sum & 0xff; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_protocol_ver(int board) -{ - dprintf("Chunithm LED Strip: Get protocol version (board %u)\n", board); - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 3 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_PROTOCOL_VER; - resp.report = 1; - - resp.data[0] = 1; - resp.data[1] = 1; - resp.data[2] = 4; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_board_status(int board) -{ - dprintf("Chunithm LED Strip: Get board status (board %u)\n", board); - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 4 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_BOARD_STATUS; - resp.report = 1; - - resp.data[0] = 0; - resp.data[1] = 0; - resp.data[2] = 0; - resp.data[3] = 0; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_set_led(int board, const struct led1509306_req_any *req) -{ - // dprintf("Chunithm LED Strip: Set LED (board %u)\n", board); - - if (!led1509306_per_board_vars[board].enable_response) - return S_OK; - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_SET_LED; - resp.report = 1; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_set_disable_response(int board, const struct led1509306_req_any *req) -{ - dprintf("Chunithm LED Strip: Disable LED responses (board %u)\n", board); - - led1509306_per_board_vars[board].enable_response = !req->payload[0]; - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 1 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_SET_DISABLE_RESPONSE; - resp.report = 1; - - resp.data[0] = req->payload[0]; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_set_timeout(int board, const struct led1509306_req_any *req) -{ - dprintf("Chunithm LED Strip: Set timeout (board %u)\n", board); - - // not actually implemented, but respond correctly anyway - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 2 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_SET_TIMEOUT; - resp.report = 1; - - resp.data[0] = req->payload[0]; - resp.data[1] = req->payload[1]; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} diff --git a/chunihook/led1509306.h b/chunihook/led1509306.h deleted file mode 100644 index 15c7c3e..0000000 --- a/chunihook/led1509306.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -#include - -struct led1509306_config { - bool enable; - 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); diff --git a/chunihook/meson.build b/chunihook/meson.build index b4c464d..3f4a35d 100644 --- a/chunihook/meson.build +++ b/chunihook/meson.build @@ -30,7 +30,5 @@ shared_library( 'jvs.h', 'slider.c', 'slider.h', - 'led1509306.c', - 'led1509306.h', ], ) diff --git a/chusanhook/config.c b/chusanhook/config.c index 7b290f3..f585926 100644 --- a/chusanhook/config.c +++ b/chusanhook/config.c @@ -71,34 +71,76 @@ void slider_config_load(struct slider_config *cfg, const wchar_t *filename) cfg->enable = GetPrivateProfileIntW(L"slider", L"enable", 1, filename); } -void led1509306_config_load(struct led1509306_config *cfg, const wchar_t *filename) +void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) { assert(cfg != NULL); assert(filename != NULL); wchar_t tmpstr[16]; - + bool cvt_port; + memset(cfg->board_number, ' ', sizeof(cfg->board_number)); memset(cfg->chip_number, ' ', sizeof(cfg->chip_number)); - - cfg->enable = GetPrivateProfileIntW(L"ledstrip", L"enable", 1, filename); - cfg->cvt_port = GetPrivateProfileIntW(L"ledstrip", L"cvt_port", 0, filename); - cfg->fw_ver = GetPrivateProfileIntW(L"ledstrip", L"fw_ver", 0x90, filename); - cfg->fw_sum = GetPrivateProfileIntW(L"ledstrip", L"fw_sum", 0xadf7, filename); - - GetPrivateProfileStringW(L"ledstrip", L"board_number", L"15093-06", tmpstr, _countof(tmpstr), filename); + memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number)); + + cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); + cvt_port = GetPrivateProfileIntW(L"led15093", L"cvtPort", 0, filename); + + if (!cvt_port) { + // SP mode: COM20, COM21 + cfg->port_no[0] = 20; + cfg->port_no[1] = 21; + } else { + // CVT mode: COM2, COM3 + cfg->port_no[0] = 2; + cfg->port_no[1] = 3; + } + + cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaudrate", 0, filename); + cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0x90, filename); + cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xadf7, filename); + + GetPrivateProfileStringW( + L"led15093", + L"boardNumber", + L"15093-06", + 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"ledstrip", L"chip_number", L"6710 ", tmpstr, _countof(tmpstr), filename); + + GetPrivateProfileStringW( + L"led15093", + L"chipNumber", + L"6710 ", + tmpstr, + _countof(tmpstr), + filename); + n = wcstombs(cfg->chip_number, tmpstr, sizeof(cfg->chip_number)); for (int i = n; i < sizeof(cfg->chip_number); i++) { cfg->chip_number[i] = ' '; - } + } + + GetPrivateProfileStringW( + L"led15093", + L"bootChipNumber", + L"6709 ", + tmpstr, + _countof(tmpstr), + filename); + + n = wcstombs(cfg->boot_chip_number, tmpstr, sizeof(cfg->boot_chip_number)); + for (int i = n; i < sizeof(cfg->boot_chip_number); i++) + { + cfg->boot_chip_number[i] = ' '; + } } @@ -118,5 +160,5 @@ void chusan_hook_config_load( gfx_config_load(&cfg->gfx, filename); chuni_dll_config_load(&cfg->dll, filename); slider_config_load(&cfg->slider, filename); - led1509306_config_load(&cfg->led1509306, filename); + led15093_config_load(&cfg->led15093, filename); } diff --git a/chusanhook/config.h b/chusanhook/config.h index 856112b..48fb696 100644 --- a/chusanhook/config.h +++ b/chusanhook/config.h @@ -3,6 +3,7 @@ #include #include "board/config.h" +#include "board/led15093.h" #include "hooklib/dvd.h" @@ -12,7 +13,6 @@ #include "chusanhook/chuni-dll.h" #include "chusanhook/slider.h" -#include "chusanhook/led1509306.h" struct chusan_hook_config { struct platform_config platform; @@ -22,7 +22,7 @@ struct chusan_hook_config { struct gfx_config gfx; struct chuni_dll_config dll; struct slider_config slider; - struct led1509306_config led1509306; + struct led15093_config led15093; }; void chuni_dll_config_load( diff --git a/chusanhook/dllmain.c b/chusanhook/dllmain.c index 4b23983..8522f67 100644 --- a/chusanhook/dllmain.c +++ b/chusanhook/dllmain.c @@ -11,7 +11,6 @@ #include "chusanhook/config.h" #include "chusanhook/io4.h" #include "chusanhook/slider.h" -#include "chusanhook/led1509306.h" #include "chuniio/chuniio.h" @@ -100,7 +99,7 @@ static DWORD CALLBACK chusan_pre_startup(void) goto fail; } - hr = led1509306_hook_init(&chusan_hook_cfg.led1509306); + hr = led15093_hook_init(&chusan_hook_cfg.led15093, 20, 21); if (FAILED(hr)) { goto fail; diff --git a/chusanhook/led1509306.c b/chusanhook/led1509306.c deleted file mode 100644 index 420c6f5..0000000 --- a/chusanhook/led1509306.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - SEGA 837-15093-06 LED controller emulator - - Credits: - - somewhatlurker, skogaby -*/ - -#include - -#include -#include -#include -#include -#include - -#include "board/led1509306-cmd.h" -#include "board/led1509306-frame.h" - -#include "chusanhook/led1509306.h" - -#include "hook/iobuf.h" -#include "hook/iohook.h" - -#include "hooklib/uart.h" - -#include "util/dprintf.h" -#include "util/dump.h" - -static HRESULT led1509306_handle_irp(struct irp *irp); -static HRESULT led1509306_handle_irp_locked(int board, struct irp *irp); - -static HRESULT led1509306_req_dispatch(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_reset(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_get_board_info(int board); -static HRESULT led1509306_req_get_fw_sum(int board); -static HRESULT led1509306_req_get_protocol_ver(int board); -static HRESULT led1509306_req_get_board_status(int board); -static HRESULT led1509306_req_set_led(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_set_disable_response(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_set_timeout(int board, const struct led1509306_req_any *req); - -static char led1509306_board_num[8]; -static char led1509306_chip_num[5]; -static uint8_t led1509306_fw_ver; -static uint16_t led1509306_fw_sum; -static uint8_t led1509306_board_adr = 2; -static uint8_t led1509306_host_adr = 1; - -#define led1509306_nboards 2 - -typedef struct { - CRITICAL_SECTION lock; - struct uart boarduart; - uint8_t written_bytes[520]; - uint8_t readable_bytes[520]; - bool enable_response; -} _led1509306_per_board_vars; - -_led1509306_per_board_vars led1509306_per_board_vars[led1509306_nboards]; - -HRESULT led1509306_hook_init(const struct led1509306_config *cfg) -{ - assert(cfg != NULL); - - if (!cfg->enable) { - return S_FALSE; - } - - memcpy(led1509306_board_num, cfg->board_number, sizeof(led1509306_board_num)); - memcpy(led1509306_chip_num, cfg->chip_number, sizeof(led1509306_chip_num)); - led1509306_fw_ver = cfg->fw_ver; - led1509306_fw_sum = cfg->fw_sum; - - int com_ports[2]; - - if (!cfg->cvt_port) { - // SP mode: COM20, COM21 - com_ports[0] = 20; - com_ports[1] = 21; - } else { - // CVT mode: COM2, COM3 - com_ports[0] = 2; - com_ports[1] = 3; - } - - for (int i = 0; i < led1509306_nboards; i++) - { - _led1509306_per_board_vars *v = &led1509306_per_board_vars[i]; - - InitializeCriticalSection(&v->lock); - - uart_init(&v->boarduart, com_ports[i]); - v->boarduart.written.bytes = v->written_bytes; - v->boarduart.written.nbytes = sizeof(v->written_bytes); - v->boarduart.readable.bytes = v->readable_bytes; - v->boarduart.readable.nbytes = sizeof(v->readable_bytes); - - v->enable_response = true; - } - - return iohook_push_handler(led1509306_handle_irp); -} - -static HRESULT led1509306_handle_irp(struct irp *irp) -{ - HRESULT hr; - - assert(irp != NULL); - - for (int i = 0; i < led1509306_nboards; i++) - { - _led1509306_per_board_vars *v = &led1509306_per_board_vars[i]; - struct uart *boarduart = &v->boarduart; - - if (uart_match_irp(boarduart, irp)) - { - CRITICAL_SECTION lock = v->lock; - - EnterCriticalSection(&lock); - hr = led1509306_handle_irp_locked(i, irp); - LeaveCriticalSection(&lock); - - return hr; - } - } - - return iohook_invoke_next(irp); -} - -static HRESULT led1509306_handle_irp_locked(int board, struct irp *irp) -{ - struct led1509306_req_any req; - struct iobuf req_iobuf; - HRESULT hr; - - struct uart *boarduart = &led1509306_per_board_vars[board].boarduart; - - hr = uart_handle_irp(boarduart, irp); - - if (FAILED(hr) || irp->op != IRP_OP_WRITE) { - return hr; - } - - for (;;) { -#if 0 - dprintf("TX Buffer:\n"); - dump_iobuf(&boarduart->written); -#endif - - req_iobuf.bytes = (byte*)&req; - req_iobuf.nbytes = sizeof(req.hdr) + sizeof(req.cmd) + sizeof(req.payload); - req_iobuf.pos = 0; - - hr = led1509306_frame_decode(&req_iobuf, &boarduart->written); - - if (hr != S_OK) { - if (FAILED(hr)) { - dprintf("Chunithm LED Strip: Deframe error: %x\n", (int) hr); - } - - return hr; - } - -#if 0 - dprintf("Deframe Buffer:\n"); - dump_iobuf(&req_iobuf); -#endif - - hr = led1509306_req_dispatch(board, &req); - - if (FAILED(hr)) { - dprintf("Chunithm LED Strip: Processing error: %x\n", (int) hr); - } - } -} - -static HRESULT led1509306_req_dispatch(int board, const struct led1509306_req_any *req) -{ - switch (req->cmd) { - case LED_15093_06_CMD_RESET: - return led1509306_req_reset(board, req); - - case LED_15093_06_CMD_BOARD_INFO: - return led1509306_req_get_board_info(board); - - case LED_15093_06_CMD_FW_SUM: - return led1509306_req_get_fw_sum(board); - - case LED_15093_06_CMD_PROTOCOL_VER: - return led1509306_req_get_protocol_ver(board); - - case LED_15093_06_CMD_BOARD_STATUS: - return led1509306_req_get_board_status(board); - - case LED_15093_06_CMD_SET_LED: - return led1509306_req_set_led(board, req); - - case LED_15093_06_CMD_SET_DISABLE_RESPONSE: - return led1509306_req_set_disable_response(board, req); - - case LED_15093_06_CMD_SET_TIMEOUT: - return led1509306_req_set_timeout(board, req); - - default: - dprintf("Chunithm LED Strip: Unhandled command %02x\n", req->cmd); - - return S_OK; - } -} - -static HRESULT led1509306_req_reset(int board, const struct led1509306_req_any *req) -{ - dprintf("Chunithm LED Strip: Reset (board %u, type %02x)\n", board, req->payload[0]); - - if (req->payload[0] != 0xd9) - dprintf("Chunithm LED Strip: Warning -- Unknown reset type %02x\n", req->payload[0]); - - led1509306_per_board_vars[board].enable_response = true; - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_RESET; - resp.report = 1; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_board_info(int board) -{ - dprintf("Chunithm LED Strip: Get board info (board %u)\n", board); - - struct led1509306_resp_board_info resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = sizeof(resp.data) + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_BOARD_INFO; - resp.report = 1; - - memcpy(resp.data.board_num, led1509306_board_num, sizeof(resp.data.board_num)); - resp.data._0a = 0x0a; - memcpy(resp.data.chip_num, led1509306_chip_num, sizeof(resp.data.chip_num)); - resp.data._ff = 0xff; - resp.data.fw_ver = led1509306_fw_ver; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_fw_sum(int board) -{ - dprintf("Chunithm LED Strip: Get firmware checksum (board %u)\n", board); - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 2 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_FW_SUM; - resp.report = 1; - - resp.data[0] = (led1509306_fw_sum >> 8) & 0xff; - resp.data[1] = led1509306_fw_sum & 0xff; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_protocol_ver(int board) -{ - dprintf("Chunithm LED Strip: Get protocol version (board %u)\n", board); - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 3 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_PROTOCOL_VER; - resp.report = 1; - - resp.data[0] = 1; - resp.data[1] = 1; - resp.data[2] = 4; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_board_status(int board) -{ - dprintf("Chunithm LED Strip: Get board status (board %u)\n", board); - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 4 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_BOARD_STATUS; - resp.report = 1; - - resp.data[0] = 0; - resp.data[1] = 0; - resp.data[2] = 0; - resp.data[3] = 0; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_set_led(int board, const struct led1509306_req_any *req) -{ - // dprintf("Chunithm LED Strip: Set LED (board %u)\n", board); - - if (!led1509306_per_board_vars[board].enable_response) - return S_OK; - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_SET_LED; - resp.report = 1; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_set_disable_response(int board, const struct led1509306_req_any *req) -{ - dprintf("Chunithm LED Strip: Disable LED responses (board %u)\n", board); - - led1509306_per_board_vars[board].enable_response = !req->payload[0]; - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 1 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_SET_DISABLE_RESPONSE; - resp.report = 1; - - resp.data[0] = req->payload[0]; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_set_timeout(int board, const struct led1509306_req_any *req) -{ - dprintf("Chunithm LED Strip: Set timeout (board %u)\n", board); - - // not actually implemented, but respond correctly anyway - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 2 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_SET_TIMEOUT; - resp.report = 1; - - resp.data[0] = req->payload[0]; - resp.data[1] = req->payload[1]; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} diff --git a/chusanhook/meson.build b/chusanhook/meson.build index 02c82b0..69250bb 100644 --- a/chusanhook/meson.build +++ b/chusanhook/meson.build @@ -28,7 +28,5 @@ shared_library( 'io4.h', 'slider.c', 'slider.h', - 'led1509306.c', - 'led1509306.h', ], ) diff --git a/dist/chuni/segatools.ini b/dist/chuni/segatools.ini index 7385546..7724c30 100644 --- a/dist/chuni/segatools.ini +++ b/dist/chuni/segatools.ini @@ -38,6 +38,10 @@ monitor=0 ; Leave empty if you want to use Segatools built-in keyboard input. path= +[led15093] +; 837-15093-06 LED strip emulation setting. +enable=1 + [chuniio] ; To use a custom Chunithm IO DLL enter its path here. ; Leave empty if you want to use Segatools built-in keyboard input. diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index b1da417..dc6e2ae 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -44,7 +44,7 @@ enable=1 ; LAN Install: If multiple machines are present on the same LAN then set ; this to 1 on exactly one machine and set this to 0 on all others. dipsw1=1 -; Monitor type: 0 = 120FPS, 1 = 60FPS +; Monitor type: 0 = 120FPS (SP), 1 = 60FPS (CVT) dipsw2=1 ; Aime reader hardware type: 0 = SP, 1 = CVT dipsw3=1 @@ -57,6 +57,18 @@ framed=1 ; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen) monitor=0 +[led15093] +; 837-15093-06 LED strip emulation setting. +enable=1 +; Set to 1 if running game in 60FPS (CVT) mode. +cvtPort=0 + +[chuniio] +; Uncomment this if you have custom chuniio implementation. +; x86 chuniio to path32, x64 to path64. Both are necessary. +;path32= +;path64= + ; ----------------------------------------------------------------------------- ; Input settings ; ----------------------------------------------------------------------------- @@ -79,18 +91,12 @@ coin=0x33 ; Set to 0 for enable separate ir control. Deafult is space key. ir=0x20 -[io4] -enable=1 - -[ledstrip] -; Set to 1 if running game in CVT mode. -cvt_port=0 - -[chuniio] -; Uncomment this if you have custom chuniio implementation. -; x86 chuniio to path32, x64 to path64. Both are necessary. -;path32= -;path64= +[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. @@ -116,10 +122,3 @@ cvt_port=0 ; Enable slider LED serial output. This follows OpeNITHM Serial LED Protocol. ; eg. COM5 ;ledport= - -[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 \ No newline at end of file diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index 0d99009..18e2bbb 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -58,10 +58,14 @@ enable=1 [ftdi] ; FTDI serial to usb adapter emulation for CABINET LED. enable=1 +; COM port number where the LED board is connected to. +portNo=17 -[ledstrip] -; 837-15093-06 LED strip emulation setting. +[led15093] +; 837-15093-06 LED board emulation setting. enable=1 +; COM port number for the first LED board. Has to be the same as the FTDI port. +portNo0=17 ; ----------------------------------------------------------------------------- ; Input settings diff --git a/fgohook/config.c b/fgohook/config.c index be6bdd0..3253568 100644 --- a/fgohook/config.c +++ b/fgohook/config.c @@ -32,10 +32,10 @@ void ftdi_config_load(struct ftdi_config *cfg, const wchar_t *filename) assert(filename != NULL); cfg->enable = GetPrivateProfileIntW(L"ftdi", L"enable", 1, filename); - cfg->port_no = GetPrivateProfileIntW(L"ftdi", L"port", 17, filename); + cfg->port_no = GetPrivateProfileIntW(L"ftdi", L"portNo", 0, filename); } -void led1509306_config_load(struct led1509306_config *cfg, const wchar_t *filename) +void led15093_config_load(struct led15093_config *cfg, const wchar_t *filename) { assert(cfg != NULL); assert(filename != NULL); @@ -44,25 +44,56 @@ void led1509306_config_load(struct led1509306_config *cfg, const wchar_t *filena memset(cfg->board_number, ' ', sizeof(cfg->board_number)); memset(cfg->chip_number, ' ', sizeof(cfg->chip_number)); - - cfg->enable = GetPrivateProfileIntW(L"ledstrip", L"enable", 1, filename); - cfg->port_no = GetPrivateProfileIntW(L"ledstrip", L"port", 17, filename); - cfg->fw_ver = GetPrivateProfileIntW(L"ledstrip", L"fw_ver", 0xA0, filename); - cfg->fw_sum = GetPrivateProfileIntW(L"ledstrip", L"fw_sum", 0xaa53, filename); - - GetPrivateProfileStringW(L"ledstrip", L"board_number", L"15093-06", tmpstr, _countof(tmpstr), filename); + memset(cfg->boot_chip_number, ' ', sizeof(cfg->boot_chip_number)); + + cfg->enable = GetPrivateProfileIntW(L"led15093", L"enable", 1, filename); + cfg->port_no[0] = GetPrivateProfileIntW(L"led15093", L"portNo0", 0, filename); + cfg->port_no[1] = GetPrivateProfileIntW(L"led15093", L"portNo1", 0, filename); + cfg->high_baudrate = GetPrivateProfileIntW(L"led15093", L"highBaudrate", 0, filename); + cfg->fw_ver = GetPrivateProfileIntW(L"led15093", L"fwVer", 0xA0, filename); + cfg->fw_sum = GetPrivateProfileIntW(L"led15093", L"fwSum", 0xaa53, filename); + + GetPrivateProfileStringW( + L"led15093", + L"boardNumber", + L"15093-06", + 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"ledstrip", L"chip_number", L"6710A", tmpstr, _countof(tmpstr), filename); + + GetPrivateProfileStringW( + L"led15093", + L"chipNumber", + L"6710A", + tmpstr, + _countof(tmpstr), + filename); + n = wcstombs(cfg->chip_number, tmpstr, sizeof(cfg->chip_number)); for (int i = n; i < sizeof(cfg->chip_number); i++) { cfg->chip_number[i] = ' '; - } + } + + GetPrivateProfileStringW( + L"led15093", + L"bootChipNumber", + L"6709 ", + tmpstr, + _countof(tmpstr), + filename); + + n = wcstombs(cfg->boot_chip_number, tmpstr, sizeof(cfg->boot_chip_number)); + for (int i = n; i < sizeof(cfg->boot_chip_number); i++) + { + cfg->boot_chip_number[i] = ' '; + } } void fgo_deck_config_load( @@ -90,6 +121,6 @@ void fgo_hook_config_load( printer_config_load(&cfg->printer, filename); fgo_deck_config_load(&cfg->deck, filename); ftdi_config_load(&cfg->ftdi, filename); - led1509306_config_load(&cfg->led1509306, filename); + led15093_config_load(&cfg->led15093, filename); fgo_dll_config_load(&cfg->dll, filename); } diff --git a/fgohook/config.h b/fgohook/config.h index a2cad3b..59b48ee 100644 --- a/fgohook/config.h +++ b/fgohook/config.h @@ -3,6 +3,7 @@ #include #include "board/config.h" +#include "board/led15093.h" #include "hooklib/dvd.h" #include "hooklib/touch.h" @@ -10,7 +11,6 @@ #include "fgohook/deck.h" #include "fgohook/ftdi.h" -#include "fgohook/led1509306.h" #include "fgohook/fgo-dll.h" #include "platform/config.h" @@ -24,7 +24,7 @@ struct fgo_hook_config { struct printer_config printer; struct deck_config deck; struct ftdi_config ftdi; - struct led1509306_config led1509306; + struct led15093_config led15093; struct fgo_dll_config dll; }; diff --git a/fgohook/dllmain.c b/fgohook/dllmain.c index 2c3af8e..4f71216 100644 --- a/fgohook/dllmain.c +++ b/fgohook/dllmain.c @@ -90,13 +90,13 @@ static DWORD CALLBACK fgo_pre_startup(void) goto fail; } - hr = ftdi_hook_init(&fgo_hook_cfg.ftdi); + hr = ftdi_hook_init(&fgo_hook_cfg.ftdi, 17); if (FAILED(hr)) { goto fail; } - hr = led1509306_hook_init(&fgo_hook_cfg.led1509306); + hr = led15093_hook_init(&fgo_hook_cfg.led15093, 17, 0); if (FAILED(hr)) { goto fail; diff --git a/fgohook/ftdi.c b/fgohook/ftdi.c index bda7507..91aea04 100644 --- a/fgohook/ftdi.c +++ b/fgohook/ftdi.c @@ -121,7 +121,7 @@ static const struct hook_symbol reg_syms[] = { static HANDLE ftdi_fd; static char port_name[8]; -HRESULT ftdi_hook_init(const struct ftdi_config *cfg) { +HRESULT ftdi_hook_init(const struct ftdi_config *cfg, unsigned int port_no) { HRESULT hr; assert(cfg != NULL); @@ -130,6 +130,10 @@ HRESULT ftdi_hook_init(const struct ftdi_config *cfg) { return S_FALSE; } + if (cfg->port_no != 0) { + port_no = cfg->port_no; + } + hook_table_apply( NULL, "setupapi.dll", @@ -156,7 +160,7 @@ HRESULT ftdi_hook_init(const struct ftdi_config *cfg) { return hr; } - sprintf(port_name, "COM%d", cfg->port_no); + sprintf(port_name, "COM%d", port_no); dprintf("FTDI: Hook enabled.\n"); return S_OK; diff --git a/fgohook/ftdi.h b/fgohook/ftdi.h index e1cd9d6..18e5d73 100644 --- a/fgohook/ftdi.h +++ b/fgohook/ftdi.h @@ -18,4 +18,4 @@ DEFINE_GUID( 0x11D0, 0x9C, 0xE4, 0x08, 0x00, 0x3E, 0x30, 0x1F, 0x73); -HRESULT ftdi_hook_init(const struct ftdi_config *cfg); +HRESULT ftdi_hook_init(const struct ftdi_config *cfg, unsigned int port_no); diff --git a/fgohook/led1509306.c b/fgohook/led1509306.c deleted file mode 100644 index e922738..0000000 --- a/fgohook/led1509306.c +++ /dev/null @@ -1,387 +0,0 @@ -/* - SEGA 837-15093-06 LED controller emulator - - Credits: - - somewhatlurker, skogaby -*/ - -#include - -#include -#include -#include -#include -#include - -#include "board/led1509306-cmd.h" -#include "board/led1509306-frame.h" - -#include "fgohook/led1509306.h" - -#include "hook/iobuf.h" -#include "hook/iohook.h" - -#include "hooklib/uart.h" - -#include "util/dprintf.h" -#include "util/dump.h" - -static HRESULT led1509306_handle_irp(struct irp *irp); -static HRESULT led1509306_handle_irp_locked(int board, struct irp *irp); - -static HRESULT led1509306_req_dispatch(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_reset(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_get_board_info(int board); -static HRESULT led1509306_req_get_fw_sum(int board); -static HRESULT led1509306_req_get_protocol_ver(int board); -static HRESULT led1509306_req_get_board_status(int board); -static HRESULT led1509306_req_set_led(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_set_disable_response(int board, const struct led1509306_req_any *req); -static HRESULT led1509306_req_set_timeout(int board, const struct led1509306_req_any *req); - -static char led1509306_board_num[8]; -static char led1509306_chip_num[5]; -static uint8_t led1509306_fw_ver; -static uint16_t led1509306_fw_sum; -static uint8_t led1509306_board_adr = 2; -static uint8_t led1509306_host_adr = 1; - -#define led1509306_nboards 2 - -typedef struct { - CRITICAL_SECTION lock; - struct uart boarduart; - uint8_t written_bytes[520]; - uint8_t readable_bytes[520]; - bool enable_response; -} _led1509306_per_board_vars; - -_led1509306_per_board_vars led1509306_per_board_vars[led1509306_nboards]; - -HRESULT led1509306_hook_init(const struct led1509306_config *cfg) -{ - assert(cfg != NULL); - - if (!cfg->enable) { - return S_FALSE; - } - - memcpy(led1509306_board_num, cfg->board_number, sizeof(led1509306_board_num)); - memcpy(led1509306_chip_num, cfg->chip_number, sizeof(led1509306_chip_num)); - led1509306_fw_ver = cfg->fw_ver; - led1509306_fw_sum = cfg->fw_sum; - - for (int i = 0; i < led1509306_nboards; i++) - { - _led1509306_per_board_vars *v = &led1509306_per_board_vars[i]; - - InitializeCriticalSection(&v->lock); - - uart_init(&v->boarduart, cfg->port_no + i); - v->boarduart.written.bytes = v->written_bytes; - v->boarduart.written.nbytes = sizeof(v->written_bytes); - v->boarduart.readable.bytes = v->readable_bytes; - v->boarduart.readable.nbytes = sizeof(v->readable_bytes); - - v->enable_response = true; - } - - dprintf("LED Strip: hook enabled.\n"); - - return iohook_push_handler(led1509306_handle_irp); -} - -static HRESULT led1509306_handle_irp(struct irp *irp) -{ - HRESULT hr; - - assert(irp != NULL); - - for (int i = 0; i < led1509306_nboards; i++) - { - _led1509306_per_board_vars *v = &led1509306_per_board_vars[i]; - struct uart *boarduart = &v->boarduart; - - if (uart_match_irp(boarduart, irp)) - { - CRITICAL_SECTION lock = v->lock; - - EnterCriticalSection(&lock); - hr = led1509306_handle_irp_locked(i, irp); - LeaveCriticalSection(&lock); - - return hr; - } - } - - return iohook_invoke_next(irp); -} - -static HRESULT led1509306_handle_irp_locked(int board, struct irp *irp) -{ - struct led1509306_req_any req; - struct iobuf req_iobuf; - HRESULT hr; - - struct uart *boarduart = &led1509306_per_board_vars[board].boarduart; - - hr = uart_handle_irp(boarduart, irp); - - if (FAILED(hr) || irp->op != IRP_OP_WRITE) { - return hr; - } - - for (;;) { -#if 0 - dprintf("TX Buffer:\n"); - dump_iobuf(&boarduart->written); -#endif - - req_iobuf.bytes = (byte*)&req; - req_iobuf.nbytes = sizeof(req.hdr) + sizeof(req.cmd) + sizeof(req.payload); - req_iobuf.pos = 0; - - hr = led1509306_frame_decode(&req_iobuf, &boarduart->written); - - if (hr != S_OK) { - if (FAILED(hr)) { - dprintf("LED Strip: Deframe error: %x\n", (int) hr); - } - - return hr; - } - -#if 0 - dprintf("Deframe Buffer:\n"); - dump_iobuf(&req_iobuf); -#endif - - hr = led1509306_req_dispatch(board, &req); - - if (FAILED(hr)) { - dprintf("LED Strip: Processing error: %x\n", (int) hr); - } - } -} - -static HRESULT led1509306_req_dispatch(int board, const struct led1509306_req_any *req) -{ - switch (req->cmd) { - case LED_15093_06_CMD_RESET: - return led1509306_req_reset(board, req); - - case LED_15093_06_CMD_BOARD_INFO: - return led1509306_req_get_board_info(board); - - case LED_15093_06_CMD_FW_SUM: - return led1509306_req_get_fw_sum(board); - - case LED_15093_06_CMD_PROTOCOL_VER: - return led1509306_req_get_protocol_ver(board); - - case LED_15093_06_CMD_BOARD_STATUS: - return led1509306_req_get_board_status(board); - - case LED_15093_06_CMD_SET_LED: - return led1509306_req_set_led(board, req); - - case LED_15093_06_CMD_SET_DISABLE_RESPONSE: - return led1509306_req_set_disable_response(board, req); - - case LED_15093_06_CMD_SET_TIMEOUT: - return led1509306_req_set_timeout(board, req); - - default: - dprintf("LED Strip: Unhandled command %02x\n", req->cmd); - - return S_OK; - } -} - -static HRESULT led1509306_req_reset(int board, const struct led1509306_req_any *req) -{ - dprintf("LED Strip: Reset (board %u, type %02x)\n", board, req->payload[0]); - - if (req->payload[0] != 0xd9) - dprintf("LED Strip: Warning -- Unknown reset type %02x\n", req->payload[0]); - - led1509306_per_board_vars[board].enable_response = true; - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_RESET; - resp.report = 1; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_board_info(int board) -{ - dprintf("LED Strip: Get board info (board %u)\n", board); - - struct led1509306_resp_board_info resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = sizeof(resp.data) + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_BOARD_INFO; - resp.report = 1; - - memcpy(resp.data.board_num, led1509306_board_num, sizeof(resp.data.board_num)); - resp.data._0a = 0x0a; - memcpy(resp.data.chip_num, led1509306_chip_num, sizeof(resp.data.chip_num)); - resp.data._ff = 0xff; - resp.data.fw_ver = led1509306_fw_ver; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_fw_sum(int board) -{ - dprintf("LED Strip: Get firmware checksum (board %u)\n", board); - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 2 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_FW_SUM; - resp.report = 1; - - resp.data[0] = (led1509306_fw_sum >> 8) & 0xff; - resp.data[1] = led1509306_fw_sum & 0xff; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_protocol_ver(int board) -{ - dprintf("LED Strip: Get protocol version (board %u)\n", board); - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 3 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_PROTOCOL_VER; - resp.report = 1; - - resp.data[0] = 1; - resp.data[1] = 1; - resp.data[2] = 4; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_get_board_status(int board) -{ - dprintf("LED Strip: Get board status (board %u)\n", board); - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 4 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_BOARD_STATUS; - resp.report = 1; - - resp.data[0] = 0; - resp.data[1] = 0; - resp.data[2] = 0; - resp.data[3] = 0; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_set_led(int board, const struct led1509306_req_any *req) -{ - // dprintf("LED Strip: Set LED (board %u)\n", board); - - if (!led1509306_per_board_vars[board].enable_response) - return S_OK; - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_SET_LED; - resp.report = 1; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_set_disable_response(int board, const struct led1509306_req_any *req) -{ - dprintf("LED Strip: Disable LED responses (board %u)\n", board); - - led1509306_per_board_vars[board].enable_response = !req->payload[0]; - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 1 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_SET_DISABLE_RESPONSE; - resp.report = 1; - - resp.data[0] = req->payload[0]; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} - -static HRESULT led1509306_req_set_timeout(int board, const struct led1509306_req_any *req) -{ - dprintf("LED Strip: Set timeout (board %u)\n", board); - - // not actually implemented, but respond correctly anyway - - struct led1509306_resp_any resp; - - memset(&resp, 0, sizeof(resp)); - resp.hdr.sync = LED_15093_06_FRAME_SYNC; - resp.hdr.dest_adr = led1509306_host_adr; - resp.hdr.src_adr = led1509306_board_adr; - resp.hdr.nbytes = 2 + 3; - - resp.status = 1; - resp.cmd = LED_15093_06_CMD_SET_TIMEOUT; - resp.report = 1; - - resp.data[0] = req->payload[0]; - resp.data[1] = req->payload[1]; - - return led1509306_frame_encode(&led1509306_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes); -} diff --git a/fgohook/led1509306.h b/fgohook/led1509306.h deleted file mode 100644 index f4b3260..0000000 --- a/fgohook/led1509306.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -#include - -struct led1509306_config { - bool enable; - unsigned int port_no; - 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); diff --git a/fgohook/meson.build b/fgohook/meson.build index 11737b2..2e9772f 100644 --- a/fgohook/meson.build +++ b/fgohook/meson.build @@ -30,7 +30,5 @@ shared_library( 'deck.h', 'ftdi.c', 'ftdi.h', - 'led1509306.c', - 'led1509306.h', ], )