1
0
mirror of https://github.com/djhackersdev/bemanitools.git synced 2024-11-28 00:10:51 +01:00

sdvxio-bio2: Add sdvxio BIO2 along with bio2drv and aciotest updates

This commit is contained in:
Will Xyen 2020-08-14 06:25:27 -07:00 committed by adfe3beeadc615e0fa48b493761cc42aae47d399
parent 4c0f60fc93
commit ff1b9ff9a2
15 changed files with 919 additions and 1 deletions

View File

@ -78,6 +78,7 @@ include src/main/aciodrv/Module.mk
include src/main/acioemu/Module.mk include src/main/acioemu/Module.mk
include src/main/aciotest/Module.mk include src/main/aciotest/Module.mk
include src/main/asio/Module.mk include src/main/asio/Module.mk
include src/main/bio2drv/Module.mk
include src/main/bio2emu/Module.mk include src/main/bio2emu/Module.mk
include src/main/bio2emu-iidx/Module.mk include src/main/bio2emu-iidx/Module.mk
include src/main/bsthook/Module.mk include src/main/bsthook/Module.mk
@ -142,6 +143,7 @@ include src/main/sdvxhook2/Module.mk
include src/main/sdvxhook2-cn/Module.mk include src/main/sdvxhook2-cn/Module.mk
include src/main/sdvxio/Module.mk include src/main/sdvxio/Module.mk
include src/main/sdvxio-kfca/Module.mk include src/main/sdvxio-kfca/Module.mk
include src/main/sdvxio-bio2/Module.mk
include src/main/security/Module.mk include src/main/security/Module.mk
include src/main/unicorntail/Module.mk include src/main/unicorntail/Module.mk
include src/main/util/Module.mk include src/main/util/Module.mk
@ -416,6 +418,7 @@ $(zipdir)/sdvx-01-to-04.zip: \
build/bin/indep-32/geninput.dll \ build/bin/indep-32/geninput.dll \
build/bin/indep-32/sdvxio.dll \ build/bin/indep-32/sdvxio.dll \
build/bin/indep-32/sdvxio-kfca.dll \ build/bin/indep-32/sdvxio-kfca.dll \
build/bin/indep-32/sdvxio-bio2.dll \
dist/sdvx/config.bat \ dist/sdvx/config.bat \
dist/sdvx/gamestart.bat \ dist/sdvx/gamestart.bat \
| $(zipdir)/ | $(zipdir)/
@ -430,6 +433,7 @@ $(zipdir)/sdvx-05.zip: \
build/bin/indep-64/geninput.dll \ build/bin/indep-64/geninput.dll \
build/bin/indep-64/sdvxio.dll \ build/bin/indep-64/sdvxio.dll \
build/bin/indep-64/sdvxio-kfca.dll \ build/bin/indep-64/sdvxio-kfca.dll \
build/bin/indep-64/sdvxio-bio2.dll \
dist/sdvx5/config.bat \ dist/sdvx5/config.bat \
dist/sdvx5/gamestart.bat \ dist/sdvx5/gamestart.bat \
dist/sdvx5/sdvxhook2.conf \ dist/sdvx5/sdvxhook2.conf \

View File

@ -1,10 +1,12 @@
exes += aciotest exes += aciotest
libs_aciotest := \ libs_aciotest := \
bio2drv \
aciodrv \ aciodrv \
util \ util \
src_aciotest := \ src_aciotest := \
icca.c \ icca.c \
kfca.c \ kfca.c \
bi2a-sdvx.c \
main.c \ main.c \

View File

