From 6fc2482c19f7c921fb0b550f4719c0b81053f66b Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Fri, 28 Apr 2023 04:25:47 -0400 Subject: [PATCH] carol: add control board emulation, document touch board more --- carolhook/controlbd.c | 341 ++++++++++++++++++++++++++++++++++++++++-- carolhook/controlbd.h | 137 +++++++++++++++++ carolhook/dllmain.c | 25 +++- carolhook/ledbd.c | 99 +++--------- carolhook/meson.build | 2 - carolhook/serial.c | 39 ----- carolhook/serial.h | 5 - carolhook/touch.c | 82 ++++++++-- carolhook/touch.h | 8 +- 9 files changed, 587 insertions(+), 151 deletions(-) delete mode 100644 carolhook/serial.c delete mode 100644 carolhook/serial.h diff --git a/carolhook/controlbd.c b/carolhook/controlbd.c index c39eb83..a59fe65 100644 --- a/carolhook/controlbd.c +++ b/carolhook/controlbd.c @@ -8,6 +8,8 @@ #include "hook/iobuf.h" #include "hook/iohook.h" +#include "hook/table.h" + #include "carolhook/carol-dll.h" #include "carolhook/controlbd.h" @@ -18,16 +20,57 @@ static HRESULT controlbd_handle_irp(struct irp *irp); static HRESULT controlbd_handle_irp_locked(struct irp *irp); +static HRESULT controlbd_frame_decode(struct controlbd_req_any *dest, struct iobuf *src); +static HRESULT controlbd_set_header(struct controlbd_resp_hdr *resp, uint8_t cmd, uint8_t len); +static uint8_t calc_checksum(void *data, size_t len); -static HRESULT controlbd_req_noop(uint8_t cmd); -static HRESULT controlbd_req_unk7c(uint8_t cmd); -static HRESULT controlbd_req_unkF0(uint8_t cmd); +static HRESULT controlbd_req_dispatch(const struct controlbd_req_any *req); +static HRESULT controlbd_req_ack_any(uint8_t cmd); +static HRESULT controlbd_req_reset(void); +static HRESULT controlbd_req_get_board_info(void); +static HRESULT controlbd_req_firmware_checksum(void); +static HRESULT controlbd_req_polling(const struct controlbd_req_any *req); + +const uint8_t CONTROLBD_SYNC_BYTE = 0xE0; static CRITICAL_SECTION controlbd_lock; static struct uart controlbd_uart; static uint8_t controlbd_written_bytes[520]; static uint8_t controlbd_readable_bytes[520]; +static BOOL WINAPI my_CreateProcessA( + LPCSTR lpApplicationName, + LPSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCSTR lpCurrentDirectory, + LPSTARTUPINFOA lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation +); +static BOOL (WINAPI *next_CreateProcessA)( + LPCSTR lpApplicationName, + LPSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCSTR lpCurrentDirectory, + LPSTARTUPINFOA lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation +); + +static const struct hook_symbol win32_hooks[] = { + { + .name = "CreateProcessA", + .patch = my_CreateProcessA, + .link = (void **) &next_CreateProcessA + } +}; + HRESULT controlbd_hook_init(const struct controlbd_config *cfg) { if (!cfg->enable) { @@ -42,12 +85,17 @@ HRESULT controlbd_hook_init(const struct controlbd_config *cfg) controlbd_uart.readable.bytes = controlbd_readable_bytes; controlbd_uart.readable.nbytes = sizeof(controlbd_readable_bytes); + hook_table_apply( + NULL, + "kernel32.dll", + win32_hooks, + _countof(win32_hooks)); + dprintf("Control Board: Init\n"); return iohook_push_handler(controlbd_handle_irp); } - static HRESULT controlbd_handle_irp(struct irp *irp) { HRESULT hr; @@ -65,9 +113,49 @@ static HRESULT controlbd_handle_irp(struct irp *irp) return hr; } +static HRESULT controlbd_frame_decode(struct controlbd_req_any *req, struct iobuf *src) +{ + uint8_t data_len = 0; + uint8_t checksum_pos = src->pos - 1; + uint8_t calculated_checksum = 0; + uint8_t checksum = 0; + + if (src->pos < 6) { + dprintf("Control Board: Decode Error, request too short (pos is 0x%08X)\n", (int)src->pos); + return SEC_E_BUFFER_TOO_SMALL; + } + + req->hdr.sync = src->bytes[0]; + req->hdr.dest = src->bytes[1]; + req->hdr.src = src->bytes[2]; + req->hdr.len = src->bytes[3]; + req->hdr.cmd = src->bytes[4]; + data_len = req->hdr.len; + src->pos -= 5; + + for (int i = 0; i < data_len; i++) { + if (src->pos == 0) { + break; + } + req->bytes[i] = src->bytes[i + 5]; + src->pos --; + } + + checksum = src->bytes[checksum_pos]; + calculated_checksum = calc_checksum(req, checksum_pos); + + if (checksum != calculated_checksum) { + dprintf("Control Board: Decode Error, checksum failure (expected 0x%02X, got 0x%02X)\n", calculated_checksum, checksum); + return HRESULT_FROM_WIN32(ERROR_CRC); + } + + return S_OK; +} + static HRESULT controlbd_handle_irp_locked(struct irp *irp) { HRESULT hr; + struct controlbd_req_any req; assert(carol_dll.controlbd_init != NULL); @@ -89,24 +177,251 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp) } for (;;) { -#if 1 - dprintf("Control Board: TX Buffer:\n"); - dump_iobuf(&controlbd_uart.written); + if (controlbd_uart.written.bytes[0] == 0xE0) { +#if 0 + dprintf("Control Board: TX Buffer:\n"); + dump_iobuf(&controlbd_uart.written); #endif + hr = controlbd_frame_decode(&req, &controlbd_uart.written); + if (FAILED(hr)) { + dprintf("Control Board: Deframe error: %x\n", (int) hr); + return hr; + } - if (FAILED(hr)) { - dprintf("Control Board: Deframe Error: 0X%X\n", (int) hr); - + hr = controlbd_req_dispatch(&req); + if (FAILED(hr)) { + dprintf("Control Board: Dispatch Error: 0X%X\n", (int) hr); + return hr; + } +#if 0 + dprintf("Control Board: RX Buffer:\n"); + dump_iobuf(&controlbd_uart.readable); +#endif + controlbd_uart.written.pos = 0; return hr; } - if (FAILED(hr)) { - dprintf("Control Board: Dispatch Error: 0X%X\n", (int) hr); + // The board has a LPC111x bootloader that gets ran over every boot + // this is to account for that. + char cmd[255]; + strcpy_s(cmd, 255, (char *)controlbd_uart.written.bytes); + cmd[controlbd_uart.written.pos] = '\0'; - return hr; + if (!strcmp(cmd, "?")) { + dprintf("Control Board: Bootloader Hello\n"); + } + else if (!strcmp(cmd, "Synchronized\r\n")) { + iobuf_write(&controlbd_uart.readable, "Synchronized\r\nNG\r\n", 19); + // Set this to OK instead of NG to do an update + } + else if (!strcmp(cmd, "12000\r\n")) { + iobuf_write(&controlbd_uart.readable, "12000\r\nOK\r\n", 12); + } + else { + // Everything other then the two commands above just want 0\r\n + // appended to the request as the response. Given that it only checks sometimes, + // it's safe to just run over the readable buffer every response. + controlbd_uart.readable.pos = 0; + cmd[controlbd_uart.written.pos] = '0'; + cmd[controlbd_uart.written.pos + 1] = '\r'; + cmd[controlbd_uart.written.pos + 2] = '\n'; + cmd[controlbd_uart.written.pos + 3] = '\0'; + // dprintf("Control Board: Return %s\n", cmd); + iobuf_write(&controlbd_uart.readable, cmd, controlbd_uart.written.pos + 3); } controlbd_uart.written.pos = 0; return hr; } +} + +static HRESULT controlbd_req_dispatch(const struct controlbd_req_any *req) +{ + switch (req->hdr.cmd) { + case CONTROLBD_CMD_RESET: + return controlbd_req_reset(); + + case CONTROLBD_CMD_BDINFO: + return controlbd_req_get_board_info(); + + case CONTROLBD_CMD_FIRM_SUM: + return controlbd_req_firmware_checksum(); + + case CONTROLBD_CMD_TIMEOUT: + dprintf("Control Board: Acknowledge Timeout\n"); + return controlbd_req_ack_any(req->hdr.cmd); + + case CONTROLBD_CMD_PORT_SETTING: + dprintf("Control Board: Acknowledge Port Setting\n"); + return controlbd_req_ack_any(req->hdr.cmd); + + case CONTROLBD_CMD_INITIALIZE: + dprintf("Control Board: Acknowledge Initialize\n"); + return controlbd_req_ack_any(req->hdr.cmd); + + case CONTROLBD_CMD_POLLING: + return controlbd_req_polling(req); + + default: + dprintf("Unhandled command 0x%02x\n", req->hdr.cmd); + return controlbd_req_ack_any(req->hdr.cmd); + } +} + +static HRESULT controlbd_set_header(struct controlbd_resp_hdr *resp, uint8_t cmd, uint8_t len) +{ + resp->sync = CONTROLBD_SYNC_BYTE; + resp->dest = 0x01; + resp->src = 0x02; + resp->len = len; + resp->report = 0x01; + resp->cmd = cmd; + return S_OK; +} + +static uint8_t calc_checksum(void *data, size_t len) +{ + uint8_t *stuff; + stuff = data; + uint8_t checksum = 0; + uint16_t tmp = 0; + + for (int i = 1; i < len; i++) { + tmp = checksum + stuff[i]; + checksum = tmp & 0xFF; + } + + return checksum; +} + +static HRESULT controlbd_req_reset(void) +{ + struct controlbd_resp_reset resp; + + dprintf("Control Board: Reset\n"); + + controlbd_set_header(&resp.hdr, CONTROLBD_CMD_RESET, 2); + resp.checksum = 0; + + // No data, just ack + resp.checksum = calc_checksum(&resp, sizeof(resp)); + return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp)); + +} + +static HRESULT controlbd_req_get_board_info(void) +{ + struct controlbd_resp_bdinfo resp; + memset(&resp, 0, sizeof(resp)); + dprintf("Control Board: Get Board Info\n"); + controlbd_set_header(&resp.hdr, CONTROLBD_CMD_BDINFO, 21); + + resp.rev = 0x90; + resp.bfr_size = 0x0001; + resp.ack = 1; + + strcpy_s(resp.bd_no, sizeof(resp.bd_no), "15312 "); + strcpy_s(resp.chip_no, sizeof(resp.chip_no), "6699 "); + resp.chip_no[5] = 0xFF; + resp.bd_no[8] = 0x0A; + + resp.checksum = calc_checksum(&resp, sizeof(resp)); + + return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp)); +} + +static HRESULT controlbd_req_firmware_checksum(void) +{ + struct controlbd_resp_fw_checksum resp; + memset(&resp, 0, sizeof(resp)); + dprintf("Control Board: Get Firmware Checksum\n"); + controlbd_set_header(&resp.hdr, CONTROLBD_CMD_FIRM_SUM, 5); + + resp.ack = 1; + resp.fw_checksum = 0x1b36; // This could change with an update... oh well + resp.checksum = calc_checksum(&resp, sizeof(resp)); + + return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp)); +} + +static HRESULT controlbd_req_polling(const struct controlbd_req_any *req) +{ + struct controlbd_req_polling req_struct; + memset(&req_struct, 0, sizeof(req_struct)); + memcpy_s(&req_struct, sizeof(req_struct), req, sizeof(req_struct)); + struct controlbd_resp_polling resp; + memset(&resp, 0, sizeof(resp)); + controlbd_set_header(&resp.hdr, CONTROLBD_CMD_POLLING, 16); + // TODO: Figure out output (pen vibration, etc) + + resp.ack = 1; + resp.unk7 = 3; + resp.unk8 = 1; + resp.unk9 = 1; + + resp.btns_pressed = 0; // bit 1 is pen button, bit 2 is dodge + resp.coord_x = 0x0; + resp.coord_y = 0x0; + resp.checksum = calc_checksum(&resp, sizeof(resp)); + + return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp)); +} + +static HRESULT controlbd_req_ack_any(uint8_t cmd) +{ + struct controlbd_resp_any_ack resp; + memset(&resp, 0, sizeof(resp)); + controlbd_set_header(&resp.hdr, cmd, 3); + + resp.ack = 1; + resp.checksum = calc_checksum(&resp, sizeof(resp)); + + return iobuf_write(&controlbd_uart.readable, &resp, sizeof(resp)); +} + +static BOOL WINAPI my_CreateProcessA( + LPCSTR lpApplicationName, + LPSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCSTR lpCurrentDirectory, + LPSTARTUPINFOA lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation +) +{ + dprintf("Control Board: my_CreateProcessA Hit! %s\n", lpCommandLine); + if (strncmp(".\\15312firm\\firmupdate_1113.exe", lpCommandLine, 31)) { + return next_CreateProcessA( + lpApplicationName, + lpCommandLine, + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwCreationFlags, + lpEnvironment, + lpCurrentDirectory, + lpStartupInfo, + lpProcessInformation + ); + } + + dprintf("Control Board: Hooking child process\n"); + char new_cmd[MAX_PATH] = "inject -d -k carolhook.dll "; + strcat_s(new_cmd, MAX_PATH, lpCommandLine); + + return next_CreateProcessA( + lpApplicationName, + new_cmd, + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwCreationFlags, + lpEnvironment, + lpCurrentDirectory, + lpStartupInfo, + lpProcessInformation + ); } \ No newline at end of file diff --git a/carolhook/controlbd.h b/carolhook/controlbd.h index 15f04ac..5f160d3 100644 --- a/carolhook/controlbd.h +++ b/carolhook/controlbd.h @@ -1,5 +1,7 @@ #pragma once #include +#include +#include #include #include @@ -8,4 +10,139 @@ struct controlbd_config { bool enable; }; +#pragma pack(push, 1) +struct controlbd_req_hdr { + uint8_t sync; + uint8_t dest; // unsure + uint8_t src; // unsure + uint8_t len; // length of the rest of the request minus checksum + uint8_t cmd; +}; + +struct controlbd_req_any { + struct controlbd_req_hdr hdr; + uint8_t bytes[255]; +}; + +struct controlbd_req_reset { + struct controlbd_req_hdr hdr; + uint8_t payload; + uint8_t checksum; +}; + +struct controlbd_req_bdinfo { + struct controlbd_req_hdr hdr; + uint8_t checksum; +}; + +struct controlbd_req_fw_checksum { + struct controlbd_req_hdr hdr; + uint8_t checksum; +}; + +struct controlbd_req_timeout { + struct controlbd_req_hdr hdr; + uint8_t unknown; + uint8_t checksum; +}; + +struct controlbd_req_polling { + struct controlbd_req_hdr hdr; + uint8_t unknown[20]; + uint8_t checksum; +}; + +struct controlbd_resp_hdr { + uint8_t sync; + uint8_t dest; // unsure + uint8_t src; // unsure + uint8_t len; // length of the rest of the request minus checksum + uint8_t report; // 0x01 for success, anything else for failure + uint8_t cmd; +}; + +struct controlbd_resp_any { + struct controlbd_resp_hdr hdr; + uint8_t bytes[255]; +}; + +struct controlbd_resp_any_ack { + struct controlbd_resp_hdr hdr; + uint8_t ack; + uint8_t checksum; +}; + +struct controlbd_resp_reset { + struct controlbd_resp_hdr hdr; + uint8_t checksum; +}; + +struct controlbd_resp_bdinfo { + struct controlbd_resp_hdr hdr; + uint8_t ack; + char bd_no[9]; + char chip_no[6]; + uint8_t rev; + uint16_t bfr_size; + uint8_t checksum; +}; + +struct controlbd_resp_fw_checksum { + struct controlbd_resp_hdr hdr; + uint8_t ack; + uint16_t fw_checksum; + uint8_t checksum; +}; + +struct controlbd_resp_polling { + struct controlbd_resp_hdr hdr; + uint8_t ack; + uint8_t unk7; + uint8_t unk8; + uint8_t unk9; + uint8_t btns_pressed; + uint8_t blob[7]; + int8_t coord_x; + int8_t coord_y; + uint8_t checksum; +}; + +enum { + PEN_BTN_PRESSED_BIT = 1, + DODGE_BTN_PRESSED_BIT = 2 +}; + +enum { + CONTROLBD_CMD_RESET = 0x10, + CONTROLBD_CMD_TIMEOUT = 0x11, + CONTROLBD_CMD_RETRY = 0x12, + + CONTROLBD_CMD_GETIN = 0x20, + CONTROLBD_CMD_GETADI = 0x21, + + CONTROLBD_CMD_SETOUTPUT = 0x30, + + CONTROLBD_CMD_INITIALIZE = 0x80, + CONTROLBD_CMD_POLLING = 0x81, + CONTROLBD_CMD_CUSTOM_PATTERN = 0x82, + CONTROLBD_CMD_DEBUG_CAROL = 0x83, + CONTROLBD_CMD_POLLING_GENERAL = 0x84, + + CONTROLBD_CMD_CMD_STATUS = 0x90, + CONTROLBD_CMD_PORT_SETTING = 0x91, + CONTROLBD_CMD_PWM_DUTY = 0x92, + CONTROLBD_CMD_LED_SET = 0x93, + CONTROLBD_CMD_LED_REFRESH = 0x94, + + CONTROLBD_CMD_DEBUG_UART = 0xB0, + CONTROLBD_CMD_DEBUG_I2C = 0xB1, + + CONTROLBD_CMD_DEBUG_STATUS = 0xC0, + + CONTROLBD_CMD_BDINFO = 0xF0, + CONTROLBD_CMD_FIRM_SUM = 0xF2, + CONTROLBD_CMD_PROTOCOL = 0xF3, + CONTROLBD_CMD_UPDATE = 0xFE, +}; +#pragma pack(pop) HRESULT controlbd_hook_init(const struct controlbd_config *cfg); \ No newline at end of file diff --git a/carolhook/dllmain.c b/carolhook/dllmain.c index 608ca49..55608c7 100644 --- a/carolhook/dllmain.c +++ b/carolhook/dllmain.c @@ -13,7 +13,6 @@ #include "carolhook/jvs.h" #include "carolhook/touch.h" #include "carolhook/ledbd.h" -#include "carolhook/serial.h" #include "carolhook/controlbd.h" #include "hook/process.h" @@ -34,14 +33,36 @@ COM Layout 01: Touchscreen 10: Aime reader 11: LED board -12: LED Board +12: Control Board */ static DWORD CALLBACK carol_pre_startup(void) { HRESULT hr; + HMODULE d3dc; + HMODULE dbghelp; dprintf("--- Begin carol_pre_startup ---\n"); + + /* Pin the D3D shader compiler. This makes startup much faster. */ + + d3dc = LoadLibraryW(L"D3DCompiler_43.dll"); + + if (d3dc != NULL) { + dprintf("Pinned shader compiler, hMod=%p\n", d3dc); + } else { + dprintf("Failed to load shader compiler!\n"); + } + + /* Pin dbghelp so the path hooks apply to it. */ + + dbghelp = LoadLibraryW(L"dbghelp.dll"); + + if (dbghelp != NULL) { + dprintf("Pinned debug helper library, hMod=%p\n", dbghelp); + } else { + dprintf("Failed to load debug helper library!\n"); + } /* Config load */ diff --git a/carolhook/ledbd.c b/carolhook/ledbd.c index 18b9aab..1513359 100644 --- a/carolhook/ledbd.c +++ b/carolhook/ledbd.c @@ -16,10 +16,12 @@ #include "util/dprintf.h" #include "util/dump.h" +#include "board/slider-frame.h" +#include "board/slider-cmd.h" + static HRESULT ledbd_handle_irp(struct irp *irp); static HRESULT ledbd_handle_irp_locked(struct irp *irp); -static HRESULT ledbd_frame_decode(struct ledbd_req *dest, struct iobuf *iobuf); -static HRESULT ledbd_frame_dispatch(struct ledbd_req *dest); +static HRESULT ledbd_frame_dispatch(const union slider_req_any *dest); static HRESULT ledbd_req_noop(uint8_t cmd); static HRESULT ledbd_req_unk7c(uint8_t cmd); @@ -68,7 +70,8 @@ static HRESULT ledbd_handle_irp(struct irp *irp) static HRESULT ledbd_handle_irp_locked(struct irp *irp) { - struct ledbd_req req; + union slider_req_any req; + struct iobuf req_iobuf; HRESULT hr; assert(carol_dll.ledbd_init != NULL); @@ -95,7 +98,11 @@ static HRESULT ledbd_handle_irp_locked(struct irp *irp) dprintf("LED Board: TX Buffer:\n"); dump_iobuf(&ledbd_uart.written); #endif - hr = ledbd_frame_decode(&req, &ledbd_uart.written); + req_iobuf.bytes = req.bytes; + req_iobuf.nbytes = sizeof(req.bytes); + req_iobuf.pos = 0; + + hr = slider_frame_decode(&req_iobuf, &ledbd_uart.written); if (FAILED(hr)) { dprintf("LED Board: Deframe Error: 0X%X\n", (int) hr); @@ -114,26 +121,26 @@ static HRESULT ledbd_handle_irp_locked(struct irp *irp) } } -static HRESULT ledbd_frame_dispatch(struct ledbd_req *req) +static HRESULT ledbd_frame_dispatch(const union slider_req_any *req) { - switch (req->cmd) { + switch (req->hdr.cmd) { case LEDBD_CMD_UNK_10: - return ledbd_req_noop(req->cmd); + return ledbd_req_noop(req->hdr.cmd); case LEDBD_CMD_UNK_7C: - return ledbd_req_unk7c(req->cmd); + return ledbd_req_unk7c(req->hdr.cmd); case LEDBD_CMD_UNK_F0: - return ledbd_req_unkF0(req->cmd); + return ledbd_req_unkF0(req->hdr.cmd); case LEDBD_CMD_UNK_30: - return ledbd_req_noop(req->cmd); + return ledbd_req_noop(req->hdr.cmd); default: - dprintf("Unhandled command 0x%02X\n", req->cmd); - return ledbd_req_noop(req->cmd); + //dprintf("Unhandled command 0x%02X\n", req->cmd); + return ledbd_req_noop(req->hdr.cmd); } } static HRESULT ledbd_req_noop(uint8_t cmd) { - dprintf("LED Board: Noop cmd 0x%02X\n", cmd); + //dprintf("LED Board: Noop cmd 0x%02X\n", cmd); uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x03, 0x01, 0x00, 0x01, 0x17 }; resp[5] = cmd; resp[7] = 0x17 + cmd; @@ -144,7 +151,7 @@ static HRESULT ledbd_req_noop(uint8_t cmd) static HRESULT ledbd_req_unk7c(uint8_t cmd) { - dprintf("LED Board: Cmd 0x7C\n"); + //dprintf("LED Board: Cmd 0x7C\n"); uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x04, 0x01, 0x7C, 0x01, 0x07, 0x9B }; iobuf_write(&ledbd_uart.readable, resp, 9); @@ -153,71 +160,9 @@ static HRESULT ledbd_req_unk7c(uint8_t cmd) static HRESULT ledbd_req_unkF0(uint8_t cmd) { - dprintf("LED Board: Cmd 0xF0\n"); + //dprintf("LED Board: Cmd 0xF0\n"); uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x0A, 0x01, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E }; iobuf_write(&ledbd_uart.readable, resp, 16); - return S_OK; -} - -/* Decodes the response into a struct that's easier to work with. TODO: Further validation */ -static HRESULT ledbd_frame_decode(struct ledbd_req *dest, struct iobuf *iobuf) -{ - int initial_pos = iobuf->pos; - int processed_pos = 0; - uint8_t check = 0; - bool escape = false; - - dest->sync = iobuf->bytes[0]; - - dest->dest = iobuf->bytes[1]; - check += dest->dest; - - dest->src = iobuf->bytes[2]; - check += dest->src; - - dest->data_len = iobuf->bytes[3]; - check += dest->data_len; - - dest->cmd = iobuf->bytes[4]; - check += dest->cmd; - - for (int i = 0; i < dest->data_len - 1; i++) { - if (iobuf->bytes[i+5] == 0xD0) { - escape = true; - check += 0xD0; - continue; - } - - dest->data[i] = iobuf->bytes[i+5]; - - if (escape) { - dest->data[i]++; - escape = false; - } - - check += iobuf->bytes[i+5]; - } - - dest->checksum = iobuf->bytes[iobuf->pos - 1]; - if (escape) { - dest->checksum++; - escape = false; - } - - iobuf->pos = 0; - - if (dest->sync != 0xe0) { - dprintf("LED Board: Sync error, expected 0xe0, got 0X%02X\n", dest->sync); - dump_iobuf(iobuf); - return E_FAIL; - } - - if (dest->checksum != (check & 0xFF)) { - dprintf("LED Board: Checksum error, expected 0X%02X, got 0X%02X\n", dest->checksum, check); - dump_iobuf(iobuf); - return E_FAIL; - } - return S_OK; } \ No newline at end of file diff --git a/carolhook/meson.build b/carolhook/meson.build index d62c897..cba763c 100644 --- a/carolhook/meson.build +++ b/carolhook/meson.build @@ -34,7 +34,5 @@ shared_library( 'controlbd.h', 'ledbd.c', 'ledbd.h', - 'serial.c', - 'serial.h', ], ) diff --git a/carolhook/serial.c b/carolhook/serial.c deleted file mode 100644 index 3a50907..0000000 --- a/carolhook/serial.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include - -#include "hook/table.h" - -#include "util/dprintf.h" - -static BOOL WINAPI my_SetCommState(HANDLE hFile, LPDCB lpDCB); -static BOOL (WINAPI *next_SetCommState)(HANDLE hFile, LPDCB lpDCB); -static void com_hook_insert_hooks(HMODULE target); - -static const struct hook_symbol win32_hooks[] = { - { - .name = "SetCommState", - .patch = my_SetCommState, - .link = (void **) &next_SetCommState - } -}; - -void serial_init() -{ - com_hook_insert_hooks(NULL); - dprintf("Serial: Spy init\n"); -} - -static void com_hook_insert_hooks(HMODULE target) -{ - hook_table_apply( - target, - "kernel32.dll", - win32_hooks, - _countof(win32_hooks)); -} - -static BOOL WINAPI my_SetCommState(HANDLE hFile, LPDCB lpDCB) -{ - dprintf("Serial: my_SetCommState with baudrate %ld\n", lpDCB->BaudRate); - return next_SetCommState(hFile, lpDCB); -} \ No newline at end of file diff --git a/carolhook/serial.h b/carolhook/serial.h deleted file mode 100644 index 8a682ac..0000000 --- a/carolhook/serial.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once -#include -#include - -void serial_init(); \ No newline at end of file diff --git a/carolhook/touch.c b/carolhook/touch.c index 9a5ab03..c062e90 100644 --- a/carolhook/touch.c +++ b/carolhook/touch.c @@ -13,14 +13,31 @@ #include "util/dprintf.h" #include "util/dump.h" +/** + * CMDS for M3 EX series + * CX -> Calibrate Extend, preform callibration + * MS -> Mode Stream, enters stream mode + * R -> Reset, resets the device + * RD -> Reset Default, Resets the device to factory + * Z -> Null, keepalive command + * NM -> Name, return the name of the device (not documented?) + * OI -> Output Identity, output unique device identity, SC followed by 4 characters + * UT -> Unit Type, returns controller unit type + status + */ + static HRESULT touch_handle_irp(struct irp *irp); static HRESULT touch_handle_irp_locked(struct irp *irp); static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf); +static HRESULT handle_touch_ack_cmd(const struct touch_req *req); +static HRESULT handle_touch_name_cmd(const struct touch_req *req); +static HRESULT handle_touch_id_cmd(const struct touch_req *req); + static CRITICAL_SECTION touch_lock; static struct uart touch_uart; static uint8_t touch_written_bytes[520]; static uint8_t touch_readable_bytes[520]; +static bool should_stream = false; HRESULT touch_hook_init(const struct touch_config *cfg) { @@ -84,7 +101,7 @@ static HRESULT touch_handle_irp_locked(struct irp *irp) } for (;;) { -#if 1 +#if 0 dprintf("Touchscreen: TX Buffer:\n"); dump_iobuf(&touch_uart.written); #endif @@ -96,24 +113,69 @@ static HRESULT touch_handle_irp_locked(struct irp *irp) return hr; } - touch_uart.written.pos = 0; + if (!strcmp("Z", (char *)req.cmd)) { + hr = handle_touch_ack_cmd(&req); + } + else if (!strcmp("OI", (char *)req.cmd)) { + hr = handle_touch_id_cmd(&req); + should_stream = true; // possibly send stuff after we get this? + } + else if (!strcmp("NM", (char *)req.cmd)) { + hr = handle_touch_name_cmd(&req); + } + else if (!strcmp("R", (char *)req.cmd)) { + should_stream = false; + dprintf("Touch: Reset\n"); + hr = handle_touch_ack_cmd(&req); + } + else { + dprintf("Touchscreen: Unhandled cmd %s\n", (char *)req.cmd); + hr = handle_touch_ack_cmd(&req); + } + return hr; } } +static HRESULT handle_touch_ack_cmd(const struct touch_req *req) +{ + return iobuf_write(&touch_uart.readable, "\0010\015", 3); +} + +static HRESULT handle_touch_name_cmd(const struct touch_req *req) +{ + dprintf("Touch: Get Name\n"); + return iobuf_write(&touch_uart.readable, "\001EX1234 EX1234\015", 15); +} + +static HRESULT handle_touch_id_cmd(const struct touch_req *req) +{ + dprintf("Touch: Get ID\n"); + return iobuf_write(&touch_uart.readable, "\001EX1234\015", 8); +} + /* Decodes the response into a struct that's easier to work with. */ static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf) { - dest->cmd = iobuf->bytes[0]; - iobuf->pos--; - dest->data_length = iobuf->pos; + dest->sync = iobuf->bytes[0]; + memset(dest->cmd, 0, sizeof(dest->cmd)); + size_t data_len = 0; - if (dest->data_length > 0) { - for (int i = 1; i < dest->data_length; i++) { - dest->data[i-1] = iobuf->bytes[i]; - } + for (int i = 1; i < 255; i++) { + if (iobuf->bytes[i] == 0x0D) { break; } + dest->cmd[i - 1] = iobuf->bytes[i]; + data_len++; + } + + dest->tail = iobuf->bytes[data_len + 1]; + dest->data_len = data_len; + + iobuf->pos = 0; + + if (dest->sync != 1 || dest->tail != 0x0D) { + dprintf("Touch: Data recieve error, sync: 0x%02X (expected 0x01) tail: 0x%02X (expected 0x0D)", dest->sync, dest->tail); + return E_FAIL; } - iobuf->pos -= dest->data_length; return S_OK; } \ No newline at end of file diff --git a/carolhook/touch.h b/carolhook/touch.h index 6881b8f..2ae3031 100644 --- a/carolhook/touch.h +++ b/carolhook/touch.h @@ -8,10 +8,12 @@ struct touch_config { bool enable; }; +// Always starts with 0x01, always ends with 0x0D struct touch_req { - uint8_t cmd; // First byte is the command byte - uint8_t data[256]; // rest of the data goes here - uint8_t data_length; // Size of the data including command byte + uint8_t sync; // Always 0x01 + uint8_t cmd[256]; // rest of the data goes here + uint8_t tail; // Always 0x0D + size_t data_len; // length of data }; HRESULT touch_hook_init(const struct touch_config *cfg); \ No newline at end of file