#include #include #include #include #include #include "carolhook/carol-dll.h" #include "carolhook/touch.h" #include "hooklib/uart.h" #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) { if (!cfg->enable) { return S_OK; } InitializeCriticalSection(&touch_lock); uart_init(&touch_uart, 1); touch_uart.written.bytes = touch_written_bytes; touch_uart.written.nbytes = sizeof(touch_written_bytes); touch_uart.readable.bytes = touch_readable_bytes; touch_uart.readable.nbytes = sizeof(touch_readable_bytes); dprintf("Touchscreen: Init\n"); return iohook_push_handler(touch_handle_irp); return S_OK; } static HRESULT touch_handle_irp(struct irp *irp) { HRESULT hr; assert(irp != NULL); if (!uart_match_irp(&touch_uart, irp)) { return iohook_invoke_next(irp); } EnterCriticalSection(&touch_lock); hr = touch_handle_irp_locked(irp); LeaveCriticalSection(&touch_lock); return hr; } static HRESULT touch_handle_irp_locked(struct irp *irp) { struct touch_req req; HRESULT hr; assert(carol_dll.touch_init != NULL); if (irp->op == IRP_OP_OPEN) { dprintf("Touchscreen: Starting backend DLL\n"); hr = carol_dll.touch_init(); if (FAILED(hr)) { dprintf("Touchscreen: Backend DLL error: %X\n", (int) hr); return hr; } } hr = uart_handle_irp(&touch_uart, irp); if (FAILED(hr) || irp->op != IRP_OP_WRITE) { return hr; } for (;;) { #if 0 dprintf("Touchscreen: TX Buffer:\n"); dump_iobuf(&touch_uart.written); #endif hr = touch_frame_decode(&req, &touch_uart.written); if (FAILED(hr)) { dprintf("Touchscreen: Deframe Error: %X\n", (int) hr); return hr; } 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->sync = iobuf->bytes[0]; memset(dest->cmd, 0, sizeof(dest->cmd)); size_t data_len = 0; 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; } return S_OK; }