@ -0,0 +1,58 @@
#include "aciotest/bi2a-sdvx.h"
#include "acio/acio.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bio2drv/bi2a-sdvx.h"
bool aciotest_bi2a_sdvx_handler_init(uint8_t node_id, void **ctx)
{
*ctx = malloc(sizeof(uint32_t));
*((uint32_t *) *ctx) = 0;
return bio2drv_bi2a_sdvx_init(node_id);
}
bool aciotest_bi2a_sdvx_handler_update(uint8_t node_id, void *ctx)
{
struct bi2a_sdvx_state_in pin;
struct bi2a_sdvx_state_out pout;
memset(&pout, 0, sizeof(pout));
if (!bio2drv_bi2a_sdvx_poll(node_id, &pout, &pin)) {
return false;
}
pin.raw[0] = ac_io_u16(pin.raw[0]);
pin.raw[1] = ac_io_u16(pin.raw[1]);
printf(
">>> BI2A (SDVX) %d:\n"
"BTN A B C D: %d %d %d %d\n"
"FX-L R: %d %d\n"
"VOL L: %d\n"
"VOL R: %d\n"
"START COIN TEST SERV REC HP: %d %d %d %d %d %d\n",
node_id,
pin.buttons_1.b_a,
pin.buttons_1.b_b,
pin.buttons_1.b_c,
pin.buttons_1.b_d,
pin.buttons_1.b_fxl,
pin.buttons_2.b_fxr,
pin.analogs[0].a_val,
pin.analogs[1].a_val,
pin.buttons_1.b_start,
pin.analogs[0].a_coin,
pin.analogs[0].a_test,
pin.analogs[0].a_service,
pin.buttons_1.b_recorder,
pin.buttons_1.b_headphone);
return true;
}

View File

@ -0,0 +1,10 @@
#ifndef ACIOTEST_BI2A_SDVX_H
#define ACIOTEST_BI2A_SDVX_H
#include <stdbool.h>
#include <stdint.h>
bool aciotest_bi2a_sdvx_handler_init(uint8_t node_id, void **ctx);
bool aciotest_bi2a_sdvx_handler_update(uint8_t node_id, void *ctx);
#endif

View File

@ -9,10 +9,12 @@
#include "aciotest/handler.h" #include "aciotest/handler.h"
#include "aciotest/icca.h" #include "aciotest/icca.h"
#include "aciotest/kfca.h" #include "aciotest/kfca.h"
#include "aciotest/bi2a-sdvx.h"
#include "util/log.h" #include "util/log.h"
static uint8_t aciotest_cnt = 0; static uint8_t aciotest_cnt = 0;
static uint8_t bi2a_mode = 0;
/** /**
* Enumerate supported ACIO nodes based on their product id. * Enumerate supported ACIO nodes based on their product id.
@ -35,6 +37,17 @@ static bool aciotest_assign_handler(
return true; return true;
} }
if (!memcmp(product, "BI2A", 4)) {
if (bi2a_mode == 0) {
handler->init = aciotest_bi2a_sdvx_handler_init;
handler->update = aciotest_bi2a_sdvx_handler_update;
return true;
} else {
printf("Unknown BI2A device specified");
}
}
return false; return false;
} }
@ -125,7 +138,7 @@ int main(int argc, char **argv)
} }
/* avoid cpu banging */ /* avoid cpu banging */
Sleep(20); Sleep(30);
} }
return 0; return 0;

View File

@ -0,0 +1,9 @@
libs += bio2drv
libs_bio2drv := \
aciodrv
src_bio2drv := \
detect.c \
config-bio2.c \
bi2a-sdvx.c \

View File

