222 lines
5.6 KiB
C
222 lines
5.6 KiB
C
//
|
|
// Created by beerpsi on 12/30/2023.
|
|
//
|
|
|
|
#include "chuniio.h"
|
|
|
|
#include <process.h>
|
|
#include <stdatomic.h>
|
|
|
|
#include "arch.h"
|
|
#include "config.h"
|
|
#include "ledoutput.h"
|
|
#include "ipc_memory_info.h"
|
|
#include "util/dprintf.h"
|
|
|
|
#ifdef ENV32BIT
|
|
|
|
#include "servers/android.h"
|
|
#include "servers/common.h"
|
|
#include "servers/ios.h"
|
|
|
|
#endif
|
|
|
|
#define MEM_FILE_NAME "Local\\BROKENITHM_SHARED_BUFFER"
|
|
|
|
static HANDLE chuni_io_file_mapping_handle;
|
|
struct IPCMemoryInfo *chuni_io_file_mapping;
|
|
|
|
HRESULT chuni_io_init_shared_memory() {
|
|
if (chuni_io_file_mapping) {
|
|
dprintf("chuni_io_init_shared_memory: shared memory already exists\n");
|
|
return E_FAIL;
|
|
}
|
|
|
|
if ((chuni_io_file_mapping_handle =
|
|
CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0,
|
|
sizeof(struct IPCMemoryInfo), MEM_FILE_NAME)) == 0) {
|
|
dprintf("chuni_io_init_shared_memory: could not create file mapping: %ld\n",
|
|
GetLastError());
|
|
return E_FAIL;
|
|
}
|
|
|
|
if ((chuni_io_file_mapping = (struct IPCMemoryInfo *) MapViewOfFile(
|
|
chuni_io_file_mapping_handle, FILE_MAP_ALL_ACCESS, 0, 0,
|
|
sizeof(struct IPCMemoryInfo))) == 0) {
|
|
dprintf("chuni_io_init_shared_memory: could not get view of file: %ld\n",
|
|
GetLastError());
|
|
return E_FAIL;
|
|
}
|
|
|
|
memset(chuni_io_file_mapping, 0, sizeof(struct IPCMemoryInfo));
|
|
SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_CONTINUOUS);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
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 volatile atomic_flag chuni_io_slider_run_flag;
|
|
static struct chuni_io_config chuni_io_cfg;
|
|
|
|
uint16_t chuni_io_get_api_version() { return 0x0102; }
|
|
|
|
HRESULT chuni_io_jvs_init() {
|
|
chuni_io_config_load(&chuni_io_cfg, L".\\segatools.ini");
|
|
|
|
HRESULT result;
|
|
|
|
if ((result = chuni_io_init_shared_memory())) {
|
|
return result;
|
|
}
|
|
|
|
led_init_mutex = CreateMutex(NULL, FALSE, NULL);
|
|
|
|
if (led_init_mutex == NULL) {
|
|
return E_FAIL;
|
|
}
|
|
|
|
#ifdef ENV32BIT
|
|
if ((result = android_init_server(chuni_io_file_mapping))) {
|
|
print_err("[ERROR] Android server intialization failed: %ld", result);
|
|
|
|
return result;
|
|
}
|
|
|
|
if ((result = ios_init_server(chuni_io_file_mapping))) {
|
|
print_err("[ERROR] iOS server initialization failed: %ld", result);
|
|
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void chuni_io_jvs_read_coin_counter(uint16_t *total) {
|
|
if (total == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (chuni_io_file_mapping && chuni_io_file_mapping->coinInsertion) {
|
|
chuni_io_coins++;
|
|
chuni_io_file_mapping->coinInsertion = 0;
|
|
} else {
|
|
if (GetAsyncKeyState(chuni_io_cfg.vk_coin)) {
|
|
if (!chuni_io_coin) {
|
|
chuni_io_coin = true;
|
|
chuni_io_coins++;
|
|
}
|
|
} else {
|
|
chuni_io_coin = false;
|
|
}
|
|
}
|
|
|
|
*total = chuni_io_coins;
|
|
}
|
|
|
|
void chuni_io_jvs_poll(uint8_t *opbtn, uint8_t *beams) {
|
|
size_t i;
|
|
|
|
if ((chuni_io_file_mapping && chuni_io_file_mapping->testBtn) ||
|
|
GetAsyncKeyState(chuni_io_cfg.vk_test)) {
|
|
*opbtn |= CHUNI_IO_OPBTN_TEST;
|
|
}
|
|
|
|
if ((chuni_io_file_mapping && chuni_io_file_mapping->serviceBtn) ||
|
|
GetAsyncKeyState(chuni_io_cfg.vk_service)) {
|
|
*opbtn |= CHUNI_IO_OPBTN_SERVICE;
|
|
}
|
|
|
|
if (GetAsyncKeyState(chuni_io_cfg.vk_ir_emu)) {
|
|
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 (chuni_io_hand_pos > i) {
|
|
*beams |= (1 << i);
|
|
}
|
|
}
|
|
|
|
// IR format is beams[5:0] = {b5,b6,b3,b4,b1,b2};
|
|
for (i = 0; i < 3; i++) {
|
|
if (chuni_io_file_mapping && chuni_io_file_mapping->airIoStatus[i * 2])
|
|
*beams |= 1 << (i * 2 + 1);
|
|
if (chuni_io_file_mapping && chuni_io_file_mapping->airIoStatus[i * 2 + 1])
|
|
*beams |= 1 << i * 2;
|
|
}
|
|
}
|
|
|
|
HRESULT chuni_io_slider_init() {
|
|
return led_output_init(&chuni_io_cfg);
|
|
}
|
|
|
|
void chuni_io_slider_start(void *callback) {
|
|
if (chuni_io_slider_thread != NULL) {
|
|
return;
|
|
}
|
|
|
|
atomic_flag_test_and_set(&chuni_io_slider_run_flag);
|
|
|
|
chuni_io_slider_thread =
|
|
(HANDLE) _beginthreadex(NULL, 0, chuni_io_slider_thread_proc, callback, 0, NULL);
|
|
}
|
|
|
|
void chuni_io_slider_stop(void) {
|
|
if (chuni_io_slider_thread == NULL) {
|
|
return;
|
|
}
|
|
|
|
atomic_flag_clear(&chuni_io_slider_run_flag);
|
|
|
|
WaitForSingleObject(chuni_io_slider_thread, INFINITE);
|
|
CloseHandle(chuni_io_slider_thread);
|
|
chuni_io_slider_thread = NULL;
|
|
}
|
|
|
|
void chuni_io_slider_set_leds(const uint8_t *rgb) {
|
|
led_output_update(2, rgb);
|
|
|
|
if (chuni_io_file_mapping) {
|
|
memcpy(chuni_io_file_mapping->ledRgbData, rgb, 32 * 3);
|
|
}
|
|
}
|
|
|
|
HRESULT chuni_io_led_init(void) {
|
|
return led_output_init(&chuni_io_cfg);
|
|
}
|
|
|
|
void chuni_io_led_set_colors(uint8_t board, uint8_t *rgb) {
|
|
led_output_update(board, rgb);
|
|
}
|
|
|
|
static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx) {
|
|
const chuni_io_slider_callback_t callback = ctx;
|
|
|
|
while (atomic_flag_test_and_set(&chuni_io_slider_run_flag)) {
|
|
uint8_t pressure[32];
|
|
if (chuni_io_file_mapping) {
|
|
memcpy(pressure, chuni_io_file_mapping->sliderIoStatus, 32);
|
|
}
|
|
|
|
callback(pressure);
|
|
Sleep(1);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
|
return TRUE;
|
|
}
|