chuniio-brokenithm/chuniio/src/servers/ios.c

248 lines
7.0 KiB
C

//
// Created by beerpsi on 12/31/2023.
//
#include "ios.h"
#include "arch.h"
#ifdef ENV32BIT
#include <libimobiledevice/libimobiledevice.h>
#include <process.h>
#include <stdatomic.h>
#include "servers/common.h"
typedef struct {
char remote_udid[41];
idevice_t device;
idevice_connection_t connection;
atomic_bool exit_flag;
bool has_previous_led_status;
uint8_t previous_led_status[3 * 32];
uint8_t led_skip_count;
struct IPCMemoryInfo *memory;
} ios_thread_ctx;
unsigned int __stdcall ios_led_broadcast_thread_proc(void *v) {
ios_thread_ctx *ctx = v;
char send_buffer[4 + 3 * 32];
send_buffer[0] = 99;
send_buffer[1] = 'L';
send_buffer[2] = 'E';
send_buffer[3] = 'D';
while (!atomic_load(&ctx->exit_flag)) {
uint8_t current_led_status[3 * 32];
memcpy(current_led_status, ctx->memory->ledRgbData, 3 * 32);
bool same;
if (!ctx->has_previous_led_status) {
same = memcmp(ctx->previous_led_status, current_led_status, 3 * 32) == 0;
} else {
same = false;
}
memcpy(ctx->previous_led_status, current_led_status, 3 * 32);
ctx->has_previous_led_status = true;
if (!same || ++ctx->led_skip_count > 50) {
memcpy(send_buffer + 4, current_led_status, 3 * 32);
int status;
uint32_t sent;
if ((status = idevice_connection_send(ctx->connection, send_buffer, 100,
&sent))) {
print_err("[iOS:ERROR] Cannot send LED packet: error %d\n", status);
}
ctx->led_skip_count = 0;
}
Sleep(10);
}
return 0;
}
unsigned int __stdcall ios_input_recv_thread_proc(void *v) {
ios_thread_ctx *ctx = v;
bool air_enabled = true;
while (!atomic_load(&ctx->exit_flag)) {
char buffer[96];
int status;
uint32_t read;
if ((status = idevice_connection_receive_timeout(ctx->connection, buffer, 4,
&read, 5))) {
if (status == IDEVICE_E_TIMEOUT) {
continue;
}
print_err("[iOS:ERROR] Could not read data from device: %d\n", status);
atomic_store(&ctx->exit_flag, true);
break;
}
int len = (unsigned char)buffer[0];
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);
break;
}
if (len >= sizeof(struct PacketInput) && memcmp(buffer + 1, "INP", 3) == 0) {
struct PacketInput *pkt = (struct PacketInput *)buffer;
if (air_enabled) {
memcpy(ctx->memory->airIoStatus, pkt->airIoStatus,
sizeof(pkt->airIoStatus));
}
memcpy(ctx->memory->sliderIoStatus, pkt->sliderIoStatus,
sizeof(pkt->sliderIoStatus));
ctx->memory->testBtn = pkt->testBtn;
ctx->memory->serviceBtn = pkt->serviceBtn;
} else if (len >= sizeof(struct PacketAirStatus) && memcmp(buffer + 1, "AIR", 3) == 0) {
struct PacketAirStatus *pkt = (struct PacketAirStatus *)buffer;
air_enabled = pkt->airEnabled != 0;
print_err("[iOS: INFO] Air input %s\n", air_enabled ? "enabled" : "disabled");
} else if (len >= sizeof(struct PacketFunction) &&
memcmp(buffer + 1, "FNC", 3) == 0) {
const struct PacketFunction *pkt = (struct PacketFunction *)buffer;
switch (pkt->funcBtn) {
case FUNCTION_COIN:
ctx->memory->coinInsertion = 1;
break;
case FUNCTION_CARD:
ctx->memory->cardRead = 1;
break;
default:
break;
}
}
}
print_err("[iOS: INFO] Device disconnected.\n");
idevice_disconnect(ctx->connection);
ctx->connection = NULL;
idevice_free(ctx->device);
free(ctx);
return 0;
}
unsigned int __stdcall connect_device(void *v) {
ios_thread_ctx *ctx = v;
int status;
if ((status = idevice_new(&ctx->device, ctx->remote_udid))) {
print_err("[iOS:ERROR] Create device failed: %d\n", status);
idevice_free(ctx->device);
return 1;
}
if ((status = idevice_connect(ctx->device, 24864, &ctx->connection))) {
print_err("[iOS:ERROR] Connection failed: %d, retrying in 5 seconds\n", status);
ctx->connection = NULL;
idevice_free(ctx->device);
Sleep(5000);
_beginthreadex(NULL, 0, connect_device, ctx, 0, NULL);
return 1;
}
char buf[5];
uint32_t read;
if ((status = idevice_connection_receive(ctx->connection, buf, 4, &read))) {
print_err("[iOS:ERROR] Receiving data failed: %d\n", status);
idevice_disconnect(ctx->connection);
ctx->connection = NULL;
idevice_free(ctx->device);
return 1;
}
if (memcmp(buf, "\x03WEL", 4) != 0) {
print_err("[iOS:ERROR] Client sent invalid data\n");
idevice_disconnect(ctx->connection);
ctx->connection = NULL;
idevice_free(ctx->device);
return 1;
}
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);
return 0;
}
void device_event_callback(const idevice_event_t *event, void *user_data) {
struct IPCMemoryInfo *memory = user_data;
switch (event->event) {
case IDEVICE_DEVICE_ADD:
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));
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;
_beginthreadex(NULL, 0, connect_device, args, 0, NULL);
break;
case IDEVICE_DEVICE_REMOVE:
print_err("[iOS: INFO] iDevice removed, udid: %s\n", event->udid);
break;
case IDEVICE_DEVICE_PAIRED:
print_err("[iOS: INFO] iDevice paired, udid: %s\n", event->udid);
break;
}
}
#endif // defined(ENV32BIT)
HRESULT ios_init_server(struct IPCMemoryInfo *memory) {
#ifdef ENV32BIT
int status;
if ((status = idevice_event_subscribe(device_event_callback, memory))) {
print_err("[iOS:ERROR] Subscribing for iDevice events failed: %d\n", status);
return E_FAIL;
} else {
print_err("[iOS: INFO] Waiting for iDevices...\n");
}
#endif // defined(ENV32BIT)
return S_OK;
}