@ -0,0 +1,138 @@
#define LOG_MODULE "bio2drv-bi2a_sdvx"
#include "bio2drv/bi2a-sdvx.h"
#include <stdio.h>
#include <string.h>
#include "aciodrv/device.h"
#include "util/log.h"
// this is probably InitIO
static bool bio2drv_bi2a_sdvx_init_io(uint8_t node_id)
{
struct ac_io_message msg;
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_CLEAR);
msg.cmd.nbytes = 1;
msg.cmd.count = 0x3B;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Init node failed");
return 0;
}
log_warning("Init of node %d, status: %d", node_id, msg.cmd.status);
return 1;
}
static bool bio2drv_bi2a_sdvx_watchdog_start(uint8_t node_id)
{
// exit early and don't actually call watchdog
// the watchdog call actually returns different sized packets depending on
// the state this results in an issue during packet processing (see: #68)
return true;
/*
struct ac_io_message msg;
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_WATCHDOG);
msg.cmd.nbytes = 2;
msg.cmd.nbytes = 2;
// uint16_t: 6000
msg.cmd.raw[0] = 23;
msg.cmd.raw[1] = 112;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + 2
)) {
log_warning("Starting watchdog failed"); return false;
}
log_warning("Started watchdog of node %d, status: %d",
node_id, msg.cmd.status);
return true;
*/
}
bool bio2drv_bi2a_sdvx_amp(
uint8_t node_id,
uint8_t unused_1,
uint8_t unused_2,
uint8_t left,
uint8_t right)
{
struct ac_io_message msg;
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_AMP_CONTROL);
msg.cmd.nbytes = 4;
// the BIO2 DOES NOT MATCH THE KFCA for what these mean
// 0 and 1 are ignored, 2 and 3 seem to map to left/right for ALL 3 AMPS
// in the future, maybe use windows APIs and write the volume levels there
msg.cmd.raw[0] = unused_1;
msg.cmd.raw[1] = unused_2;
msg.cmd.raw[2] = left;
msg.cmd.raw[3] = right;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + 1)) {
log_warning("Setting AMP failed");
return false;
}
log_warning("Started AMP node %d", node_id);
return true;
}
bool bio2drv_bi2a_sdvx_init(uint8_t node_id)
{
if (!bio2drv_bi2a_sdvx_init_io(node_id)) {
return false;
}
if (!bio2drv_bi2a_sdvx_watchdog_start(node_id)) {
return false;
}
if (!bio2drv_bi2a_sdvx_amp(node_id, 0, 0, 0, 0)) {
return false;
}
return true;
}
bool bio2drv_bi2a_sdvx_poll(
uint8_t node_id,
const struct bi2a_sdvx_state_out *pout,
struct bi2a_sdvx_state_in *pin)
{
struct ac_io_message msg;
msg.addr = node_id + 1;
msg.cmd.code = ac_io_u16(AC_IO_CMD_KFCA_POLL);
msg.cmd.nbytes = sizeof(*pout);
/* buffer size of data we expect */
*(struct bi2a_sdvx_state_out *) msg.cmd.raw = *pout;
if (!aciodrv_send_and_recv(
&msg, offsetof(struct ac_io_message, cmd.raw) + sizeof(*pin))) {
log_warning("Polling of node %d failed", node_id + 1);
return false;
}
if (pin != NULL) {
memcpy(pin, &msg.cmd.raw, sizeof(*pin));
}
return true;
}

View File

@ -0,0 +1,51 @@
#ifndef BIO2DRV_BI2A_H
#define BIO2DRV_BI2A_H
#include "bio2/bi2a-sdvx.h"
/**
* Initialize a BI2A node.
*
* @param node_id Id of the node to initialize (0 based).
* @return True if successful, false on error.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool bio2drv_bi2a_sdvx_init(uint8_t node_id);
/**
* Poll the board
*
* @param node_id Id of the node to query (0 based).
* @param state Pointer to a state struct to return the current state to
* (optional, NULL for none).
* @return True on success, false on error.
* @note This module is supposed to be used in combination with the common
* device driver foundation.
* @see driver.h
*/
bool bio2drv_bi2a_sdvx_poll(
uint8_t node_id,
const struct bi2a_sdvx_state_out *pout,
struct bi2a_sdvx_state_in *pin);
/**
* Set the BIO2 BI2A SDVX digital amp level
*
* @param node_id Id of the node to query (0 based).
* @param primary primary volume (96-0)
* @param headphone headphone volume (96-0)
* @param unused unknown volume (96-0) (unused)
* @param subwoofer subwoofer volume (96-0)
* @return True on success, false on error.
* @note Note 96 is lowest volume level, 0 is highest
*/
bool bio2drv_bi2a_sdvx_amp(
uint8_t node_id,
uint8_t unused_1,
uint8_t unused_2,
uint8_t left,
uint8_t right);
#endif

