/* 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 #include #include #include #include #include #include #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 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[32][4]; uint8_t dc[32][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 first_port, unsigned int num_boards) { assert(cfg != NULL); if (!cfg->enable) { return S_FALSE; } if (cfg->port_no != 0) { first_port = cfg->port_no; } 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); // TODO: IMPROVE! first_port = i == 1 ? first_port + 2 : first_port; uart_init(&v->boarduart, first_port); 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->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; } } } 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 = 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 0 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) { dprintf("LED 15070: Set input (board %u)\n", board); 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]; dprintf("LED 15070: Set LED - Normal 12bit (board %u, index %u)\n", board, idx); // 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]; // dprintf("LED 15070: Set LED - Normal 8bit (board %u, index %u)\n", // board, idx); 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 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 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_end = req->payload[1]; uint8_t idx_skip = req->payload[2]; // TODO: useful? // dprintf("LED 15070: Set LED - Multi flash 8bit (board %u, start %u, end %u, skip %u)\n", // board, idx_start, idx_end, idx_skip); 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].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 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_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_end = req->payload[1]; uint8_t idx_skip = req->payload[2]; // dprintf("LED 15070: Set LED - Multi fade 8bit (board %u, start %u, end %u, skip %u)\n", // board, idx_start, idx_end, idx_skip); 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].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 led15070_per_board_vars[board].gs[i][3] = req->payload[6]; // Speed 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_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) { dprintf("LED 15070: Set palette - 7 Normal LED (board %u)\n", board); 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) { dprintf("LED 15070: Set palette - 6 Flash LED (board %u)\n", board); 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) { dprintf("LED 15070: Set 15DC out (board %u)\n", board); 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) { dprintf("LED 15070: Set 15GS out (board %u)\n", board); 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) { dprintf("LED 15070: Set PSC max (board %u)\n", board); 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) { dprintf("LED 15070: Set FET output (board %u)\n", board); 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((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]; dprintf("LED 15070: Set GS palette (board %u, index %u)\n", board, idx); 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) { // dprintf("LED 15070: DC update (board %u)\n", board); if (led_dc_update) led_dc_update((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) { // dprintf("LED 15070: GS update (board %u)\n", board); if (led_gs_update) led_gs_update((const uint8_t*)led15070_per_board_vars[board].gs); 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) { dprintf("LED 15070: Rotate (board %u)\n", board); 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]; // dprintf("LED 15070: Set DC data (board %u, start %u, end %u, skip %u)\n", // board, idx_start, idx_end, idx_skip); 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]; dprintf("LED 15070: EEPROM write (board %u, address %02x, data %02x)\n", board, addr, data); 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; dprintf("LED 15070: EEPROM read (board %u, address %02x)\n", board, addr); 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) { dprintf("LED 15070: Acknowledge commands ON (board %u)\n", board); 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) { dprintf("LED 15070: Acknowledge commands OFF (board %u)\n", board); 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) { dprintf("LED 15070: Get board info (board %u)\n", board); 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) { dprintf("LED 15070: Get board status (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 = 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) { dprintf("LED 15070: Get firmware checksum (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 = 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) { dprintf("LED 15070: Get protocol version (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 + 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 0 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 0 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; }