mirror of
https://gitea.tendokyu.moe/Hay1tsme/segatools.git
synced 2026-05-09 04:03:03 -05:00
## Overview This PR addresses the severe memory leak and performance issues observed in `mai2`, while also introducing improvements to the touch emulation logic. ## Root Cause Analysis As discussed previously, the root cause of the `mai2` memory leak is not a global `segatools` buffer bug. Instead, the game aggressively spams overlapped empty reads specifically on the `LED 15070` UART. On real hardware, the serial driver naturally throttles this. Under emulation, without a throttle, it hits approximately **260kHz of empty async reads**, which causes the memory usage to explode. ## The Fix Instead of introducing complex locking mechanisms and condition variables globally in `uart.c`, this PR applies a targeted fix: * Added a local `Sleep(1)` directly in `common/board/led15070.c` to rate-limit empty reads on the LED path. * Because this is isolated to LED communications, it completely resolves the memory leak without introducing any lag, livelocks, or overhead to other critical inputs. ## Additional Changes in this PR Alongside the memory leak fix, this PR includes a few touch-related improvements (as touch emulation was reviewed during the debugging process): * Enhanced touch input handling and improved auto-scan state management. * Implemented IOCTL handling for touch input to properly manage communication status. ## Testing * **mai2:** Tested successfully on multiple machines. The memory leak is completely gone, and the game runs smoothly. * **chusan:** Tested to ensure no regressions. Sliders and inputs work flawlessly without the lag. Reviewed-on: https://gitea.tendokyu.moe/TeamTofuShop/segatools/pulls/101 Co-authored-by: Gl0w1amp <gl0w1amp@noreply.gitea.tendokyu.moe> Co-committed-by: Gl0w1amp <gl0w1amp@noreply.gitea.tendokyu.moe>
1391 lines
43 KiB
C
1391 lines
43 KiB
C
/*
|
|
SEGA 837-15070-0X LED Controller Board Emulator
|
|
|
|
Credits:
|
|
837-15070-04 LED Controller Board Emulator (emihiok)
|
|
837-15093-06 LED Controller Board Emulator (somewhatlurker, skogaby)
|
|
(a/o June 2023)
|
|
*/
|
|
|
|
#include <windows.h>
|
|
|
|
#include <assert.h>
|
|
#include <process.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "board/led15070-cmd.h"
|
|
#include "board/led15070-frame.h"
|
|
|
|
#include "board/led15070.h"
|
|
|
|
#include "hook/iobuf.h"
|
|
#include "hook/iohook.h"
|
|
|
|
#include "hooklib/uart.h"
|
|
|
|
#include "util/dprintf.h"
|
|
#include "util/dump.h"
|
|
|
|
static HRESULT led15070_handle_irp(struct irp *irp);
|
|
static HRESULT led15070_handle_irp_locked(int board, struct irp *irp);
|
|
|
|
static HRESULT led15070_req_dispatch(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_reset(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_set_input(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_set_normal_12bit(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_set_normal_8bit(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_set_multi_flash_8bit(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_set_multi_fade_8bit(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_set_palette_7_normal_led(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_set_palette_6_flash_led(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_set_15dc_out(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_set_15gs_out(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_set_psc_max(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_set_fet_output(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_set_gs_palette(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_dc_update(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_gs_update(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_rotate(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_set_dc_data(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_eeprom_write(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_eeprom_read(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_ack_on(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_ack_off(int board, const struct led15070_req_any *req);
|
|
static HRESULT led15070_req_board_info(int board);
|
|
static HRESULT led15070_req_board_status(int board);
|
|
static HRESULT led15070_req_fw_sum(int board);
|
|
static HRESULT led15070_req_protocol_ver(int board);
|
|
static HRESULT led15070_req_to_boot_mode(int board);
|
|
static HRESULT led15070_req_fw_update(int board, const struct led15070_req_any *req);
|
|
|
|
static HRESULT led15070_eeprom_open(int board, wchar_t *path, HANDLE *handle);
|
|
static HRESULT led15070_eeprom_close(int board, wchar_t *path, HANDLE *handle);
|
|
|
|
static char led15070_board_num[8];
|
|
static uint8_t led15070_fw_ver;
|
|
static uint16_t led15070_fw_sum;
|
|
static uint8_t led15070_host_adr = 0x01;
|
|
|
|
#define led15070_nboards 2
|
|
#define led15070_nleds 32
|
|
|
|
typedef struct {
|
|
CRITICAL_SECTION lock;
|
|
bool started;
|
|
HRESULT start_hr;
|
|
struct uart boarduart;
|
|
uint8_t written_bytes[520];
|
|
uint8_t readable_bytes[520];
|
|
uint8_t gs[led15070_nleds][4];
|
|
uint8_t gs_fade[led15070_nleds][4];
|
|
bool gs_fade_pending[led15070_nleds];
|
|
uint8_t dc[led15070_nleds][3];
|
|
uint8_t fet[3];
|
|
uint8_t gs_palette[8][3];
|
|
wchar_t eeprom_path[MAX_PATH];
|
|
HANDLE eeprom_handle;
|
|
uint8_t boardadr;
|
|
bool enable_bootloader;
|
|
bool enable_response;
|
|
} _led15070_per_board_vars;
|
|
|
|
_led15070_per_board_vars led15070_per_board_vars[led15070_nboards];
|
|
|
|
static io_led_init_t led_init;
|
|
static io_led_set_fet_output_t led_set_fet_output;
|
|
static io_led_dc_update_t led_dc_update;
|
|
static io_led_gs_update_t led_gs_update;
|
|
|
|
HRESULT led15070_hook_init(
|
|
const struct led15070_config *cfg,
|
|
io_led_init_t _led_init,
|
|
io_led_set_fet_output_t _led_set_fet_output,
|
|
io_led_dc_update_t _led_dc_update,
|
|
io_led_gs_update_t _led_gs_update,
|
|
unsigned int port_no[2])
|
|
{
|
|
unsigned int num_boards = 0;
|
|
|
|
assert(cfg != NULL);
|
|
assert(_led_init != NULL);
|
|
|
|
if (!cfg->enable) {
|
|
return S_FALSE;
|
|
}
|
|
|
|
for (int i = 0; i < led15070_nboards; i++)
|
|
{
|
|
if (cfg->port_no[i] != 0) {
|
|
port_no[i] = cfg->port_no[i];
|
|
}
|
|
|
|
if (port_no[i] != 0) {
|
|
num_boards++;
|
|
}
|
|
}
|
|
|
|
assert(num_boards != 0);
|
|
|
|
led_init = _led_init;
|
|
led_set_fet_output = _led_set_fet_output;
|
|
led_dc_update = _led_dc_update;
|
|
led_gs_update = _led_gs_update;
|
|
|
|
memcpy(led15070_board_num, cfg->board_number, sizeof(led15070_board_num));
|
|
led15070_fw_ver = cfg->fw_ver;
|
|
led15070_fw_sum = cfg->fw_sum;
|
|
|
|
for (int i = 0; i < num_boards; i++)
|
|
{
|
|
_led15070_per_board_vars *v = &led15070_per_board_vars[i];
|
|
|
|
InitializeCriticalSection(&v->lock);
|
|
|
|
uart_init(&v->boarduart, port_no[i]);
|
|
v->boarduart.baud.BaudRate = 115200;
|
|
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);
|
|
|
|
memset(v->gs, 0, sizeof(v->gs));
|
|
memset(v->gs_fade, 0, sizeof(v->gs_fade));
|
|
memset(v->gs_fade_pending, 0, sizeof(v->gs_fade_pending));
|
|
memset(v->dc, 0, sizeof(v->dc));
|
|
memset(v->fet, 0, sizeof(v->fet));
|
|
memset(v->gs_palette, 0, sizeof(v->gs_palette));
|
|
memset(v->eeprom_path, 0, sizeof(v->eeprom_path));
|
|
v->eeprom_handle = NULL;
|
|
|
|
swprintf_s
|
|
(
|
|
v->eeprom_path, MAX_PATH,
|
|
L"%s\\led15070_eeprom_%d.bin",
|
|
cfg->eeprom_path, i
|
|
);
|
|
|
|
/* Generate board EEPROM file if it doesn't already exist */
|
|
led15070_eeprom_open(i, v->eeprom_path, &(v->eeprom_handle));
|
|
led15070_eeprom_close(i, v->eeprom_path, &(v->eeprom_handle));
|
|
|
|
v->boardadr = 0x11;
|
|
v->enable_bootloader = false;
|
|
v->enable_response = false;
|
|
}
|
|
|
|
dprintf("LED 15070: hook enabled.\n");
|
|
|
|
return iohook_push_handler(led15070_handle_irp);
|
|
}
|
|
|
|
static HRESULT led15070_handle_irp(struct irp *irp)
|
|
{
|
|
HRESULT hr;
|
|
|
|
assert(irp != NULL);
|
|
|
|
for (int i = 0; i < led15070_nboards; i++)
|
|
{
|
|
_led15070_per_board_vars *v = &led15070_per_board_vars[i];
|
|
struct uart *boarduart = &v->boarduart;
|
|
|
|
if (uart_match_irp(boarduart, irp))
|
|
{
|
|
CRITICAL_SECTION lock = v->lock;
|
|
|
|
EnterCriticalSection(&lock);
|
|
hr = led15070_handle_irp_locked(i, irp);
|
|
LeaveCriticalSection(&lock);
|
|
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
return iohook_invoke_next(irp);
|
|
}
|
|
|
|
static HRESULT led15070_handle_irp_locked(int board, struct irp *irp)
|
|
{
|
|
struct led15070_req_any req;
|
|
struct iobuf req_iobuf;
|
|
HRESULT hr;
|
|
|
|
_led15070_per_board_vars *v = &led15070_per_board_vars[board];
|
|
struct uart *boarduart = &led15070_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 15070: Starting LED backend\n");
|
|
hr = led_init();
|
|
|
|
v->started = true;
|
|
v->start_hr = hr;
|
|
|
|
if (FAILED(hr)) {
|
|
dprintf("LED 15070: Backend error, LED controller "
|
|
"disconnected: %x\n",
|
|
(int) hr);
|
|
|
|
return hr;
|
|
}
|
|
} else {
|
|
hr = v->start_hr;
|
|
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (irp->op == IRP_OP_READ) {
|
|
if (irp->ovl != NULL && boarduart->readable.pos == 0) {
|
|
Sleep(1);
|
|
}
|
|
}
|
|
|
|
hr = uart_handle_irp(boarduart, irp);
|
|
|
|
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
|
|
return hr;
|
|
}
|
|
|
|
for (;;) {
|
|
#if defined(LOG_LED15070)
|
|
dprintf("TX Buffer:\n");
|
|
dump_iobuf(&boarduart->written);
|
|
#endif
|
|
|
|
req_iobuf.bytes = (uint8_t*)&req;
|
|
req_iobuf.nbytes = sizeof(req.hdr) + sizeof(req.cmd) + sizeof(req.payload);
|
|
req_iobuf.pos = 0;
|
|
|
|
hr = led15070_frame_decode(&req_iobuf, &boarduart->written);
|
|
|
|
if (hr != S_OK) {
|
|
if (FAILED(hr)) {
|
|
dprintf("LED 15070: Deframe error: %x\n", (int) hr);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
#if defined(LOG_LED15070)
|
|
dprintf("Deframe Buffer:\n");
|
|
dump_iobuf(&req_iobuf);
|
|
#endif
|
|
|
|
hr = led15070_req_dispatch(board, &req);
|
|
|
|
if (FAILED(hr)) {
|
|
dprintf("LED 15070: Processing error: %x\n", (int) hr);
|
|
}
|
|
}
|
|
}
|
|
|
|
static HRESULT led15070_req_dispatch(int board, const struct led15070_req_any *req)
|
|
{
|
|
switch (req->cmd) {
|
|
case LED_15070_CMD_RESET:
|
|
return led15070_req_reset(board, req);
|
|
|
|
case LED_15070_CMD_SET_INPUT:
|
|
return led15070_req_set_input(board, req);
|
|
|
|
case LED_15070_CMD_SET_NORMAL_12BIT:
|
|
return led15070_req_set_normal_12bit(board, req);
|
|
|
|
case LED_15070_CMD_SET_NORMAL_8BIT:
|
|
return led15070_req_set_normal_8bit(board, req);
|
|
|
|
case LED_15070_CMD_SET_MULTI_FLASH_8BIT:
|
|
return led15070_req_set_multi_flash_8bit(board, req);
|
|
|
|
case LED_15070_CMD_SET_MULTI_FADE_8BIT:
|
|
return led15070_req_set_multi_fade_8bit(board, req);
|
|
|
|
case LED_15070_CMD_SET_PALETTE_7_NORMAL_LED:
|
|
return led15070_req_set_palette_7_normal_led(board, req);
|
|
|
|
case LED_15070_CMD_SET_PALETTE_6_FLASH_LED:
|
|
return led15070_req_set_palette_6_flash_led(board, req);
|
|
|
|
case LED_15070_CMD_SET_15DC_OUT:
|
|
return led15070_req_set_15dc_out(board, req);
|
|
|
|
case LED_15070_CMD_SET_15GS_OUT:
|
|
return led15070_req_set_15gs_out(board, req);
|
|
|
|
case LED_15070_CMD_SET_PSC_MAX:
|
|
return led15070_req_set_psc_max(board, req);
|
|
|
|
case LED_15070_CMD_SET_FET_OUTPUT:
|
|
return led15070_req_set_fet_output(board, req);
|
|
|
|
case LED_15070_CMD_SET_GS_PALETTE:
|
|
return led15070_req_set_gs_palette(board, req);
|
|
|
|
case LED_15070_CMD_DC_UPDATE:
|
|
return led15070_req_dc_update(board, req);
|
|
|
|
case LED_15070_CMD_GS_UPDATE:
|
|
return led15070_req_gs_update(board, req);
|
|
|
|
case LED_15070_CMD_ROTATE:
|
|
return led15070_req_rotate(board, req);
|
|
|
|
case LED_15070_CMD_SET_DC_DATA:
|
|
return led15070_req_set_dc_data(board, req);
|
|
|
|
case LED_15070_CMD_EEPROM_WRITE:
|
|
return led15070_req_eeprom_write(board, req);
|
|
|
|
case LED_15070_CMD_EEPROM_READ:
|
|
return led15070_req_eeprom_read(board, req);
|
|
|
|
case LED_15070_CMD_ACK_ON:
|
|
return led15070_req_ack_on(board, req);
|
|
|
|
case LED_15070_CMD_ACK_OFF:
|
|
return led15070_req_ack_off(board, req);
|
|
|
|
case LED_15070_CMD_BOARD_INFO:
|
|
return led15070_req_board_info(board);
|
|
|
|
case LED_15070_CMD_BOARD_STATUS:
|
|
return led15070_req_board_status(board);
|
|
|
|
case LED_15070_CMD_FW_SUM:
|
|
return led15070_req_fw_sum(board);
|
|
|
|
case LED_15070_CMD_PROTOCOL_VER:
|
|
return led15070_req_protocol_ver(board);
|
|
|
|
case LED_15070_CMD_TO_BOOT_MODE:
|
|
return led15070_req_to_boot_mode(board);
|
|
|
|
case LED_15070_CMD_FW_UPDATE:
|
|
return led15070_req_fw_update(board, req);
|
|
|
|
default:
|
|
dprintf("LED 15070: Unhandled command %02x\n", req->cmd);
|
|
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
static HRESULT led15070_req_reset(int board, const struct led15070_req_any *req)
|
|
{
|
|
dprintf("LED 15070: Reset (board %u)\n", board);
|
|
|
|
led15070_per_board_vars[board].enable_bootloader = false;
|
|
led15070_per_board_vars[board].enable_response = true;
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_RESET;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_set_input(int board, const struct led15070_req_any *req)
|
|
{
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Set input (board %u)\n", board);
|
|
#endif
|
|
|
|
if (!led15070_per_board_vars[board].enable_response)
|
|
return S_OK;
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_SET_INPUT;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_set_normal_12bit(int board, const struct led15070_req_any *req)
|
|
{
|
|
uint8_t idx = req->payload[0];
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Set LED - Normal 12bit (board %u, index %u)\n",
|
|
board, idx);
|
|
#endif
|
|
|
|
// TODO: Data for this command. Seen with Carol
|
|
|
|
if (!led15070_per_board_vars[board].enable_response)
|
|
return S_OK;
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_SET_NORMAL_12BIT;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_set_normal_8bit(int board, const struct led15070_req_any *req)
|
|
{
|
|
uint8_t idx = req->payload[0];
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Set LED - Normal 8bit (board %u, index %u)\n",
|
|
board, idx);
|
|
#endif
|
|
|
|
led15070_per_board_vars[board].gs[idx][0] = req->payload[1]; // R
|
|
led15070_per_board_vars[board].gs[idx][1] = req->payload[2]; // G
|
|
led15070_per_board_vars[board].gs[idx][2] = req->payload[3]; // B
|
|
led15070_per_board_vars[board].gs[idx][3] = 0;
|
|
led15070_per_board_vars[board].gs_fade_pending[idx] = false;
|
|
|
|
if (!led15070_per_board_vars[board].enable_response)
|
|
return S_OK;
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_SET_NORMAL_8BIT;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static void led15070_calc_range(
|
|
uint8_t start,
|
|
uint8_t count,
|
|
uint8_t skip,
|
|
uint8_t *out_start,
|
|
uint8_t *out_end)
|
|
{
|
|
uint16_t s = start;
|
|
uint16_t c = count;
|
|
|
|
if (c == 0) {
|
|
*out_start = 0;
|
|
*out_end = 0;
|
|
return;
|
|
}
|
|
|
|
if (c >= led15070_nleds) {
|
|
c = led15070_nleds;
|
|
}
|
|
|
|
if (skip > 0 && skip <= c) {
|
|
s += skip;
|
|
c -= skip;
|
|
}
|
|
|
|
if (s >= led15070_nleds || c == 0) {
|
|
*out_start = led15070_nleds;
|
|
*out_end = led15070_nleds;
|
|
return;
|
|
}
|
|
|
|
*out_start = (uint8_t) s;
|
|
*out_end = (s + c > led15070_nleds) ? led15070_nleds : (uint8_t) (s + c);
|
|
}
|
|
|
|
static HRESULT led15070_req_set_multi_flash_8bit(int board, const struct led15070_req_any *req)
|
|
{
|
|
uint8_t idx_start = req->payload[0];
|
|
uint8_t idx_count = req->payload[1];
|
|
uint8_t idx_skip = req->payload[2];
|
|
uint8_t start;
|
|
uint8_t end;
|
|
|
|
// TODO: useful?
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Set LED - Multi flash 8bit (board %u, start %u, count %u, skip %u)\n",
|
|
board, idx_start, idx_count, idx_skip);
|
|
#endif
|
|
|
|
led15070_calc_range(idx_start, idx_count, idx_skip, &start, &end);
|
|
|
|
for (int i = start; i < end; i++) {
|
|
led15070_per_board_vars[board].gs[i][0] = req->payload[3]; // R
|
|
led15070_per_board_vars[board].gs[i][1] = req->payload[4]; // G
|
|
led15070_per_board_vars[board].gs[i][2] = req->payload[5]; // B
|
|
/* Always 0, tells the controller to immediately change to this color */
|
|
led15070_per_board_vars[board].gs[i][3] = req->payload[6]; // Speed
|
|
led15070_per_board_vars[board].gs_fade_pending[i] = false;
|
|
}
|
|
|
|
if (!led15070_per_board_vars[board].enable_response)
|
|
return S_OK;
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_SET_MULTI_FLASH_8BIT;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_set_multi_fade_8bit(int board, const struct led15070_req_any *req)
|
|
{
|
|
uint8_t idx_start = req->payload[0];
|
|
uint8_t idx_count = req->payload[1];
|
|
uint8_t idx_skip = req->payload[2];
|
|
uint8_t start;
|
|
uint8_t end;
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Set LED - Multi fade 8bit (board %u, start %u, count %u, skip %u)\n",
|
|
board, idx_start, idx_count, idx_skip);
|
|
#endif
|
|
|
|
led15070_calc_range(idx_start, idx_count, idx_skip, &start, &end);
|
|
|
|
for (int i = start; i < end; i++) {
|
|
led15070_per_board_vars[board].gs_fade[i][0] = req->payload[3]; // R
|
|
led15070_per_board_vars[board].gs_fade[i][1] = req->payload[4]; // G
|
|
led15070_per_board_vars[board].gs_fade[i][2] = req->payload[5]; // B
|
|
led15070_per_board_vars[board].gs_fade[i][3] = req->payload[6]; // Speed
|
|
led15070_per_board_vars[board].gs_fade_pending[i] = true;
|
|
}
|
|
|
|
if (!led15070_per_board_vars[board].enable_response)
|
|
return S_OK;
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_SET_MULTI_FADE_8BIT;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_set_palette_7_normal_led(int board, const struct led15070_req_any *req)
|
|
{
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Set palette - 7 Normal LED (board %u)\n", board);
|
|
#endif
|
|
|
|
if (!led15070_per_board_vars[board].enable_response)
|
|
return S_OK;
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_SET_PALETTE_7_NORMAL_LED;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_set_palette_6_flash_led(int board, const struct led15070_req_any *req)
|
|
{
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Set palette - 6 Flash LED (board %u)\n", board);
|
|
#endif
|
|
|
|
if (!led15070_per_board_vars[board].enable_response)
|
|
return S_OK;
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_SET_PALETTE_6_FLASH_LED;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_set_15dc_out(int board, const struct led15070_req_any *req)
|
|
{
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Set 15DC out (board %u)\n", board);
|
|
#endif
|
|
|
|
if (!led15070_per_board_vars[board].enable_response)
|
|
return S_OK;
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_SET_15DC_OUT;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_set_15gs_out(int board, const struct led15070_req_any *req)
|
|
{
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Set 15GS out (board %u)\n", board);
|
|
#endif
|
|
|
|
if (!led15070_per_board_vars[board].enable_response)
|
|
return S_OK;
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_SET_15GS_OUT;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_set_psc_max(int board, const struct led15070_req_any *req)
|
|
{
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Set PSC max (board %u)\n", board);
|
|
#endif
|
|
|
|
if (!led15070_per_board_vars[board].enable_response)
|
|
return S_OK;
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_SET_PSC_MAX;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_set_fet_output(int board, const struct led15070_req_any *req)
|
|
{
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Set FET output (board %u)\n", board);
|
|
#endif
|
|
|
|
led15070_per_board_vars[board].fet[0] = req->payload[0]; // R or FET0 intensity
|
|
led15070_per_board_vars[board].fet[1] = req->payload[1]; // G or FET1 intensity
|
|
led15070_per_board_vars[board].fet[2] = req->payload[2]; // B or FET2 intensity
|
|
|
|
if (led_set_fet_output)
|
|
led_set_fet_output(board, (const uint8_t*)led15070_per_board_vars[board].fet);
|
|
|
|
if (!led15070_per_board_vars[board].enable_response)
|
|
return S_OK;
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_SET_FET_OUTPUT;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_set_gs_palette(int board, const struct led15070_req_any *req)
|
|
{
|
|
uint8_t idx = req->payload[0];
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Set GS palette (board %u, index %u)\n", board, idx);
|
|
#endif
|
|
|
|
led15070_per_board_vars[board].gs_palette[idx][0] = req->payload[1]; // R
|
|
led15070_per_board_vars[board].gs_palette[idx][1] = req->payload[2]; // G
|
|
led15070_per_board_vars[board].gs_palette[idx][2] = req->payload[3]; // B
|
|
|
|
if (!led15070_per_board_vars[board].enable_response)
|
|
return S_OK;
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_SET_GS_PALETTE;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_dc_update(int board, const struct led15070_req_any *req)
|
|
{
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: DC update (board %u)\n", board);
|
|
#endif
|
|
|
|
if (led_dc_update)
|
|
led_dc_update(board, (const uint8_t*)led15070_per_board_vars[board].dc);
|
|
|
|
if (!led15070_per_board_vars[board].enable_response)
|
|
return S_OK;
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_DC_UPDATE;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_gs_update(int board, const struct led15070_req_any *req)
|
|
{
|
|
_led15070_per_board_vars *v = &led15070_per_board_vars[board];
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: GS update (board %u)\n", board);
|
|
#endif
|
|
|
|
if (led_gs_update) {
|
|
bool has_fade = false;
|
|
uint8_t payload[led15070_nleds][4];
|
|
|
|
for (int i = 0; i < led15070_nleds; i++) {
|
|
if (v->gs_fade_pending[i]) {
|
|
has_fade = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (has_fade) {
|
|
for (int i = 0; i < led15070_nleds; i++) {
|
|
payload[i][0] = v->gs[i][0];
|
|
payload[i][1] = v->gs[i][1];
|
|
payload[i][2] = v->gs[i][2];
|
|
payload[i][3] = 0;
|
|
}
|
|
|
|
led_gs_update(board, (const uint8_t*)payload);
|
|
|
|
for (int i = 0; i < led15070_nleds; i++) {
|
|
if (v->gs_fade_pending[i]) {
|
|
payload[i][0] = v->gs_fade[i][0];
|
|
payload[i][1] = v->gs_fade[i][1];
|
|
payload[i][2] = v->gs_fade[i][2];
|
|
payload[i][3] = v->gs_fade[i][3];
|
|
v->gs_fade_pending[i] = false;
|
|
} else {
|
|
payload[i][0] = v->gs[i][0];
|
|
payload[i][1] = v->gs[i][1];
|
|
payload[i][2] = v->gs[i][2];
|
|
payload[i][3] = v->gs[i][3];
|
|
}
|
|
}
|
|
|
|
led_gs_update(board, (const uint8_t*)payload);
|
|
} else {
|
|
led_gs_update(board, (const uint8_t*)v->gs);
|
|
}
|
|
} else {
|
|
for (int i = 0; i < led15070_nleds; i++) {
|
|
v->gs_fade_pending[i] = false;
|
|
}
|
|
}
|
|
|
|
if (!led15070_per_board_vars[board].enable_response)
|
|
return S_OK;
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_GS_UPDATE;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_rotate(int board, const struct led15070_req_any *req)
|
|
{
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Rotate (board %u)\n", board);
|
|
#endif
|
|
|
|
if (!led15070_per_board_vars[board].enable_response)
|
|
return S_OK;
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_ROTATE;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_set_dc_data(int board, const struct led15070_req_any *req)
|
|
{
|
|
uint8_t idx_start = req->payload[0];
|
|
uint8_t idx_end = req->payload[1];
|
|
uint8_t idx_skip = req->payload[2];
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Set DC data (board %u, start %u, end %u, skip %u)\n",
|
|
board, idx_start, idx_end, idx_skip);
|
|
#endif
|
|
|
|
if (idx_skip > 0 && idx_skip <= (idx_end - idx_start + 1)) {
|
|
idx_start += idx_skip;
|
|
}
|
|
|
|
int i = idx_start;
|
|
do {
|
|
led15070_per_board_vars[board].dc[i][0] = req->payload[3]; // R
|
|
led15070_per_board_vars[board].dc[i][1] = req->payload[4]; // G
|
|
led15070_per_board_vars[board].dc[i][2] = req->payload[5]; // B
|
|
i++;
|
|
} while (i < idx_end);
|
|
|
|
if (!led15070_per_board_vars[board].enable_response)
|
|
return S_OK;
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_SET_DC_DATA;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_eeprom_write(int board, const struct led15070_req_any *req)
|
|
{
|
|
DWORD eeprom_bytes_written = 0;
|
|
HRESULT hr;
|
|
BOOL ok;
|
|
|
|
uint8_t addr = req->payload[0];
|
|
uint8_t data = req->payload[1];
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: EEPROM write (board %u, address %02x, data %02x)\n",
|
|
board, addr, data);
|
|
#endif
|
|
|
|
if (addr > 0x07) {
|
|
dprintf("LED 15070: Error -- Invalid EEPROM write address %02x\n",
|
|
addr);
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
hr = led15070_eeprom_open(
|
|
board,
|
|
led15070_per_board_vars[board].eeprom_path,
|
|
&(led15070_per_board_vars[board].eeprom_handle));
|
|
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
hr = SetFilePointer(
|
|
led15070_per_board_vars[board].eeprom_handle,
|
|
addr,
|
|
NULL,
|
|
FILE_BEGIN);
|
|
|
|
if (hr == INVALID_SET_FILE_POINTER) {
|
|
dprintf("LED 10570: Error -- Failed to set pointer to EEPROM file "
|
|
"(board %u)\n", board);
|
|
led15070_eeprom_close(
|
|
board,
|
|
led15070_per_board_vars[board].eeprom_path,
|
|
&(led15070_per_board_vars[board].eeprom_handle));
|
|
|
|
return hr;
|
|
}
|
|
|
|
ok = WriteFile(
|
|
led15070_per_board_vars[board].eeprom_handle,
|
|
&data,
|
|
sizeof(data),
|
|
&eeprom_bytes_written, NULL);
|
|
|
|
if (!ok || eeprom_bytes_written == 0) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
dprintf("LED 15070: Error -- Failed to write to EEPROM file: %x "
|
|
"(board %u)\n", (int) hr, board);
|
|
led15070_eeprom_close(
|
|
board,
|
|
led15070_per_board_vars[board].eeprom_path,
|
|
&(led15070_per_board_vars[board].eeprom_handle));
|
|
|
|
return hr;
|
|
}
|
|
|
|
hr = led15070_eeprom_close(
|
|
board,
|
|
led15070_per_board_vars[board].eeprom_path,
|
|
&(led15070_per_board_vars[board].eeprom_handle));
|
|
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 2 + 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_EEPROM_WRITE;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
resp.data[0] = addr;
|
|
resp.data[1] = data;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_eeprom_read(int board, const struct led15070_req_any *req)
|
|
{
|
|
DWORD eeprom_bytes_read = 0;
|
|
HRESULT hr;
|
|
BOOL ok;
|
|
|
|
uint8_t addr = req->payload[0];
|
|
uint8_t data = 0;
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: EEPROM read (board %u, address %02x)\n", board, addr);
|
|
#endif
|
|
|
|
if (addr > 0x07) {
|
|
dprintf("LED 15070: Error -- Invalid EEPROM read address %02x\n",
|
|
addr);
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
hr = led15070_eeprom_open(
|
|
board,
|
|
led15070_per_board_vars[board].eeprom_path,
|
|
&(led15070_per_board_vars[board].eeprom_handle));
|
|
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
hr = SetFilePointer(
|
|
led15070_per_board_vars[board].eeprom_handle,
|
|
addr,
|
|
NULL,
|
|
FILE_BEGIN);
|
|
|
|
if (hr == INVALID_SET_FILE_POINTER) {
|
|
dprintf("LED 10570: Error -- Failed to set pointer to EEPROM file "
|
|
"(board %u)\n", board);
|
|
led15070_eeprom_close(
|
|
board,
|
|
led15070_per_board_vars[board].eeprom_path,
|
|
&(led15070_per_board_vars[board].eeprom_handle));
|
|
|
|
return hr;
|
|
}
|
|
|
|
ok = ReadFile(
|
|
led15070_per_board_vars[board].eeprom_handle,
|
|
&data,
|
|
sizeof(data),
|
|
&eeprom_bytes_read,
|
|
NULL);
|
|
|
|
if (!ok || eeprom_bytes_read == 0) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
dprintf("LED 15070: Error -- Failed to read from EEPROM file: %x "
|
|
"(board %u)\n", (int) hr, board);
|
|
led15070_eeprom_close(
|
|
board,
|
|
led15070_per_board_vars[board].eeprom_path,
|
|
&(led15070_per_board_vars[board].eeprom_handle));
|
|
|
|
return hr;
|
|
}
|
|
|
|
hr = led15070_eeprom_close(
|
|
board,
|
|
led15070_per_board_vars[board].eeprom_path,
|
|
&(led15070_per_board_vars[board].eeprom_handle));
|
|
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 1 + 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_EEPROM_READ;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
resp.data[0] = data;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_ack_on(int board, const struct led15070_req_any *req)
|
|
{
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Acknowledge commands ON (board %u)\n", board);
|
|
#endif
|
|
|
|
led15070_per_board_vars[board].enable_response = true;
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_ACK_ON;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_ack_off(int board, const struct led15070_req_any *req)
|
|
{
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Acknowledge commands OFF (board %u)\n", board);
|
|
#endif
|
|
|
|
led15070_per_board_vars[board].enable_response = false;
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_ACK_OFF;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_board_info(int board)
|
|
{
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Get board info (board %u)\n", board);
|
|
#endif
|
|
|
|
struct led15070_resp_board_info resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 10 + 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_BOARD_INFO;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
memcpy(resp.board_num, led15070_board_num, sizeof(resp.board_num));
|
|
resp.endcode = 0xff;
|
|
resp.fw_ver = led15070_fw_ver;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_board_status(int board)
|
|
{
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Get board status (board %u)\n", board);
|
|
#endif
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 4 + 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_BOARD_STATUS;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
resp.data[0] = 0; // Timeout status
|
|
resp.data[1] = 0; // Timeout sec
|
|
resp.data[2] = 0; // PWM IO
|
|
resp.data[3] = 0; // FET timeout
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_fw_sum(int board)
|
|
{
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Get firmware checksum (board %u)\n", board);
|
|
#endif
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 2 + 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_FW_SUM;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
resp.data[0] = (led15070_fw_sum >> 8) & 0xff;
|
|
resp.data[1] = led15070_fw_sum & 0xff;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_protocol_ver(int board)
|
|
{
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Get protocol version (board %u)\n", board);
|
|
#endif
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3 + 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_PROTOCOL_VER;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
if (led15070_per_board_vars[board].enable_bootloader) {
|
|
resp.data[0] = 0; // BOOT mode
|
|
resp.data[1] = 1; // Version major
|
|
resp.data[2] = 1; // Version minor
|
|
} else {
|
|
resp.data[0] = 1; // APPLI mode
|
|
resp.data[1] = 1; // Version major
|
|
resp.data[2] = 4; // Version minor
|
|
}
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_to_boot_mode(int board)
|
|
{
|
|
dprintf("LED 15070: To boot mode (board %u)\n", board);
|
|
|
|
led15070_per_board_vars[board].enable_bootloader = true;
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_TO_BOOT_MODE;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_req_fw_update(int board, const struct led15070_req_any *req)
|
|
{
|
|
dprintf("LED 15070: Firmware update (UNIMPLEMENTED) (board %u)\n", board);
|
|
|
|
struct led15070_resp_any resp;
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.hdr.sync = LED_15070_FRAME_SYNC;
|
|
resp.hdr.dest_adr = led15070_host_adr;
|
|
resp.hdr.src_adr = led15070_per_board_vars[board].boardadr;
|
|
resp.hdr.nbytes = 3;
|
|
|
|
resp.status = LED_15070_STATUS_OK;
|
|
resp.cmd = LED_15070_CMD_FW_UPDATE;
|
|
resp.report = LED_15070_REPORT_OK;
|
|
|
|
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
|
}
|
|
|
|
static HRESULT led15070_eeprom_open(int board, wchar_t *path, HANDLE *handle)
|
|
{
|
|
DWORD eeprom_bytes_written;
|
|
BYTE null_bytes[8] = { 0x00 };
|
|
HRESULT hr;
|
|
BOOL ok;
|
|
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Opening EEPROM file '%S' handle (board %u)\n", path, board);
|
|
#endif
|
|
|
|
*handle = CreateFileW(
|
|
path,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (*handle == INVALID_HANDLE_VALUE) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
dprintf("LED 15070: Failed to open EEPROM file '%S' handle: %x "
|
|
"(board %u)\n", path, (int) hr, board);
|
|
|
|
return hr;
|
|
}
|
|
|
|
if (GetLastError() == ERROR_ALREADY_EXISTS) return S_OK;
|
|
|
|
ok = WriteFile(
|
|
*handle,
|
|
null_bytes,
|
|
sizeof(null_bytes),
|
|
&eeprom_bytes_written,
|
|
NULL);
|
|
|
|
if (!ok || eeprom_bytes_written != sizeof(null_bytes)) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
dprintf("LED 15070: Failed to initialize empty EEPROM file '%S': %x "
|
|
"(board %u)\n", path, (int) hr, board);
|
|
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT led15070_eeprom_close(int board, wchar_t *path, HANDLE *handle)
|
|
{
|
|
HRESULT hr;
|
|
BOOL ok;
|
|
|
|
#if defined(LOG_LED15070)
|
|
dprintf("LED 15070: Closing EEPROM file '%S' handle (board %u)\n", path, board);
|
|
#endif
|
|
|
|
ok = CloseHandle(*handle);
|
|
|
|
if (!ok) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
dprintf("LED 15070: Failed to close EEPROM file '%S' handle: %x "
|
|
"(board %u)\n", path, (int) hr, board);
|
|
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|