View File

@ -0,0 +1,75 @@
#include "cconfig/cconfig-util.h"
#include "bio2drv/config-bio2.h"
#include "util/log.h"
#define BIO2DRV_CONFIG_BIO2_AUTO_KEY "bio2.autodetect"
#define BIO2DRV_CONFIG_BIO2_PORT_KEY "bio2.port"
#define BIO2DRV_CONFIG_BIO2_BAUD_KEY "bio2.baud"
#define BIO2DRV_CONFIG_BIO2_DEFAULT_AUTO_VALUE true
#define BIO2DRV_CONFIG_BIO2_DEFAULT_PORT_VALUE "COM4"
#define BIO2DRV_CONFIG_BIO2_DEFAULT_BAUD_VALUE 115200
void bio2drv_config_bio2_init(struct cconfig *config)
{
cconfig_util_set_bool(
config,
BIO2DRV_CONFIG_BIO2_AUTO_KEY,
BIO2DRV_CONFIG_BIO2_DEFAULT_AUTO_VALUE,
"Autodetect BIO2 port (default: on)");
cconfig_util_set_str(
config,
BIO2DRV_CONFIG_BIO2_PORT_KEY,
BIO2DRV_CONFIG_BIO2_DEFAULT_PORT_VALUE,
"BIO2 serial port");
cconfig_util_set_int(
config,
BIO2DRV_CONFIG_BIO2_BAUD_KEY,
BIO2DRV_CONFIG_BIO2_DEFAULT_BAUD_VALUE,
"BIO2 bus baudrate (real devices expect 115200)");
}
void bio2drv_config_bio2_get(
struct bio2drv_config_bio2 *config_bio2, struct cconfig *config)
{
if (!cconfig_util_get_bool(
config,
BIO2DRV_CONFIG_BIO2_AUTO_KEY,
&config_bio2->autodetect,
BIO2DRV_CONFIG_BIO2_DEFAULT_AUTO_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%d'",
BIO2DRV_CONFIG_BIO2_AUTO_KEY,
BIO2DRV_CONFIG_BIO2_DEFAULT_AUTO_VALUE);
}
if (!cconfig_util_get_str(
config,
BIO2DRV_CONFIG_BIO2_PORT_KEY,
config_bio2->port,
sizeof(config_bio2->port) - 1,
BIO2DRV_CONFIG_BIO2_DEFAULT_PORT_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%s'",
BIO2DRV_CONFIG_BIO2_PORT_KEY,
BIO2DRV_CONFIG_BIO2_DEFAULT_PORT_VALUE);
}
if (!cconfig_util_get_int(
config,
BIO2DRV_CONFIG_BIO2_BAUD_KEY,
&config_bio2->baud,
BIO2DRV_CONFIG_BIO2_DEFAULT_BAUD_VALUE)) {
log_warning(
"Invalid value for key '%s' specified, fallback "
"to default '%d'",
BIO2DRV_CONFIG_BIO2_BAUD_KEY,
BIO2DRV_CONFIG_BIO2_DEFAULT_BAUD_VALUE);
}
}

View File

@ -0,0 +1,19 @@
#ifndef BIO2DRV_CONFIG_BIO2_H
#define BIO2DRV_CONFIG_BIO2_H
#include <windows.h>
#include "cconfig/cconfig.h"
struct bio2drv_config_bio2 {
bool autodetect;
char port[64];
int32_t baud;
};
void bio2drv_config_bio2_init(struct cconfig *config);
void bio2drv_config_bio2_get(
struct bio2drv_config_bio2 *config_bio2, struct cconfig *config);
#endif

163
src/main/bio2drv/detect.c Normal file
View File

