add LED pipe for billboard

This commit is contained in:
beerpsi 2024-01-10 13:58:31 +07:00
parent 44ba947998
commit 48c5a4f053
10 changed files with 592 additions and 108 deletions

View File

@ -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 ()

View File

@ -9,13 +9,16 @@
#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"
@ -30,16 +33,16 @@ HRESULT chuni_io_init_shared_memory() {
}
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 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 E_FAIL;
@ -71,6 +74,12 @@ HRESULT chuni_io_jvs_init() {
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);
@ -148,7 +157,9 @@ 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) {
@ -158,7 +169,7 @@ void chuni_io_slider_start(void *callback) {
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) {
@ -174,14 +185,20 @@ void chuni_io_slider_stop(void) {
}
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;

22
chuniio/src/leddata.h Normal file
View File

@ -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};

131
chuniio/src/ledoutput.c Normal file
View File

@ -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);
}
}
}

19
chuniio/src/ledoutput.h Normal file
View File

@ -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);

160
chuniio/src/pipeimpl.c Normal file
View File

@ -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);
}

14
chuniio/src/pipeimpl.h Normal file
View File

@ -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);

99
chuniio/src/serialimpl.c Normal file
View File

@ -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);
}

15
chuniio/src/serialimpl.h Normal file
View File

@ -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);

View File

@ -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