From bfa5d0dd6e00d9f9e6273266ea634396ef32c3e8 Mon Sep 17 00:00:00 2001 From: Dniel97 Date: Sun, 6 Oct 2024 20:37:20 +0200 Subject: [PATCH] aime, vfd: updated and improved --- aimeio/aimeio.c | 74 +++++++- board/config.c | 10 ++ board/config.h | 2 + board/meson.build | 3 + board/sg-cmd.h | 7 + board/sg-led.c | 16 +- board/sg-led.h | 2 + board/sg-nfc-cmd.h | 29 ++-- board/sg-nfc.c | 54 +++++- board/sg-nfc.h | 2 + board/sg-reader.c | 19 ++- board/sg-reader.h | 3 + board/usio.c | 6 +- board/vfd-cmd.h | 123 ++++++++++++++ board/vfd-frame.c | 88 ++++++++++ board/vfd-frame.h | 20 +++ board/vfd.c | 355 ++++++++++++++++++++++++++++++++++++++- board/vfd.h | 10 +- dist/sao/bananatools.ini | 6 +- kizunahook/config.c | 2 +- kizunahook/config.h | 2 +- kizunahook/dllmain.c | 4 +- saohook/config.c | 2 +- saohook/config.h | 2 +- saohook/dllmain.c | 9 +- saohook/meson.build | 1 + saohook/sao-dll.c | 2 +- saohook/saohook.def | 2 +- saohook/systype.c | 2 +- taikohook/config.c | 2 +- taikohook/config.h | 1 + taikohook/dllmain.c | 2 +- 32 files changed, 808 insertions(+), 54 deletions(-) create mode 100644 board/vfd-cmd.h create mode 100644 board/vfd-frame.c create mode 100644 board/vfd-frame.h diff --git a/aimeio/aimeio.c b/aimeio/aimeio.c index 2555eb4..3b3d92b 100644 --- a/aimeio/aimeio.c +++ b/aimeio/aimeio.c @@ -17,6 +17,7 @@ struct aime_io_config { wchar_t aime_path[MAX_PATH]; wchar_t felica_path[MAX_PATH]; bool felica_gen; + bool aime_gen; uint8_t vk_scan; }; @@ -40,6 +41,11 @@ static HRESULT aime_io_generate_felica( uint8_t *bytes, size_t nbytes); +static HRESULT aime_io_generate_aime( + const wchar_t *path, + uint8_t *bytes, + size_t nbytes); + static void aime_io_config_read( struct aime_io_config *cfg, const wchar_t *filename) @@ -62,11 +68,16 @@ static void aime_io_config_read( cfg->felica_path, _countof(cfg->felica_path), filename); - dprintf("NFC: felicaPath GetLastError %lx\n", GetLastError()); cfg->felica_gen = GetPrivateProfileIntW( L"aime", L"felicaGen", + 0, + filename); + + cfg->aime_gen = GetPrivateProfileIntW( + L"aime", + L"aimeGen", 1, filename); @@ -136,7 +147,7 @@ static HRESULT aime_io_generate_felica( srand(time(NULL)); - for (i = 0 ; i < nbytes ; i++) { + for (i = 0; i < nbytes; i++) { bytes[i] = rand(); } @@ -151,7 +162,7 @@ static HRESULT aime_io_generate_felica( return E_FAIL; } - for (i = 0 ; i < nbytes ; i++) { + for (i = 0; i < nbytes; i++) { fprintf(f, "%02X", bytes[i]); } @@ -163,6 +174,47 @@ static HRESULT aime_io_generate_felica( return S_OK; } +static HRESULT aime_io_generate_aime( + const wchar_t *path, + uint8_t *bytes, + size_t nbytes) +{ + size_t i; + FILE *f; + + assert(path != NULL); + assert(bytes != NULL); + assert(nbytes > 0); + + srand(time(NULL)); + + /* AiMe IDs should not start with 3, due to a missing check for BananaPass IDs */ + do { + for (i = 0; i < nbytes; i++) { + bytes[i] = rand() % 10 << 4 | rand() % 10; + } + } while (bytes[0] >> 4 == 3); + + f = _wfopen(path, L"w"); + + if (f == NULL) { + dprintf("AimeIO DLL: %S: fopen failed: %i\n", path, (int) errno); + + return E_FAIL; + } + + for (i = 0; i < nbytes; i++) { + fprintf(f, "%02x", bytes[i]); + } + + fprintf(f, "\n"); + fclose(f); + + dprintf("AimeIO DLL: Generated random AiMe ID\n"); + + return S_OK; +} + uint16_t aime_io_get_api_version(void) { return 0x0100; @@ -210,6 +262,22 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no) return S_OK; } + /* Try generating AiMe IC (if enabled) */ + + if (aime_io_cfg.aime_gen) { + hr = aime_io_generate_aime( + aime_io_cfg.aime_path, + aime_io_aime_id, + sizeof(aime_io_aime_id)); + + if (FAILED(hr)) { + return hr; + } + + aime_io_aime_id_present = true; + return S_OK; + } + /* Try FeliCa IC */ hr = aime_io_read_id_file( diff --git a/board/config.c b/board/config.c index a54cee3..a285b19 100644 --- a/board/config.c +++ b/board/config.c @@ -71,3 +71,13 @@ void aime_config_load(struct aime_config *cfg, const wchar_t *filename) aime_dll_config_load(&cfg->dll, filename); cfg->enable = GetPrivateProfileIntW(L"aime", L"enable", 1, filename); } + +void vfd_config_load(struct vfd_config *cfg, const wchar_t *filename) +{ + assert(cfg != NULL); + assert(filename != NULL); + + cfg->enable = GetPrivateProfileIntW(L"vfd", L"enable", 1, filename); + cfg->port = GetPrivateProfileIntW(L"vfd", L"portNo", 0, filename); + cfg->utf_conversion = GetPrivateProfileIntW(L"vfd", L"utfConversion", 0, filename); +} diff --git a/board/config.h b/board/config.h index 5815f0b..df99d99 100644 --- a/board/config.h +++ b/board/config.h @@ -7,8 +7,10 @@ #include "board/bpreader.h" #include "board/qr.h" #include "board/sg-reader.h" +#include "board/vfd.h" void bpreader_config_load(struct bpreader_config *cfg, const wchar_t *filename); void usio_config_load(struct usio_config *cfg, const wchar_t *filename); void qr_config_load(struct qr_config *cfg, const wchar_t *filename); void aime_config_load(struct aime_config *cfg, const wchar_t *filename); +void vfd_config_load(struct vfd_config *cfg, const wchar_t *filename); diff --git a/board/meson.build b/board/meson.build index 5bb6452..a1e7956 100644 --- a/board/meson.build +++ b/board/meson.build @@ -39,6 +39,9 @@ board_lib = static_library( 'sg-nfc-cmd.h', 'sg-reader.c', 'sg-reader.h', + 'vfd-cmd.h', + 'vfd-frame.c', + 'vfd-frame.h', 'vfd.c', 'vfd.h', ], diff --git a/board/sg-cmd.h b/board/sg-cmd.h index 685377f..73029ec 100644 --- a/board/sg-cmd.h +++ b/board/sg-cmd.h @@ -25,6 +25,13 @@ struct sg_res_header { uint8_t payload_len; }; +/* struct to save the version string with its length + to fix NUL terminator issues */ +struct version_info { + const char *version; + uint8_t length; +}; + typedef HRESULT (*sg_dispatch_fn_t)( void *ctx, const void *req, diff --git a/board/sg-led.c b/board/sg-led.c index 855e36b..47f97c2 100644 --- a/board/sg-led.c +++ b/board/sg-led.c @@ -27,14 +27,18 @@ static HRESULT sg_led_cmd_set_color( const struct sg_led *led, const struct sg_led_req_set_color *req); -static const uint8_t sg_led_info[] = { - '1', '5', '0', '8', '4', 0xFF, 0x10, 0x00, 0x12, +static const struct version_info led_version[] = { + {"15084\xFF\x10\x00\x12", 9}, + {"000-00000\xFF\x11\x40", 12}, + // maybe the same? + {"000-00000\xFF\x11\x40", 12} }; void sg_led_init( struct sg_led *led, uint8_t addr, const struct sg_led_ops *ops, + unsigned int gen, void *ctx) { assert(led != NULL); @@ -43,6 +47,7 @@ void sg_led_init( led->ops = ops; led->ops_ctx = ctx; led->addr = addr; + led->gen = gen; } void sg_led_transact( @@ -150,8 +155,11 @@ static HRESULT sg_led_cmd_get_info( struct sg_led_res_get_info *res) { sg_led_dprintf(led, "Get info\n"); - sg_res_init(&res->res, req, sizeof(res->payload)); - memcpy(res->payload, sg_led_info, sizeof(sg_led_info)); + + const struct version_info *fw = &led_version[led->gen - 1]; + + sg_res_init(&res->res, req, fw->length); + memcpy(res->payload, fw->version, fw->length); return S_OK; } diff --git a/board/sg-led.h b/board/sg-led.h index de3caa6..eaa8d16 100644 --- a/board/sg-led.h +++ b/board/sg-led.h @@ -15,12 +15,14 @@ struct sg_led { const struct sg_led_ops *ops; void *ops_ctx; uint8_t addr; + unsigned int gen; }; void sg_led_init( struct sg_led *led, uint8_t addr, const struct sg_led_ops *ops, + unsigned int gen, void *ctx); void sg_led_transact( diff --git a/board/sg-nfc-cmd.h b/board/sg-nfc-cmd.h index b6754c2..08923fd 100644 --- a/board/sg-nfc-cmd.h +++ b/board/sg-nfc-cmd.h @@ -5,18 +5,21 @@ #pragma pack(push, 1) enum { - SG_NFC_CMD_GET_FW_VERSION = 0x30, - SG_NFC_CMD_GET_HW_VERSION = 0x32, - SG_NFC_CMD_RADIO_ON = 0x40, - SG_NFC_CMD_RADIO_OFF = 0x41, - SG_NFC_CMD_POLL = 0x42, - SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43, - SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x50, - SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52, - SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x54, - SG_NFC_CMD_MIFARE_AUTHENTICATE = 0x55, /* guess based on time sent */ - SG_NFC_CMD_RESET = 0x62, - SG_NFC_CMD_FELICA_ENCAP = 0x71, + SG_NFC_CMD_GET_FW_VERSION = 0x30, + SG_NFC_CMD_GET_HW_VERSION = 0x32, + SG_NFC_CMD_RADIO_ON = 0x40, + SG_NFC_CMD_RADIO_OFF = 0x41, + SG_NFC_CMD_POLL = 0x42, + SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43, + SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x50, + SG_NFC_CMD_MIFARE_AUTHENTICATE_A = 0x51, + SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52, + SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x54, + SG_NFC_CMD_MIFARE_AUTHENTICATE_B = 0x55, + SG_NFC_CMD_TO_UPDATE_MODE = 0x60, + SG_NFC_CMD_SEND_HEX_DATA = 0x61, + SG_NFC_CMD_RESET = 0x62, + SG_NFC_CMD_FELICA_ENCAP = 0x71, }; struct sg_nfc_res_get_fw_version { @@ -31,7 +34,7 @@ struct sg_nfc_res_get_hw_version { struct sg_nfc_req_mifare_set_key { struct sg_req_header req; - uint8_t key_a[6]; + uint8_t key[6]; }; struct sg_nfc_req_mifare_50 { diff --git a/board/sg-nfc.c b/board/sg-nfc.c index 3e57b26..9709c81 100644 --- a/board/sg-nfc.c +++ b/board/sg-nfc.c @@ -60,15 +60,33 @@ static HRESULT sg_nfc_cmd_felica_encap( const struct sg_nfc_req_felica_encap *req, struct sg_nfc_res_felica_encap *res); +static HRESULT sg_nfc_cmd_send_hex_data( + struct sg_nfc *nfc, + const struct sg_req_header *req, + struct sg_res_header *res); + static HRESULT sg_nfc_cmd_dummy( struct sg_nfc *nfc, const struct sg_req_header *req, struct sg_res_header *res); +static const struct version_info hw_version[] = { + {"TN32MSEC003S H/W Ver3.0", 23}, + {"837-15286", 9}, + {"837-15396", 9} +}; + +static const struct version_info fw_version[] = { + {"TN32MSEC003S F/W Ver1.2", 23}, + {"\x94", 1}, + {"\x94", 1} +}; + void sg_nfc_init( struct sg_nfc *nfc, uint8_t addr, const struct sg_nfc_ops *ops, + unsigned int gen, void *ops_ctx) { assert(nfc != NULL); @@ -77,6 +95,7 @@ void sg_nfc_init( nfc->ops = ops; nfc->ops_ctx = ops_ctx; nfc->addr = addr; + nfc->gen = gen; } #ifdef NDEBUG @@ -170,12 +189,17 @@ static HRESULT sg_nfc_dispatch( &req->felica_encap, &res->felica_encap); - case SG_NFC_CMD_MIFARE_AUTHENTICATE: + case SG_NFC_CMD_MIFARE_AUTHENTICATE_A: + case SG_NFC_CMD_MIFARE_AUTHENTICATE_B: + case SG_NFC_CMD_SEND_HEX_DATA: + return sg_nfc_cmd_send_hex_data(nfc, &req->simple, &res->simple); + case SG_NFC_CMD_MIFARE_SELECT_TAG: case SG_NFC_CMD_MIFARE_SET_KEY_AIME: case SG_NFC_CMD_MIFARE_SET_KEY_BANA: case SG_NFC_CMD_RADIO_ON: case SG_NFC_CMD_RADIO_OFF: + case SG_NFC_CMD_TO_UPDATE_MODE: return sg_nfc_cmd_dummy(nfc, &req->simple, &res->simple); default: @@ -202,9 +226,11 @@ static HRESULT sg_nfc_cmd_get_fw_version( const struct sg_req_header *req, struct sg_nfc_res_get_fw_version *res) { + const struct version_info *fw = &fw_version[nfc->gen - 1]; + /* Dest version is not NUL terminated, this is intentional */ - sg_res_init(&res->res, req, sizeof(res->version)); - memcpy(res->version, "\x94", sizeof(res->version)); + sg_res_init(&res->res, req, fw->length); + memcpy(res->version, fw->version, fw->length); return S_OK; } @@ -214,9 +240,11 @@ static HRESULT sg_nfc_cmd_get_hw_version( const struct sg_req_header *req, struct sg_nfc_res_get_hw_version *res) { + const struct version_info *hw = &hw_version[nfc->gen - 1]; + /* Dest version is not NUL terminated, this is intentional */ - sg_res_init(&res->res, req, sizeof(res->version)); - memcpy(res->version, "837-15396-6728", sizeof(res->version)); + sg_res_init(&res->res, req, hw->length); + memcpy(res->version, hw->version, hw->length); return S_OK; } @@ -423,6 +451,22 @@ static HRESULT sg_nfc_cmd_felica_encap( return S_OK; } +static HRESULT sg_nfc_cmd_send_hex_data( + struct sg_nfc *nfc, + const struct sg_req_header *req, + struct sg_res_header *res) +{ + sg_res_init(res, req, 0); + + /* Firmware checksum length? */ + if (req->payload_len == 0x2b) { + /* The firmware is identical flag? */ + res->status = 0x20; + } + + return S_OK; +} + static HRESULT sg_nfc_cmd_dummy( struct sg_nfc *nfc, const struct sg_req_header *req, diff --git a/board/sg-nfc.h b/board/sg-nfc.h index 5562b2b..3c8eb49 100644 --- a/board/sg-nfc.h +++ b/board/sg-nfc.h @@ -22,6 +22,7 @@ struct sg_nfc { const struct sg_nfc_ops *ops; void *ops_ctx; uint8_t addr; + unsigned int gen; struct felica felica; struct mifare mifare; }; @@ -30,6 +31,7 @@ void sg_nfc_init( struct sg_nfc *nfc, uint8_t addr, const struct sg_nfc_ops *ops, + unsigned int gen, void *ops_ctx); void sg_nfc_transact( diff --git a/board/sg-reader.c b/board/sg-reader.c index dbf0392..24df4df 100644 --- a/board/sg-reader.c +++ b/board/sg-reader.c @@ -48,6 +48,7 @@ static struct sg_led sg_reader_led; HRESULT sg_reader_hook_init( const struct aime_config *cfg, unsigned int port_no, + unsigned int gen, HINSTANCE self) { HRESULT hr; @@ -65,11 +66,25 @@ HRESULT sg_reader_hook_init( return hr; } - sg_nfc_init(&sg_reader_nfc, 0x00, &sg_reader_nfc_ops, NULL); - sg_led_init(&sg_reader_led, 0x08, &sg_reader_led_ops, NULL); + if (cfg->gen != 0) { + gen = cfg->gen; + } + + if (gen < 1 || gen > 3) { + dprintf("NFC Assembly: Invalid reader generation: %u\n", gen); + + return E_INVALIDARG; + } + + sg_nfc_init(&sg_reader_nfc, 0x00, &sg_reader_nfc_ops, gen, NULL); + sg_led_init(&sg_reader_led, 0x08, &sg_reader_led_ops, gen, NULL); InitializeCriticalSection(&sg_reader_lock); + if (!cfg->high_baudrate) { + sg_reader_uart.baud.BaudRate = 38400; + } + uart_init(&sg_reader_uart, port_no); sg_reader_uart.written.bytes = sg_reader_written_bytes; sg_reader_uart.written.nbytes = sizeof(sg_reader_written_bytes); diff --git a/board/sg-reader.h b/board/sg-reader.h index 673a8bd..01eb0b3 100644 --- a/board/sg-reader.h +++ b/board/sg-reader.h @@ -9,9 +9,12 @@ struct aime_config { struct aime_dll_config dll; bool enable; + bool high_baudrate; + unsigned int gen; }; HRESULT sg_reader_hook_init( const struct aime_config *cfg, unsigned int port_no, + unsigned int gen, HINSTANCE self); diff --git a/board/usio.c b/board/usio.c index 8456c4a..880152b 100644 --- a/board/usio.c +++ b/board/usio.c @@ -307,7 +307,7 @@ static int my_bnusio_SetCoinLock(uint8_t id, char value) static int my_bnusio_GetCoin(uint8_t id) { - //dprintf("USIO: GetCoin ID %d\n", id); + // dprintf("USIO: GetCoin ID %d\n", id); usio_ops->poll(usio_ops_ctx, &state); if (id < 2) { return state.coins[id].current_coin_count; @@ -317,7 +317,7 @@ static int my_bnusio_GetCoin(uint8_t id) static int my_bnusio_GetCoinError(uint8_t id) { - //dprintf("USIO: GetCoinErrorID %d\n", id); + // dprintf("USIO: GetCoinErrorID %d\n", id); if (id >= _countof(state.coins)) { return 0; } @@ -373,4 +373,4 @@ static intptr_t my_bnusio_GetIoBoardName() intptr_t ret = (intptr_t)malloc(sizeof(usio_name) / 2); wcstombs((char *)ret, usio_name, sizeof(usio_name) / 2); return ret; -} \ No newline at end of file +} diff --git a/board/vfd-cmd.h b/board/vfd-cmd.h new file mode 100644 index 0000000..28bcb16 --- /dev/null +++ b/board/vfd-cmd.h @@ -0,0 +1,123 @@ +#pragma once + +#include "board/vfd-frame.h" + +enum { + VFD_CMD_GET_VERSION = 0x5B, + VFD_CMD_RESET = 0x0B, + VFD_CMD_CLEAR_SCREEN = 0x0C, + VFD_CMD_SET_BRIGHTNESS = 0x20, + VFD_CMD_SET_SCREEN_ON = 0x21, + VFD_CMD_SET_H_SCROLL = 0x22, + VFD_CMD_DRAW_IMAGE = 0x2E, + VFD_CMD_SET_CURSOR = 0x30, + VFD_CMD_SET_ENCODING = 0x32, + VFD_CMD_SET_TEXT_WND = 0x40, + VFD_CMD_SET_TEXT_SPEED = 0x41, + VFD_CMD_WRITE_TEXT = 0x50, + VFD_CMD_ENABLE_SCROLL = 0x51, + VFD_CMD_DISABLE_SCROLL = 0x52, + VFD_CMD_ROTATE = 0x5D, + VFD_CMD_CREATE_CHAR = 0xA3, + VFD_CMD_CREATE_CHAR2 = 0xA4, +}; + +enum { + VFD_ENC_GB2312 = 0, + VFD_ENC_BIG5 = 1, + VFD_ENC_SHIFT_JIS = 2, + VFD_ENC_KSC5601 = 3, + VFD_ENC_MAX = 3, +}; + +struct vfd_req_hdr { + uint8_t sync; + uint8_t cmd; +}; + +struct vfd_req_any { + struct vfd_req_hdr hdr; + uint8_t payload[2054]; +}; + +struct vfd_req_board_info { + struct vfd_req_hdr hdr; + uint8_t unk1; +}; + +struct vfd_resp_board_info { // \x0201.20\x03 + uint8_t unk1; + char version[5]; + uint8_t unk2; +}; + +struct vfd_req_reset { + struct vfd_req_hdr hdr; +}; + +struct vfd_req_cls { + struct vfd_req_hdr hdr; +}; + +struct vfd_req_brightness { + struct vfd_req_hdr hdr; + uint8_t brightness; +}; + +struct vfd_req_power { + struct vfd_req_hdr hdr; + uint8_t power_state; +}; + +struct vfd_req_hscroll { + struct vfd_req_hdr hdr; + uint8_t x_pos; +}; + +struct vfd_req_draw { + struct vfd_req_hdr hdr; + uint16_t x0; + uint8_t y0; + uint16_t x1; + uint8_t y1; + uint8_t image[2048]; +}; + +struct vfd_req_cursor { + struct vfd_req_hdr hdr; + uint16_t x; + uint8_t y; +}; + +struct vfd_req_encoding { + struct vfd_req_hdr hdr; + uint8_t encoding; +}; + +struct vfd_req_wnd { + struct vfd_req_hdr hdr; + uint16_t x0; + uint8_t y0; + uint16_t x1; + uint8_t y1; +}; + +struct vfd_req_speed { + struct vfd_req_hdr hdr; + uint8_t encoding; +}; + +struct vfd_req_scroll { + struct vfd_req_hdr hdr; +}; + +struct vfd_req_rotate { + struct vfd_req_hdr hdr; + uint8_t unk1; +}; + +struct vfd_req_create_char { + struct vfd_req_hdr hdr; + uint8_t type; + uint8_t pixels[32]; +}; diff --git a/board/vfd-frame.c b/board/vfd-frame.c new file mode 100644 index 0000000..05fe302 --- /dev/null +++ b/board/vfd-frame.c @@ -0,0 +1,88 @@ +#include + +#include +#include +#include +#include + +#define SUPER_VERBOSE 1 + +#include "board/vfd-frame.h" + +#include "hook/iobuf.h" + +#include "util/dprintf.h" + +static HRESULT vfd_frame_encode_byte(struct iobuf *dest, uint8_t byte); + +/* Frame structure: + + REQUEST: + [0] Sync byte (0x1A or 0x1B) + [1] Packet ID + [2...n-1] Data/payload + + --- OR --- + + if no sync byte is given, plain static text in the currently configured encoding is expected. + + RESPONSE: + This thing never responds, unless it's VFD_CMD_GET_VERSION + */ + +bool vfd_frame_sync(struct const_iobuf *src) { + return src->bytes[src->pos] == VFD_SYNC_BYTE || src->bytes[src->pos] == VFD_SYNC_BYTE2; +} + +HRESULT vfd_frame_encode( + struct iobuf *dest, + const void *ptr, + size_t nbytes) { + const uint8_t *src; + uint8_t byte; + size_t i; + HRESULT hr; + + assert(dest != NULL); + assert(dest->bytes != NULL || dest->nbytes == 0); + assert(dest->pos <= dest->nbytes); + assert(ptr != NULL); + + src = ptr; + + if (dest->pos >= dest->nbytes) { + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + +#if SUPER_VERBOSE + dprintf("VFD: RX Buffer:\n"); +#endif + + for (i = 1; i < nbytes; i++) { + byte = src[i]; +#if SUPER_VERBOSE + dprintf("%02x ", byte); +#endif + + hr = vfd_frame_encode_byte(dest, byte); + + if (FAILED(hr)) { + return hr; + } + } +#if SUPER_VERBOSE + dprintf("\n"); +#endif + + return hr; +} + +static HRESULT vfd_frame_encode_byte(struct iobuf *dest, uint8_t byte) { + if (dest->pos + 1 > dest->nbytes) { + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + + dest->bytes[dest->pos++] = byte; + + return S_OK; +} diff --git a/board/vfd-frame.h b/board/vfd-frame.h new file mode 100644 index 0000000..7055f5b --- /dev/null +++ b/board/vfd-frame.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +#include +#include + +#include "hook/iobuf.h" + +enum { + VFD_SYNC_BYTE = 0x1B, + VFD_SYNC_BYTE2 = 0x1A, +}; + +bool vfd_frame_sync(struct const_iobuf *src); + +HRESULT vfd_frame_encode( + struct iobuf *dest, + const void *ptr, + size_t nbytes); diff --git a/board/vfd.c b/board/vfd.c index 081a8d8..8c6ea29 100644 --- a/board/vfd.c +++ b/board/vfd.c @@ -3,16 +3,20 @@ of electronic payments. Part number in schematics is "VFD GP1232A02A FUTABA". - - Little else about this board is known. Black-holing the RS232 comms that it - receives seems to be sufficient for the time being. */ + + Credits: + + Haruka +*/ #include #include #include +#include "board/config.h" #include "board/vfd.h" +#include "board/vfd-cmd.h" #include "hook/iohook.h" @@ -21,15 +25,51 @@ #include "util/dprintf.h" #include "util/dump.h" +#define SUPER_VERBOSE 0 + static HRESULT vfd_handle_irp(struct irp *irp); static struct uart vfd_uart; -static uint8_t vfd_written[512]; -static uint8_t vfd_readable[512]; +static uint8_t vfd_written[4096]; +static uint8_t vfd_readable[4096]; -HRESULT vfd_hook_init(unsigned int port_no) +static int encoding = VFD_ENC_SHIFT_JIS; + +HRESULT vfd_handle_get_version(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_reset(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_clear_screen(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_set_brightness(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_set_screen_on(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_set_h_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_draw_image(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_set_cursor(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_set_encoding(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_set_text_wnd(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_set_text_speed(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_write_text(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_enable_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_disable_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_rotate(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_create_char(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); +HRESULT vfd_handle_create_char2(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart); + +static bool utf_enabled; + +HRESULT vfd_hook_init(struct vfd_config *cfg, int default_port) { - uart_init(&vfd_uart, port_no); + if (!cfg->enable){ + return S_FALSE; + } + + utf_enabled = cfg->utf_conversion; + + int port = cfg->port; + if (port == 0){ + port = default_port; + } + + dprintf("VFD: enabling (port=%d)\n", port); + uart_init(&vfd_uart, port); vfd_uart.written.bytes = vfd_written; vfd_uart.written.nbytes = sizeof(vfd_written); vfd_uart.readable.bytes = vfd_readable; @@ -38,6 +78,48 @@ HRESULT vfd_hook_init(unsigned int port_no) return iohook_push_handler(vfd_handle_irp); } + +const char* get_encoding_name(int b){ + switch (b){ + case 0: return "gb2312"; + case 1: return "big5"; + case 2: return "shift-jis"; + case 3: return "ks_c_5601-1987"; + default: return "unknown"; + } +} + +void print_vfd_text(const char* str, int len){ + + if (utf_enabled){ + + wchar_t encoded[1024]; + memset(encoded, 0, 1024 * sizeof(wchar_t)); + + int codepage = 0; + if (encoding == VFD_ENC_GB2312){ + codepage = 936; + } else if (encoding == VFD_ENC_BIG5){ + codepage = 950; + } else if (encoding == VFD_ENC_SHIFT_JIS){ + codepage = 932; + } else if (encoding == VFD_ENC_KSC5601) { + codepage = 949; + } + + if (!MultiByteToWideChar(codepage, MB_USEGLYPHCHARS, str, len, encoded, 1024)){ + dprintf("VFD: Text conversion failed: %ld", GetLastError()); + return; + } + + dprintf("VFD: Text: %ls\n", encoded); + } else { + + dprintf("VFD: Text: %s\n", str); + + } +} + static HRESULT vfd_handle_irp(struct irp *irp) { HRESULT hr; @@ -48,15 +130,274 @@ static HRESULT vfd_handle_irp(struct irp *irp) return iohook_invoke_next(irp); } + if (irp->op == IRP_OP_OPEN){ + dprintf("VFD: Open\n"); + } else if (irp->op == IRP_OP_CLOSE){ + dprintf("VFD: Close\n"); + } + hr = uart_handle_irp(&vfd_uart, irp); if (FAILED(hr) || irp->op != IRP_OP_WRITE) { return hr; } +#if SUPER_VERBOSE dprintf("VFD TX:\n"); dump_iobuf(&vfd_uart.written); +#endif + + struct const_iobuf reader; + iobuf_flip(&reader, &vfd_uart.written); + + struct iobuf* writer = &vfd_uart.readable; + for (; reader.pos < reader.nbytes ; ){ + + if (vfd_frame_sync(&reader)) { + + reader.pos++; // get the sync byte out of the way + + uint8_t cmd; + iobuf_read_8(&reader, &cmd); + + if (cmd == VFD_CMD_GET_VERSION) { + hr = vfd_handle_get_version(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_RESET) { + hr = vfd_handle_reset(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_CLEAR_SCREEN) { + hr = vfd_handle_clear_screen(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_SET_BRIGHTNESS) { + hr = vfd_handle_set_brightness(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_SET_SCREEN_ON) { + hr = vfd_handle_set_screen_on(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_SET_H_SCROLL) { + hr = vfd_handle_set_h_scroll(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_DRAW_IMAGE) { + hr = vfd_handle_draw_image(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_SET_CURSOR) { + hr = vfd_handle_set_cursor(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_SET_ENCODING) { + hr = vfd_handle_set_encoding(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_SET_TEXT_WND) { + hr = vfd_handle_set_text_wnd(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_SET_TEXT_SPEED) { + hr = vfd_handle_set_text_speed(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_WRITE_TEXT) { + hr = vfd_handle_write_text(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_ENABLE_SCROLL) { + hr = vfd_handle_enable_scroll(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_DISABLE_SCROLL) { + hr = vfd_handle_disable_scroll(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_ROTATE) { + hr = vfd_handle_rotate(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_CREATE_CHAR) { + hr = vfd_handle_create_char(&reader, writer, &vfd_uart); + } else if (cmd == VFD_CMD_CREATE_CHAR2) { + hr = vfd_handle_create_char2(&reader, writer, &vfd_uart); + } else { + dprintf("VFD: Unknown command 0x%x\n", cmd); + dump_const_iobuf(&reader); + hr = S_FALSE; + } + } else { + + // if no sync byte is sent, we are just getting plain text... + + if (reader.pos < reader.nbytes){ + int len = 0; + + // read chars until we hit a new sync byte or the data ends + while (reader.pos + len + 1 < reader.nbytes && reader.bytes[reader.pos + len] != VFD_SYNC_BYTE && reader.bytes[reader.pos + len] != VFD_SYNC_BYTE2){ + len++; + } + + char* str = malloc(len); + memset(str, 0, len); + iobuf_read(&reader, str, len); + print_vfd_text(str, len); + free(str); + + reader.pos += len; + } + + } + + if (!SUCCEEDED(hr)){ + return hr; + } + + } + vfd_uart.written.pos = 0; return hr; } + +HRESULT vfd_handle_get_version(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + dprintf("VFD: Get Version\n"); + + struct vfd_resp_board_info resp; + + memset(&resp, 0, sizeof(resp)); + resp.unk1 = 2; + strcpy(resp.version, "01.20"); + resp.unk2 = 1; + + return vfd_frame_encode(writer, &resp, sizeof(resp)); +} +HRESULT vfd_handle_reset(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + dprintf("VFD: Reset\n"); + + encoding = VFD_ENC_SHIFT_JIS; + + return S_FALSE; +} +HRESULT vfd_handle_clear_screen(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + dprintf("VFD: Clear Screen\n"); + + return S_FALSE; +} +HRESULT vfd_handle_set_brightness(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint8_t b; + iobuf_read_8(reader, &b); + + if (b > 4){ + dprintf("VFD: Brightness, invalid argument\n"); + return E_FAIL; + } + + dprintf("VFD: Brightness, %d\n", b); + + return S_FALSE; +} +HRESULT vfd_handle_set_screen_on(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint8_t b; + iobuf_read_8(reader, &b); + + if (b > 1){ + dprintf("VFD: Screen Power, invalid argument\n"); + return E_FAIL; + } + + dprintf("VFD: Screen Power, %d\n", b); + return S_FALSE; +} +HRESULT vfd_handle_set_h_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint8_t x; + iobuf_read_8(reader, &x); + + dprintf("VFD: Horizontal Scroll, X=%d\n", x); + return S_FALSE; +} +HRESULT vfd_handle_draw_image(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + int w, h; + uint16_t x0, x1; + uint8_t y0, y1; + uint8_t image[2048]; + + iobuf_read_be16(reader, &x0); + iobuf_read_8(reader, &y0); + iobuf_read_be16(reader, &x1); + iobuf_read_8(reader, &y1); + w = x1 - x0; + h = y1 - y0; + iobuf_read(reader, image, w*h); + + dprintf("VFD: Draw image, %dx%d\n", w, h); + return S_FALSE; +} + +HRESULT vfd_handle_set_cursor(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint16_t x; + uint8_t y; + + iobuf_read_be16(reader, &x); + iobuf_read_8(reader, &y); + + dprintf("VFD: Set Cursor, x=%d,y=%d\n", x, y); + + return S_FALSE; +} + +HRESULT vfd_handle_set_encoding(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint8_t b; + iobuf_read_8(reader, &b); + + dprintf("VFD: Set Encoding, %d (%s)\n", b, get_encoding_name(b)); + + if (b < 0 || b > VFD_ENC_MAX){ + dprintf("Invalid encoding specified\n"); + return E_FAIL; + } + + encoding = b; + + return S_FALSE; +} +HRESULT vfd_handle_set_text_wnd(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint16_t x0, x1; + uint8_t y0, y1; + + iobuf_read_be16(reader, &x0); + iobuf_read_8(reader, &y0); + iobuf_read_be16(reader, &x1); + iobuf_read_8(reader, &y1); + + dprintf("VFD: Set Text Window, p0:%d,%d, p1:%d,%d\n", x0, y0, x1, y1); + return S_FALSE; +} +HRESULT vfd_handle_set_text_speed(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint8_t b; + iobuf_read_8(reader, &b); + + dprintf("VFD: Set Text Speed, %d\n", b); + return S_FALSE; +} +HRESULT vfd_handle_write_text(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint8_t len; + iobuf_read_8(reader, &len); + + char* str = malloc(len); + iobuf_read(reader, str, len); + + print_vfd_text(str, len); + free(str); + + return S_FALSE; +} +HRESULT vfd_handle_enable_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + dprintf("VFD: Enable Scrolling\n"); + return S_FALSE; +} +HRESULT vfd_handle_disable_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + dprintf("VFD: Disable Scrolling\n"); + return S_FALSE; +} +HRESULT vfd_handle_rotate(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint8_t b; + iobuf_read_8(reader, &b); + + dprintf("VFD: Rotate, %d\n", b); + return S_FALSE; +} +HRESULT vfd_handle_create_char(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint8_t b; + iobuf_read_8(reader, &b); + char buf[32]; + + iobuf_read(reader, buf, 32); + + dprintf("VFD: Create character, %d\n", b); + return S_FALSE; +} +HRESULT vfd_handle_create_char2(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){ + uint8_t b, b2; + iobuf_read_8(reader, &b); + iobuf_read_8(reader, &b2); + char buf[16]; + + iobuf_read(reader, buf, 16); + + dprintf("VFD: Create character, %d, %d\n", b, b2); + return S_FALSE; +} diff --git a/board/vfd.h b/board/vfd.h index 01cd82e..3e67061 100644 --- a/board/vfd.h +++ b/board/vfd.h @@ -2,4 +2,12 @@ #include -HRESULT vfd_hook_init(unsigned int port_no); +struct vfd_config { + bool enable; + int port; + bool utf_conversion; +}; + + +HRESULT vfd_hook_init(struct vfd_config *cfg, int default_port); + diff --git a/dist/sao/bananatools.ini b/dist/sao/bananatools.ini index 85d5bf6..34d2e51 100644 --- a/dist/sao/bananatools.ini +++ b/dist/sao/bananatools.ini @@ -30,10 +30,10 @@ windowed=1 framed=0 monitor=0 -; Banapass reader -[reader] +; Aime reader +[aime] enable=1 -access_code=00000000000000000000 +aimePath=DEVICE\\aime.txt ; Control the AMCUS replacement class [amcus] diff --git a/kizunahook/config.c b/kizunahook/config.c index 87af819..a1f75ec 100644 --- a/kizunahook/config.c +++ b/kizunahook/config.c @@ -32,6 +32,6 @@ void kizuna_hook_config_load( platform_config_load(&cfg->platform, filename); kizuna_dll_config_load(&cfg->dll, filename); gfx_config_load(&cfg->gfx, filename); - bpreader_config_load(&cfg->reader, filename); usio_config_load(&cfg->usio, filename); + vfd_config_load(&cfg->vfd, filename); } diff --git a/kizunahook/config.h b/kizunahook/config.h index 8128af2..632ca74 100644 --- a/kizunahook/config.h +++ b/kizunahook/config.h @@ -15,8 +15,8 @@ struct kizuna_hook_config { struct kizuna_dll_config dll; struct gfx_config gfx; struct amcus_config amcus; - struct bpreader_config reader; struct usio_config usio; + struct vfd_config vfd; }; void kizuna_dll_config_load( diff --git a/kizunahook/dllmain.c b/kizunahook/dllmain.c index cc71c61..566de79 100644 --- a/kizunahook/dllmain.c +++ b/kizunahook/dllmain.c @@ -44,13 +44,13 @@ static DWORD CALLBACK kizuna_pre_startup(void) ExitProcess(EXIT_FAILURE); } - hr = sg_reader_hook_init(&kizuna_hook_cfg.aime, 1, kizuna_hook_mod); + hr = sg_reader_hook_init(&kizuna_hook_cfg.aime, 1, 3, kizuna_hook_mod); if (FAILED(hr)) { ExitProcess(EXIT_FAILURE); } - hr = vfd_hook_init(2); + hr = vfd_hook_init(&kizuna_hook_cfg.vfd, 2); if (FAILED(hr)) { ExitProcess(EXIT_FAILURE); diff --git a/saohook/config.c b/saohook/config.c index 4e4e98f..79c3d58 100644 --- a/saohook/config.c +++ b/saohook/config.c @@ -64,8 +64,8 @@ void sao_hook_config_load( sao_dll_config_load(&cfg->dll, filename); gfx_config_load(&cfg->gfx, filename); qr_config_load(&cfg->qr, filename); - bpreader_config_load(&cfg->reader, filename); usio_config_load(&cfg->usio, filename); systype_config_load(&cfg->systype, filename); sao_touch_config_load(&cfg->touch, filename); + vfd_config_load(&cfg->vfd, filename); } diff --git a/saohook/config.h b/saohook/config.h index e20ef77..4c3ba8b 100644 --- a/saohook/config.h +++ b/saohook/config.h @@ -18,10 +18,10 @@ struct sao_hook_config { struct gfx_config gfx; struct amcus_config amcus; struct qr_config qr; - struct bpreader_config reader; struct usio_config usio; struct systype_config systype; struct sao_touch_config touch; + struct vfd_config vfd; }; void sao_dll_config_load( diff --git a/saohook/dllmain.c b/saohook/dllmain.c index e8dba61..904b69e 100644 --- a/saohook/dllmain.c +++ b/saohook/dllmain.c @@ -47,13 +47,13 @@ static DWORD CALLBACK sao_pre_startup(void) ExitProcess(EXIT_FAILURE); } - hr = sg_reader_hook_init(&sao_hook_cfg.aime, 1, sao_hook_mod); + hr = sg_reader_hook_init(&sao_hook_cfg.aime, 1, 3, sao_hook_mod); if (FAILED(hr)) { ExitProcess(EXIT_FAILURE); } - hr = vfd_hook_init(2); + hr = vfd_hook_init(&sao_hook_cfg.vfd, 2); if (FAILED(hr)) { ExitProcess(EXIT_FAILURE); @@ -89,6 +89,11 @@ static DWORD CALLBACK sao_pre_startup(void) ExitProcess(EXIT_FAILURE); } + /* Initialize Unity native plugin DLL hooks + + There seems to be an issue with other DLL hooks if `LoadLibraryW` is + hooked earlier in the `mu3hook` initialization. */ + unity_hook_init(); gfx_hook_init(&sao_hook_cfg.gfx); diff --git a/saohook/meson.build b/saohook/meson.build index 4445d54..5b16d4a 100644 --- a/saohook/meson.build +++ b/saohook/meson.build @@ -11,6 +11,7 @@ shared_library( xinput_lib, ], link_with : [ + aimeio_lib, saoio_lib, amcus_lib, platform_lib, diff --git a/saohook/sao-dll.c b/saohook/sao-dll.c index 0e0f787..1848e0c 100644 --- a/saohook/sao-dll.c +++ b/saohook/sao-dll.c @@ -103,4 +103,4 @@ end: } return hr; -} \ No newline at end of file +} diff --git a/saohook/saohook.def b/saohook/saohook.def index 6a0d4fe..7e6e862 100644 --- a/saohook/saohook.def +++ b/saohook/saohook.def @@ -12,4 +12,4 @@ EXPORTS sao_io_read_coin_counter sao_io_get_analog sao_io_get_gamebtns - sao_io_get_opbtns \ No newline at end of file + sao_io_get_opbtns diff --git a/saohook/systype.c b/saohook/systype.c index b57c72a..7828774 100644 --- a/saohook/systype.c +++ b/saohook/systype.c @@ -108,4 +108,4 @@ static int my_GetSerialNumber(ULONG usercode, intptr_t serialnumber) wcstombs((char *)serialnumber, dong_config.serial, 32); dprintf("Systype: my_GetSerialNumber %ls\n", dong_config.serial); return 0; -} \ No newline at end of file +} diff --git a/taikohook/config.c b/taikohook/config.c index 01bdb59..dd4c442 100644 --- a/taikohook/config.c +++ b/taikohook/config.c @@ -45,5 +45,5 @@ void taiko_hook_config_load( network_config_load(&cfg->network, filename); bpreader_config_load(&cfg->reader, filename); usio_config_load(&cfg->usio, filename); - + vfd_config_load(&cfg->vfd, filename); } diff --git a/taikohook/config.h b/taikohook/config.h index d0f94dd..173c74d 100644 --- a/taikohook/config.h +++ b/taikohook/config.h @@ -19,6 +19,7 @@ struct taiko_hook_config { struct taiko_network_config network; struct bpreader_config reader; struct usio_config usio; + struct vfd_config vfd; }; void taiko_dll_config_load( diff --git a/taikohook/dllmain.c b/taikohook/dllmain.c index ae5767d..b1a00b9 100644 --- a/taikohook/dllmain.c +++ b/taikohook/dllmain.c @@ -66,7 +66,7 @@ static DWORD CALLBACK taiko_pre_startup(void) ExitProcess(EXIT_FAILURE); } - hr = vfd_hook_init(2); + hr = vfd_hook_init(&taiko_hook_cfg.vfd, 2); if (FAILED(hr)) { ExitProcess(EXIT_FAILURE);