@ -0,0 +1,163 @@
#define LOG_MODULE "bio2drv-detect"
#include <initguid.h>
#include <windows.h>
#include <cfgmgr32.h>
#include <setupapi.h>
#include "bio2drv/detect.h"
#include <stdio.h>
#include <string.h>
#include "util/log.h"
DEFINE_GUID(
GUID_COM_BUS_ENUMERATOR,
0x4D36E978,
0xE325,
0x11CE,
0xBF,
0xC1,
0x08,
0x00,
0x2B,
0xE1,
0x03,
0x18);
static char work_buffer[0x400];
static bool check_property(
HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA PDeviceInfoData, DWORD property)
{
if (SetupDiGetDeviceRegistryPropertyA(
DeviceInfoSet,
PDeviceInfoData,
property,
NULL,
(BYTE *) work_buffer,
sizeof(work_buffer),
NULL)) {
if (strstr(work_buffer, "BIO2(VIDEO)")) {
log_info("Found matching device: %s", work_buffer);
return true;
}
}
log_info("Device with property: %s does not match", work_buffer);
return false;
}
static bool check_id(
HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA PDeviceInfoData)
{
if (CM_Get_Device_IDA(PDeviceInfoData->DevInst, work_buffer, sizeof(work_buffer), 0)) {
return false;
}
if (strstr(work_buffer, "VID_1CCF&PID_804C")) {
log_info("Found matching device: %s", work_buffer);
return true;
}
if (strstr(work_buffer, "VID_1CCF&PID_8040")) {
log_info("Found matching device: %s", work_buffer);
return true;
}
log_info("Device with ID: %s does not match", work_buffer);
return false;
}
static bool get_device_by_filter(
bool id_filter, DWORD property, size_t devnum, char *path, size_t length)
{
HDEVINFO DeviceInfoSet = SetupDiGetClassDevsA(
&GUID_COM_BUS_ENUMERATOR, NULL, NULL, DIGCF_PRESENT);
if (DeviceInfoSet == INVALID_HANDLE_VALUE) {
return false;
}
SP_DEVINFO_DATA DeviceInfoData;
ZeroMemory(&DeviceInfoData, sizeof(SP_DEVINFO_DATA));
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
DWORD idx = 0;
size_t num_found = 0;
while (SetupDiEnumDeviceInfo(DeviceInfoSet, idx, &DeviceInfoData)) {
HKEY DeviceRegKey = SetupDiOpenDevRegKey(
DeviceInfoSet,
&DeviceInfoData,
DICS_FLAG_GLOBAL,
0,
DIREG_DEV,
KEY_QUERY_VALUE);
if (DeviceRegKey) {
bool found = false;
log_info("Found a serial device at index: %d", idx);
if (!id_filter) {
if (check_property(DeviceInfoSet, &DeviceInfoData, property)) {
found = true;
}
} else {
if (check_id(DeviceInfoSet, &DeviceInfoData)) {
found = true;
}
}
if (found) {
if (num_found == devnum) {
DWORD path_length = length;
RegQueryValueExA(
DeviceRegKey,
"PortName",
0,
NULL,
(BYTE *) path,
&path_length);
log_info("Using port: %s", path);
return true;
}
num_found++;
}
}
++idx;
}
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
log_warning("No matching device found");
return false;
}
void bio2drv_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);
}
bool bio2drv_detect(
enum bio2drv_detect_mode mode, size_t index, char *path, size_t length)
{
if (mode == DETECT_DEVICEDESC) {
return get_device_by_filter(
false, SPDRP_DEVICEDESC, index, path, length);
} else if (mode == DETECT_FRIENDLYNAME) {
return get_device_by_filter(
false, SPDRP_FRIENDLYNAME, index, path, length);
} else if (mode == DETECT_DEVICEID) {
return get_device_by_filter(true, -1, index, path, length);
}
log_warning("Unknown autodetect mode: %d", mode);
return false;
}

