carol: add control board emulation, document touch board more

This commit is contained in:
Hay1tsme 2023-04-28 04:25:47 -04:00
parent 74c8b312c5
commit 6fc2482c19
9 changed files with 587 additions and 151 deletions

View File

@ -8,6 +8,8 @@
#include "hook/iobuf.h" #include "hook/iobuf.h"
#include "hook/iohook.h" #include "hook/iohook.h"
#include "hook/table.h"
#include "carolhook/carol-dll.h" #include "carolhook/carol-dll.h"
#include "carolhook/controlbd.h" #include "carolhook/controlbd.h"
@ -18,16 +20,57 @@
static HRESULT controlbd_handle_irp(struct irp *irp); static HRESULT controlbd_handle_irp(struct irp *irp);
static HRESULT controlbd_handle_irp_locked(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_dispatch(const struct controlbd_req_any *req);
static HRESULT controlbd_req_unk7c(uint8_t cmd); static HRESULT controlbd_req_ack_any(uint8_t cmd);
static HRESULT controlbd_req_unkF0(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 CRITICAL_SECTION controlbd_lock;
static struct uart controlbd_uart; static struct uart controlbd_uart;
static uint8_t controlbd_written_bytes[520]; static uint8_t controlbd_written_bytes[520];
static uint8_t controlbd_readable_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) HRESULT controlbd_hook_init(const struct controlbd_config *cfg)
{ {
if (!cfg->enable) { 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.bytes = controlbd_readable_bytes;
controlbd_uart.readable.nbytes = sizeof(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"); dprintf("Control Board: Init\n");
return iohook_push_handler(controlbd_handle_irp); return iohook_push_handler(controlbd_handle_irp);
} }
static HRESULT controlbd_handle_irp(struct irp *irp) static HRESULT controlbd_handle_irp(struct irp *irp)
{ {
HRESULT hr; HRESULT hr;
@ -65,9 +113,49 @@ static HRESULT controlbd_handle_irp(struct irp *irp)
return hr; 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) static HRESULT controlbd_handle_irp_locked(struct irp *irp)
{ {
HRESULT hr; HRESULT hr;
struct controlbd_req_any req;
assert(carol_dll.controlbd_init != NULL); assert(carol_dll.controlbd_init != NULL);
@ -89,24 +177,251 @@ static HRESULT controlbd_handle_irp_locked(struct irp *irp)
} }
for (;;) { for (;;) {
#if 1 if (controlbd_uart.written.bytes[0] == 0xE0) {
#if 0
dprintf("Control Board: TX Buffer:\n"); dprintf("Control Board: TX Buffer:\n");
dump_iobuf(&controlbd_uart.written); dump_iobuf(&controlbd_uart.written);
#endif #endif
hr = controlbd_frame_decode(&req, &controlbd_uart.written);
if (FAILED(hr)) { if (FAILED(hr)) {
dprintf("Control Board: Deframe Error: 0X%X\n", (int) hr); dprintf("Control Board: Deframe error: %x\n", (int) hr);
return hr; return hr;
} }
hr = controlbd_req_dispatch(&req);
if (FAILED(hr)) { if (FAILED(hr)) {
dprintf("Control Board: Dispatch Error: 0X%X\n", (int) hr); dprintf("Control Board: Dispatch Error: 0X%X\n", (int) hr);
return hr; return hr;
} }
#if 0
dprintf("Control Board: RX Buffer:\n");
dump_iobuf(&controlbd_uart.readable);
#endif
controlbd_uart.written.pos = 0;
return 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';
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; controlbd_uart.written.pos = 0;
return hr; 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
);
}

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <windows.h> #include <windows.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@ -8,4 +10,139 @@ struct controlbd_config {
bool enable; 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); HRESULT controlbd_hook_init(const struct controlbd_config *cfg);

View File

@ -13,7 +13,6 @@
#include "carolhook/jvs.h" #include "carolhook/jvs.h"
#include "carolhook/touch.h" #include "carolhook/touch.h"
#include "carolhook/ledbd.h" #include "carolhook/ledbd.h"
#include "carolhook/serial.h"
#include "carolhook/controlbd.h" #include "carolhook/controlbd.h"
#include "hook/process.h" #include "hook/process.h"
@ -34,15 +33,37 @@ COM Layout
01: Touchscreen 01: Touchscreen
10: Aime reader 10: Aime reader
11: LED board 11: LED board
12: LED Board 12: Control Board
*/ */
static DWORD CALLBACK carol_pre_startup(void) static DWORD CALLBACK carol_pre_startup(void)
{ {
HRESULT hr; HRESULT hr;
HMODULE d3dc;
HMODULE dbghelp;
dprintf("--- Begin carol_pre_startup ---\n"); 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 */ /* Config load */
carol_hook_config_load(&carol_hook_cfg, L".\\segatools.ini"); carol_hook_config_load(&carol_hook_cfg, L".\\segatools.ini");

View File

@ -16,10 +16,12 @@
#include "util/dprintf.h" #include "util/dprintf.h"
#include "util/dump.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(struct irp *irp);
static HRESULT ledbd_handle_irp_locked(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(const union slider_req_any *dest);
static HRESULT ledbd_frame_dispatch(struct ledbd_req *dest);
static HRESULT ledbd_req_noop(uint8_t cmd); static HRESULT ledbd_req_noop(uint8_t cmd);
static HRESULT ledbd_req_unk7c(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) static HRESULT ledbd_handle_irp_locked(struct irp *irp)
{ {
struct ledbd_req req; union slider_req_any req;
struct iobuf req_iobuf;
HRESULT hr; HRESULT hr;
assert(carol_dll.ledbd_init != NULL); 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"); dprintf("LED Board: TX Buffer:\n");
dump_iobuf(&ledbd_uart.written); dump_iobuf(&ledbd_uart.written);
#endif #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)) { if (FAILED(hr)) {
dprintf("LED Board: Deframe Error: 0X%X\n", (int) 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: case LEDBD_CMD_UNK_10:
return ledbd_req_noop(req->cmd); return ledbd_req_noop(req->hdr.cmd);
case LEDBD_CMD_UNK_7C: case LEDBD_CMD_UNK_7C:
return ledbd_req_unk7c(req->cmd); return ledbd_req_unk7c(req->hdr.cmd);
case LEDBD_CMD_UNK_F0: case LEDBD_CMD_UNK_F0:
return ledbd_req_unkF0(req->cmd); return ledbd_req_unkF0(req->hdr.cmd);
case LEDBD_CMD_UNK_30: case LEDBD_CMD_UNK_30:
return ledbd_req_noop(req->cmd); return ledbd_req_noop(req->hdr.cmd);
default: default:
dprintf("Unhandled command 0x%02X\n", req->cmd); //dprintf("Unhandled command 0x%02X\n", req->cmd);
return ledbd_req_noop(req->cmd); return ledbd_req_noop(req->hdr.cmd);
} }
} }
static HRESULT ledbd_req_noop(uint8_t 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 }; uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x03, 0x01, 0x00, 0x01, 0x17 };
resp[5] = cmd; resp[5] = cmd;
resp[7] = 0x17 + 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) 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 }; uint8_t resp[] = { 0xE0, 0x01, 0x11, 0x04, 0x01, 0x7C, 0x01, 0x07, 0x9B };
iobuf_write(&ledbd_uart.readable, resp, 9); 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) 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 }; 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); iobuf_write(&ledbd_uart.readable, resp, 16);
return S_OK; 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;
}

