coin blocker fix
This commit is contained in:
Binary file not shown.
Binary file not shown.
+84
-74
@@ -11,19 +11,21 @@ extern "C" {
|
||||
#include "ezusb.h"
|
||||
|
||||
//#define DEBUG
|
||||
//#define DEBUG_LAMP
|
||||
|
||||
HANDLE g_hid_handle;
|
||||
uint8_t g_dip_state = 0;
|
||||
// GUID_DEVCLASS_HIDCLASS
|
||||
static GUID hidclass_guid = {0x745a17a0, 0x74d3, 0x11d0, 0xb6, 0xfe, 0x00, 0xa0, 0xc9, 0x0f, 0x57, 0xda};
|
||||
|
||||
|
||||
BOOLEAN get_device_path(wchar_t *lPath)
|
||||
{
|
||||
|
||||
const GUID *guid = &hidclass_guid;
|
||||
HidD_GetHidGuid(&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.
|
||||
HDEVINFO hDevInfo = SetupDiGetClassDevs(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); // Function class devices.
|
||||
if(hDevInfo == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
@@ -38,8 +40,8 @@ BOOLEAN get_device_path(wchar_t *lPath)
|
||||
|
||||
// Iterate through all the interfaces and try to match one based on
|
||||
// the device number.
|
||||
DWORD device_index = 0;
|
||||
|
||||
DWORD device_index = 0;
|
||||
|
||||
for(DWORD i = 0; SetupDiEnumDeviceInterfaces(hDevInfo, NULL,guid, i, &spdid); i++)
|
||||
{
|
||||
// Get the device path.
|
||||
@@ -47,29 +49,29 @@ BOOLEAN get_device_path(wchar_t *lPath)
|
||||
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;
|
||||
|
||||
/* check if the device contains our wanted vid/pid */
|
||||
if ( wcsstr( pspdidd->DevicePath, L"vid_1ccf&pid_1000&mi_02" ) == NULL )
|
||||
{
|
||||
|
||||
/* check if the device contains our wanted vid/pid */
|
||||
if ( wcsstr( pspdidd->DevicePath, L"vid_1ccf&pid_1000&mi_02" ) == NULL )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("\r\nDevice found at %S\r\n", &pspdidd->DevicePath);
|
||||
printf("\r\nDevice found at %S\r\n", &pspdidd->DevicePath);
|
||||
#endif
|
||||
//copy devpath into lPath
|
||||
wcscpy(lPath, pspdidd->DevicePath);
|
||||
SetupDiDestroyDeviceInfoList(hDevInfo);
|
||||
return TRUE;
|
||||
//copy devpath into lPath
|
||||
wcscpy(lPath, pspdidd->DevicePath);
|
||||
SetupDiDestroyDeviceInfoList(hDevInfo);
|
||||
return TRUE;
|
||||
}
|
||||
SetupDiDestroyDeviceInfoList(hDevInfo);
|
||||
return FALSE;
|
||||
SetupDiDestroyDeviceInfoList(hDevInfo);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,46 +83,46 @@ BOOLEAN get_device_path(wchar_t *lPath)
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
static int controller_init(){
|
||||
static uint8_t err_count = 0;
|
||||
wchar_t lPath[256];
|
||||
char path[256];
|
||||
FILE *file;
|
||||
static uint8_t err_count = 0;
|
||||
wchar_t lPath[256];
|
||||
char path[256];
|
||||
FILE *file;
|
||||
|
||||
/* first check if there's a devicepath.dat override */
|
||||
file = fopen("devicepath.dat", "r");
|
||||
/* first check if there's a devicepath.dat override */
|
||||
file = fopen("devicepath.dat", "r");
|
||||
if (file != NULL)
|
||||
{
|
||||
while ( fgets(path,256,file) != NULL )
|
||||
{
|
||||
path[strcspn(path, "\r\n")] = 0;
|
||||
g_hid_handle = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if ( g_hid_handle != INVALID_HANDLE_VALUE )
|
||||
{
|
||||
fclose(file);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
while ( fgets(path,256,file) != NULL )
|
||||
{
|
||||
path[strcspn(path, "\r\n")] = 0;
|
||||
g_hid_handle = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if ( g_hid_handle != INVALID_HANDLE_VALUE )
|
||||
{
|
||||
fclose(file);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
/* auto detect device path */
|
||||
if (!get_device_path(lPath))
|
||||
{
|
||||
printf("\r\nPOPN MUSIC USB not detected.\r\n");
|
||||
err_count++;
|
||||
if (err_count > 2){
|
||||
printf("Could not init device after multiple attempts. Exiting.\r\n");
|
||||
exit(1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/* auto detect device path */
|
||||
if (!get_device_path(lPath))
|
||||
{
|
||||
printf("\r\nPOPN MUSIC USB not detected.\r\n");
|
||||
err_count++;
|
||||
if (err_count > 2){
|
||||
printf("Could not init device after multiple attempts. Exiting.\r\n");
|
||||
exit(1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_hid_handle = CreateFile(lPath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
||||
g_hid_handle = CreateFile(lPath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
||||
|
||||
if ( g_hid_handle == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
printf("Could not open detected device (err = %x).\r\n", GetLastError());
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -140,7 +142,7 @@ static int controller_init(){
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
static int controller_read_buttons(uint32_t *pad_bits){
|
||||
DWORD bytesRead = 0;
|
||||
DWORD bytesRead = 0;
|
||||
uint8_t res[4];
|
||||
unsigned char buf[6]; // gamepad report length is 3 bytes in firmware, doubled because NumInputBuffer is set to 2
|
||||
|
||||
@@ -158,18 +160,15 @@ static int controller_read_buttons(uint32_t *pad_bits){
|
||||
}
|
||||
|
||||
/* HID read ok, convert latest report bytes to pop'n bitfield */
|
||||
res[3] = 0;
|
||||
res[2] = (buf[bytesRead-1]<<3 | buf[bytesRead-1]) & 0x41;
|
||||
res[1] = buf[bytesRead-2];
|
||||
res[3] = g_dip_state; // dip switches
|
||||
res[2] = (buf[bytesRead-1]<<3 | buf[bytesRead-1]) & 0x41; // button 9 (0x01) and coin mech (0x40)
|
||||
res[1] = buf[bytesRead-2]; // button 1 to 8
|
||||
res[0] = 0;
|
||||
buf[bytesRead-1] >>= 1;
|
||||
if ( buf[bytesRead-1]&1 ) res[0] |= 0x80;
|
||||
if ( buf[bytesRead-1]&1 ) res[0] |= 0x80; // test
|
||||
buf[bytesRead-1] >>= 1;
|
||||
if ( buf[bytesRead-1]&1 ) res[0] |= 0x40;
|
||||
if ( buf[bytesRead-1]&1 ) res[0] |= 0x40; // service
|
||||
*pad_bits = *(uint32_t *)res;
|
||||
|
||||
/* dip switches */
|
||||
*pad_bits |= g_dip_state << 24;
|
||||
|
||||
#ifdef DEBUG
|
||||
for (int i = 0; i<32; i++){
|
||||
@@ -177,7 +176,7 @@ static int controller_read_buttons(uint32_t *pad_bits){
|
||||
if (((i+1)%4)==0) printf(" ");
|
||||
}
|
||||
printf("\n");
|
||||
if (*pad_bits & 0x8000000) printf("31kHz mode\r\n");
|
||||
if (*pad_bits & 0x8000000) printf("31kHz mode\r\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -188,22 +187,33 @@ static int controller_read_buttons(uint32_t *pad_bits){
|
||||
* Pop'n Music sends lights state as a int32_t bitfield with the following format :
|
||||
* bits 0 (LSB) to 4 : neons from top to bottom
|
||||
* bits 8 to 11 : side lamps (left blue, left red, right blue, right red)
|
||||
* bits 23 to 31 : button lamps from left to right
|
||||
* bits 16 to 19 : coin blocker (0x0 for on, 0xF for off)
|
||||
* bits 23 to 31 : button lamps from left to right (note: technically game sets the whole 20-23 to 0xF rather than 0x8 for lamp 1)
|
||||
*
|
||||
* @param lamp_bits[in] lamp state bitfield
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
static int controller_write_leds(int32_t lamp_bits){
|
||||
DWORD bytesWritten = 0;
|
||||
DWORD bytesWritten = 0;
|
||||
uint8_t *src = (uint8_t*) &lamp_bits; //cast as uint8_t array for fast conversion
|
||||
uint8_t buf[5]; // HID lights report length is 5 bytes in Arduino firmware
|
||||
|
||||
#ifdef DEBUG_LAMP
|
||||
for (int i = 0; i<32; i++){
|
||||
printf("%c",( ((uint32_t )lamp_bits>>(31-i))&1)?'1':'0');
|
||||
if (((i+1)%4)==0) printf(" ");
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
/* convert bitfield into HID Report format */
|
||||
buf[4] = 0;
|
||||
buf[3] = (src[1] >> 2);
|
||||
buf[2] = (src[1] << 6) | (src[0] << 1) | (src[3] >> 7);
|
||||
buf[1] = (src[3] << 1) | (src[2] >> 7);
|
||||
buf[0] = 0x05; // HID lights report id is 5 in Arduino firmware
|
||||
buf[4] = 0; // hid report padding
|
||||
buf[3] = ((src[1]&0x0F) >> 2); // right lamps
|
||||
if ( !(src[2] & 0x0F) ) buf[3] |= 0x04; // coin blocker
|
||||
if ( src[1] & 0xF0 ) buf[3] |= 0x08; // coin counter?
|
||||
buf[2] = (src[1] << 6) | (src[0] << 1) | (src[3] >> 7); // button 9, top and left lamps
|
||||
buf[1] = (src[3] << 1) | (src[2] >> 7); // button lamps 1-8
|
||||
buf[0] = 0x05; // HID lights report id
|
||||
|
||||
/* send HID Report */
|
||||
WriteFile(g_hid_handle, buf, 5, &bytesWritten, NULL);
|
||||
@@ -316,13 +326,13 @@ __declspec(dllexport) int __cdecl usbStart(int i) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* read dip switches */
|
||||
uint8_t feat[2] = {0x06, 0x00};
|
||||
if (!HidD_GetFeature(g_hid_handle, &feat, 2))
|
||||
{
|
||||
printf("Cannot read dipswitches (error %d)\r\n",GetLastError());
|
||||
};
|
||||
g_dip_state = feat[1];
|
||||
/* read dip switches */
|
||||
uint8_t feat[2] = {0x06, 0x00};
|
||||
if (!HidD_GetFeature(g_hid_handle, &feat, 2))
|
||||
{
|
||||
printf("Cannot read dipswitches (error %d)\r\n",GetLastError());
|
||||
};
|
||||
g_dip_state = feat[1];
|
||||
|
||||
#ifdef FORCE_DIP4
|
||||
g_dip_state |= 0x08;
|
||||
@@ -335,7 +345,7 @@ __declspec(dllexport) int __cdecl usbStart(int i) {
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("Managed to open device %x\n",g_hid_handle);
|
||||
printf("Dip state is %x\n", g_dip_state);
|
||||
printf("Dip state is %x\n", g_dip_state);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -360,7 +370,7 @@ __declspec(dllexport) int __cdecl usbWdtStartDone() {
|
||||
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||
DWORD fdwReason,
|
||||
LPVOID lpReserved
|
||||
) {
|
||||
) {
|
||||
if (fdwReason == 1) {
|
||||
//https://blogs.msdn.microsoft.com/larryosterman/2004/06/03/little-known-win32-apis-disablethreadlibrarycalls/
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
|
||||
Reference in New Issue
Block a user