23
src/main/bio2drv/detect.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef BIO2DRV_DETECT_H
#define BIO2DRV_DETECT_H
#include <stdbool.h>
#include "bemanitools/glue.h"
enum bio2drv_detect_mode {
DETECT_DEVICEDESC = 0x1, // look for serial devices containing BIO2(VIDEO)
DETECT_FRIENDLYNAME = 0x2, // look for serial devices containing BIO2(VIDEO)
DETECT_DEVICEID = 0x3, // look for serial devices by vid/pid
};
void bio2drv_set_loggers(
log_formatter_t misc,
log_formatter_t info,
log_formatter_t warning,
log_formatter_t fatal);
bool bio2drv_detect(
enum bio2drv_detect_mode mode, size_t devnum, char *path, size_t length);
#endif

View File

@ -0,0 +1,14 @@
dlls += sdvxio-bio2
ldflags_sdvxio-bio2 := \
-lsetupapi \
libs_sdvxio-bio2 := \
aciodrv \
bio2drv \
cconfig \
util \
src_sdvxio-bio2 := \
sdvxio.c \

View File

@ -0,0 +1,15 @@
LIBRARY sdvxio-bio2
EXPORTS
sdvx_io_fini
sdvx_io_get_input_gpio
sdvx_io_get_input_gpio_sys
sdvx_io_get_spinner_pos
sdvx_io_init
sdvx_io_read_input
sdvx_io_set_gpio_lights
sdvx_io_set_loggers
sdvx_io_set_pwm_light
sdvx_io_write_output
sdvx_io_set_amp_volume
_bio2_sdvx_io_poll

View File

