diff --git a/ezusb/ezusb-popn15.dll b/ezusb/ezusb-popn15.dll index 27f4ca8..dab1b16 100644 Binary files a/ezusb/ezusb-popn15.dll and b/ezusb/ezusb-popn15.dll differ diff --git a/ezusb/ezusb.dll b/ezusb/ezusb.dll index 8e20d49..8bbc8cf 100644 Binary files a/ezusb/ezusb.dll and b/ezusb/ezusb.dll differ diff --git a/ezusb/src/ezusb.cpp b/ezusb/src/ezusb.cpp index 1358759..0483f7f 100644 --- a/ezusb/src/ezusb.cpp +++ b/ezusb/src/ezusb.cpp @@ -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);