Compare commits
7 Commits
Author | SHA1 | Date |
---|---|---|
beerpsi | 48c5a4f053 | |
beerpsi | 44ba947998 | |
beerpsi | 348d6020c5 | |
beerpsi | 1bb616e1ec | |
beerpsi | db9ac578e3 | |
beerpsi | 1ec4c35ae4 | |
beerpsi | 3dffb242c3 |
|
@ -5,6 +5,12 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
|
|||
include_directories("${CMAKE_SOURCE_DIR}/include/")
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
|
||||
include(CheckIPOSupported)
|
||||
check_ipo_supported(RESULT IPO_SUPPORTED)
|
||||
if (IPO_SUPPORTED)
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
endif ()
|
||||
|
||||
include_directories(.)
|
||||
|
||||
add_subdirectory(aimeio)
|
||||
|
|
|
@ -27,10 +27,10 @@ coin=0x33
|
|||
ir=0x20
|
||||
|
||||
[brokenithm]
|
||||
; Use TCP instead of UDP for connections (default TCP)
|
||||
; Brokenithm-Android: Use TCP instead of UDP for connections (default TCP)
|
||||
tcp=1
|
||||
|
||||
; Port to accept connections on (default 52468)
|
||||
; Brokenithm-Android: Port to accept connections on (default 52468)
|
||||
port=52468
|
||||
```
|
||||
|
||||
|
|
|
@ -1,33 +1,40 @@
|
|||
cmake_minimum_required(VERSION 3.27)
|
||||
project(chuniio_brokenithm)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
|
||||
include_directories("${CMAKE_SOURCE_DIR}/include/")
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
|
||||
link_directories(src)
|
||||
add_library(chuniio_brokenithm SHARED src/chuniio.c
|
||||
src/chuniio.h
|
||||
src/config.c
|
||||
src/config.h
|
||||
src/servers/socket.h
|
||||
src/ipc_memory_info.h
|
||||
src/servers/android.c
|
||||
src/servers/android.h
|
||||
src/servers/common.h
|
||||
src/servers/common.c
|
||||
src/servers/ios.c
|
||||
src/servers/ios.h)
|
||||
|
||||
target_link_libraries(chuniio_brokenithm util)
|
||||
set_target_properties(chuniio_brokenithm PROPERTIES PREFIX "")
|
||||
target_include_directories(chuniio_brokenithm PRIVATE src)
|
||||
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
# Ugly hack around libimobiledevice shipping a DllMain for some reason???
|
||||
set_target_properties(chuniio_brokenithm PROPERTIES LINK_FLAGS "-Wl,--allow-multiple-definition")
|
||||
|
||||
target_link_libraries(chuniio_brokenithm "-static-libgcc -Wl,-Bstatic -limobiledevice-1.0 -lssl -lcrypto -lplist-2.0 -lusbmuxd-2.0 -lpthread -Wl,-Bdynamic -lws2_32 -lcrypt32 -liphlpapi")
|
||||
elseif (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
target_link_libraries(chuniio_brokenithm "-static-libgcc")
|
||||
endif ()
|
||||
cmake_minimum_required(VERSION 3.27)
|
||||
project(chuniio_brokenithm)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
|
||||
include_directories("${CMAKE_SOURCE_DIR}/include/")
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
|
||||
link_directories(src)
|
||||
add_library(chuniio_brokenithm SHARED src/chuniio.c
|
||||
src/chuniio.h
|
||||
src/config.c
|
||||
src/config.h
|
||||
src/leddata.h
|
||||
src/ledoutput.c
|
||||
src/ledoutput.h
|
||||
src/pipeimpl.c
|
||||
src/pipeimpl.h
|
||||
src/serialimpl.c
|
||||
src/serialimpl.h
|
||||
src/servers/socket.h
|
||||
src/ipc_memory_info.h
|
||||
src/servers/android.c
|
||||
src/servers/android.h
|
||||
src/servers/common.h
|
||||
src/servers/common.c
|
||||
src/servers/ios.c
|
||||
src/servers/ios.h)
|
||||
|
||||
target_link_libraries(chuniio_brokenithm util)
|
||||
set_target_properties(chuniio_brokenithm PROPERTIES PREFIX "")
|
||||
target_include_directories(chuniio_brokenithm PRIVATE src)
|
||||
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
# Ugly hack around libimobiledevice shipping a DllMain for some reason???
|
||||
set_target_properties(chuniio_brokenithm PROPERTIES LINK_FLAGS "-Wl,--allow-multiple-definition")
|
||||
|
||||
target_link_libraries(chuniio_brokenithm "-static-libgcc -Wl,-Bstatic -limobiledevice-1.0 -lssl -lcrypto -lplist-2.0 -lusbmuxd-2.0 -lpthread -Wl,-Bdynamic -lws2_32 -lcrypt32 -liphlpapi")
|
||||
elseif (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
target_link_libraries(chuniio_brokenithm "-static-libgcc")
|
||||
endif ()
|
||||
|
|
|
@ -5,20 +5,14 @@
|
|||
#ifndef BROKENITHM_ARCH_H
|
||||
#define BROKENITHM_ARCH_H
|
||||
|
||||
#if _WIN32 || _WIN64
|
||||
#if _WIN64
|
||||
#define ENV64BIT
|
||||
#else
|
||||
#define ENV32BIT
|
||||
#endif // _WIN64
|
||||
#endif // _WIN32 || _WIN64
|
||||
#include <stdint.h>
|
||||
|
||||
#if __GNUC__
|
||||
#if __x86_64__ || __ppc64__
|
||||
#define ENV64BIT
|
||||
#if UINTPTR_MAX == UINT32_MAX
|
||||
#define ENV32BIT
|
||||
#elif UINTPTR_MAX == UINT64_MAX
|
||||
#define ENV64BIT
|
||||
#else
|
||||
#define ENV32BIT
|
||||
#endif // __x86_64__ || __ppc64__
|
||||
#error "Environment is neither 32-bit nor 64-bit."
|
||||
#endif
|
||||
|
||||
#endif // BROKENITHM_ARCH_H
|
||||
|
|
|
@ -5,85 +5,54 @@
|
|||
#include "chuniio.h"
|
||||
|
||||
#include <process.h>
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include "arch.h"
|
||||
#include "config.h"
|
||||
#include "ledoutput.h"
|
||||
#include "ipc_memory_info.h"
|
||||
|
||||
#define MEM_FILE_NAME "Local\\BROKENITHM_SHARED_BUFFER"
|
||||
|
||||
struct IPCMemoryInfo *chuni_io_file_mapping;
|
||||
#include "util/dprintf.h"
|
||||
|
||||
#ifdef ENV32BIT
|
||||
|
||||
#include "servers/android.h"
|
||||
#include "servers/common.h"
|
||||
#include "servers/ios.h"
|
||||
|
||||
HRESULT server_start() {
|
||||
HANDLE hMapFile = OpenFileMappingA(FILE_MAP_ALL_ACCESS, false, MEM_FILE_NAME);
|
||||
|
||||
if (hMapFile == NULL) {
|
||||
hMapFile = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
|
||||
1024, MEM_FILE_NAME);
|
||||
if (hMapFile == NULL) {
|
||||
print_err("[ERROR] CreateFileMapping failed! error: %lu\n", GetLastError());
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
struct IPCMemoryInfo *memory =
|
||||
MapViewOfFileEx(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 1024, NULL);
|
||||
chuni_io_file_mapping = memory;
|
||||
|
||||
HRESULT result;
|
||||
|
||||
if ((result = android_init_server(memory))) {
|
||||
print_err("[ERROR] Android server intialization failed: %ld", result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((result = ios_init_server(memory))) {
|
||||
print_err("[ERROR] iOS server initialization failed: %ld", result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENV64BIT
|
||||
#include "util/dprintf.h"
|
||||
#define MEM_FILE_NAME "Local\\BROKENITHM_SHARED_BUFFER"
|
||||
|
||||
static HANDLE chuni_io_file_mapping_handle;
|
||||
struct IPCMemoryInfo *chuni_io_file_mapping;
|
||||
|
||||
void chuni_io_init_shared_memory() {
|
||||
HRESULT chuni_io_init_shared_memory() {
|
||||
if (chuni_io_file_mapping) {
|
||||
dprintf("chuni_io_init_shared_memory: shared memory already exists\n");
|
||||
return;
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
if ((chuni_io_file_mapping_handle =
|
||||
CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0,
|
||||
sizeof(struct IPCMemoryInfo), MEM_FILE_NAME)) == 0) {
|
||||
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;
|
||||
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) {
|
||||
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;
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
memset(chuni_io_file_mapping, 0, sizeof(struct IPCMemoryInfo));
|
||||
SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_CONTINUOUS);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx);
|
||||
|
||||
|
@ -91,7 +60,7 @@ 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 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; }
|
||||
|
@ -99,14 +68,30 @@ uint16_t chuni_io_get_api_version() { return 0x0102; }
|
|||
HRESULT chuni_io_jvs_init() {
|
||||
chuni_io_config_load(&chuni_io_cfg, L".\\segatools.ini");
|
||||
|
||||
#ifdef ENV32BIT
|
||||
HRESULT result = server_start();
|
||||
if (result != S_OK) {
|
||||
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
|
||||
#ifdef ENV64BIT
|
||||
chuni_io_init_shared_memory();
|
||||
#endif
|
||||
|
||||
return S_OK;
|
||||
|
@ -139,12 +124,12 @@ void chuni_io_jvs_poll(uint8_t *opbtn, uint8_t *beams) {
|
|||
|
||||
if ((chuni_io_file_mapping && chuni_io_file_mapping->testBtn) ||
|
||||
GetAsyncKeyState(chuni_io_cfg.vk_test)) {
|
||||
*opbtn |= CHUNI_IO_OPBTN_TEST; /* 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; /* Service */
|
||||
*opbtn |= CHUNI_IO_OPBTN_SERVICE;
|
||||
}
|
||||
|
||||
if (GetAsyncKeyState(chuni_io_cfg.vk_ir_emu)) {
|
||||
|
@ -172,15 +157,19 @@ void chuni_io_jvs_poll(uint8_t *opbtn, uint8_t *beams) {
|
|||
}
|
||||
}
|
||||
|
||||
HRESULT chuni_io_slider_init() { return S_OK; }
|
||||
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);
|
||||
(HANDLE) _beginthreadex(NULL, 0, chuni_io_slider_thread_proc, callback, 0, NULL);
|
||||
}
|
||||
|
||||
void chuni_io_slider_stop(void) {
|
||||
|
@ -188,31 +177,33 @@ void chuni_io_slider_stop(void) {
|
|||
return;
|
||||
}
|
||||
|
||||
chuni_io_slider_stop_flag = true;
|
||||
atomic_flag_clear(&chuni_io_slider_run_flag);
|
||||
|
||||
WaitForSingleObject(chuni_io_slider_thread, INFINITE);
|
||||
CloseHandle(chuni_io_slider_thread);
|
||||
chuni_io_slider_thread = NULL;
|
||||
chuni_io_slider_stop_flag = false;
|
||||
}
|
||||
|
||||
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 S_OK; }
|
||||
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) {}
|
||||
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;
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma ide diagnostic ignored "LoopDoesntUseConditionVariableInspection"
|
||||
// ReSharper disable once CppDFALoopConditionNotUpdated
|
||||
while (!chuni_io_slider_stop_flag) {
|
||||
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);
|
||||
|
@ -221,7 +212,6 @@ static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx) {
|
|||
callback(pressure);
|
||||
Sleep(1);
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define LED_PACKET_FRAMING 0xE0
|
||||
#define LED_PACKET_ESCAPE 0xD0
|
||||
#define LED_NUM_MAX 66
|
||||
#define LED_BOARDS_TOTAL 3
|
||||
#define LED_OUTPUT_HEADER_SIZE 2
|
||||
#define LED_OUTPUT_DATA_SIZE_MAX LED_NUM_MAX * 3 * 2 // max if every byte's escaped
|
||||
#define LED_OUTPUT_TOTAL_SIZE_MAX LED_OUTPUT_HEADER_SIZE + LED_OUTPUT_DATA_SIZE_MAX
|
||||
|
||||
// This struct is used to send data related to the slider and billboard LEDs
|
||||
struct _chuni_led_data_buf_t {
|
||||
byte framing; // Sync byte
|
||||
uint8_t board; // LED output the data is for (0-1: billboard, 2: slider)
|
||||
byte data[LED_OUTPUT_DATA_SIZE_MAX]; // Buffer for LEDs
|
||||
byte data_len; // How many bytes to output from the buffer
|
||||
};
|
||||
|
||||
static byte chuni_led_board_data_lens[LED_BOARDS_TOTAL] = {53*3, 63*3, 31*3};
|
|
@ -0,0 +1,131 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "leddata.h"
|
||||
#include "ledoutput.h"
|
||||
#include "pipeimpl.h"
|
||||
#include "serialimpl.h"
|
||||
|
||||
static struct _chuni_led_data_buf_t led_unescaped_buf[LED_BOARDS_TOTAL];
|
||||
static struct _chuni_led_data_buf_t led_escaped_buf[LED_BOARDS_TOTAL];
|
||||
|
||||
static bool led_output_is_init = false;
|
||||
static struct chuni_io_config* config;
|
||||
static bool any_outputs_enabled;
|
||||
|
||||
HANDLE led_init_mutex;
|
||||
|
||||
HRESULT led_output_init(struct chuni_io_config* const cfg)
|
||||
{
|
||||
DWORD dwWaitResult = WaitForSingleObject(led_init_mutex, INFINITE);
|
||||
if (dwWaitResult == WAIT_FAILED)
|
||||
{
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
// return 1;
|
||||
}
|
||||
else if (dwWaitResult != WAIT_OBJECT_0)
|
||||
{
|
||||
return E_FAIL;
|
||||
// return 1;
|
||||
}
|
||||
|
||||
if (!led_output_is_init)
|
||||
{
|
||||
config = cfg;
|
||||
|
||||
// Set up the framing bytes for the packets
|
||||
for (int i = 0; i < LED_BOARDS_TOTAL; i++) {
|
||||
led_unescaped_buf[i].framing = LED_PACKET_FRAMING;
|
||||
led_unescaped_buf[i].board = i;
|
||||
led_unescaped_buf[i].data_len = chuni_led_board_data_lens[i];
|
||||
|
||||
led_escaped_buf[i].framing = LED_PACKET_FRAMING;
|
||||
led_escaped_buf[i].board = i;
|
||||
led_escaped_buf[i].data_len = chuni_led_board_data_lens[i];
|
||||
}
|
||||
|
||||
any_outputs_enabled = config->led_output_pipe || config->slider_led_output_pipe
|
||||
|| config->led_output_serial || config->slider_led_output_serial;
|
||||
|
||||
if (config->led_output_pipe || config->slider_led_output_pipe)
|
||||
{
|
||||
led_pipe_init(); // don't really care about errors here tbh
|
||||
}
|
||||
|
||||
if (config->led_output_serial || config->slider_led_output_serial)
|
||||
{
|
||||
led_serial_init(config->led_serial_port, config->led_serial_baud);
|
||||
}
|
||||
}
|
||||
|
||||
led_output_is_init = true;
|
||||
|
||||
ReleaseMutex(led_init_mutex);
|
||||
return S_OK;
|
||||
// return 0;
|
||||
}
|
||||
|
||||
struct _chuni_led_data_buf_t* escape_led_data(struct _chuni_led_data_buf_t* unescaped)
|
||||
{
|
||||
struct _chuni_led_data_buf_t* out_struct = &led_escaped_buf[unescaped->board];
|
||||
|
||||
byte* in_buf = unescaped->data;
|
||||
byte* out_buf = out_struct->data;
|
||||
int i = 0;
|
||||
int o = 0;
|
||||
|
||||
while (i < unescaped->data_len)
|
||||
{
|
||||
byte b = in_buf[i++];
|
||||
if (b == LED_PACKET_FRAMING || b == LED_PACKET_ESCAPE)
|
||||
{
|
||||
out_buf[o++] = LED_PACKET_ESCAPE;
|
||||
b--;
|
||||
}
|
||||
out_buf[o++] = b;
|
||||
}
|
||||
|
||||
out_struct->data_len = o;
|
||||
|
||||
return out_struct;
|
||||
}
|
||||
|
||||
void led_output_update(uint8_t board, const uint8_t* rgb)
|
||||
{
|
||||
if (board < 0 || board > 2 || !any_outputs_enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(led_unescaped_buf[board].data, rgb, led_unescaped_buf[board].data_len);
|
||||
struct _chuni_led_data_buf_t* escaped_data = escape_led_data(&led_unescaped_buf[board]);
|
||||
|
||||
if (board < 2)
|
||||
{
|
||||
// billboard
|
||||
if (config->led_output_pipe)
|
||||
{
|
||||
led_pipe_update(escaped_data);
|
||||
}
|
||||
|
||||
if (config->led_output_serial)
|
||||
{
|
||||
led_serial_update(escaped_data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// slider
|
||||
if (config->slider_led_output_pipe)
|
||||
{
|
||||
led_pipe_update(escaped_data);
|
||||
}
|
||||
|
||||
if (config->slider_led_output_serial)
|
||||
{
|
||||
led_serial_update(escaped_data);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
LED output functions
|
||||
|
||||
Credits:
|
||||
somewhatlurker, skogaby
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
extern HANDLE led_init_mutex;
|
||||
HRESULT led_output_init(struct chuni_io_config* const cfg);
|
||||
void led_output_update(uint8_t board, const uint8_t* rgb);
|
|
@ -0,0 +1,160 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <process.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "leddata.h"
|
||||
#include "pipeimpl.h"
|
||||
|
||||
static bool pipe_update[LED_BOARDS_TOTAL];
|
||||
|
||||
// incoming data is copied into these to ensure it isn't written during output
|
||||
static struct _chuni_led_data_buf_t pipe_write_buf[LED_BOARDS_TOTAL];
|
||||
static HANDLE pipe_write_mutex;
|
||||
|
||||
static HRESULT pipe_create(LPHANDLE hPipe, LPCWSTR lpszPipename, DWORD dwBufSize)
|
||||
{
|
||||
*hPipe = INVALID_HANDLE_VALUE;
|
||||
|
||||
*hPipe = CreateNamedPipeW(
|
||||
lpszPipename, // pipe name
|
||||
PIPE_ACCESS_OUTBOUND, // read/write access
|
||||
PIPE_TYPE_BYTE | // byte type pipe
|
||||
PIPE_WAIT, // blocking mode
|
||||
PIPE_UNLIMITED_INSTANCES, // max. instances
|
||||
dwBufSize, // output buffer size
|
||||
0, // input buffer size
|
||||
0, // client time-out
|
||||
NULL); // default security attribute
|
||||
|
||||
if (*hPipe == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT pipe_write(HANDLE hPipe, LPCVOID lpBuffer, DWORD dwSize)
|
||||
{
|
||||
DWORD cbWritten = 0;
|
||||
|
||||
bool fSuccess = WriteFile(
|
||||
hPipe,
|
||||
lpBuffer,
|
||||
dwSize,
|
||||
&cbWritten,
|
||||
NULL);
|
||||
|
||||
if (!fSuccess || cbWritten != dwSize)
|
||||
{
|
||||
DWORD last_err = GetLastError();
|
||||
return (last_err == ERROR_BROKEN_PIPE) ? E_ABORT : E_FAIL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static unsigned int __stdcall chuni_io_led_pipe_thread_proc(void *ctx)
|
||||
{
|
||||
HANDLE hPipe;
|
||||
LPCWSTR lpszPipename = L"\\\\.\\pipe\\chuni_led";
|
||||
|
||||
while (true)
|
||||
{
|
||||
hPipe = INVALID_HANDLE_VALUE;
|
||||
|
||||
if (pipe_create(&hPipe, lpszPipename, LED_OUTPUT_TOTAL_SIZE_MAX) != S_OK)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// wait for a connection to the pipe
|
||||
bool fConnected = ConnectNamedPipe(hPipe, NULL) ?
|
||||
true : (GetLastError() == ERROR_PIPE_CONNECTED);
|
||||
|
||||
while (fConnected)
|
||||
{
|
||||
if (WaitForSingleObject(pipe_write_mutex, INFINITE) != WAIT_OBJECT_0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < LED_BOARDS_TOTAL; i++) {
|
||||
if (pipe_update[i])
|
||||
{
|
||||
HRESULT result = pipe_write(
|
||||
hPipe,
|
||||
&pipe_write_buf[i],
|
||||
LED_OUTPUT_HEADER_SIZE + pipe_write_buf[i].data_len);
|
||||
|
||||
if (result != S_OK)
|
||||
{
|
||||
//if (result == E_ABORT)
|
||||
//{
|
||||
fConnected = false;
|
||||
//}
|
||||
break;
|
||||
}
|
||||
|
||||
pipe_update[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseMutex(pipe_write_mutex);
|
||||
}
|
||||
|
||||
FlushFileBuffers(hPipe);
|
||||
DisconnectNamedPipe(hPipe);
|
||||
CloseHandle(hPipe);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
HRESULT led_pipe_init()
|
||||
{
|
||||
pipe_write_mutex = CreateMutex(
|
||||
NULL, // default security attributes
|
||||
FALSE, // initially not owned
|
||||
NULL); // unnamed mutex
|
||||
|
||||
if (pipe_write_mutex == NULL)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// clear out update bools
|
||||
for (int i = 0; i < LED_BOARDS_TOTAL; i++) {
|
||||
pipe_update[i] = false;
|
||||
}
|
||||
|
||||
_beginthreadex(
|
||||
NULL,
|
||||
0,
|
||||
chuni_io_led_pipe_thread_proc,
|
||||
0,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void led_pipe_update(struct _chuni_led_data_buf_t* data)
|
||||
{
|
||||
if (data->board > 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (WaitForSingleObject(pipe_write_mutex, INFINITE) != WAIT_OBJECT_0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&pipe_write_buf[data->board], data, sizeof(struct _chuni_led_data_buf_t));
|
||||
pipe_update[data->board] = true;
|
||||
|
||||
ReleaseMutex(pipe_write_mutex);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
Pipe implementation for chuniio
|
||||
|
||||
Credits:
|
||||
somewhatlurker, skogaby
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "leddata.h"
|
||||
|
||||
HRESULT led_pipe_init();
|
||||
void led_pipe_update(struct _chuni_led_data_buf_t* data);
|
|
@ -0,0 +1,99 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <process.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "leddata.h"
|
||||
#include "serialimpl.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static HANDLE serial_port;
|
||||
static HANDLE serial_write_mutex;
|
||||
|
||||
HRESULT led_serial_init(wchar_t led_com[12], DWORD baud)
|
||||
{
|
||||
// Setup the serial communications
|
||||
BOOL status;
|
||||
|
||||
serial_port = CreateFileW(led_com,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
if (serial_port == INVALID_HANDLE_VALUE)
|
||||
dprintf("Chunithm Serial LEDs: Failed to open COM port (Attempted on %S)\n", led_com);
|
||||
else
|
||||
dprintf("Chunithm Serial LEDs: COM port success!\n");
|
||||
|
||||
DCB dcb_serial_params = { 0 };
|
||||
dcb_serial_params.DCBlength = sizeof(dcb_serial_params);
|
||||
status = GetCommState(serial_port, &dcb_serial_params);
|
||||
|
||||
dcb_serial_params.BaudRate = baud;
|
||||
dcb_serial_params.ByteSize = 8;
|
||||
dcb_serial_params.StopBits = ONESTOPBIT;
|
||||
dcb_serial_params.Parity = NOPARITY;
|
||||
SetCommState(serial_port, &dcb_serial_params);
|
||||
|
||||
COMMTIMEOUTS timeouts = { 0 };
|
||||
timeouts.ReadIntervalTimeout = 50;
|
||||
timeouts.ReadTotalTimeoutConstant = 50;
|
||||
timeouts.ReadTotalTimeoutMultiplier = 10;
|
||||
timeouts.WriteTotalTimeoutConstant = 50;
|
||||
timeouts.WriteTotalTimeoutMultiplier = 10;
|
||||
|
||||
SetCommTimeouts(serial_port, &timeouts);
|
||||
|
||||
if (!status)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
serial_write_mutex = CreateMutex(
|
||||
NULL, // default security attributes
|
||||
FALSE, // initially not owned
|
||||
NULL); // unnamed mutex
|
||||
|
||||
if (serial_write_mutex == NULL)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void led_serial_update(struct _chuni_led_data_buf_t* data)
|
||||
{
|
||||
if (data->board > 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (WaitForSingleObject(serial_write_mutex, INFINITE) != WAIT_OBJECT_0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BOOL status = true;
|
||||
DWORD bytes_written = 0;
|
||||
|
||||
if (serial_port != INVALID_HANDLE_VALUE) {
|
||||
status = WriteFile(
|
||||
serial_port,
|
||||
data,
|
||||
LED_OUTPUT_HEADER_SIZE + data->data_len,
|
||||
&bytes_written,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (!status) {
|
||||
DWORD last_err = GetLastError();
|
||||
// dprintf("Chunithm Serial LEDs: Serial port write failed -- %d\n", last_err);
|
||||
}
|
||||
|
||||
ReleaseMutex(serial_write_mutex);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
Serial LED implementation for chuniio
|
||||
|
||||
Credits:
|
||||
somewhatlurker, skogaby
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "leddata.h"
|
||||
|
||||
HRESULT led_serial_init(wchar_t led_com[12], DWORD baud);
|
||||
void led_serial_update(struct _chuni_led_data_buf_t* data);
|
|
@ -28,8 +28,8 @@ typedef struct {
|
|||
char remote_address[40];
|
||||
uint16_t remote_port;
|
||||
|
||||
atomic_bool exit_flag;
|
||||
atomic_bool connected;
|
||||
volatile atomic_flag keep_running_flag;
|
||||
volatile atomic_bool connected;
|
||||
|
||||
uint32_t last_input_packet_id;
|
||||
uint8_t last_card_id[10];
|
||||
|
@ -130,7 +130,7 @@ unsigned int __stdcall led_broadcast_thread_proc(void *v) {
|
|||
send_buffer[2] = 'E';
|
||||
send_buffer[3] = 'D';
|
||||
|
||||
while (!atomic_load(&ctx->exit_flag)) {
|
||||
while (atomic_flag_test_and_set(&ctx->keep_running_flag)) {
|
||||
uint8_t current_led_status[3 * 32];
|
||||
|
||||
if (!atomic_load(&ctx->connected)) {
|
||||
|
@ -165,7 +165,7 @@ unsigned int __stdcall led_broadcast_thread_proc(void *v) {
|
|||
|
||||
print_err("[Android: INFO] Device disconnected!\n");
|
||||
ctx->connected = false;
|
||||
ctx->exit_flag = true;
|
||||
atomic_flag_clear(&ctx->keep_running_flag);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ unsigned int __stdcall input_recv_thread_proc(void *v) {
|
|||
int recv_len, packet_len;
|
||||
uint8_t real_len;
|
||||
|
||||
while (!atomic_load(&ctx->exit_flag)) {
|
||||
while (atomic_flag_test_and_set(&ctx->keep_running_flag)) {
|
||||
char buffer[96];
|
||||
|
||||
if (!tcp_mode) {
|
||||
|
@ -235,8 +235,10 @@ unsigned int __stdcall input_recv_thread_proc(void *v) {
|
|||
"%d, os error %ld)\n",
|
||||
errno, error);
|
||||
atomic_store(&ctx->connected, false);
|
||||
atomic_store(&ctx->exit_flag, true);
|
||||
break;
|
||||
atomic_flag_clear(&ctx->keep_running_flag);
|
||||
|
||||
free(ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
recv_len = recv_len + read;
|
||||
|
@ -262,8 +264,10 @@ unsigned int __stdcall input_recv_thread_proc(void *v) {
|
|||
"%d, os error %ld)\n",
|
||||
errno, error);
|
||||
atomic_store(&ctx->connected, false);
|
||||
atomic_store(&ctx->exit_flag, true);
|
||||
break;
|
||||
atomic_flag_clear(&ctx->keep_running_flag);
|
||||
|
||||
free(ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
recv_len = recv_len + read;
|
||||
|
@ -319,7 +323,7 @@ unsigned int __stdcall input_recv_thread_proc(void *v) {
|
|||
atomic_store(&ctx->connected, false);
|
||||
|
||||
if (tcp_mode) {
|
||||
atomic_store(&ctx->exit_flag, true);
|
||||
atomic_flag_clear(&ctx->keep_running_flag);
|
||||
print_err("[Android: INFO] Device disconnected (clean disconnect).\n");
|
||||
break;
|
||||
}
|
||||
|
@ -384,8 +388,8 @@ unsigned int __stdcall server_thread_proc(void *v) {
|
|||
print_err("[Android: INFO] Waiting for device on port %d...\n", server_port);
|
||||
|
||||
android_thread_ctx *ctx = malloc(sizeof(android_thread_ctx));
|
||||
atomic_flag_test_and_set(&ctx->keep_running_flag);
|
||||
ctx->sock = sock;
|
||||
ctx->exit_flag = ATOMIC_VAR_INIT(false);
|
||||
ctx->connected = ATOMIC_VAR_INIT(false);
|
||||
ctx->last_input_packet_id = 0;
|
||||
ctx->memory = memory;
|
||||
|
@ -431,8 +435,8 @@ unsigned int __stdcall server_thread_proc(void *v) {
|
|||
}
|
||||
|
||||
android_thread_ctx *ctx = malloc(sizeof(android_thread_ctx));
|
||||
atomic_flag_test_and_set(&ctx->keep_running_flag);
|
||||
ctx->sock = acc_socket;
|
||||
ctx->exit_flag = ATOMIC_VAR_INIT(false);
|
||||
ctx->connected = ATOMIC_VAR_INIT(true);
|
||||
ctx->last_input_packet_id = 0;
|
||||
ctx->memory = memory;
|
||||
|
|
|
@ -1,66 +1,66 @@
|
|||
//
|
||||
// Created by beerpsi on 12/31/2023.
|
||||
//
|
||||
|
||||
#ifndef CHUNIIO_BROKENITHM_ANDROID_H
|
||||
#define CHUNIIO_BROKENITHM_ANDROID_H
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#include "ipc_memory_info.h"
|
||||
|
||||
;
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
struct AndroidPacketInput {
|
||||
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 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;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
HRESULT android_init_server(struct IPCMemoryInfo *memory);
|
||||
|
||||
#endif // CHUNIIO_BROKENITHM_ANDROID_H
|
||||
//
|
||||
// Created by beerpsi on 12/31/2023.
|
||||
//
|
||||
|
||||
#ifndef CHUNIIO_BROKENITHM_ANDROID_H
|
||||
#define CHUNIIO_BROKENITHM_ANDROID_H
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#include "ipc_memory_info.h"
|
||||
|
||||
;
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
struct AndroidPacketInput {
|
||||
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 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;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
HRESULT android_init_server(struct IPCMemoryInfo *memory);
|
||||
|
||||
#endif // CHUNIIO_BROKENITHM_ANDROID_H
|
||||
|
|
|
@ -17,7 +17,7 @@ typedef struct {
|
|||
idevice_t device;
|
||||
idevice_connection_t connection;
|
||||
|
||||
atomic_bool exit_flag;
|
||||
volatile atomic_flag keep_running_flag;
|
||||
|
||||
bool has_previous_led_status;
|
||||
uint8_t previous_led_status[3 * 32];
|
||||
|
@ -35,7 +35,7 @@ unsigned int __stdcall ios_led_broadcast_thread_proc(void *v) {
|
|||
send_buffer[2] = 'E';
|
||||
send_buffer[3] = 'D';
|
||||
|
||||
while (!atomic_load(&ctx->exit_flag)) {
|
||||
while (atomic_flag_test_and_set(&ctx->keep_running_flag)) {
|
||||
uint8_t current_led_status[3 * 32];
|
||||
|
||||
memcpy(current_led_status, ctx->memory->ledRgbData, 3 * 32);
|
||||
|
@ -75,7 +75,7 @@ unsigned int __stdcall ios_input_recv_thread_proc(void *v) {
|
|||
|
||||
bool air_enabled = true;
|
||||
|
||||
while (!atomic_load(&ctx->exit_flag)) {
|
||||
while (atomic_flag_test_and_set(&ctx->keep_running_flag)) {
|
||||
char buffer[96];
|
||||
int status;
|
||||
uint32_t read;
|
||||
|
@ -87,7 +87,7 @@ unsigned int __stdcall ios_input_recv_thread_proc(void *v) {
|
|||
}
|
||||
|
||||
print_err("[iOS:ERROR] Could not read data from device: %d\n", status);
|
||||
atomic_store(&ctx->exit_flag, true);
|
||||
atomic_flag_clear(&ctx->keep_running_flag);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ unsigned int __stdcall ios_input_recv_thread_proc(void *v) {
|
|||
if ((status = idevice_connection_receive_timeout(ctx->connection, buffer + 4,
|
||||
len - 3, &read, 5))) {
|
||||
print_err("[iOS:ERROR] Could not read data from device: %d\n", status);
|
||||
atomic_store(&ctx->exit_flag, true);
|
||||
atomic_flag_clear(&ctx->keep_running_flag);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -197,7 +197,6 @@ unsigned int __stdcall connect_device(void *v) {
|
|||
}
|
||||
|
||||
print_err("[iOS: INFO] Connected to device\n");
|
||||
atomic_store(&ctx->exit_flag, false);
|
||||
_beginthreadex(NULL, 0, ios_input_recv_thread_proc, ctx, 0, NULL);
|
||||
_beginthreadex(NULL, 0, ios_led_broadcast_thread_proc, ctx, 0, NULL);
|
||||
|
||||
|
@ -212,10 +211,10 @@ void device_event_callback(const idevice_event_t *event, void *user_data) {
|
|||
print_err("[iOS: INFO] iDevice added, udid: %s\n", event->udid);
|
||||
|
||||
ios_thread_ctx *args = malloc(sizeof(ios_thread_ctx));
|
||||
memcpy(args->remote_udid, event->udid, strlen(event->udid));
|
||||
strcpy_s(args->remote_udid, 41, event->udid);
|
||||
atomic_flag_test_and_set(&args->keep_running_flag);
|
||||
args->device = NULL;
|
||||
args->connection = NULL;
|
||||
args->exit_flag = ATOMIC_VAR_INIT(false);
|
||||
args->has_previous_led_status = false;
|
||||
args->led_skip_count = 0;
|
||||
args->memory = memory;
|
||||
|
|
Loading…
Reference in New Issue