Add support for scanning Aime and FeliCa card

Refactor packet parsing.
Update to latest segatools.
Clean up codes.
This commit is contained in:
Tindy X 2021-07-20 15:15:53 +08:00
parent 1d7fc82e7c
commit f01e7d3320
No known key found for this signature in database
GPG Key ID: C6AD413169968D58
5 changed files with 299 additions and 97 deletions

View File

@ -26,7 +26,7 @@ static uint8_t aime_io_felica_id[8];
static bool aime_io_aime_id_present;
static bool aime_io_felica_id_present;
struct IPCMemoryInfo
struct aime_io_ipc_memory_info
{
uint8_t airIoStatus[6];
uint8_t sliderIoStatus[32];
@ -35,28 +35,31 @@ struct IPCMemoryInfo
uint8_t serviceBtn;
uint8_t coinInsertion;
uint8_t cardRead;
uint8_t remoteCardRead;
uint8_t remoteCardType;
uint8_t remoteCardId[10];
};
typedef struct IPCMemoryInfo IPCMemoryInfo;
static HANDLE FileMappingHandle;
IPCMemoryInfo* FileMapping;
typedef struct aime_io_ipc_memory_info aime_io_ipc_memory_info;
static HANDLE aime_io_file_mapping_handle;
aime_io_ipc_memory_info* aime_io_file_mapping;
void initSharedMemory()
void aime_io_init_shared_memory()
{
if (FileMapping)
if (aime_io_file_mapping)
{
return;
}
if ((FileMappingHandle = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, sizeof(IPCMemoryInfo), "Local\\BROKENITHM_SHARED_BUFFER")) == 0)
if ((aime_io_file_mapping_handle = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, sizeof(aime_io_ipc_memory_info), "Local\\BROKENITHM_SHARED_BUFFER")) == 0)
{
return;
}
if ((FileMapping = (IPCMemoryInfo*)MapViewOfFile(FileMappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(IPCMemoryInfo))) == 0)
if ((aime_io_file_mapping = (aime_io_ipc_memory_info*)MapViewOfFile(aime_io_file_mapping_handle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(aime_io_ipc_memory_info))) == 0)
{
return;
}
memset(FileMapping, 0, sizeof(IPCMemoryInfo));
memset(aime_io_file_mapping, 0, sizeof(aime_io_ipc_memory_info));
SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_CONTINUOUS);
}
@ -196,19 +199,20 @@ static HRESULT aime_io_generate_felica(
return S_OK;
}
uint16_t aime_io_get_api_version(void)
{
return 0x0100;
}
HRESULT aime_io_init(void)
{
aime_io_config_read(&aime_io_cfg, L".\\segatools.ini");
initSharedMemory();
aime_io_init_shared_memory();
return S_OK;
}
void aime_io_fini(void)
{
}
HRESULT aime_io_nfc_poll(uint8_t unit_no)
{
bool sense;
@ -223,11 +227,27 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no)
aime_io_aime_id_present = false;
aime_io_felica_id_present = false;
/* First check remote card status, if there is one report it */
if (aime_io_file_mapping && aime_io_file_mapping->remoteCardRead) {
switch (aime_io_file_mapping->remoteCardType) {
case 0: // Aime
memcpy(aime_io_aime_id, aime_io_file_mapping->remoteCardId, 10);
aime_io_aime_id_present = true;
break;
case 1: // FeliCa
memcpy(aime_io_felica_id, aime_io_file_mapping->remoteCardId, 8);
aime_io_felica_id_present = true;
break;
}
return S_OK;
}
/* Don't do anything more if the scan key is not held */
if (FileMapping && FileMapping->cardRead) {
if (aime_io_file_mapping && aime_io_file_mapping->cardRead) {
sense = true;
FileMapping->cardRead = 0;
aime_io_file_mapping->cardRead = 0;
} else {
sense = GetAsyncKeyState(aime_io_cfg.vk_scan) & 0x8000;
}

View File

@ -11,11 +11,12 @@ static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx);
static bool chuni_io_coin;
static uint16_t chuni_io_coins;
static uint8_t chuni_io_hand_pos;
static HANDLE chuni_io_slider_thread;
static bool chuni_io_slider_stop_flag;
static struct chuni_io_config chuni_io_cfg;
struct IPCMemoryInfo
struct chuni_io_ipc_memory_info
{
uint8_t airIoStatus[6];
uint8_t sliderIoStatus[32];
@ -24,36 +25,44 @@ struct IPCMemoryInfo
uint8_t serviceBtn;
uint8_t coinInsertion;
uint8_t cardRead;
uint8_t remoteCardRead;
uint8_t remoteCardType;
uint8_t remoteCardId[10];
};
typedef struct IPCMemoryInfo IPCMemoryInfo;
static HANDLE FileMappingHandle;
IPCMemoryInfo* FileMapping;
typedef struct chuni_io_ipc_memory_info chuni_io_ipc_memory_info;
static HANDLE chuni_io_file_mapping_handle;
chuni_io_ipc_memory_info* chuni_io_file_mapping;
void initSharedMemory()
void chuni_io_init_shared_memory()
{
if (FileMapping)
if (chuni_io_file_mapping)
{
return;
}
if ((FileMappingHandle = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, sizeof(IPCMemoryInfo), "Local\\BROKENITHM_SHARED_BUFFER")) == 0)
if ((chuni_io_file_mapping_handle = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, sizeof(chuni_io_ipc_memory_info), "Local\\BROKENITHM_SHARED_BUFFER")) == 0)
{
return;
}
if ((FileMapping = (IPCMemoryInfo*)MapViewOfFile(FileMappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(IPCMemoryInfo))) == 0)
if ((chuni_io_file_mapping = (chuni_io_ipc_memory_info*)MapViewOfFile(chuni_io_file_mapping_handle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(chuni_io_ipc_memory_info))) == 0)
{
return;
}
memset(FileMapping, 0, sizeof(IPCMemoryInfo));
memset(chuni_io_file_mapping, 0, sizeof(chuni_io_ipc_memory_info));
SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_CONTINUOUS);
}
uint16_t chuni_io_get_api_version(void)
{
return 0x0101;
}
HRESULT chuni_io_jvs_init(void)
{
chuni_io_config_load(&chuni_io_cfg, L".\\segatools.ini");
initSharedMemory();
chuni_io_init_shared_memory();
return S_OK;
}
@ -64,9 +73,9 @@ void chuni_io_jvs_read_coin_counter(uint16_t *out)
return;
}
if (FileMapping && FileMapping->coinInsertion) {
if (chuni_io_file_mapping && chuni_io_file_mapping->coinInsertion) {
chuni_io_coins++;
FileMapping->coinInsertion = 0;
chuni_io_file_mapping->coinInsertion = 0;
} else {
if (GetAsyncKeyState(chuni_io_cfg.vk_coin)) {
if (!chuni_io_coin) {
@ -85,24 +94,31 @@ void chuni_io_jvs_poll(uint8_t *opbtn, uint8_t *beams)
{
size_t i;
if ((FileMapping && FileMapping->testBtn) || GetAsyncKeyState(chuni_io_cfg.vk_test)) {
if ((chuni_io_file_mapping && chuni_io_file_mapping->testBtn) || GetAsyncKeyState(chuni_io_cfg.vk_test)) {
*opbtn |= 0x01; /* Test */
}
if ((FileMapping && FileMapping->serviceBtn) || GetAsyncKeyState(chuni_io_cfg.vk_service)) {
if ((chuni_io_file_mapping && chuni_io_file_mapping->serviceBtn) || GetAsyncKeyState(chuni_io_cfg.vk_service)) {
*opbtn |= 0x02; /* Service */
}
if (GetAsyncKeyState(chuni_io_cfg.vk_ir)) {
if (chuni_io_hand_pos < 6) {
chuni_io_hand_pos++;
}
} else {
if (chuni_io_hand_pos > 0) {
chuni_io_hand_pos--;
}
}
for (i = 0 ; i < 6 ; i++) {
if (FileMapping && FileMapping->airIoStatus[i]) {
if ((chuni_io_file_mapping && chuni_io_file_mapping->airIoStatus[i]) || chuni_io_hand_pos > i) {
*beams |= (1 << i);
}
}
}
void chuni_io_jvs_set_coin_blocker(bool open)
{}
HRESULT chuni_io_slider_init(void)
{
return S_OK;
@ -139,22 +155,21 @@ void chuni_io_slider_stop(void)
void chuni_io_slider_set_leds(const uint8_t *rgb)
{
if (FileMapping)
{
memcpy(FileMapping->ledRgbData, rgb, 32 * 3);
if (chuni_io_file_mapping) {
memcpy(chuni_io_file_mapping->ledRgbData, rgb, 32 * 3);
}
}
static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx)
{
chuni_io_slider_callback_t callback;
uint8_t pressure[32] = { 0 };
uint8_t pressure[32];
callback = ctx;
while (!chuni_io_slider_stop_flag) {
if (FileMapping) {
memcpy(pressure, FileMapping->sliderIoStatus, 32);
if (chuni_io_file_mapping) {
memcpy(pressure, chuni_io_file_mapping->sliderIoStatus, 32);
}
callback(pressure);

View File

@ -8,6 +8,7 @@
#include "socket.h"
#include "defer.h"
#include "version.h"
#include "struct.h"
#include <windows.h>
std::string remote_address;
@ -96,7 +97,7 @@ void printErr(const char* format, Args... args)
fprintf(stderr, format, args...);
}
void UDPLEDBroadcast(SOCKET sHost, const char* memory)
void UDPLEDBroadcast(SOCKET sHost, const IPCMemoryInfo* memory)
{
static std::string previous_status;
static int skip_count = 0;
@ -108,7 +109,7 @@ void UDPLEDBroadcast(SOCKET sHost, const char* memory)
continue;
}
std::string current_status;
current_status.assign(reinterpret_cast<const char*>(memory + 6 + 32), 32 * 3);
current_status.assign(reinterpret_cast<const char*>(memory->ledRgbData), sizeof(memory->ledRgbData));
bool same = true;
if(!previous_status.empty())
{
@ -153,7 +154,7 @@ void UDPLEDBroadcast(SOCKET sHost, const char* memory)
}
}
void TCPLEDBroadcast(SOCKET sHost, const char* memory)
void TCPLEDBroadcast(SOCKET sHost, const IPCMemoryInfo* memory)
{
static std::string previous_status;
static int skip_count = 0;
@ -165,7 +166,7 @@ void TCPLEDBroadcast(SOCKET sHost, const char* memory)
continue;
}
std::string current_status;
current_status.assign(reinterpret_cast<const char*>(memory + 6 + 32), 32 * 3);
current_status.assign(reinterpret_cast<const char*>(memory->ledRgbData), sizeof(memory->ledRgbData));
bool same = true;
if(!previous_status.empty())
{
@ -234,23 +235,22 @@ enum
FUNCTION_CARD
};
std::tuple<std::string, uint16_t> getSocksAddress(const std::string &data)
void getSocksAddress(const PacketConnect* pkt, std::string &address, uint16_t &port)
{
char cAddr[128] = {};
std::string retAddr, port_str = data.substr(1, 2);
int family = data[0];
uint16_t port = ntohs(*(short*)port_str.data());
std::string retAddr;
int family = pkt->addrType;
port = ntohs(pkt->port);
switch(family)
{
case 1: //IPv4
inet_ntop(AF_INET, data.data() + 3, cAddr, 127);
inet_ntop(AF_INET, pkt->addr.addr4.addr, cAddr, 127);
break;
case 2: //IPv6
inet_ntop(AF_INET6, data.data() + 3, cAddr, 127);
inet_ntop(AF_INET6, pkt->addr.addr6, cAddr, 127);
break;
}
retAddr.assign(cAddr);
return std::make_tuple(retAddr, port);
address.assign(cAddr);
}
uint32_t last_input_packet_id = 0;
@ -272,7 +272,85 @@ void updatePacketId(uint32_t newPacketId)
last_input_packet_id = newPacketId;
}
void InputReceive(SOCKET sHost, char *memory)
template <typename... Args>
void dprintf(const char* format, Args... args)
{
fprintf(stderr, format, args...);
}
void dump(const void *ptr, size_t nbytes, bool hex_string = false)
{
const uint8_t *bytes;
uint8_t c;
size_t i;
size_t j;
if (nbytes == 0) {
dprintf("\t--- Empty ---\n");
}
bytes = (const unsigned char*)ptr;
if (hex_string) {
for (i = 0 ; i < nbytes ; i++) {
dprintf("%02x", bytes[i]);
}
dprintf("\n");
return;
}
for (i = 0 ; i < nbytes ; i += 16) {
dprintf(" %08x:", (int) i);
for (j = 0 ; i + j < nbytes && j < 16 ; j++) {
dprintf(" %02x", bytes[i + j]);
}
while (j < 16) {
dprintf(" ");
j++;
}
dprintf(" ");
for (j = 0 ; i + j < nbytes && j < 16 ; j++) {
c = bytes[i + j];
if (c < 0x20 || c >= 0x7F) {
c = '.';
}
dprintf("%c", c);
}
dprintf("\n");
}
dprintf("\n");
}
enum
{
CARD_AIME,
CARD_FELICA
};
void printCardInfo(uint8_t cardType, uint8_t *cardId)
{
switch(cardType)
{
case CARD_AIME:
printErr("[INFO] Card Type: Aime\t\tID: ");
dump(cardId, 10, true);
break;
case CARD_FELICA:
printErr("[INFO] Card Type: FeliCa\tIDm: ");
dump(cardId, 8, true);
break;
}
}
void InputReceive(SOCKET sHost, IPCMemoryInfo *memory)
{
char recv_buffer[tcp_buffer_size];
char buffer[BUFSIZ];
@ -280,6 +358,7 @@ void InputReceive(SOCKET sHost, char *memory)
while(!EXIT_FLAG)
{
int recv_len, real_len;
size_t packet_len;
uint32_t current_packet_id;
if(!tcp_mode)
{
@ -293,6 +372,7 @@ void InputReceive(SOCKET sHost, char *memory)
real_len = buffer[0];
if(real_len > recv_len)
continue;
packet_len = real_len + 1;
}
else
{
@ -311,54 +391,52 @@ void InputReceive(SOCKET sHost, char *memory)
real_len = remains[0];
if(real_len > data_left)
continue;
size_t data_copied = real_len + 1;
memcpy(buffer, remains.data(), data_copied);
remains.erase(0, data_copied);
packet_len = real_len + 1;
memcpy(buffer, remains.data(), packet_len);
remains.erase(0, packet_len);
}
if(real_len >= 3 + 4 + 6 + 32 && buffer[1] == 'I' && buffer[2] == 'N' && buffer[3] == 'P')
if(packet_len >= sizeof(PacketInput) && buffer[1] == 'I' && buffer[2] == 'N' && buffer[3] == 'P')
{
memcpy(memory, buffer + 4 + 4, 32 + 6);
if(real_len > 3 + 4 + 6 + 32)
{
memcpy(memory + 6 + 32 + 96, buffer + 4 + 4 + 6 + 32, real_len - (3 + 6 + 32 + 4));
}
current_packet_id = ntohl(*(uint32_t*)(buffer + 4));
PacketInput *pkt = reinterpret_cast<PacketInput*>(buffer);
memcpy(memory->airIoStatus, pkt->airIoStatus, sizeof(pkt->airIoStatus));
memcpy(memory->sliderIoStatus, pkt->sliderIoStatus, sizeof(pkt->sliderIoStatus));
memory->testBtn = pkt->testBtn;
memory->serviceBtn = pkt->serviceBtn;
current_packet_id = ntohl(pkt->packetId);
updatePacketId(current_packet_id);
}
else if(real_len >= 3 + 4 + 32 && buffer[1] == 'I' && buffer[2] == 'P' && buffer[3] == 'T') /// without air block
else if(packet_len >= sizeof(PacketInputNoAir) && buffer[1] == 'I' && buffer[2] == 'P' && buffer[3] == 'T') /// without air block
{
memcpy(memory + 6, buffer + 4 + 4, 32);
if(real_len > 3 + 4 + 32)
{
memcpy(memory + 6 + 32 + 96, buffer + 4 + 4 + 32, real_len - (3 + 32 + 4));
}
current_packet_id = ntohl(*(uint32_t*)(buffer + 4));
PacketInputNoAir *pkt = reinterpret_cast<PacketInputNoAir*>(buffer);
memcpy(memory->sliderIoStatus, pkt->sliderIoStatus, sizeof(pkt->sliderIoStatus));
memory->testBtn = pkt->testBtn;
memory->serviceBtn = pkt->serviceBtn;
current_packet_id = ntohl(pkt->packetId);
updatePacketId(current_packet_id);
}
else if(real_len >= 4 && buffer[1] == 'F' && buffer[2] == 'N' && buffer[3] == 'C')
else if(packet_len >= sizeof(PacketFunction) && buffer[1] == 'F' && buffer[2] == 'N' && buffer[3] == 'C')
{
switch(buffer[4])
PacketFunction *pkt = reinterpret_cast<PacketFunction*>(buffer);
switch(pkt->funcBtn)
{
case FUNCTION_COIN:
*(memory + 6 + 32 + 96 + 2) = 1;
memory->coinInsertion = 1;
break;
case FUNCTION_CARD:
*(memory + 6 + 32 + 96 + 3) = 1;
memory->cardRead = 1;
break;
}
}
else if(real_len >= 10 && buffer[1] == 'C' && buffer[2] == 'O' && buffer[3] == 'N')
else if(packet_len >= sizeof(PacketConnect) && buffer[1] == 'C' && buffer[2] == 'O' && buffer[3] == 'N')
{
last_input_packet_id = 0;
std::string data;
data.assign(buffer + 4, real_len - 3);
std::tie(remote_address, remote_port) = getSocksAddress(data);
//std::cout << "Device " << remote_address << ":" << remote_port << " connected." <<std::endl;
PacketConnect *pkt = reinterpret_cast<PacketConnect*>(buffer);
getSocksAddress(pkt, remote_address, remote_port);
printErr("[INFO] Device %s:%d connected.\n", remote_address.data(), remote_port);
CONNECTED = true;
}
else if(real_len >= 3 && buffer[1] == 'D' && buffer[2] == 'I' && buffer[3] == 'S')
else if(packet_len >= 4 && buffer[1] == 'D' && buffer[2] == 'I' && buffer[3] == 'S')
{
CONNECTED = false;
if(tcp_mode)
@ -370,11 +448,10 @@ void InputReceive(SOCKET sHost, char *memory)
if(!remote_address.empty())
{
printErr("[INFO] Device %s:%d disconnected.\n", remote_address.data(), remote_port);
//std::cout << "Device " << remote_address << ":" << remote_port << " disconnected." << std::endl;
remote_address.clear();
}
}
else if(real_len >= 11 && buffer[1] == 'P' && buffer[2] == 'I' && buffer[3] == 'N')
else if(packet_len >= sizeof(PacketPing) && buffer[1] == 'P' && buffer[2] == 'I' && buffer[3] == 'N')
{
if(!CONNECTED)
continue;
@ -383,6 +460,31 @@ void InputReceive(SOCKET sHost, char *memory)
response.replace(2, 1, "O");
udp_send(sHost, remote_address, remote_port, response);
}
else if(packet_len >= sizeof(PacketCard) && buffer[1] == 'C' && buffer[2] == 'R' && buffer[3] == 'D')
{
PacketCard *pkt = reinterpret_cast<PacketCard*>(buffer);
static uint8_t lastId[10] = {};
if(pkt->remoteCardRead)
{
if(memcmp(lastId, pkt->remoteCardId, 10))
{
printErr("[INFO] Got remote card.\n");
printCardInfo(pkt->remoteCardType, pkt->remoteCardId);
memcpy(lastId, pkt->remoteCardId, 10);
}
}
else
{
if(memory->remoteCardRead)
{
printErr("[INFO] Remote card removed.\n");
memset(lastId, 0, 10);
}
}
memory->remoteCardRead = pkt->remoteCardRead;
memory->remoteCardType = pkt->remoteCardType;
memcpy(memory->remoteCardId, pkt->remoteCardId, 10);
}
}
}
@ -443,7 +545,7 @@ int main(int argc, char* argv[])
}
}
defer(CloseHandle(hMapFile))
char *memory = reinterpret_cast<char*>(MapViewOfFileEx(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 1024, NULL));
IPCMemoryInfo *memory = reinterpret_cast<IPCMemoryInfo*>(MapViewOfFileEx(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 1024, NULL));
if(memory == nullptr)
{
//std::cerr << "Cannot get view of memory map! Error " + std::to_string(GetLastError());

View File

@ -8,25 +8,11 @@
#ifdef RC_INVOKED
//
// Set up debug information
//
#if DBG
#define VER_DBG VS_FF_DEBUG
#else
#define VER_DBG 0
#endif
// ------- version info -------------------------------------------------------
VS_VERSION_INFO VERSIONINFO
FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0
PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
FILEFLAGS VER_DBG
FILEOS VOS_NT
FILETYPE VFT_DRV
FILESUBTYPE VFT2_DRV_SYSTEM
BEGIN
BLOCK "StringFileInfo"
BEGIN

79
src/struct.h Normal file
View File

@ -0,0 +1,79 @@
#ifndef STRUCT_H_INCLUDED
#define STRUCT_H_INCLUDED
struct IPCMemoryInfo
{
uint8_t airIoStatus[6];
uint8_t sliderIoStatus[32];
uint8_t ledRgbData[32 * 3];
uint8_t testBtn;
uint8_t serviceBtn;
uint8_t coinInsertion;
uint8_t cardRead;
uint8_t remoteCardRead;
uint8_t remoteCardType;
uint8_t remoteCardId[10];
};
struct PacketInput
{
uint8_t packetSize;
uint8_t packetName[3];
uint32_t packetId;
uint8_t airIoStatus[6];
uint8_t sliderIoStatus[32];
uint8_t testBtn;
uint8_t serviceBtn;
};
struct PacketInputNoAir
{
uint8_t packetSize;
uint8_t packetName[3];
uint32_t packetId;
uint8_t sliderIoStatus[32];
uint8_t testBtn;
uint8_t serviceBtn;
};
struct PacketFunction
{
uint8_t packetSize;
uint8_t packetName[3];
uint8_t funcBtn;
};
struct PacketConnect
{
uint8_t packetSize;
uint8_t packetName[3];
uint8_t addrType;
uint16_t port;
union
{
struct
{
uint8_t addr[4];
uint8_t padding[12];
} addr4;
uint8_t addr6[16];
} addr;
};
struct PacketCard
{
uint8_t packetSize;
uint8_t packetName[3];
uint8_t remoteCardRead;
uint8_t remoteCardType;
uint8_t remoteCardId[10];
};
struct PacketPing
{
uint8_t packetSize;
uint8_t packetName[3];
uint64_t remotePingTime;
};
#endif // STRUCT_H_INCLUDED