forked from TeamTofuShop/segatools
chuni/chusan: added LED output to DLLs (will break most DLLs)
Credits: somewhatlurker, skogaby https://dev.s-ul.net/skogaby/segatools/-/blob/ongeki-15093/
This commit is contained in:
@ -7,6 +7,7 @@
|
||||
|
||||
#include "chuniio/chuniio.h"
|
||||
#include "chuniio/config.h"
|
||||
#include "chuniio/ledoutput.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
@ -18,7 +19,6 @@ 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;
|
||||
static HANDLE chuni_io_slider_led_port;
|
||||
|
||||
uint16_t chuni_io_get_api_version(void)
|
||||
{
|
||||
@ -28,7 +28,17 @@ uint16_t chuni_io_get_api_version(void)
|
||||
HRESULT chuni_io_jvs_init(void)
|
||||
{
|
||||
chuni_io_config_load(&chuni_io_cfg, L".\\segatools.ini");
|
||||
|
||||
|
||||
led_init_mutex = CreateMutex(
|
||||
NULL, // default security attributes
|
||||
FALSE, // initially not owned
|
||||
NULL); // unnamed mutex
|
||||
|
||||
if (led_init_mutex == NULL)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@ -93,7 +103,7 @@ void chuni_io_jvs_poll(uint8_t *opbtn, uint8_t *beams)
|
||||
|
||||
HRESULT chuni_io_slider_init(void)
|
||||
{
|
||||
return S_OK;
|
||||
return led_output_init(&chuni_io_cfg); // because of slider LEDs
|
||||
}
|
||||
|
||||
void chuni_io_slider_start(chuni_io_slider_callback_t callback)
|
||||
@ -111,39 +121,6 @@ void chuni_io_slider_start(chuni_io_slider_callback_t callback)
|
||||
callback,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
chuni_io_slider_led_port = CreateFileW(chuni_io_cfg.led_com,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
if (chuni_io_slider_led_port == INVALID_HANDLE_VALUE)
|
||||
dprintf("Chunithm LEDs: Failed to open COM port (Attempted on %S)\n", chuni_io_cfg.led_com);
|
||||
else
|
||||
dprintf("Chunithm LEDs: COM Port Success!\n");
|
||||
|
||||
DCB dcb_serial_params = { 0 };
|
||||
dcb_serial_params.DCBlength = sizeof(dcb_serial_params);
|
||||
status = GetCommState(chuni_io_slider_led_port, &dcb_serial_params);
|
||||
|
||||
dcb_serial_params.BaudRate = CBR_115200; // Setting BaudRate = 115200
|
||||
dcb_serial_params.ByteSize = 8; // Setting ByteSize = 8
|
||||
dcb_serial_params.StopBits = ONESTOPBIT;// Setting StopBits = 1
|
||||
dcb_serial_params.Parity = NOPARITY; // Setting Parity = None
|
||||
SetCommState(chuni_io_slider_led_port, &dcb_serial_params);
|
||||
|
||||
COMMTIMEOUTS timeouts = { 0 };
|
||||
timeouts.ReadIntervalTimeout = 50; // in milliseconds
|
||||
timeouts.ReadTotalTimeoutConstant = 50; // in milliseconds
|
||||
timeouts.ReadTotalTimeoutMultiplier = 10; // in milliseconds
|
||||
timeouts.WriteTotalTimeoutConstant = 50; // in milliseconds
|
||||
timeouts.WriteTotalTimeoutMultiplier = 10; // in milliseconds
|
||||
|
||||
SetCommTimeouts(chuni_io_slider_led_port, &timeouts);
|
||||
|
||||
}
|
||||
|
||||
void chuni_io_slider_stop(void)
|
||||
@ -158,34 +135,11 @@ void chuni_io_slider_stop(void)
|
||||
CloseHandle(chuni_io_slider_thread);
|
||||
chuni_io_slider_thread = NULL;
|
||||
chuni_io_slider_stop_flag = false;
|
||||
|
||||
dprintf("Chunithm LEDs: Closing COM port\n");
|
||||
CloseHandle(chuni_io_slider_led_port);
|
||||
}
|
||||
|
||||
void chuni_io_slider_set_leds(const uint8_t *rgb)
|
||||
{
|
||||
if (chuni_io_slider_led_port != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
char led_buffer[100];
|
||||
DWORD bytes_to_write; // No of bytes to write into the port
|
||||
DWORD bytes_written = 0; // No of bytes written to the port
|
||||
bytes_to_write = sizeof(led_buffer);
|
||||
BOOL status;
|
||||
|
||||
led_buffer[0] = 0xAA;
|
||||
led_buffer[1] = 0xAA;
|
||||
memcpy(led_buffer+2, rgb, sizeof(uint8_t) * 96);
|
||||
led_buffer[98] = 0xDD;
|
||||
led_buffer[99] = 0xDD;
|
||||
|
||||
status = WriteFile(chuni_io_slider_led_port, // Handle to the Serial port
|
||||
led_buffer, // Data to be written to the port
|
||||
bytes_to_write, //No of bytes to write
|
||||
&bytes_written, //Bytes written
|
||||
NULL);
|
||||
}
|
||||
|
||||
led_output_update(2, rgb);
|
||||
}
|
||||
|
||||
static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx)
|
||||
@ -211,3 +165,13 @@ static unsigned int __stdcall chuni_io_slider_thread_proc(void *ctx)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int chuni_io_led_init()
|
||||
{
|
||||
return led_output_init(&chuni_io_cfg);
|
||||
}
|
||||
|
||||
void chuni_io_led_set_colors(uint8_t board, uint8_t *rgb)
|
||||
{
|
||||
led_output_update(board, rgb);
|
||||
}
|
||||
|
@ -145,3 +145,21 @@ void chuni_io_slider_stop(void);
|
||||
Minimum API version: 0x0100 */
|
||||
|
||||
void chuni_io_slider_set_leds(const uint8_t *rgb);
|
||||
|
||||
/* Initialize LED emulation. This function will be called before any
|
||||
other chuni_io_led_*() function calls.
|
||||
|
||||
All subsequent calls may originate from arbitrary threads and some may
|
||||
overlap with each other. Ensuring synchronization inside your IO DLL is
|
||||
your responsibility. */
|
||||
|
||||
int chuni_io_led_init();
|
||||
|
||||
/* Update the RGB LEDs. rgb is a pointer to an array of 66 * 3 = 198
|
||||
bytes. The majority of these are for the marquee display, but the final
|
||||
LEDs are for the side partitions.
|
||||
|
||||
Chunithm uses two chains/boards. One is on the left side and one on the
|
||||
right side of the cab. Exact layout is TBD. */
|
||||
|
||||
void chuni_io_led_set_colors(uint8_t board, uint8_t *rgb);
|
||||
|
@ -57,7 +57,24 @@ void chuni_io_config_load(
|
||||
filename);
|
||||
}
|
||||
|
||||
GetPrivateProfileStringW(L"slider", L"ledport", L"COM5", port_input, 6, filename);
|
||||
wcsncpy(cfg->led_com, L"\\\\.\\", 4);
|
||||
wcsncat_s(cfg->led_com, 11, port_input, 6);
|
||||
cfg->led_output_pipe = GetPrivateProfileIntW(L"led", L"cabLedOutputPipe", 1, filename);
|
||||
cfg->led_output_serial = GetPrivateProfileIntW(L"led", L"cabLedOutputSerial", 0, filename);
|
||||
|
||||
cfg->slider_led_output_pipe = GetPrivateProfileIntW(L"led", L"controllerLedOutputPipe", 1, filename);
|
||||
cfg->slider_led_output_serial = GetPrivateProfileIntW(L"led", L"controllerLedOutputSerial", 0, filename);
|
||||
|
||||
cfg->led_serial_baud = GetPrivateProfileIntW(L"led", L"serialBaud", 921600, filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"led",
|
||||
L"serialPort",
|
||||
L"COM5",
|
||||
port_input,
|
||||
6,
|
||||
filename);
|
||||
|
||||
// Sanitize the output path. If it's a serial COM port, it needs to be prefixed
|
||||
// with `\\.\`.
|
||||
wcsncpy(cfg->led_serial_port, L"\\\\.\\", 4);
|
||||
wcsncat_s(cfg->led_serial_port, 11, port_input, 6);
|
||||
}
|
||||
|
@ -10,7 +10,18 @@ struct chuni_io_config {
|
||||
uint8_t vk_ir_emu;
|
||||
uint8_t vk_ir[6];
|
||||
uint8_t vk_cell[32];
|
||||
wchar_t led_com[12];
|
||||
|
||||
// Which ways to output LED information are enabled
|
||||
bool led_output_pipe;
|
||||
bool led_output_serial;
|
||||
|
||||
bool slider_led_output_pipe;
|
||||
bool slider_led_output_serial;
|
||||
|
||||
// The name of a COM port to output LED data on, in serial mode
|
||||
wchar_t led_serial_port[12];
|
||||
int32_t led_serial_baud;
|
||||
|
||||
};
|
||||
|
||||
void chuni_io_config_load(
|
||||
|
22
chuniio/leddata.h
Normal file
22
chuniio/leddata.h
Normal 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};
|
133
chuniio/ledoutput.c
Normal file
133
chuniio/ledoutput.c
Normal file
@ -0,0 +1,133 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <process.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "chuniio/config.h"
|
||||
#include "chuniio/leddata.h"
|
||||
#include "chuniio/ledoutput.h"
|
||||
#include "chuniio/pipeimpl.h"
|
||||
#include "chuniio/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;
|
||||
|
||||
int 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;
|
||||
|
||||
// Setup 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 byte* 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/ledoutput.h
Normal file
19
chuniio/ledoutput.h
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
LED output functions
|
||||
|
||||
Credits:
|
||||
somewhatlurker, skogaby
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "chuniio/config.h"
|
||||
|
||||
extern HANDLE led_init_mutex;
|
||||
int led_output_init(struct chuni_io_config* const cfg);
|
||||
void led_output_update(uint8_t board, const byte* rgb);
|
@ -9,5 +9,12 @@ chuniio_lib = static_library(
|
||||
'chuniio.h',
|
||||
'config.c',
|
||||
'config.h',
|
||||
'leddata.h',
|
||||
'ledoutput.c',
|
||||
'ledoutput.h',
|
||||
'pipeimpl.c',
|
||||
'pipeimpl.h',
|
||||
'serialimpl.c',
|
||||
'serialimpl.h'
|
||||
],
|
||||
)
|
||||
|
160
chuniio/pipeimpl.c
Normal file
160
chuniio/pipeimpl.c
Normal file
@ -0,0 +1,160 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <process.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "chuniio/leddata.h"
|
||||
#include "chuniio/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/pipeimpl.h
Normal file
14
chuniio/pipeimpl.h
Normal file
@ -0,0 +1,14 @@
|
||||
/*
|
||||
Pipe implementation for chuniio
|
||||
|
||||
Credits:
|
||||
somewhatlurker, skogaby
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "chuniio/leddata.h"
|
||||
|
||||
HRESULT led_pipe_init();
|
||||
void led_pipe_update(struct _chuni_led_data_buf_t* data);
|
99
chuniio/serialimpl.c
Normal file
99
chuniio/serialimpl.c
Normal file
@ -0,0 +1,99 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <process.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "chuniio/leddata.h"
|
||||
#include "chuniio/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/serialimpl.h
Normal file
15
chuniio/serialimpl.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
Serial LED implementation for chuniio
|
||||
|
||||
Credits:
|
||||
somewhatlurker, skogaby
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "chuniio/leddata.h"
|
||||
|
||||
HRESULT led_serial_init(wchar_t led_com[12], DWORD baud);
|
||||
void led_serial_update(struct _chuni_led_data_buf_t* data);
|
Reference in New Issue
Block a user