Files
TeamTofuShop_taitools/board/k92x0249.c
T
2026-03-14 01:12:10 -04:00

458 lines
12 KiB
C

#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include "board/k92x0249.h"
#include "board/config.h"
#include "jvs/jvs-bus.h"
#include "jvs/jvs-cmd.h"
#include "jvs/jvs-util.h"
#include "util/dprintf.h"
#include "util/dump.h"
// JVS card reader, A/B/C vairants
static const uint8_t k92x0249_ident[] = "TAITO CORP.;RFID CTRL P.C.B.;Ver1.11;";
static const uint8_t card_uid[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00 };
static const uint8_t card_id[] = {
0x01, 0x2E, 0x4C, 0xE4, 0x00, 0x01, 0x00, 0x01,
0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static struct k92x0249_config cfg;
static uint8_t k92x0249_features[] = {
// Misc. SW
0x07,
0x00,
0x08,
0x00,
// GPIO Out
0x12,
0x08,
0x00,
0x00,
// End
0x00,
};
static void k92x0249_transact(
struct jvs_node *node,
const void *bytes,
size_t nbytes,
struct iobuf *resp);
static bool k92x0249_sense(struct jvs_node *node);
static HRESULT k92x0249_cmd(
void *ctx,
struct const_iobuf *req,
struct iobuf *resp);
static HRESULT k92x0249_cmd_reset(struct k92x0249 *k92x0249, struct const_iobuf *req_buf);
static HRESULT k92x0249_cmd_assign_addr(struct k92x0249 *k92x0249, struct const_iobuf *req_buf, struct iobuf *resp_buf);
static HRESULT k92x0249_cmd_read_id(struct k92x0249 *k92x0249, struct const_iobuf *req_buf, struct iobuf *resp_buf);
static HRESULT k92x0249_cmd_get_cmd_version(struct k92x0249 *k92x0249, struct const_iobuf *req_buf, struct iobuf *resp_buf);
static HRESULT k92x0249_cmd_get_jvs_version(struct k92x0249 *k92x0249, struct const_iobuf *req_buf, struct iobuf *resp_buf);
static HRESULT k92x0249_cmd_get_comm_version(struct k92x0249 *k92x0249, struct const_iobuf *req_buf, struct iobuf *resp_buf);
static HRESULT k92x0249_cmd_get_features(struct k92x0249 *k92x0249, struct const_iobuf *req_buf, struct iobuf *resp_buf);
static HRESULT k92x0249_cmd_write_gpio1(struct k92x0249 *k92x0249, struct const_iobuf *req_buf, struct iobuf *resp_buf);
static HRESULT k92x0249_cmd_read_misc_switches(struct k92x0249 *k92x0249, struct const_iobuf *req_buf, struct iobuf *resp_buf);
static HRESULT k92x0249_cmd_taito_nesica_read(struct k92x0249 *k92x0249, struct const_iobuf *req_buf, struct iobuf *resp_buf);
static HRESULT k92x0249_cmd_taito_aic_read(struct k92x0249 *k92x0249, struct const_iobuf *req_buf, struct iobuf *resp_buf);
void k92x0249_init(
struct k92x0249 *k92x0249,
struct jvs_node *next,
void *ops_ctx)
{
assert(k92x0249 != NULL);
k92x0249_config_load(&cfg, L".\\taitools.ini");
k92x0249->jvs.next = next;
k92x0249->jvs.transact = k92x0249_transact;
k92x0249->jvs.sense = k92x0249_sense;
k92x0249->jvs.sense_out = true;
k92x0249->addr = 0xFF;
k92x0249->state = IDLE;
k92x0249->ops_ctx = ops_ctx;
}
struct jvs_node *k92x0249_to_jvs_node(struct k92x0249 *k92x0249)
{
assert(k92x0249 != NULL);
return &k92x0249->jvs;
}
static void k92x0249_transact(
struct jvs_node *node,
const void *bytes,
size_t nbytes,
struct iobuf *resp)
{
struct k92x0249 *k92x0249;
assert(node != NULL);
assert(bytes != NULL);
assert(resp != NULL);
k92x0249 = CONTAINING_RECORD(node, struct k92x0249, jvs);
jvs_crack_request(bytes, nbytes, resp, k92x0249->addr, k92x0249_cmd, k92x0249);
}
static bool k92x0249_sense(struct jvs_node *node)
{
struct k92x0249 *k92x0249;
assert(node != NULL);
k92x0249 = CONTAINING_RECORD(node, struct k92x0249, jvs);
return k92x0249->jvs.sense_out;
}
static HRESULT k92x0249_cmd(
void *ctx,
struct const_iobuf *req,
struct iobuf *resp)
{
struct k92x0249 *k92x0249;
k92x0249 = (struct k92x0249 *)ctx;
switch (req->bytes[req->pos]) {
case JVS_CMD_RESET:
return k92x0249_cmd_reset(k92x0249, req);
case JVS_CMD_ASSIGN_ADDR:
return k92x0249_cmd_assign_addr(k92x0249, req, resp);
case JVS_CMD_READ_ID:
return k92x0249_cmd_read_id(k92x0249, req, resp);
case JVS_CMD_GET_CMD_VERSION:
return k92x0249_cmd_get_cmd_version(k92x0249, req, resp);
case JVS_CMD_GET_JVS_VERSION:
return k92x0249_cmd_get_jvs_version(k92x0249, req, resp);
case JVS_CMD_GET_COMM_VERSION:
return k92x0249_cmd_get_comm_version(k92x0249, req, resp);
case JVS_CMD_GET_FEATURES:
return k92x0249_cmd_get_features(k92x0249, req, resp);
case JVS_CMD_WRITE_GPIO1: // Set reader state
return k92x0249_cmd_write_gpio1(k92x0249, req, resp);
case JVS_CMD_READ_MISC_SWITCHES: // Read for old (1.00/0.02) fw
return k92x0249_cmd_read_misc_switches(k92x0249, req, resp);
case JVS_CMD_TAITO_NESICA_READ: // Check reader state for new fw
return k92x0249_cmd_taito_nesica_read(k92x0249, req, resp);
case JVS_CMD_TAITO_AIC_READ: // Check reader state for new fw
return k92x0249_cmd_taito_aic_read(k92x0249, req, resp);
default:
dprintf("K92X0249: Node %02x: Unhandled command byte @ %02X %02x\n",
k92x0249->addr,
(uint8_t)req->pos,
req->bytes[req->pos]);
dump_const_iobuf(req);
return E_NOTIMPL;
}
return S_OK;
}
static HRESULT k92x0249_cmd_reset(struct k92x0249 *k92x0249, struct const_iobuf *req_buf)
{
struct jvs_req_reset req;
HRESULT hr;
hr = iobuf_read(req_buf, &req, sizeof(req));
if (FAILED(hr)) {
return hr;
}
dprintf("K92X0249: Reset (param %02x)\n", req.unknown);
k92x0249->addr = 0xFF;
k92x0249->jvs.sense_out = true;
/* No ack for this since it really is addressed to everybody */
return S_OK;
}
static HRESULT k92x0249_cmd_assign_addr(
struct k92x0249 *k92x0249,
struct const_iobuf *req_buf,
struct iobuf *resp_buf)
{
struct jvs_req_assign_addr req;
bool sense;
HRESULT hr;
hr = iobuf_read(req_buf, &req, sizeof(req));
if (FAILED(hr)) {
return hr;
}
sense = jvs_node_sense(k92x0249->jvs.next);
if (sense) {
/* That address is for somebody else */
return S_OK;
}
dprintf("K92X0249: Assign addr %02x sense %i\n", req.addr, sense);
k92x0249->addr = req.addr;
k92x0249->jvs.sense_out = false;
return iobuf_write_8(resp_buf, 0x01);
}
static HRESULT k92x0249_cmd_read_id(struct k92x0249 *k92x0249, struct const_iobuf *req_buf, struct iobuf *resp_buf)
{
uint8_t req;
HRESULT hr;
hr = iobuf_read_8(req_buf, &req);
if (FAILED(hr)) {
return hr;
}
dprintf("K92X0249: Read ID\n");
/* Write report byte */
hr = iobuf_write_8(resp_buf, 0x01);
if (FAILED(hr)) {
return hr;
}
/* Write the identification string. The NUL terminator at the end of this C
string is also sent, and it naturally terminates the response chunk. */
return iobuf_write(resp_buf, k92x0249_ident, sizeof(k92x0249_ident));
}
static HRESULT k92x0249_cmd_get_cmd_version(struct k92x0249 *k92x0249, struct const_iobuf *req_buf, struct iobuf *resp_buf)
{
uint8_t req;
uint8_t resp[2];
HRESULT hr;
hr = iobuf_read_8(req_buf, &req);
if (FAILED(hr)) {
return hr;
}
dprintf("K92X0249: Get command format version\n");
resp[0] = 0x01; /* Report byte */
resp[1] = 0x13; /* Command format version BCD */
return iobuf_write(resp_buf, resp, sizeof(resp));
}
static HRESULT k92x0249_cmd_get_jvs_version(struct k92x0249 *k92x0249, struct const_iobuf *req_buf, struct iobuf *resp_buf)
{
uint8_t req;
uint8_t resp[2];
HRESULT hr;
hr = iobuf_read_8(req_buf, &req);
if (FAILED(hr)) {
return hr;
}
dprintf("K92X0249: Get JVS format version\n");
resp[0] = 0x01; /* Report byte */
resp[1] = 0x30; /* JVS format version BCD */
return iobuf_write(resp_buf, resp, sizeof(resp));
}
static HRESULT k92x0249_cmd_get_comm_version(struct k92x0249 *k92x0249, struct const_iobuf *req_buf, struct iobuf *resp_buf)
{
uint8_t req;
uint8_t resp[2];
HRESULT hr;
hr = iobuf_read_8(req_buf, &req);
if (FAILED(hr)) {
return hr;
}
dprintf("K92X0249: Get COMM format version\n");
resp[0] = 0x01; /* Report byte */
resp[1] = 0x10; /* COMM format version BCD */
return iobuf_write(resp_buf, resp, sizeof(resp));
}
static HRESULT k92x0249_cmd_get_features(struct k92x0249 *k92x0249, struct const_iobuf *req_buf, struct iobuf *resp_buf)
{
uint8_t req;
uint8_t resp[2];
HRESULT hr;
hr = iobuf_read_8(req_buf, &req);
if (FAILED(hr)) {
return hr;
}
dprintf("K92X0249: Get reader features\n");
hr = iobuf_write_8(resp_buf, 0x01); /* Write report byte */
if (FAILED(hr)) {
return hr;
}
return iobuf_write(resp_buf, k92x0249_features, sizeof(k92x0249_features));
}
static HRESULT k92x0249_cmd_write_gpio1(struct k92x0249 *k92x0249, struct const_iobuf *req_buf, struct iobuf *resp_buf)
{
uint8_t unk;
uint8_t num_io;
uint8_t io_state[255];
HRESULT hr = iobuf_read_8(req_buf, &unk);
if (FAILED(hr)) {
return hr;
}
hr = iobuf_read_8(req_buf, &num_io);
if (FAILED(hr)) {
return hr;
}
hr = iobuf_read(req_buf, io_state, num_io);
if (FAILED(hr)) {
return hr;
}
if (k92x0249->state != io_state[0]) {
dprintf("K92X0249: Update state %02X\n", io_state[0]);
}
k92x0249->state = io_state[0];
return iobuf_write_8(resp_buf, 0x01); /* Write report byte */
}
static HRESULT k92x0249_cmd_read_misc_switches(struct k92x0249 *k92x0249, struct const_iobuf *req_buf, struct iobuf *resp_buf)
{
uint8_t cmd;
uint8_t arg;
HRESULT hr;
hr = iobuf_read_8(req_buf, &cmd);
if (FAILED(hr)) {
return hr;
}
hr = iobuf_read_8(req_buf, &arg);
if (FAILED(hr)) {
return hr;
}
hr = iobuf_write_8(resp_buf, 0x01); /* Write report byte */
if (FAILED(hr)) {
return hr;
}
if (k92x0249->state == POLL_AICC && (GetAsyncKeyState(cfg.read_button) & 0x8000)) {
dprintf("K92X0249: Detect Card\n");
return iobuf_write_8(resp_buf, CARD_READ_OK);
}
return iobuf_write_8(resp_buf, NO_CARD); /* Write status byte */
}
static HRESULT k92x0249_cmd_taito_nesica_read(struct k92x0249 *k92x0249, struct const_iobuf *req_buf, struct iobuf *resp_buf)
{
uint8_t cmd;
HRESULT hr = iobuf_read_8(req_buf, &cmd);
if (FAILED(hr)) {
return hr;
}
hr = iobuf_write_8(resp_buf, 0x01); /* Write report byte */
if (FAILED(hr)) {
return hr;
}
hr = iobuf_write(resp_buf, card_uid, 8); // AICC: Unused, should be IDm
if (FAILED(hr)) {
return hr;
}
return iobuf_write(resp_buf, cfg.serial, 16); // AICC: SPAD0
}
static HRESULT k92x0249_cmd_taito_aic_read(struct k92x0249 *k92x0249, struct const_iobuf *req_buf, struct iobuf *resp_buf)
{
uint8_t cmd;
HRESULT hr = iobuf_read_8(req_buf, &cmd);
if (FAILED(hr)) {
return hr;
}
hr = iobuf_write_8(resp_buf, 0x01); /* Write report byte */
if (FAILED(hr)) {
return hr;
}
hr = iobuf_write(resp_buf, card_id, 16); // ID
if (FAILED(hr)) {
return hr;
}
hr = iobuf_write(resp_buf, "\x00\x01", 2); // CKV
if (FAILED(hr)) {
return hr;
}
hr = iobuf_write(resp_buf, "\x02\x00\x00", 3); // WCNT
if (FAILED(hr)) {
return hr;
}
return iobuf_write(resp_buf, "12345678", 8); // MAC_A?
}