View File

@ -34,7 +34,5 @@ shared_library(
'controlbd.h', 'controlbd.h',
'ledbd.c', 'ledbd.c',
'ledbd.h', 'ledbd.h',
'serial.c',
'serial.h',
], ],
) )

View File

@ -1,39 +0,0 @@
#include <windows.h>
#include <winbase.h>
#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);
}

View File

@ -1,5 +0,0 @@
#pragma once
#include <windows.h>
#include <winbase.h>
void serial_init();

View File

@ -13,14 +13,31 @@
#include "util/dprintf.h" #include "util/dprintf.h"
#include "util/dump.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(struct irp *irp);
static HRESULT touch_handle_irp_locked(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 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 CRITICAL_SECTION touch_lock;
static struct uart touch_uart; static struct uart touch_uart;
static uint8_t touch_written_bytes[520]; static uint8_t touch_written_bytes[520];
static uint8_t touch_readable_bytes[520]; static uint8_t touch_readable_bytes[520];
static bool should_stream = false;
HRESULT touch_hook_init(const struct touch_config *cfg) HRESULT touch_hook_init(const struct touch_config *cfg)
{ {
@ -84,7 +101,7 @@ static HRESULT touch_handle_irp_locked(struct irp *irp)
} }
for (;;) { for (;;) {
#if 1 #if 0
dprintf("Touchscreen: TX Buffer:\n"); dprintf("Touchscreen: TX Buffer:\n");
dump_iobuf(&touch_uart.written); dump_iobuf(&touch_uart.written);
#endif #endif
@ -96,24 +113,69 @@ static HRESULT touch_handle_irp_locked(struct irp *irp)
return hr; 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; 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. */ /* Decodes the response into a struct that's easier to work with. */
static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf) static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf)
{ {
dest->cmd = iobuf->bytes[0]; dest->sync = iobuf->bytes[0];
iobuf->pos--; memset(dest->cmd, 0, sizeof(dest->cmd));
dest->data_length = iobuf->pos; size_t data_len = 0;
if (dest->data_length > 0) { for (int i = 1; i < 255; i++) {
for (int i = 1; i < dest->data_length; i++) { if (iobuf->bytes[i] == 0x0D) { break; }
dest->data[i-1] = iobuf->bytes[i]; 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; return S_OK;
} }

View File

@ -8,10 +8,12 @@ struct touch_config {
bool enable; bool enable;
}; };
// Always starts with 0x01, always ends with 0x0D
struct touch_req { struct touch_req {
uint8_t cmd; // First byte is the command byte uint8_t sync; // Always 0x01
uint8_t data[256]; // rest of the data goes here uint8_t cmd[256]; // rest of the data goes here
uint8_t data_length; // Size of the data including command byte uint8_t tail; // Always 0x0D
size_t data_len; // length of data
}; };
HRESULT touch_hook_init(const struct touch_config *cfg); HRESULT touch_hook_init(const struct touch_config *cfg);