@ -0,0 +1,324 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "bemanitools/glue.h"
#include "bemanitools/sdvxio.h"
#include "cconfig/cconfig-main.h"
#include "aciodrv/device.h"
#include "bio2drv/bi2a-sdvx.h"
#include "bio2drv/config-bio2.h"
#include "bio2drv/detect.h"
#define LOG_MODULE "sdvxio-bio2"
#define log_misc(...) sdvx_io_log_misc(LOG_MODULE, __VA_ARGS__)
#define log_info(...) sdvx_io_log_info(LOG_MODULE, __VA_ARGS__)
#define log_warning(...) sdvx_io_log_warning(LOG_MODULE, __VA_ARGS__)
#define log_fatal(...) sdvx_io_log_fatal(LOG_MODULE, __VA_ARGS__)
static log_formatter_t sdvx_io_log_misc;
static log_formatter_t sdvx_io_log_info;
static log_formatter_t sdvx_io_log_warning;
static log_formatter_t sdvx_io_log_fatal;
static uint16_t sdvx_io_gpio[2];
static uint8_t sdvx_io_gpio_sys;
static uint16_t sdvx_io_analog[2];
static char autodetect_buffer[512];
static bool running;
static bool processing_io;
static int16_t bio2_node_id;
uint8_t wing_staging[12];
struct bi2a_sdvx_state_out pout_staging;
struct bi2a_sdvx_state_out pout_ready;
void sdvx_io_set_loggers(
log_formatter_t misc,
log_formatter_t info,
log_formatter_t warning,
log_formatter_t fatal)
{
sdvx_io_log_misc = misc;
sdvx_io_log_info = info;
sdvx_io_log_warning = warning;
sdvx_io_log_fatal = fatal;
bio2drv_set_loggers(misc, info, warning, fatal);
}
bool sdvx_io_init(
thread_create_t thread_create,
thread_join_t thread_join,
thread_destroy_t thread_destroy)
{
struct cconfig *config;
struct bio2drv_config_bio2 config_bio2;
config = cconfig_init();
bio2drv_config_bio2_init(config);
if (!cconfig_main_config_init(
config,
"--bio2-config",
"sdvxio-bio2.conf",
"--help",
"-h",
"sdvxio-bio2",
CCONFIG_CMD_USAGE_OUT_STDOUT)) {
cconfig_finit(config);
exit(EXIT_FAILURE);
}
bio2drv_config_bio2_get(&config_bio2, config);
cconfig_finit(config);
const char *selected_port = config_bio2.port;
if (config_bio2.autodetect) {
log_info("Attempting autodetect");
if (bio2drv_detect(
DETECT_DEVICEID,
0,
autodetect_buffer,
sizeof(autodetect_buffer))) {
selected_port = autodetect_buffer;
} else {
log_info("Autodetect failed, falling back to using specified port");
}
}
if (!aciodrv_device_open(selected_port, config_bio2.baud)) {
log_info("Opening BIO2 device on [%s] failed", selected_port);
return 0;
}
log_info("Opening BIO2 device on [%s] successful", selected_port);
uint8_t node_count = aciodrv_device_get_node_count();
log_info("Enumerated %d nodes", node_count);
bio2_node_id = -1;
for (uint8_t i = 0; i < node_count; i++) {
char product[4];
aciodrv_device_get_node_product_ident(i, product);
log_info(
"> %d: %c%c%c%c\n",
i,
product[0],
product[1],
product[2],
product[3]);
if (!memcmp(product, "BI2A", 4)) {
if (bio2_node_id != -1) {
log_warning("Multiple BI2A found! Using highest node id.");
}
bio2_node_id = i;
}
}
if (bio2_node_id != -1) {
log_warning("Using BI2A on node: %d", bio2_node_id);
if (!bio2drv_bi2a_sdvx_init(bio2_node_id)) {
log_warning("Unable to start BI2A on node: %d", bio2_node_id);
return false;
}
running = true;
log_warning("sdvxio-bio2 now running");
} else {
log_warning("No KFCA device found");
}
return running;
}
void sdvx_io_fini(void)
{
running = false;
while (processing_io) {
}
}
static uint8_t assign_light(uint32_t gpio_lights, uint32_t shift)
{
uint32_t shifted = (1 << shift);
if ((gpio_lights & shifted) == shifted) {
return 255;
}
return 0;
}
void sdvx_io_set_gpio_lights(uint32_t gpio_lights)
{
pout_staging.gpio[0] = assign_light(gpio_lights, SDVX_IO_OUT_GPIO_START);
pout_staging.gpio[1] = assign_light(gpio_lights, SDVX_IO_OUT_GPIO_A);
pout_staging.gpio[2] = assign_light(gpio_lights, SDVX_IO_OUT_GPIO_B);
pout_staging.gpio[3] = assign_light(gpio_lights, SDVX_IO_OUT_GPIO_C);
pout_staging.gpio[4] = assign_light(gpio_lights, SDVX_IO_OUT_GPIO_D);
pout_staging.gpio[5] = assign_light(gpio_lights, SDVX_IO_OUT_GPIO_FX_L);
pout_staging.gpio[6] = assign_light(gpio_lights, SDVX_IO_OUT_GPIO_FX_R);
}
void sdvx_io_set_pwm_light(uint8_t light_no, uint8_t intensity)
{
if (light_no < 12) {
wing_staging[light_no] = intensity;
} else {
switch (light_no) {
case 12:
pout_staging.woof_r = intensity;
break;
case 13:
pout_staging.woof_g = intensity;
break;
case 14:
pout_staging.woof_b = intensity;
break;
case 15:
pout_staging.controller[0] = intensity;
break;
case 16:
pout_staging.controller[1] = intensity;
break;
case 17:
pout_staging.controller[2] = intensity;
break;
default:
break;
}
}
}
bool sdvx_io_write_output(void)
{
memcpy(&pout_ready, &pout_staging, sizeof(struct bi2a_sdvx_state_out));
pout_ready.wingUpper[0] = wing_staging[0] / 2 + wing_staging[3] / 2;
pout_ready.wingUpper[1] = wing_staging[1] / 2 + wing_staging[4] / 2;
pout_ready.wingUpper[2] = wing_staging[2] / 2 + wing_staging[5] / 2;
pout_ready.wingLower[0] = wing_staging[6] / 2 + wing_staging[9] / 2;
pout_ready.wingLower[1] = wing_staging[7] / 2 + wing_staging[10] / 2;
pout_ready.wingLower[2] = wing_staging[8] / 2 + wing_staging[11] / 2;
return true;
}
static uint8_t shift_pin(uint16_t value, uint8_t pin)
{
if (value) {
return (1 << pin);
}
return 0;
}
bool _bio2_sdvx_io_poll(
const struct bi2a_sdvx_state_out *pout, struct bi2a_sdvx_state_in *pin)
{
if (!running) {
return false;
}
processing_io = true;
if (!bio2drv_bi2a_sdvx_poll(bio2_node_id, pout, pin)) {
processing_io = false;
return false;
}
processing_io = false;
return true;
}
bool sdvx_io_read_input(void)
{
struct bi2a_sdvx_state_in pin;
if (!_bio2_sdvx_io_poll(&pout_ready, &pin)) {
return false;
}
pin.raw[0] = ac_io_u16(pin.raw[0]);
pin.raw[1] = ac_io_u16(pin.raw[1]);
sdvx_io_analog[0] = pin.analogs[0].a_val;
sdvx_io_analog[1] = pin.analogs[1].a_val;
sdvx_io_gpio_sys = 0;
sdvx_io_gpio_sys |=
shift_pin(pin.analogs[0].a_coin, SDVX_IO_IN_GPIO_SYS_COIN);
sdvx_io_gpio_sys |=
shift_pin(pin.analogs[0].a_test, SDVX_IO_IN_GPIO_SYS_TEST);
sdvx_io_gpio_sys |=
shift_pin(pin.analogs[0].a_service, SDVX_IO_IN_GPIO_SYS_SERVICE);
sdvx_io_gpio[0] = 0;
sdvx_io_gpio[1] = 0;
sdvx_io_gpio[0] |=
shift_pin(pin.buttons_1.b_start, SDVX_IO_IN_GPIO_0_START);
sdvx_io_gpio[0] |=
shift_pin(pin.buttons_1.b_headphone, SDVX_IO_IN_GPIO_0_HEADPHONE);
sdvx_io_gpio[0] |= shift_pin(pin.buttons_1.b_a, SDVX_IO_IN_GPIO_0_A);
sdvx_io_gpio[0] |= shift_pin(pin.buttons_1.b_b, SDVX_IO_IN_GPIO_0_B);
sdvx_io_gpio[0] |= shift_pin(pin.buttons_1.b_c, SDVX_IO_IN_GPIO_0_C);
sdvx_io_gpio[1] |= shift_pin(pin.buttons_1.b_d, SDVX_IO_IN_GPIO_1_D);
sdvx_io_gpio[1] |= shift_pin(pin.buttons_1.b_fxl, SDVX_IO_IN_GPIO_1_FX_L);
sdvx_io_gpio[1] |= shift_pin(pin.buttons_2.b_fxr, SDVX_IO_IN_GPIO_1_FX_R);
return true;
}
uint8_t sdvx_io_get_input_gpio_sys(void)
{
return sdvx_io_gpio_sys;
}
uint16_t sdvx_io_get_input_gpio(uint8_t gpio_bank)
{
if (gpio_bank > 1) {
return 0;
}
return sdvx_io_gpio[gpio_bank];
}
uint16_t sdvx_io_get_spinner_pos(uint8_t spinner_no)
{
if (spinner_no >= 2) {
return 0;
}
return sdvx_io_analog[spinner_no];
}
bool sdvx_io_set_amp_volume(
uint8_t primary, uint8_t headphone, uint8_t subwoofer)
{
if (!running) {
return false;
}
// yes, the BIO2 doesn't allow control of the amps individually
// so let's just set it so that people's ear's don't blow out
if (!bio2drv_bi2a_sdvx_amp(bio2_node_id, 0, 0, primary, primary)) {
return false;
}
return true;
}