Bemanitools v5.26 release
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
dlls += ddrio-smx
|
||||
imps += SMX
|
||||
|
||||
deplibs_ddrio-smx := \
|
||||
SMX \
|
||||
|
||||
libs_ddrio-smx := \
|
||||
geninput \
|
||||
util \
|
||||
|
||||
src_ddrio-smx := \
|
||||
ddrio.c \
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
LIBRARY ddrio-smx
|
||||
|
||||
EXPORTS
|
||||
ddr_io_set_loggers
|
||||
ddr_io_fini
|
||||
ddr_io_init
|
||||
ddr_io_read_pad
|
||||
ddr_io_set_lights_extio
|
||||
ddr_io_set_lights_p3io
|
||||
@@ -0,0 +1,212 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "bemanitools/ddrio.h"
|
||||
#include "bemanitools/input.h"
|
||||
|
||||
#include "imports/avs.h"
|
||||
#include "imports/SMX.h"
|
||||
|
||||
#include "util/defs.h"
|
||||
#include "util/log.h"
|
||||
|
||||
struct ddr_io_smx_pad_map {
|
||||
int pad_no;
|
||||
uint16_t smx_bit;
|
||||
uint32_t ddr_bit;
|
||||
};
|
||||
|
||||
struct ddr_io_smx_light_map {
|
||||
uint32_t extio_bit;
|
||||
int smx_light_offset;
|
||||
unsigned char r;
|
||||
unsigned char g;
|
||||
unsigned char b;
|
||||
};
|
||||
|
||||
static void ddr_io_smx_callback(
|
||||
int pad_no,
|
||||
enum SMXUpdateCallbackReason reason,
|
||||
void *ctx);
|
||||
|
||||
static const struct ddr_io_smx_pad_map ddr_io_smx_pad_map[] = {
|
||||
{ 0, 1 << 1, 1 << DDR_P1_UP },
|
||||
{ 0, 1 << 3, 1 << DDR_P1_LEFT },
|
||||
{ 0, 1 << 5, 1 << DDR_P1_RIGHT },
|
||||
{ 0, 1 << 7, 1 << DDR_P1_DOWN },
|
||||
|
||||
{ 1, 1 << 1, 1 << DDR_P2_UP },
|
||||
{ 1, 1 << 3, 1 << DDR_P2_LEFT },
|
||||
{ 1, 1 << 5, 1 << DDR_P2_RIGHT },
|
||||
{ 1, 1 << 7, 1 << DDR_P2_DOWN },
|
||||
};
|
||||
|
||||
static const struct ddr_io_smx_light_map ddr_io_smx_light_map[] = {
|
||||
/* Light L/R blue and U/D red to match DDR pad color scheme */
|
||||
|
||||
{ 1 << LIGHT_P1_UP, 48 * 1, 0xFF, 0x00, 0x00 },
|
||||
{ 1 << LIGHT_P1_LEFT, 48 * 3, 0x00, 0x00, 0xFF },
|
||||
{ 1 << LIGHT_P1_RIGHT, 48 * 5, 0x00, 0x00, 0xFF },
|
||||
{ 1 << LIGHT_P1_DOWN, 48 * 7, 0xFF, 0x00, 0x00 },
|
||||
|
||||
{ 1 << LIGHT_P2_UP, 48 * 10, 0xFF, 0x00, 0x00 },
|
||||
{ 1 << LIGHT_P2_LEFT, 48 * 12, 0x00, 0x00, 0xFF },
|
||||
{ 1 << LIGHT_P2_RIGHT, 48 * 14, 0x00, 0x00, 0xFF },
|
||||
{ 1 << LIGHT_P2_DOWN, 48 * 16, 0xFF, 0x00, 0x00 },
|
||||
};
|
||||
|
||||
static _Atomic uint32_t ddr_io_smx_pad_state[2];
|
||||
static CRITICAL_SECTION ddr_io_smx_lights_lock;
|
||||
static uint8_t ddr_io_smx_lights_counter;
|
||||
static char ddr_io_smx_lights[864];
|
||||
|
||||
void ddr_io_set_loggers(
|
||||
log_formatter_t misc,
|
||||
log_formatter_t info,
|
||||
log_formatter_t warning,
|
||||
log_formatter_t fatal)
|
||||
{
|
||||
log_to_external(misc, info, warning, fatal);
|
||||
input_set_loggers(misc, info, warning, fatal);
|
||||
|
||||
/* We would need a log server thread to accept log messages from SMX, since
|
||||
it uses raw Win32 threads and not AVS threads (only AVS threads are
|
||||
permitted to use the AVS logging API). So it's not really worth it. */
|
||||
}
|
||||
|
||||
bool ddr_io_init(
|
||||
thread_create_t thread_create,
|
||||
thread_join_t thread_join,
|
||||
thread_destroy_t thread_destroy)
|
||||
{
|
||||
/* Use geninput for menu/operator btns */
|
||||
|
||||
input_init(thread_create, thread_join, thread_destroy);
|
||||
mapper_config_load("ddr");
|
||||
|
||||
/* Start up SMX API */
|
||||
|
||||
log_info("Starting SMX.DLL");
|
||||
log_info("SMX.DLL version: %s", "[predates SMX_Version()]");
|
||||
SMX_Start(ddr_io_smx_callback, NULL);
|
||||
log_info("Started SMX.DLL");
|
||||
|
||||
InitializeCriticalSection(&ddr_io_smx_lights_lock);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t ddr_io_read_pad(void)
|
||||
{
|
||||
/* SMX pads require a constant stream of lighting updates or they will
|
||||
quickly revert to autonomous lighting control. Here is a hacky way of
|
||||
feeding that light data to the pad. Hopefully it won't starve anything
|
||||
important.
|
||||
|
||||
Changing the light state causes the counter to reset, and the counter
|
||||
itself ought to roll over at a rate of about 4 Hz. */
|
||||
|
||||
EnterCriticalSection(&ddr_io_smx_lights_lock);
|
||||
|
||||
if (ddr_io_smx_lights_counter == 0) {
|
||||
SMX_SetLights(ddr_io_smx_lights);
|
||||
}
|
||||
|
||||
ddr_io_smx_lights_counter++;
|
||||
|
||||
LeaveCriticalSection(&ddr_io_smx_lights_lock);
|
||||
|
||||
/* Sleep first: input is timestamped immediately AFTER the ioctl returns.
|
||||
|
||||
Which is the right thing to do, for once. We sleep here because
|
||||
the game polls input in a tight loop. Can't complain, at there isn't
|
||||
an artificial limit on the poll frequency. */
|
||||
|
||||
Sleep(1);
|
||||
|
||||
/* We don't atomically read both pads, but they are separate USB devices
|
||||
so they don't update in lockstep anyway. */
|
||||
|
||||
return mapper_update() |
|
||||
atomic_load(&ddr_io_smx_pad_state[0]) |
|
||||
atomic_load(&ddr_io_smx_pad_state[1]) ;
|
||||
}
|
||||
|
||||
void ddr_io_set_lights_extio(uint32_t lights)
|
||||
{
|
||||
const struct ddr_io_smx_light_map *map;
|
||||
size_t offset;
|
||||
size_t i;
|
||||
size_t j;
|
||||
|
||||
EnterCriticalSection(&ddr_io_smx_lights_lock);
|
||||
|
||||
ddr_io_smx_lights_counter = 0;
|
||||
memset(ddr_io_smx_lights, 0, sizeof(ddr_io_smx_lights));
|
||||
|
||||
for (i = 0 ; i < lengthof(ddr_io_smx_light_map) ; i++) {
|
||||
map = &ddr_io_smx_light_map[i];
|
||||
|
||||
if (lights & map->extio_bit) {
|
||||
offset = map->smx_light_offset;
|
||||
|
||||
for (j = 0 ; j < 48 ; j += 3) {
|
||||
ddr_io_smx_lights[offset + j ] = map->r;
|
||||
ddr_io_smx_lights[offset + j + 1] = map->g;
|
||||
ddr_io_smx_lights[offset + j + 2] = map->b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&ddr_io_smx_lights_lock);
|
||||
}
|
||||
|
||||
void ddr_io_set_lights_p3io(uint32_t lights)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0x0E; i <= 0x1E; i++) {
|
||||
mapper_write_light(i, lights & (1 << i) ? 255 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
void ddr_io_fini(void)
|
||||
{
|
||||
log_info("Stopping SMX.DLL");
|
||||
SMX_Stop();
|
||||
log_info("Stopped SMX.DLL");
|
||||
|
||||
DeleteCriticalSection(&ddr_io_smx_lights_lock);
|
||||
input_fini();
|
||||
}
|
||||
|
||||
static void ddr_io_smx_callback(
|
||||
int pad_no,
|
||||
enum SMXUpdateCallbackReason reason,
|
||||
void *ctx)
|
||||
{
|
||||
const struct ddr_io_smx_pad_map *map;
|
||||
uint16_t smx_state;
|
||||
uint32_t ddr_state;
|
||||
size_t i;
|
||||
|
||||
if (pad_no < 0 || pad_no > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
smx_state = SMX_GetInputState(pad_no);
|
||||
ddr_state = 0;
|
||||
|
||||
for (i = 0 ; i < lengthof(ddr_io_smx_pad_map) ; i++) {
|
||||
map = &ddr_io_smx_pad_map[i];
|
||||
|
||||
if (pad_no == map->pad_no && (smx_state & map->smx_bit) != 0) {
|
||||
ddr_state |= map->ddr_bit;
|
||||
}
|
||||
}
|
||||
|
||||
atomic_store(&ddr_io_smx_pad_state[pad_no], ddr_state);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user