diff --git a/mercuryhook/touch.c b/mercuryhook/touch.c index 2c2c594..66c483a 100644 --- a/mercuryhook/touch.c +++ b/mercuryhook/touch.c @@ -28,9 +28,17 @@ static HRESULT touch1_handle_irp_locked(struct irp *irp); static HRESULT touch_req_dispatch(const struct touch_req *req); static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf, int side); +static HRESULT touch_frame_encode(struct iobuf *dest, const void *ptr, size_t nbytes); +static uint8_t calc_checksum(const void *ptr, size_t nbytes); static HRESULT touch_handle_get_rev_date(const struct touch_req *req); static HRESULT touch_handle_startup(const struct touch_req *req); +static HRESULT touch_handle_get_rev_date_detail(const struct touch_req *req); +static HRESULT touch_handle_mystery1(const struct touch_req *req); +static HRESULT touch_handle_mystery2(const struct touch_req *req); +static HRESULT touch_handle_start_auto_scan(const struct touch_req *req); + +uint8_t input_frame_count = 0x7b; static CRITICAL_SECTION touch0_lock; static struct uart touch0_uart; @@ -43,9 +51,9 @@ static uint8_t touch1_written_bytes[520]; static uint8_t touch1_readable_bytes[520]; HRESULT touch_hook_init(const struct touch_config *cfg) -{ +{ assert(cfg != NULL); - assert(mercury_dll.touch_init != NULL); + assert(mercury_dll.touch_init != NULL); // not sure why this always returns false... /*if (!cfg->enable) { @@ -82,7 +90,7 @@ static HRESULT touch_handle_irp(struct irp *irp) hr = touch0_handle_irp_locked(irp); LeaveCriticalSection(&touch0_lock); } - else if (uart_match_irp(&touch1_uart, irp)) { + else if (uart_match_irp(&touch1_uart, irp)) { EnterCriticalSection(&touch1_lock); hr = touch1_handle_irp_locked(irp); LeaveCriticalSection(&touch1_lock); @@ -117,7 +125,7 @@ static HRESULT touch0_handle_irp_locked(struct irp *irp) } for (;;) { -#if 1 +#if 0 dprintf("TX0 Buffer:\n"); dump_iobuf(&touch0_uart.written); #endif @@ -164,7 +172,7 @@ static HRESULT touch1_handle_irp_locked(struct irp *irp) } for (;;) { -#if 1 +#if 0 dprintf("TX1 Buffer:\n"); dump_iobuf(&touch1_uart.written); #endif @@ -196,37 +204,191 @@ static HRESULT touch_req_dispatch(const struct touch_req *req) return touch_handle_get_rev_date(req); case CMD_STARTUP: return touch_handle_startup(req); + case CMD_GET_REV_DATE_DETAIL: + return touch_handle_get_rev_date_detail(req); + case CMD_MYSTERY1: + return touch_handle_mystery1(req); + case CMD_MYSTERY2: + return touch_handle_mystery2(req); + case CMD_START_AUTO_SCAN: + return touch_handle_start_auto_scan(req); + case CMD_BEGIN_WRITE: + dprintf("Wacca touch: Begin write for side %d\n", req->side); + return S_OK; + case CMD_NEXT_WRITE: + dprintf("Wacca touch: continue write for side %d\n", req->side); + return S_OK; default: dprintf("Wacca touch: Unhandled command %02x\n", req->cmd); - return S_OK; } } static HRESULT touch_handle_get_rev_date(const struct touch_req *req) { + struct touch_resp_get_rev_date resp; + HRESULT hr; + uint8_t rev[6] = { 0x31, 0x39, 0x30, 0x35, 0x32, 0x33 }; + dprintf("Wacca Touch%d: Get board rev date\n", req->side); + + resp.cmd = 0xa0; + memcpy(resp.data, rev, sizeof(rev)); + //resp.data = rev; + if (req->side == 0) { - // TODO: a0 31 39 30 35 32 33 2c + hr = touch_frame_encode(&touch0_uart.readable, &resp, sizeof(resp)); } else { - // TODO: see above + hr = touch_frame_encode(&touch1_uart.readable, &resp, sizeof(resp)); } - return S_OK; + return hr; } +/* TODO: Very ugly please make better before upstreaming */ static HRESULT touch_handle_startup(const struct touch_req *req) { + struct touch_resp_startup resp; + HRESULT hr; + uint8_t *rev; + dprintf("Wacca Touch%d: Startup\n", req->side); - if (req->side == 0) { - // TODO: 20 20 20 20 30 20 20 20 20 30 20 20 20 20 31 20 20 20 20 32 20 20 20 20 33 20 20 20 20 34 20 20 20 20 35 20 20 20 31 35 20 20 20 31 35 20 20 20 31 35 20 20 20 31 35 20 20 20 31 35 20 20 20 31 35 20 20 20 31 31 20 20 20 31 31 20 20 20 31 31 0d + + switch (req->data[2]) { + case 0x30: + rev = (uint8_t[80]) { 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, + 0x20, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x20, 0x32, 0x20, 0x20, 0x20, 0x20, + 0x33, 0x20, 0x20, 0x20, 0x20, 0x34, 0x20, 0x20, 0x20, 0x20, 0x35, 0x20, 0x20, + 0x20, 0x31, 0x35, 0x20, 0x20, 0x20, 0x31, 0x35, 0x20, 0x20, 0x20, 0x31, 0x35, + 0x20, 0x20, 0x20, 0x31, 0x35, 0x20, 0x20, 0x20, 0x31, 0x35, 0x20, 0x20, 0x20, + 0x31, 0x35, 0x20, 0x20, 0x20, 0x31, 0x31, 0x20, 0x20, 0x20, 0x31, 0x31, 0x20, + 0x20, 0x20, 0x31, 0x31 }; + break; + case 0x31: + rev = (uint8_t[80]) { 0x20, 0x20, 0x20, 0x31, 0x31, 0x20, 0x20, 0x20, 0x31, 0x31, 0x20, + 0x20, 0x20, 0x31, 0x31, 0x20, 0x20, 0x31, 0x32, 0x38, 0x20, 0x20, 0x31, 0x30, + 0x33, 0x20, 0x20, 0x31, 0x30, 0x33, 0x20, 0x20, 0x31, 0x31, 0x35, 0x20, 0x20, + 0x31, 0x33, 0x38, 0x20, 0x20, 0x31, 0x32, 0x37, 0x20, 0x20, 0x31, 0x30, 0x33, + 0x20, 0x20, 0x31, 0x30, 0x35, 0x20, 0x20, 0x31, 0x31, 0x31, 0x20, 0x20, 0x31, + 0x32, 0x36, 0x20, 0x20, 0x31, 0x31, 0x33, 0x20, 0x20, 0x20, 0x39, 0x35, 0x20, + 0x20, 0x31, 0x30, 0x30 }; + break; + case 0x33: + rev = (uint8_t[80]) { 0x20, 0x20, 0x31, 0x30, 0x31, 0x20, 0x20, 0x31, 0x31, 0x35, 0x20, + 0x20, 0x20, 0x39, 0x38, 0x20, 0x20, 0x20, 0x38, 0x36, 0x20, 0x20, 0x20, 0x37, + 0x36, 0x20, 0x20, 0x20, 0x36, 0x37, 0x20, 0x20, 0x20, 0x36, 0x38, 0x20, 0x20, + 0x20, 0x34, 0x38, 0x20, 0x20, 0x31, 0x31, 0x37, 0x20, 0x20, 0x20, 0x20, 0x30, + 0x20, 0x20, 0x20, 0x38, 0x32, 0x20, 0x20, 0x31, 0x35, 0x34, 0x20, 0x20, 0x20, + 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x36, 0x20, 0x20, 0x20, 0x33, 0x35, 0x20, + 0x20, 0x20, 0x20, 0x34 }; + break; + default: + dprintf("Wacca touch: BAD STARTUP REQUEST %2hx\n", req->data[2]); + return 1; + } + + memcpy(resp.data, rev, 80 * sizeof(uint8_t)); + + if (req->side == 0) { + hr = touch_frame_encode(&touch0_uart.readable, &resp, sizeof(resp)); } else { - // TODO: see above + hr = touch_frame_encode(&touch1_uart.readable, &resp, sizeof(resp)); } - return S_OK; + return hr; } +static HRESULT touch_handle_get_rev_date_detail(const struct touch_req *req) +{ + struct touch_resp_get_rev_date_detail resp; + HRESULT hr; + uint8_t rev[43] = { 0x31, 0x39, 0x30, 0x35, 0x32, 0x33, 0x52, 0x31, + 0x39, 0x30, 0x35, 0x31, 0x34, 0x31, 0x39, 0x30, 0x35, 0x31, 0x34, 0x31, + 0x39, 0x30, 0x35, 0x31, 0x34, 0x31, 0x39, 0x30, 0x35, 0x31, 0x34, 0x31, + 0x39, 0x30, 0x35, 0x31, 0x34, 0x31, 0x39, 0x30, 0x35, 0x31, 0x34 }; + + dprintf("Wacca Touch%d: get rev date detail\n", req->side); + + resp.cmd = 0xa8; + memcpy(resp.data, rev, sizeof(rev)); + + if (req->side == 0) { + hr = touch_frame_encode(&touch0_uart.readable, &resp, sizeof(resp)); + } + else { + hr = touch_frame_encode(&touch1_uart.readable, &resp, sizeof(resp)); + } + return hr; + +} + +static HRESULT touch_handle_mystery1(const struct touch_req *req) +{ + struct touch_resp_mystery1 resp; + HRESULT hr; + + dprintf("Wacca Touch%d: mystery command 1\n", req->side); + + resp.cmd = 0xa2; + resp.data = 0x3f; + + if (req->side == 0) { + hr = touch_frame_encode(&touch0_uart.readable, &resp, sizeof(resp)); + } + else { + hr = touch_frame_encode(&touch1_uart.readable, &resp, sizeof(resp)); + } + return hr; +} + +static HRESULT touch_handle_mystery2(const struct touch_req *req) +{ + struct touch_resp_mystery2 resp; + HRESULT hr; + + dprintf("Wacca Touch%d: mystery command 2\n", req->side); + + resp.cmd = 0x94; + resp.data = 0; + + if (req->side == 0) { + hr = touch_frame_encode(&touch0_uart.readable, &resp, sizeof(resp)); + } + else { + hr = touch_frame_encode(&touch1_uart.readable, &resp, sizeof(resp)); + } + return hr; +} + +static HRESULT touch_handle_start_auto_scan(const struct touch_req *req) +{ + struct touch_resp_start_auto resp; + HRESULT hr; + uint8_t data1[24] = { 0 }; + uint8_t data2[9] = { 0x0d, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00 }; + + dprintf("Wacca Touch%d: Start Auto\n", req->side); + + resp.cmd = 0x9c; + resp.data = 0; + resp.checksum = 0x49; + + resp.frame.cmd= 0x81; + resp.frame.count = input_frame_count++; + memcpy(resp.frame.data1, data1, sizeof(data1)); + memcpy(resp.frame.data2, data2, sizeof(data2)); + resp.frame.checksum = calc_checksum(&resp.frame, sizeof(resp.frame)); + + if (req->side == 0) { + hr = touch_frame_encode(&touch0_uart.readable, &resp, sizeof(resp)); + } + else { + hr = touch_frame_encode(&touch1_uart.readable, &resp, sizeof(resp)); + } + return hr; +} + +/* Decodes the response into a struct that's easier to work with. */ static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf, int side) { dest->side = side; @@ -243,3 +405,39 @@ static HRESULT touch_frame_decode(struct touch_req *dest, struct iobuf *iobuf, i return S_OK; } + +/* Encode and send the response. + * The last byte of every response is a checksum. + * This checksum is calculated by bitwise XORing + * every byte in the response, then dropping the MSB. + * Thanks the CrazyRedMachine for figuring that out!! + */ +static HRESULT touch_frame_encode(struct iobuf *dest, const void *ptr, size_t nbytes) +{ + const uint8_t *src; + uint8_t checksum = 0; + + src = ptr; + + for (size_t i = 0; i < nbytes; i++) { + dest->bytes[dest->pos++] = src[i]; + checksum = checksum^(src[i]); + } + + dest->bytes[dest->pos++] = checksum&0x7f; + return S_OK; +} + +static uint8_t calc_checksum(const void *ptr, size_t nbytes) +{ + const uint8_t *src; + uint8_t checksum = 0; + + src = ptr; + + for (size_t i = 0; i < nbytes; i++) { + checksum = checksum^(src[i]); + } + + return checksum&0x7f; +} diff --git a/mercuryhook/touch.h b/mercuryhook/touch.h index dd2f760..77784dc 100644 --- a/mercuryhook/touch.h +++ b/mercuryhook/touch.h @@ -12,20 +12,60 @@ enum touch_cmd { CMD_GET_REV_DATE = 0xa0, CMD_STARTUP = 0x72, CMD_GET_REV_DATE_DETAIL = 0xa8, - CMD_UNKNOWN1 = 0xa2, - CMD_UNKNOWN2 = 0x94, - CMD_START_AUTO = 0xc9 + CMD_MYSTERY1 = 0xa2, + CMD_MYSTERY2 = 0x94, + CMD_START_AUTO_SCAN = 0xc9, + CMD_BEGIN_WRITE = 0x77, + CMD_NEXT_WRITE = 0x20 }; struct touch_req { - int side; - int cmd; // First byte is the command byte - int data[256]; // rest of the data goes here - int data_length; // Size of the data including command byte + uint8_t side; // COM3 or COM4 + 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 }; +// The checksum is only calculated when we're about to send it so +// it's not part of any of these structs. Just note that the last +// byte of every response is a checksum struct touch_input_frame { - int data[36]; + uint8_t cmd; + uint8_t data1[24]; + uint8_t data2[9]; + uint8_t count; + uint8_t checksum; +}; + +struct touch_resp_get_rev_date { + uint8_t cmd; + uint8_t data[6]; +}; + +struct touch_resp_startup { + uint8_t data[80]; +}; + +struct touch_resp_get_rev_date_detail { + uint8_t cmd; + uint8_t data[43]; +}; + +struct touch_resp_mystery1 { + uint8_t cmd; + uint8_t data; +}; + +struct touch_resp_mystery2 { + uint8_t cmd; + uint8_t data; +}; + +struct touch_resp_start_auto { + uint8_t cmd; + uint8_t data; + uint8_t checksum; + struct touch_input_frame frame; }; HRESULT touch_hook_init(const struct touch_config *cfg);