mirror of
https://github.com/whowechina/mai_pico.git
synced 2024-11-13 16:10:46 +01:00
Custom HID mai2io DLL and 1KHz FPS
This commit is contained in:
parent
aef8ce1931
commit
84d808b89d
49
firmware/mai2/mai2io/config.c
Normal file
49
firmware/mai2/mai2io/config.c
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "mai2io/config.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Maimai DX Default key binding
|
||||||
|
1P: self-explanatory
|
||||||
|
2P: (Numpad) 8, 9, 6, 3, 2, 1, 4, 7, *
|
||||||
|
*/
|
||||||
|
static const int mai2_io_1p_default[] = {'W', 'E', 'D', 'C', 'X', 'Z', 'A', 'Q', '3'};
|
||||||
|
static const int mai2_io_2p_default[] = {0x68, 0x69, 0x66, 0x63, 0x62, 0x61, 0x64, 0x67, 0x54};
|
||||||
|
|
||||||
|
void mai2_io_config_load(
|
||||||
|
struct mai2_io_config *cfg,
|
||||||
|
const wchar_t *filename)
|
||||||
|
{
|
||||||
|
wchar_t key[16];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
assert(cfg != NULL);
|
||||||
|
assert(filename != NULL);
|
||||||
|
|
||||||
|
cfg->vk_test = GetPrivateProfileIntW(L"io4", L"test", '1', filename);
|
||||||
|
cfg->vk_service = GetPrivateProfileIntW(L"io4", L"service", '2', filename);
|
||||||
|
cfg->vk_coin = GetPrivateProfileIntW(L"io4", L"coin", '3', filename);
|
||||||
|
|
||||||
|
for (i = 0 ; i < 9 ; i++) {
|
||||||
|
swprintf_s(key, _countof(key), L"1p_btn%i", i + 1);
|
||||||
|
cfg->vk_1p_btn[i] = GetPrivateProfileIntW(
|
||||||
|
L"button",
|
||||||
|
key,
|
||||||
|
mai2_io_1p_default[i],
|
||||||
|
filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0 ; i < 9 ; i++) {
|
||||||
|
swprintf_s(key, _countof(key), L"2p_btn%i", i + 1);
|
||||||
|
cfg->vk_2p_btn[i] = GetPrivateProfileIntW(
|
||||||
|
L"button",
|
||||||
|
key,
|
||||||
|
mai2_io_2p_default[i],
|
||||||
|
filename);
|
||||||
|
}
|
||||||
|
}
|
18
firmware/mai2/mai2io/config.h
Normal file
18
firmware/mai2/mai2io/config.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
struct mai2_io_config {
|
||||||
|
uint8_t vk_test;
|
||||||
|
uint8_t vk_service;
|
||||||
|
uint8_t vk_coin;
|
||||||
|
uint8_t vk_1p_btn[9];
|
||||||
|
uint8_t vk_2p_btn[9];
|
||||||
|
};
|
||||||
|
|
||||||
|
void mai2_io_config_load(
|
||||||
|
struct mai2_io_config *cfg,
|
||||||
|
const wchar_t *filename);
|
324
firmware/mai2/mai2io/mai2io.c
Normal file
324
firmware/mai2/mai2io/mai2io.c
Normal file
@ -0,0 +1,324 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <hidsdi.h>
|
||||||
|
#include <setupapi.h>
|
||||||
|
|
||||||
|
#include "mai2io/mai2io.h"
|
||||||
|
#include "mai2io/config.h"
|
||||||
|
|
||||||
|
static GUID hidclass_guid = {0x745a17a0, 0x74d3, 0x11d0, {0xb6, 0xfe, 0x00, 0xa0, 0xc9, 0x0f, 0x57, 0xda}};
|
||||||
|
|
||||||
|
static BOOLEAN get_device_path(char *lPath, uint16_t vid, uint16_t pid, int8_t mi)
|
||||||
|
{
|
||||||
|
const GUID *guid = &hidclass_guid;
|
||||||
|
HidD_GetHidGuid(&hidclass_guid);
|
||||||
|
// Get device interface info set handle
|
||||||
|
// for all devices attached to system
|
||||||
|
HDEVINFO hDevInfo = SetupDiGetClassDevs(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); // Function class devices.
|
||||||
|
if(hDevInfo == INVALID_HANDLE_VALUE)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
// Retrieve a context structure for a device interface of a device information set.
|
||||||
|
BYTE buf[1024];
|
||||||
|
PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)buf;
|
||||||
|
SP_DEVICE_INTERFACE_DATA spdid;
|
||||||
|
SP_DEVINFO_DATA spdd;
|
||||||
|
DWORD dwSize;
|
||||||
|
char vidstr[64];
|
||||||
|
char mistr[64];
|
||||||
|
|
||||||
|
(void) pid; /* not used for now */
|
||||||
|
//sprintf(vidpidstr, "vid_%04x&pid_%04x&mi_%02x", vid, pid, mi);
|
||||||
|
sprintf(vidstr, "vid_%04x&", vid);
|
||||||
|
if (mi != -1) sprintf(mistr, "&mi_%02x", mi);
|
||||||
|
|
||||||
|
#if DEBUG == 1
|
||||||
|
printf("looking for substring %s in device path\r\n", vidstr);
|
||||||
|
#endif
|
||||||
|
spdid.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
||||||
|
|
||||||
|
// Iterate through all the interfaces and try to match one based on
|
||||||
|
// the device number.
|
||||||
|
for(DWORD i = 0; SetupDiEnumDeviceInterfaces(hDevInfo, NULL,guid, i, &spdid); i++)
|
||||||
|
{
|
||||||
|
// Get the device path.
|
||||||
|
dwSize = 0;
|
||||||
|
SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, NULL, 0, &dwSize, NULL);
|
||||||
|
if(dwSize == 0 || dwSize > sizeof(buf))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pspdidd->cbSize = sizeof(*pspdidd);
|
||||||
|
ZeroMemory((PVOID)&spdd, sizeof(spdd));
|
||||||
|
spdd.cbSize = sizeof(spdd);
|
||||||
|
if(!SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, pspdidd,
|
||||||
|
dwSize, &dwSize, &spdd))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
#if DEBUG == 1
|
||||||
|
printf("checking path %s... ", pspdidd->DevicePath);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* check if the device contains our wanted vid/pid */
|
||||||
|
// if ( strstr( pspdidd->DevicePath, vidpidstr ) == NULL )
|
||||||
|
if ( strstr( pspdidd->DevicePath, vidstr ) == NULL || ((mi!= -1) && strstr( pspdidd->DevicePath, mistr ) == NULL) )
|
||||||
|
{
|
||||||
|
#if DEBUG == 1
|
||||||
|
printf("that's not it.\r\n");
|
||||||
|
#endif
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#if DEBUG == 1
|
||||||
|
printf("\r\nDevice found at %s\r\n", pspdidd->DevicePath);
|
||||||
|
#endif
|
||||||
|
//copy devpath into lPath
|
||||||
|
strcpy(lPath, pspdidd->DevicePath);
|
||||||
|
SetupDiDestroyDeviceInfoList(hDevInfo);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
SetupDiDestroyDeviceInfoList(hDevInfo);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int hid_open_device(HANDLE *device_handle, uint16_t vid, uint16_t pid, uint8_t mi){
|
||||||
|
static uint8_t err_count = 0;
|
||||||
|
char path[256];
|
||||||
|
|
||||||
|
if (!get_device_path(path, vid, pid, mi))
|
||||||
|
{
|
||||||
|
#if DEBUG == 1
|
||||||
|
printf("\r\nDevice not detected (vid %04x pid %04x mi %02x).\r\n",vid,pid,mi);
|
||||||
|
#endif
|
||||||
|
err_count++;
|
||||||
|
if (err_count > 2){
|
||||||
|
printf("Could not init device after multiple attempts. Exiting.\r\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#if DEBUG == 1
|
||||||
|
printf("\r\nDevice found (vid %04x pid %04x mi %02x).\r\n",vid,pid,mi);
|
||||||
|
#endif
|
||||||
|
*device_handle = CreateFile(path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
||||||
|
|
||||||
|
if ( *device_handle == INVALID_HANDLE_VALUE )
|
||||||
|
{
|
||||||
|
printf("Could not open detected device (err = %lx).\r\n", GetLastError());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hid_get_report(HANDLE device_handle, uint8_t *buf, uint8_t report_id, uint8_t nb_bytes)
|
||||||
|
{
|
||||||
|
DWORD bytesRead = 0;
|
||||||
|
static uint8_t tmp_buf[128];
|
||||||
|
|
||||||
|
if (buf == NULL) return -1;
|
||||||
|
|
||||||
|
tmp_buf[0] = report_id;
|
||||||
|
|
||||||
|
ReadFile(device_handle, tmp_buf, nb_bytes*2, &bytesRead, NULL);
|
||||||
|
// bytesRead should either be nb_bytes*2 (if it successfully read 2 reports) or nb_bytes (only one)
|
||||||
|
if ( bytesRead != nb_bytes*2 && bytesRead != nb_bytes )
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("HID read error (expected %u (or twice that), but got %lu bytes)\n",nb_bytes, bytesRead);
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HID read ok, copy latest report bytes */
|
||||||
|
memcpy(buf, tmp_buf + bytesRead - nb_bytes, nb_bytes);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t mai2_opbtn;
|
||||||
|
static uint16_t mai2_player1_btn;
|
||||||
|
static uint16_t mai2_player2_btn;
|
||||||
|
static struct mai2_io_config mai2_io_cfg;
|
||||||
|
static bool mai2_io_coin;
|
||||||
|
|
||||||
|
uint16_t mai2_io_get_api_version(void)
|
||||||
|
{
|
||||||
|
return 0x0100;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HANDLE joy_handle;
|
||||||
|
|
||||||
|
HRESULT mai2_io_init(void)
|
||||||
|
{
|
||||||
|
mai2_io_config_load(&mai2_io_cfg, L".\\segatools.ini");
|
||||||
|
|
||||||
|
if (hid_open_device(&joy_handle, 0x0f0d, 0x0092, 0) != 0) {
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HidD_SetNumInputBuffers(joy_handle, 2);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
typedef struct joy_report_s {
|
||||||
|
uint8_t report_id;
|
||||||
|
uint16_t buttons; // 16 buttons; see JoystickButtons_t for bit mapping
|
||||||
|
uint8_t HAT; // HAT switch; one nibble w/ unused nibble
|
||||||
|
uint32_t axis;
|
||||||
|
uint8_t VendorSpec;
|
||||||
|
} joy_report_t;
|
||||||
|
|
||||||
|
joy_report_t joy_data;
|
||||||
|
|
||||||
|
HRESULT mai2_io_poll_(void)
|
||||||
|
{
|
||||||
|
mai2_opbtn = 0;
|
||||||
|
mai2_player1_btn = 0;
|
||||||
|
mai2_player2_btn = 0;
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_test) & 0x8000) {
|
||||||
|
mai2_opbtn |= MAI2_IO_OPBTN_TEST;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_service) & 0x8000) {
|
||||||
|
mai2_opbtn |= MAI2_IO_OPBTN_SERVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_coin) & 0x8000) {
|
||||||
|
if (!mai2_io_coin) {
|
||||||
|
mai2_io_coin = true;
|
||||||
|
mai2_opbtn |= MAI2_IO_OPBTN_COIN;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mai2_io_coin = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Player 1
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[0])) {
|
||||||
|
mai2_player1_btn |= MAI2_IO_GAMEBTN_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[1])) {
|
||||||
|
mai2_player1_btn |= MAI2_IO_GAMEBTN_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[2])) {
|
||||||
|
mai2_player1_btn |= MAI2_IO_GAMEBTN_3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[3])) {
|
||||||
|
mai2_player1_btn |= MAI2_IO_GAMEBTN_4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[4])) {
|
||||||
|
mai2_player1_btn |= MAI2_IO_GAMEBTN_5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[5])) {
|
||||||
|
mai2_player1_btn |= MAI2_IO_GAMEBTN_6;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[6])) {
|
||||||
|
mai2_player1_btn |= MAI2_IO_GAMEBTN_7;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[7])) {
|
||||||
|
mai2_player1_btn |= MAI2_IO_GAMEBTN_8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_1p_btn[8])) {
|
||||||
|
mai2_player1_btn |= MAI2_IO_GAMEBTN_SELECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Player 2
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_2p_btn[0])) {
|
||||||
|
mai2_player2_btn |= MAI2_IO_GAMEBTN_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_2p_btn[1])) {
|
||||||
|
mai2_player2_btn |= MAI2_IO_GAMEBTN_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_2p_btn[2])) {
|
||||||
|
mai2_player2_btn |= MAI2_IO_GAMEBTN_3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_2p_btn[3])) {
|
||||||
|
mai2_player2_btn |= MAI2_IO_GAMEBTN_4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_2p_btn[4])) {
|
||||||
|
mai2_player2_btn |= MAI2_IO_GAMEBTN_5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_2p_btn[5])) {
|
||||||
|
mai2_player2_btn |= MAI2_IO_GAMEBTN_6;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_2p_btn[6])) {
|
||||||
|
mai2_player2_btn |= MAI2_IO_GAMEBTN_7;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_2p_btn[7])) {
|
||||||
|
mai2_player2_btn |= MAI2_IO_GAMEBTN_8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_2p_btn[8])) {
|
||||||
|
mai2_player2_btn |= MAI2_IO_GAMEBTN_SELECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT mai2_io_poll(void)
|
||||||
|
{
|
||||||
|
mai2_opbtn = 0;
|
||||||
|
mai2_player1_btn = 0;
|
||||||
|
mai2_player2_btn = 0;
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_test) & 0x8000) {
|
||||||
|
mai2_opbtn |= MAI2_IO_OPBTN_TEST;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_service) & 0x8000) {
|
||||||
|
mai2_opbtn |= MAI2_IO_OPBTN_SERVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAsyncKeyState(mai2_io_cfg.vk_coin) & 0x8000) {
|
||||||
|
if (!mai2_io_coin) {
|
||||||
|
mai2_io_coin = true;
|
||||||
|
mai2_opbtn |= MAI2_IO_OPBTN_COIN;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mai2_io_coin = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hid_get_report(joy_handle, (uint8_t *)&joy_data, 0x01, sizeof(joy_data));
|
||||||
|
mai2_player1_btn = joy_data.buttons;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mai2_io_get_opbtns(uint8_t *opbtn)
|
||||||
|
{
|
||||||
|
if (opbtn != NULL) {
|
||||||
|
*opbtn = mai2_opbtn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mai2_io_get_gamebtns(uint16_t *player1, uint16_t *player2)
|
||||||
|
{
|
||||||
|
if (player1 != NULL) {
|
||||||
|
*player1 = mai2_player1_btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player2 != NULL ){
|
||||||
|
*player2 = mai2_player2_btn;
|
||||||
|
}
|
||||||
|
}
|
8
firmware/mai2/mai2io/mai2io.def
Normal file
8
firmware/mai2/mai2io/mai2io.def
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
LIBRARY mai2io
|
||||||
|
|
||||||
|
EXPORTS
|
||||||
|
mai2_io_get_api_version
|
||||||
|
mai2_io_init
|
||||||
|
mai2_io_poll
|
||||||
|
mai2_io_get_opbtns
|
||||||
|
mai2_io_get_gamebtns
|
68
firmware/mai2/mai2io/mai2io.h
Normal file
68
firmware/mai2/mai2io/mai2io.h
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MAI2_IO_OPBTN_TEST = 0x01,
|
||||||
|
MAI2_IO_OPBTN_SERVICE = 0x02,
|
||||||
|
MAI2_IO_OPBTN_COIN = 0x04,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MAI2_IO_GAMEBTN_1 = 0x01,
|
||||||
|
MAI2_IO_GAMEBTN_2 = 0x02,
|
||||||
|
MAI2_IO_GAMEBTN_3 = 0x04,
|
||||||
|
MAI2_IO_GAMEBTN_4 = 0x08,
|
||||||
|
MAI2_IO_GAMEBTN_5 = 0x10,
|
||||||
|
MAI2_IO_GAMEBTN_6 = 0x20,
|
||||||
|
MAI2_IO_GAMEBTN_7 = 0x40,
|
||||||
|
MAI2_IO_GAMEBTN_8 = 0x80,
|
||||||
|
MAI2_IO_GAMEBTN_SELECT = 0x100,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Get the version of the Maimai IO API that this DLL supports. This
|
||||||
|
function should return a positive 16-bit integer, where the high byte is
|
||||||
|
the major version and the low byte is the minor version (as defined by the
|
||||||
|
Semantic Versioning standard).
|
||||||
|
|
||||||
|
The latest API version as of this writing is 0x0100. */
|
||||||
|
|
||||||
|
uint16_t mai2_io_get_api_version(void);
|
||||||
|
|
||||||
|
/* Initialize the IO DLL. This is the second function that will be called on
|
||||||
|
your DLL, after mai2_io_get_api_version.
|
||||||
|
|
||||||
|
All subsequent calls to this API may originate from arbitrary threads.
|
||||||
|
|
||||||
|
Minimum API version: 0x0100 */
|
||||||
|
|
||||||
|
HRESULT mai2_io_init(void);
|
||||||
|
|
||||||
|
/* Send any queued outputs (of which there are currently none, though this may
|
||||||
|
change in subsequent API versions) and retrieve any new inputs.
|
||||||
|
|
||||||
|
Minimum API version: 0x0100 */
|
||||||
|
|
||||||
|
HRESULT mai2_io_poll(void);
|
||||||
|
|
||||||
|
/* Get the state of the cabinet's operator buttons as of the last poll. See
|
||||||
|
MAI2_IO_OPBTN enum above: this contains bit mask definitions for button
|
||||||
|
states returned in *opbtn. All buttons are active-high.
|
||||||
|
|
||||||
|
Minimum API version: 0x0100 */
|
||||||
|
|
||||||
|
void mai2_io_get_opbtns(uint8_t *opbtn);
|
||||||
|
|
||||||
|
/* Get the state of the cabinet's gameplay buttons as of the last poll. See
|
||||||
|
MAI2_IO_GAMEBTN enum above for bit mask definitions. Inputs are split into
|
||||||
|
a left hand side set of inputs and a right hand side set of inputs: the bit
|
||||||
|
mappings are the same in both cases.
|
||||||
|
|
||||||
|
All buttons are active-high, even though some buttons' electrical signals
|
||||||
|
on a real cabinet are active-low.
|
||||||
|
|
||||||
|
Minimum API version: 0x0100 */
|
||||||
|
|
||||||
|
void mai2_io_get_gamebtns(uint16_t *player1, uint16_t *player2);
|
53
firmware/mai2/mai2io/meson.build
Normal file
53
firmware/mai2/mai2io/meson.build
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
project('mai2io_dll', 'c', version: '0.1.0')
|
||||||
|
|
||||||
|
|
||||||
|
add_project_arguments(
|
||||||
|
'-DCOBJMACROS',
|
||||||
|
'-DDIRECTINPUT_VERSION=0x0800',
|
||||||
|
'-DWIN32_LEAN_AND_MEAN',
|
||||||
|
'-D_WIN32_WINNT=_WIN32_WINNT_WIN7',
|
||||||
|
'-DMINGW_HAS_SECURE_API=1',
|
||||||
|
language: 'c',
|
||||||
|
)
|
||||||
|
|
||||||
|
# Use get_argument_syntax() instead once Meson 0.49.0 releases
|
||||||
|
if meson.get_compiler('c').get_id() != 'msvc'
|
||||||
|
add_project_arguments(
|
||||||
|
'-ffunction-sections',
|
||||||
|
'-fdata-sections',
|
||||||
|
language: 'c',
|
||||||
|
)
|
||||||
|
|
||||||
|
add_project_link_arguments(
|
||||||
|
'-Wl,--enable-stdcall-fixup',
|
||||||
|
'-Wl,--exclude-all-symbols',
|
||||||
|
'-Wl,--gc-sections',
|
||||||
|
'-static-libgcc',
|
||||||
|
language: 'c',
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
|
cc = meson.get_compiler('c')
|
||||||
|
hid_lib = cc.find_library('hid')
|
||||||
|
setupapi_lib = cc.find_library('setupapi')
|
||||||
|
|
||||||
|
inc = include_directories('.')
|
||||||
|
|
||||||
|
|
||||||
|
mai2io_lib = shared_library(
|
||||||
|
'mai2io',
|
||||||
|
name_prefix : '',
|
||||||
|
include_directories : [inc, '../'],
|
||||||
|
vs_module_defs : 'mai2io.def',
|
||||||
|
implicit_include_directories : false,
|
||||||
|
dependencies : [
|
||||||
|
hid_lib,
|
||||||
|
setupapi_lib,
|
||||||
|
],
|
||||||
|
sources : [
|
||||||
|
'mai2io.c',
|
||||||
|
'mai2io.h',
|
||||||
|
'config.c',
|
||||||
|
'config.h',
|
||||||
|
],
|
||||||
|
)
|
@ -50,7 +50,11 @@ void report_usb_hid()
|
|||||||
if (tud_hid_ready()) {
|
if (tud_hid_ready()) {
|
||||||
hid_joy.HAT = 0;
|
hid_joy.HAT = 0;
|
||||||
hid_joy.VendorSpec = 0;
|
hid_joy.VendorSpec = 0;
|
||||||
if (mai_cfg->hid.nkro &&
|
if (mai_cfg->hid.joy) {
|
||||||
|
hid_joy.buttons = button_read();
|
||||||
|
tud_hid_n_report(0x00, REPORT_ID_JOYSTICK, &hid_joy, sizeof(hid_joy));
|
||||||
|
}
|
||||||
|
if (mai_cfg->hid.nkro &&
|
||||||
(memcmp(&hid_nkro, &sent_hid_nkro, sizeof(hid_nkro)) != 0)) {
|
(memcmp(&hid_nkro, &sent_hid_nkro, sizeof(hid_nkro)) != 0)) {
|
||||||
sent_hid_nkro = hid_nkro;
|
sent_hid_nkro = hid_nkro;
|
||||||
tud_hid_n_report(0x02, 0, &sent_hid_nkro, sizeof(sent_hid_nkro));
|
tud_hid_n_report(0x02, 0, &sent_hid_nkro, sizeof(sent_hid_nkro));
|
||||||
@ -84,7 +88,7 @@ static void run_lights()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (now - io_last_io_time() < 5000000) {
|
if (now - io_last_io_time() < 60000000) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,6 +122,8 @@ static void core1_loop()
|
|||||||
|
|
||||||
static void core0_loop()
|
static void core0_loop()
|
||||||
{
|
{
|
||||||
|
static uint64_t next_frame = 0;
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
tud_task();
|
tud_task();
|
||||||
io_update();
|
io_update();
|
||||||
@ -126,6 +132,9 @@ static void core0_loop()
|
|||||||
save_loop();
|
save_loop();
|
||||||
cli_fps_count(0);
|
cli_fps_count(0);
|
||||||
|
|
||||||
|
sleep_until(next_frame);
|
||||||
|
next_frame = time_us_64() + 1000; // 1KHz
|
||||||
|
|
||||||
touch_update();
|
touch_update();
|
||||||
button_update();
|
button_update();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user