1
0
mirror of synced 2024-11-27 15:00:49 +01:00

aime, vfd: updated and improved

This commit is contained in:
Dniel97 2024-10-06 20:37:20 +02:00
parent fadbd0d2bf
commit bfa5d0dd6e
No known key found for this signature in database
GPG Key ID: 6180B3C768FB2E08
32 changed files with 808 additions and 54 deletions

View File

@ -17,6 +17,7 @@ struct aime_io_config {
wchar_t aime_path[MAX_PATH]; wchar_t aime_path[MAX_PATH];
wchar_t felica_path[MAX_PATH]; wchar_t felica_path[MAX_PATH];
bool felica_gen; bool felica_gen;
bool aime_gen;
uint8_t vk_scan; uint8_t vk_scan;
}; };
@ -40,6 +41,11 @@ static HRESULT aime_io_generate_felica(
uint8_t *bytes, uint8_t *bytes,
size_t nbytes); 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( static void aime_io_config_read(
struct aime_io_config *cfg, struct aime_io_config *cfg,
const wchar_t *filename) const wchar_t *filename)
@ -62,11 +68,16 @@ static void aime_io_config_read(
cfg->felica_path, cfg->felica_path,
_countof(cfg->felica_path), _countof(cfg->felica_path),
filename); filename);
dprintf("NFC: felicaPath GetLastError %lx\n", GetLastError());
cfg->felica_gen = GetPrivateProfileIntW( cfg->felica_gen = GetPrivateProfileIntW(
L"aime", L"aime",
L"felicaGen", L"felicaGen",
0,
filename);
cfg->aime_gen = GetPrivateProfileIntW(
L"aime",
L"aimeGen",
1, 1,
filename); filename);
@ -136,7 +147,7 @@ static HRESULT aime_io_generate_felica(
srand(time(NULL)); srand(time(NULL));
for (i = 0 ; i < nbytes ; i++) { for (i = 0; i < nbytes; i++) {
bytes[i] = rand(); bytes[i] = rand();
} }
@ -151,7 +162,7 @@ static HRESULT aime_io_generate_felica(
return E_FAIL; return E_FAIL;
} }
for (i = 0 ; i < nbytes ; i++) { for (i = 0; i < nbytes; i++) {
fprintf(f, "%02X", bytes[i]); fprintf(f, "%02X", bytes[i]);
} }
@ -163,6 +174,47 @@ static HRESULT aime_io_generate_felica(
return S_OK; 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) uint16_t aime_io_get_api_version(void)
{ {
return 0x0100; return 0x0100;
@ -210,6 +262,22 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no)
return S_OK; 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 */ /* Try FeliCa IC */
hr = aime_io_read_id_file( hr = aime_io_read_id_file(

View File

@ -71,3 +71,13 @@ void aime_config_load(struct aime_config *cfg, const wchar_t *filename)
aime_dll_config_load(&cfg->dll, filename); aime_dll_config_load(&cfg->dll, filename);
cfg->enable = GetPrivateProfileIntW(L"aime", L"enable", 1, 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);
}

View File

@ -7,8 +7,10 @@
#include "board/bpreader.h" #include "board/bpreader.h"
#include "board/qr.h" #include "board/qr.h"
#include "board/sg-reader.h" #include "board/sg-reader.h"
#include "board/vfd.h"
void bpreader_config_load(struct bpreader_config *cfg, const wchar_t *filename); 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 usio_config_load(struct usio_config *cfg, const wchar_t *filename);
void qr_config_load(struct qr_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 aime_config_load(struct aime_config *cfg, const wchar_t *filename);
void vfd_config_load(struct vfd_config *cfg, const wchar_t *filename);

View File

@ -39,6 +39,9 @@ board_lib = static_library(
'sg-nfc-cmd.h', 'sg-nfc-cmd.h',
'sg-reader.c', 'sg-reader.c',
'sg-reader.h', 'sg-reader.h',
'vfd-cmd.h',
'vfd-frame.c',
'vfd-frame.h',
'vfd.c', 'vfd.c',
'vfd.h', 'vfd.h',
], ],

View File

@ -25,6 +25,13 @@ struct sg_res_header {
uint8_t payload_len; 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)( typedef HRESULT (*sg_dispatch_fn_t)(
void *ctx, void *ctx,
const void *req, const void *req,

View File

@ -27,14 +27,18 @@ static HRESULT sg_led_cmd_set_color(
const struct sg_led *led, const struct sg_led *led,
const struct sg_led_req_set_color *req); const struct sg_led_req_set_color *req);
static const uint8_t sg_led_info[] = { static const struct version_info led_version[] = {
'1', '5', '0', '8', '4', 0xFF, 0x10, 0x00, 0x12, {"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( void sg_led_init(
struct sg_led *led, struct sg_led *led,
uint8_t addr, uint8_t addr,
const struct sg_led_ops *ops, const struct sg_led_ops *ops,
unsigned int gen,
void *ctx) void *ctx)
{ {
assert(led != NULL); assert(led != NULL);
@ -43,6 +47,7 @@ void sg_led_init(
led->ops = ops; led->ops = ops;
led->ops_ctx = ctx; led->ops_ctx = ctx;
led->addr = addr; led->addr = addr;
led->gen = gen;
} }
void sg_led_transact( void sg_led_transact(
@ -150,8 +155,11 @@ static HRESULT sg_led_cmd_get_info(
struct sg_led_res_get_info *res) struct sg_led_res_get_info *res)
{ {
sg_led_dprintf(led, "Get info\n"); 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; return S_OK;
} }

View File

@ -15,12 +15,14 @@ struct sg_led {
const struct sg_led_ops *ops; const struct sg_led_ops *ops;
void *ops_ctx; void *ops_ctx;
uint8_t addr; uint8_t addr;
unsigned int gen;
}; };
void sg_led_init( void sg_led_init(
struct sg_led *led, struct sg_led *led,
uint8_t addr, uint8_t addr,
const struct sg_led_ops *ops, const struct sg_led_ops *ops,
unsigned int gen,
void *ctx); void *ctx);
void sg_led_transact( void sg_led_transact(

View File

@ -5,18 +5,21 @@
#pragma pack(push, 1) #pragma pack(push, 1)
enum { enum {
SG_NFC_CMD_GET_FW_VERSION = 0x30, SG_NFC_CMD_GET_FW_VERSION = 0x30,
SG_NFC_CMD_GET_HW_VERSION = 0x32, SG_NFC_CMD_GET_HW_VERSION = 0x32,
SG_NFC_CMD_RADIO_ON = 0x40, SG_NFC_CMD_RADIO_ON = 0x40,
SG_NFC_CMD_RADIO_OFF = 0x41, SG_NFC_CMD_RADIO_OFF = 0x41,
SG_NFC_CMD_POLL = 0x42, SG_NFC_CMD_POLL = 0x42,
SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43, SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43,
SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x50, SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x50,
SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52, SG_NFC_CMD_MIFARE_AUTHENTICATE_A = 0x51,
SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x54, SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52,
SG_NFC_CMD_MIFARE_AUTHENTICATE = 0x55, /* guess based on time sent */ SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x54,
SG_NFC_CMD_RESET = 0x62, SG_NFC_CMD_MIFARE_AUTHENTICATE_B = 0x55,
SG_NFC_CMD_FELICA_ENCAP = 0x71, 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 { 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_nfc_req_mifare_set_key {
struct sg_req_header req; struct sg_req_header req;
uint8_t key_a[6]; uint8_t key[6];
}; };
struct sg_nfc_req_mifare_50 { struct sg_nfc_req_mifare_50 {

View File

@ -60,15 +60,33 @@ static HRESULT sg_nfc_cmd_felica_encap(
const struct sg_nfc_req_felica_encap *req, const struct sg_nfc_req_felica_encap *req,
struct sg_nfc_res_felica_encap *res); 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( static HRESULT sg_nfc_cmd_dummy(
struct sg_nfc *nfc, struct sg_nfc *nfc,
const struct sg_req_header *req, const struct sg_req_header *req,
struct sg_res_header *res); 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( void sg_nfc_init(
struct sg_nfc *nfc, struct sg_nfc *nfc,
uint8_t addr, uint8_t addr,
const struct sg_nfc_ops *ops, const struct sg_nfc_ops *ops,
unsigned int gen,
void *ops_ctx) void *ops_ctx)
{ {
assert(nfc != NULL); assert(nfc != NULL);
@ -77,6 +95,7 @@ void sg_nfc_init(
nfc->ops = ops; nfc->ops = ops;
nfc->ops_ctx = ops_ctx; nfc->ops_ctx = ops_ctx;
nfc->addr = addr; nfc->addr = addr;
nfc->gen = gen;
} }
#ifdef NDEBUG #ifdef NDEBUG
@ -170,12 +189,17 @@ static HRESULT sg_nfc_dispatch(
&req->felica_encap, &req->felica_encap,
&res->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_SELECT_TAG:
case SG_NFC_CMD_MIFARE_SET_KEY_AIME: case SG_NFC_CMD_MIFARE_SET_KEY_AIME:
case SG_NFC_CMD_MIFARE_SET_KEY_BANA: case SG_NFC_CMD_MIFARE_SET_KEY_BANA:
case SG_NFC_CMD_RADIO_ON: case SG_NFC_CMD_RADIO_ON:
case SG_NFC_CMD_RADIO_OFF: case SG_NFC_CMD_RADIO_OFF:
case SG_NFC_CMD_TO_UPDATE_MODE:
return sg_nfc_cmd_dummy(nfc, &req->simple, &res->simple); return sg_nfc_cmd_dummy(nfc, &req->simple, &res->simple);
default: default:
@ -202,9 +226,11 @@ static HRESULT sg_nfc_cmd_get_fw_version(
const struct sg_req_header *req, const struct sg_req_header *req,
struct sg_nfc_res_get_fw_version *res) 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 */ /* Dest version is not NUL terminated, this is intentional */
sg_res_init(&res->res, req, sizeof(res->version)); sg_res_init(&res->res, req, fw->length);
memcpy(res->version, "\x94", sizeof(res->version)); memcpy(res->version, fw->version, fw->length);
return S_OK; return S_OK;
} }
@ -214,9 +240,11 @@ static HRESULT sg_nfc_cmd_get_hw_version(
const struct sg_req_header *req, const struct sg_req_header *req,
struct sg_nfc_res_get_hw_version *res) 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 */ /* Dest version is not NUL terminated, this is intentional */
sg_res_init(&res->res, req, sizeof(res->version)); sg_res_init(&res->res, req, hw->length);
memcpy(res->version, "837-15396-6728", sizeof(res->version)); memcpy(res->version, hw->version, hw->length);
return S_OK; return S_OK;
} }
@ -423,6 +451,22 @@ static HRESULT sg_nfc_cmd_felica_encap(
return S_OK; 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( static HRESULT sg_nfc_cmd_dummy(
struct sg_nfc *nfc, struct sg_nfc *nfc,
const struct sg_req_header *req, const struct sg_req_header *req,

View File

@ -22,6 +22,7 @@ struct sg_nfc {
const struct sg_nfc_ops *ops; const struct sg_nfc_ops *ops;
void *ops_ctx; void *ops_ctx;
uint8_t addr; uint8_t addr;
unsigned int gen;
struct felica felica; struct felica felica;
struct mifare mifare; struct mifare mifare;
}; };
@ -30,6 +31,7 @@ void sg_nfc_init(
struct sg_nfc *nfc, struct sg_nfc *nfc,
uint8_t addr, uint8_t addr,
const struct sg_nfc_ops *ops, const struct sg_nfc_ops *ops,
unsigned int gen,
void *ops_ctx); void *ops_ctx);
void sg_nfc_transact( void sg_nfc_transact(

View File

@ -48,6 +48,7 @@ static struct sg_led sg_reader_led;
HRESULT sg_reader_hook_init( HRESULT sg_reader_hook_init(
const struct aime_config *cfg, const struct aime_config *cfg,
unsigned int port_no, unsigned int port_no,
unsigned int gen,
HINSTANCE self) HINSTANCE self)
{ {
HRESULT hr; HRESULT hr;
@ -65,11 +66,25 @@ HRESULT sg_reader_hook_init(
return hr; return hr;
} }
sg_nfc_init(&sg_reader_nfc, 0x00, &sg_reader_nfc_ops, NULL); if (cfg->gen != 0) {
sg_led_init(&sg_reader_led, 0x08, &sg_reader_led_ops, NULL); 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); InitializeCriticalSection(&sg_reader_lock);
if (!cfg->high_baudrate) {
sg_reader_uart.baud.BaudRate = 38400;
}
uart_init(&sg_reader_uart, port_no); uart_init(&sg_reader_uart, port_no);
sg_reader_uart.written.bytes = sg_reader_written_bytes; sg_reader_uart.written.bytes = sg_reader_written_bytes;
sg_reader_uart.written.nbytes = sizeof(sg_reader_written_bytes); sg_reader_uart.written.nbytes = sizeof(sg_reader_written_bytes);

View File

@ -9,9 +9,12 @@
struct aime_config { struct aime_config {
struct aime_dll_config dll; struct aime_dll_config dll;
bool enable; bool enable;
bool high_baudrate;
unsigned int gen;
}; };
HRESULT sg_reader_hook_init( HRESULT sg_reader_hook_init(
const struct aime_config *cfg, const struct aime_config *cfg,
unsigned int port_no, unsigned int port_no,
unsigned int gen,
HINSTANCE self); HINSTANCE self);

View File

@ -307,7 +307,7 @@ static int my_bnusio_SetCoinLock(uint8_t id, char value)
static int my_bnusio_GetCoin(uint8_t id) 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); usio_ops->poll(usio_ops_ctx, &state);
if (id < 2) { if (id < 2) {
return state.coins[id].current_coin_count; 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) 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)) { if (id >= _countof(state.coins)) {
return 0; return 0;
} }

123
board/vfd-cmd.h Normal file
View File

@ -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];
};

88
board/vfd-frame.c Normal file
View File

@ -0,0 +1,88 @@
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#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;
}

20
board/vfd-frame.h Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
#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);

View File

@ -4,15 +4,19 @@
Part number in schematics is "VFD GP1232A02A FUTABA". Part number in schematics is "VFD GP1232A02A FUTABA".
Little else about this board is known. Black-holing the RS232 comms that it Credits:
receives seems to be sufficient for the time being. */
Haruka
*/
#include <windows.h> #include <windows.h>
#include <assert.h> #include <assert.h>
#include <stdint.h> #include <stdint.h>
#include "board/config.h"
#include "board/vfd.h" #include "board/vfd.h"
#include "board/vfd-cmd.h"
#include "hook/iohook.h" #include "hook/iohook.h"
@ -21,15 +25,51 @@
#include "util/dprintf.h" #include "util/dprintf.h"
#include "util/dump.h" #include "util/dump.h"
#define SUPER_VERBOSE 0
static HRESULT vfd_handle_irp(struct irp *irp); static HRESULT vfd_handle_irp(struct irp *irp);
static struct uart vfd_uart; static struct uart vfd_uart;
static uint8_t vfd_written[512]; static uint8_t vfd_written[4096];
static uint8_t vfd_readable[512]; 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.bytes = vfd_written;
vfd_uart.written.nbytes = sizeof(vfd_written); vfd_uart.written.nbytes = sizeof(vfd_written);
vfd_uart.readable.bytes = vfd_readable; 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); 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) static HRESULT vfd_handle_irp(struct irp *irp)
{ {
HRESULT hr; HRESULT hr;
@ -48,15 +130,274 @@ static HRESULT vfd_handle_irp(struct irp *irp)
return iohook_invoke_next(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); hr = uart_handle_irp(&vfd_uart, irp);
if (FAILED(hr) || irp->op != IRP_OP_WRITE) { if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
return hr; return hr;
} }
#if SUPER_VERBOSE
dprintf("VFD TX:\n"); dprintf("VFD TX:\n");
dump_iobuf(&vfd_uart.written); 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; vfd_uart.written.pos = 0;
return hr; 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;
}

View File

@ -2,4 +2,12 @@
#include <windows.h> #include <windows.h>
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);

View File

@ -30,10 +30,10 @@ windowed=1
framed=0 framed=0
monitor=0 monitor=0
; Banapass reader ; Aime reader
[reader] [aime]
enable=1 enable=1
access_code=00000000000000000000 aimePath=DEVICE\\aime.txt
; Control the AMCUS replacement class ; Control the AMCUS replacement class
[amcus] [amcus]

View File

@ -32,6 +32,6 @@ void kizuna_hook_config_load(
platform_config_load(&cfg->platform, filename); platform_config_load(&cfg->platform, filename);
kizuna_dll_config_load(&cfg->dll, filename); kizuna_dll_config_load(&cfg->dll, filename);
gfx_config_load(&cfg->gfx, filename); gfx_config_load(&cfg->gfx, filename);
bpreader_config_load(&cfg->reader, filename);
usio_config_load(&cfg->usio, filename); usio_config_load(&cfg->usio, filename);
vfd_config_load(&cfg->vfd, filename);
} }

View File

@ -15,8 +15,8 @@ struct kizuna_hook_config {
struct kizuna_dll_config dll; struct kizuna_dll_config dll;
struct gfx_config gfx; struct gfx_config gfx;
struct amcus_config amcus; struct amcus_config amcus;
struct bpreader_config reader;
struct usio_config usio; struct usio_config usio;
struct vfd_config vfd;
}; };
void kizuna_dll_config_load( void kizuna_dll_config_load(

View File

@ -44,13 +44,13 @@ static DWORD CALLBACK kizuna_pre_startup(void)
ExitProcess(EXIT_FAILURE); 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)) { if (FAILED(hr)) {
ExitProcess(EXIT_FAILURE); ExitProcess(EXIT_FAILURE);
} }
hr = vfd_hook_init(2); hr = vfd_hook_init(&kizuna_hook_cfg.vfd, 2);
if (FAILED(hr)) { if (FAILED(hr)) {
ExitProcess(EXIT_FAILURE); ExitProcess(EXIT_FAILURE);

View File

@ -64,8 +64,8 @@ void sao_hook_config_load(
sao_dll_config_load(&cfg->dll, filename); sao_dll_config_load(&cfg->dll, filename);
gfx_config_load(&cfg->gfx, filename); gfx_config_load(&cfg->gfx, filename);
qr_config_load(&cfg->qr, filename); qr_config_load(&cfg->qr, filename);
bpreader_config_load(&cfg->reader, filename);
usio_config_load(&cfg->usio, filename); usio_config_load(&cfg->usio, filename);
systype_config_load(&cfg->systype, filename); systype_config_load(&cfg->systype, filename);
sao_touch_config_load(&cfg->touch, filename); sao_touch_config_load(&cfg->touch, filename);
vfd_config_load(&cfg->vfd, filename);
} }

View File

@ -18,10 +18,10 @@ struct sao_hook_config {
struct gfx_config gfx; struct gfx_config gfx;
struct amcus_config amcus; struct amcus_config amcus;
struct qr_config qr; struct qr_config qr;
struct bpreader_config reader;
struct usio_config usio; struct usio_config usio;
struct systype_config systype; struct systype_config systype;
struct sao_touch_config touch; struct sao_touch_config touch;
struct vfd_config vfd;
}; };
void sao_dll_config_load( void sao_dll_config_load(

View File

@ -47,13 +47,13 @@ static DWORD CALLBACK sao_pre_startup(void)
ExitProcess(EXIT_FAILURE); 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)) { if (FAILED(hr)) {
ExitProcess(EXIT_FAILURE); ExitProcess(EXIT_FAILURE);
} }
hr = vfd_hook_init(2); hr = vfd_hook_init(&sao_hook_cfg.vfd, 2);
if (FAILED(hr)) { if (FAILED(hr)) {
ExitProcess(EXIT_FAILURE); ExitProcess(EXIT_FAILURE);
@ -89,6 +89,11 @@ static DWORD CALLBACK sao_pre_startup(void)
ExitProcess(EXIT_FAILURE); 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(); unity_hook_init();
gfx_hook_init(&sao_hook_cfg.gfx); gfx_hook_init(&sao_hook_cfg.gfx);

View File

@ -11,6 +11,7 @@ shared_library(
xinput_lib, xinput_lib,
], ],
link_with : [ link_with : [
aimeio_lib,
saoio_lib, saoio_lib,
amcus_lib, amcus_lib,
platform_lib, platform_lib,

View File

@ -45,5 +45,5 @@ void taiko_hook_config_load(
network_config_load(&cfg->network, filename); network_config_load(&cfg->network, filename);
bpreader_config_load(&cfg->reader, filename); bpreader_config_load(&cfg->reader, filename);
usio_config_load(&cfg->usio, filename); usio_config_load(&cfg->usio, filename);
vfd_config_load(&cfg->vfd, filename);
} }

View File

@ -19,6 +19,7 @@ struct taiko_hook_config {
struct taiko_network_config network; struct taiko_network_config network;
struct bpreader_config reader; struct bpreader_config reader;
struct usio_config usio; struct usio_config usio;
struct vfd_config vfd;
}; };
void taiko_dll_config_load( void taiko_dll_config_load(

View File

@ -66,7 +66,7 @@ static DWORD CALLBACK taiko_pre_startup(void)
ExitProcess(EXIT_FAILURE); ExitProcess(EXIT_FAILURE);
} }
hr = vfd_hook_init(2); hr = vfd_hook_init(&taiko_hook_cfg.vfd, 2);
if (FAILED(hr)) { if (FAILED(hr)) {
ExitProcess(EXIT_FAILURE); ExitProcess(EXIT_FAILURE);