From f8632b3624b1e58964d0d050eabd02188d16479d Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Thu, 2 Jan 2020 23:06:00 -0800 Subject: [PATCH 1/9] Adding FTDI nuget package as a dependency. --- vsprojects/pcsx-redux/packages.config | 1 + vsprojects/pcsx-redux/pcsx-redux.vcxproj | 2 ++ 2 files changed, 3 insertions(+) diff --git a/vsprojects/pcsx-redux/packages.config b/vsprojects/pcsx-redux/packages.config index 36c05cdf8..484bb9ea4 100644 --- a/vsprojects/pcsx-redux/packages.config +++ b/vsprojects/pcsx-redux/packages.config @@ -1,5 +1,6 @@  + \ No newline at end of file diff --git a/vsprojects/pcsx-redux/pcsx-redux.vcxproj b/vsprojects/pcsx-redux/pcsx-redux.vcxproj index 880177996..0f835d453 100644 --- a/vsprojects/pcsx-redux/pcsx-redux.vcxproj +++ b/vsprojects/pcsx-redux/pcsx-redux.vcxproj @@ -201,6 +201,7 @@ + @@ -208,5 +209,6 @@ + \ No newline at end of file From aa427752912fc9d7f5d2a817bd191e3f4cf1065e Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 3 Jan 2020 22:06:19 -0800 Subject: [PATCH 2/9] Creating ftdi project for abstraction. --- vsprojects/ftdi/ftdi.vcxproj | 153 +++++++++++++++++++++++++++ vsprojects/ftdi/ftdi.vcxproj.filters | 20 ++++ vsprojects/ftdi/packages.config | 4 + 3 files changed, 177 insertions(+) create mode 100644 vsprojects/ftdi/ftdi.vcxproj create mode 100644 vsprojects/ftdi/ftdi.vcxproj.filters create mode 100644 vsprojects/ftdi/packages.config diff --git a/vsprojects/ftdi/ftdi.vcxproj b/vsprojects/ftdi/ftdi.vcxproj new file mode 100644 index 000000000..d6f32cc96 --- /dev/null +++ b/vsprojects/ftdi/ftdi.vcxproj @@ -0,0 +1,153 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {832D8D53-3EE4-43D7-B5DF-48B249CE0709} + ftdi + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/vsprojects/ftdi/ftdi.vcxproj.filters b/vsprojects/ftdi/ftdi.vcxproj.filters new file mode 100644 index 000000000..e1de0051b --- /dev/null +++ b/vsprojects/ftdi/ftdi.vcxproj.filters @@ -0,0 +1,20 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + \ No newline at end of file diff --git a/vsprojects/ftdi/packages.config b/vsprojects/ftdi/packages.config new file mode 100644 index 000000000..1cf8b5eae --- /dev/null +++ b/vsprojects/ftdi/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From f770ed7e83f5c607650cc98ba0276f650458f169 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 3 Jan 2020 22:48:01 -0800 Subject: [PATCH 3/9] Adding skeleton files. --- src/ftdi/abstract-ftd2xx-win32.cc | 20 ++++++++++++++++++++ src/ftdi/abstract.h | 20 ++++++++++++++++++++ vsprojects/ftdi/ftdi.vcxproj | 18 ++++++++++++++---- vsprojects/ftdi/ftdi.vcxproj.filters | 10 ++++++++++ vsprojects/pcsx-redux.sln | 13 ++++++++++++- vsprojects/pcsx-redux/pcsx-redux.vcxproj | 3 +++ 6 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 src/ftdi/abstract-ftd2xx-win32.cc create mode 100644 src/ftdi/abstract.h diff --git a/src/ftdi/abstract-ftd2xx-win32.cc b/src/ftdi/abstract-ftd2xx-win32.cc new file mode 100644 index 000000000..ebb47ac46 --- /dev/null +++ b/src/ftdi/abstract-ftd2xx-win32.cc @@ -0,0 +1,20 @@ +/*************************************************************************** + * Copyright (C) 2019 PCSX-Redux authors * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "ftdi/abstract.h" diff --git a/src/ftdi/abstract.h b/src/ftdi/abstract.h new file mode 100644 index 000000000..33c9bdd0a --- /dev/null +++ b/src/ftdi/abstract.h @@ -0,0 +1,20 @@ +/*************************************************************************** + * Copyright (C) 2020 PCSX-Redux authors * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#pragma once diff --git a/vsprojects/ftdi/ftdi.vcxproj b/vsprojects/ftdi/ftdi.vcxproj index d6f32cc96..def6bb858 100644 --- a/vsprojects/ftdi/ftdi.vcxproj +++ b/vsprojects/ftdi/ftdi.vcxproj @@ -26,26 +26,26 @@ - Application + StaticLibrary true v142 Unicode - Application + StaticLibrary false v142 true Unicode - Application + StaticLibrary true v142 Unicode - Application + StaticLibrary false v142 true @@ -87,6 +87,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true + ..\..\src Console @@ -99,6 +100,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true + ..\..\src Console @@ -113,6 +115,7 @@ true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true + ..\..\src Console @@ -129,6 +132,7 @@ true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true + ..\..\src Console @@ -140,6 +144,12 @@ + + + + + + diff --git a/vsprojects/ftdi/ftdi.vcxproj.filters b/vsprojects/ftdi/ftdi.vcxproj.filters index e1de0051b..14e85ecbf 100644 --- a/vsprojects/ftdi/ftdi.vcxproj.filters +++ b/vsprojects/ftdi/ftdi.vcxproj.filters @@ -17,4 +17,14 @@ + + + Header Files + + + + + Source Files + + \ No newline at end of file diff --git a/vsprojects/pcsx-redux.sln b/vsprojects/pcsx-redux.sln index fc7d6329d..4167025f3 100644 --- a/vsprojects/pcsx-redux.sln +++ b/vsprojects/pcsx-redux.sln @@ -37,6 +37,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ImGuiColorTextEdit", "ImGui EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libuv", "libuv\libuv.vcxproj", "{4B88E4F6-56B3-4F66-BEE8-0A4A21937BEE}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftdi", "ftdi\ftdi.vcxproj", "{832D8D53-3EE4-43D7-B5DF-48B249CE0709}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -133,6 +135,14 @@ Global {4B88E4F6-56B3-4F66-BEE8-0A4A21937BEE}.Release|x64.Build.0 = Release|x64 {4B88E4F6-56B3-4F66-BEE8-0A4A21937BEE}.Release|x86.ActiveCfg = Release|Win32 {4B88E4F6-56B3-4F66-BEE8-0A4A21937BEE}.Release|x86.Build.0 = Release|Win32 + {832D8D53-3EE4-43D7-B5DF-48B249CE0709}.Debug|x64.ActiveCfg = Debug|x64 + {832D8D53-3EE4-43D7-B5DF-48B249CE0709}.Debug|x64.Build.0 = Debug|x64 + {832D8D53-3EE4-43D7-B5DF-48B249CE0709}.Debug|x86.ActiveCfg = Debug|Win32 + {832D8D53-3EE4-43D7-B5DF-48B249CE0709}.Debug|x86.Build.0 = Debug|Win32 + {832D8D53-3EE4-43D7-B5DF-48B249CE0709}.Release|x64.ActiveCfg = Release|x64 + {832D8D53-3EE4-43D7-B5DF-48B249CE0709}.Release|x64.Build.0 = Release|x64 + {832D8D53-3EE4-43D7-B5DF-48B249CE0709}.Release|x86.ActiveCfg = Release|Win32 + {832D8D53-3EE4-43D7-B5DF-48B249CE0709}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -150,9 +160,10 @@ Global {BF968FD3-EF46-45AF-B74E-46A41A96276F} = {008A2872-432F-480B-828D-FF9AAA4846BC} {CBF9B825-F140-4A02-8A3F-059103D6CA90} = {64A05F50-3203-42CC-B632-09D6EE6EA856} {4B88E4F6-56B3-4F66-BEE8-0A4A21937BEE} = {64A05F50-3203-42CC-B632-09D6EE6EA856} + {832D8D53-3EE4-43D7-B5DF-48B249CE0709} = {008A2872-432F-480B-828D-FF9AAA4846BC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {AC54A867-F976-4B3D-A6EF-F57EB764DCD4} SolutionGuid = {284E91C1-764E-441A-854D-CFD3623A6501} + SolutionGuid = {AC54A867-F976-4B3D-A6EF-F57EB764DCD4} EndGlobalSection EndGlobal diff --git a/vsprojects/pcsx-redux/pcsx-redux.vcxproj b/vsprojects/pcsx-redux/pcsx-redux.vcxproj index 0f835d453..653cdadab 100644 --- a/vsprojects/pcsx-redux/pcsx-redux.vcxproj +++ b/vsprojects/pcsx-redux/pcsx-redux.vcxproj @@ -158,6 +158,9 @@ {9372d878-f76c-418b-8e2a-8e9896ff575b} + + {832d8d53-3ee4-43d7-b5df-48b249ce0709} + {6ec7fdf3-1418-40bd-8584-1eea34ac3e3e} From 67e333cfd464283dfbf27c177f0901b8a0e554c4 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Sat, 4 Jan 2020 13:27:30 -0800 Subject: [PATCH 4/9] Starting to interface with the devices a bit. --- src/ftdi/abstract-ftd2xx-win32.cc | 40 ++++++++++++++++++++++++ src/ftdi/abstract.h | 43 ++++++++++++++++++++++++++ src/gui/gui.cc | 5 +++ src/gui/gui.h | 12 +++++--- src/gui/widgets/ftdi.cc | 49 ++++++++++++++++++++++++++++++ src/gui/widgets/ftdi.h | 38 +++++++++++++++++++++++ vsprojects/gui/gui.vcxproj | 2 ++ vsprojects/gui/gui.vcxproj.filters | 6 ++++ 8 files changed, 190 insertions(+), 5 deletions(-) create mode 100644 src/gui/widgets/ftdi.cc create mode 100644 src/gui/widgets/ftdi.h diff --git a/src/ftdi/abstract-ftd2xx-win32.cc b/src/ftdi/abstract-ftd2xx-win32.cc index ebb47ac46..c702537a4 100644 --- a/src/ftdi/abstract-ftd2xx-win32.cc +++ b/src/ftdi/abstract-ftd2xx-win32.cc @@ -17,4 +17,44 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ +#ifdef _WIN32 + +#define WIN32_LEAN_AND_MEAN +#include "ftd2xx.h" #include "ftdi/abstract.h" + +static std::vector s_devices; + +void PCSX::FTDI::DeviceList::scan() { + FT_STATUS status; + DWORD numDevs = 0; + + s_devices.clear(); + status = FT_CreateDeviceInfoList(&numDevs); + + if (status != FT_OK || numDevs == 0) return; + + FT_DEVICE_LIST_INFO_NODE* nodes = new FT_DEVICE_LIST_INFO_NODE[numDevs]; + + status = FT_GetDeviceInfoList(nodes, &numDevs); + + if (status == FT_OK && numDevs != 0) { + s_devices.resize(numDevs); + for (DWORD i = 0; i < numDevs; i++) { + const FT_DEVICE_LIST_INFO_NODE* n = nodes + i; + s_devices[i].m_locked = n->Flags & FT_FLAGS_OPENED; + s_devices[i].m_highSpeed = n->Flags & FT_FLAGS_HISPEED; + s_devices[i].m_vendorID = (n->ID >> 16) & 0xffff; + s_devices[i].m_deviceID = n->ID & 0xffff; + s_devices[i].m_type = n->Type; + s_devices[i].m_serial = n->SerialNumber; + s_devices[i].m_description = n->Description; + } + } + + delete[] nodes; +} + +const std::vector& PCSX::FTDI::DeviceList::get() { return s_devices; } + +#endif diff --git a/src/ftdi/abstract.h b/src/ftdi/abstract.h index 33c9bdd0a..6d450d6b4 100644 --- a/src/ftdi/abstract.h +++ b/src/ftdi/abstract.h @@ -18,3 +18,46 @@ ***************************************************************************/ #pragma once + +#include + +#include +#include + +namespace PCSX { + +namespace FTDI { + +class DeviceList; +class Device { + public: + bool isLocked() const { return m_locked; } + bool isHighSpeed() const { return m_highSpeed; } + uint16_t getVendorID() const { return m_vendorID; } + uint16_t getDeviceID() const { return m_deviceID; } + uint32_t getType() const { return m_type; } + const std::string& getSerial() const { return m_serial; } + const std::string& getDescription() const { return m_description; } + + private: + bool m_locked = false; + bool m_highSpeed = false; + uint16_t m_vendorID = 0; + uint16_t m_deviceID = 0; + uint32_t m_type = 0; + std::string m_serial = ""; + std::string m_description = ""; + void* m_handle = nullptr; + + friend class DeviceList; +}; + +class DeviceList { + public: + static void scan(); + static const std::vector& get(); +}; + +} // namespace FTDI + +} // namespace PCSX diff --git a/src/gui/gui.cc b/src/gui/gui.cc index 2c02e7e52..7a57a5834 100644 --- a/src/gui/gui.cc +++ b/src/gui/gui.cc @@ -465,6 +465,7 @@ void PCSX::GUI::endFrame() { ImGui::MenuItem(_("Show ImGui Demo"), nullptr, &m_showDemo); ImGui::Separator(); ImGui::MenuItem(_("About"), nullptr, &m_showAbout); + ImGui::MenuItem(_("FTDI"), nullptr, &m_showFTDI); ImGui::EndMenu(); } ImGui::Separator(); @@ -572,6 +573,10 @@ void PCSX::GUI::endFrame() { m_breakpoints.draw(_("Breakpoints")); } + if (m_showFTDI) { + m_ftdi.draw(_("FTDI")); + } + about(); biosCounters(); interruptsScaler(); diff --git a/src/gui/gui.h b/src/gui/gui.h index 8c4436b52..e6da5a54c 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -24,18 +24,17 @@ #include -#include "flags.h" - -#include "imgui.h" -#include "imgui_memory_editor/imgui_memory_editor.h" - #include "core/system.h" +#include "flags.h" #include "gui/widgets/assembly.h" #include "gui/widgets/breakpoints.h" #include "gui/widgets/filedialog.h" +#include "gui/widgets/ftdi.h" #include "gui/widgets/log.h" #include "gui/widgets/registers.h" #include "gui/widgets/vram-viewer.h" +#include "imgui.h" +#include "imgui_memory_editor/imgui_memory_editor.h" #include "main/settings.h" #if defined(__MACOSX__) @@ -132,6 +131,7 @@ class GUI final { bool m_showDemo = false; bool m_showAbout = false; bool m_showInterruptsScaler = false; + bool m_showFTDI = false; Widgets::Log m_log = {settings.get().value}; struct MemoryEditorWrapper { MemoryEditorWrapper() { @@ -173,6 +173,8 @@ class GUI final { Widgets::VRAMViewer m_clutVRAMviewer; Widgets::VRAMViewer m_VRAMviewers[4]; + Widgets::FTDI m_ftdi = {m_showFTDI}; + uv_loop_t m_loop; }; diff --git a/src/gui/widgets/ftdi.cc b/src/gui/widgets/ftdi.cc new file mode 100644 index 000000000..17f6c8084 --- /dev/null +++ b/src/gui/widgets/ftdi.cc @@ -0,0 +1,49 @@ +/*************************************************************************** + * Copyright (C) 2020 PCSX-Redux authors * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "gui/widgets/ftdi.h" + +#include "core/system.h" +#include "ftdi/abstract.h" + +void PCSX::Widgets::FTDI::draw(const char* title) { + if (!ImGui::Begin(title, &m_show)) { + ImGui::End(); + return; + } + + if (ImGui::Button(_("Scan"))) ::PCSX::FTDI::DeviceList::scan(); + + auto& devices = ::PCSX::FTDI::DeviceList::get(); + + ImGui::Text((std::to_string(devices.size()) + " devices detected").c_str()); + ImGui::Separator(); + for (auto& d : devices) { + ImGui::Text("Vendor Id: %04x", d.getVendorID()); + ImGui::Text("Device Id: %04x", d.getDeviceID()); + ImGui::Text("Type: %i", d.getType()); + ImGui::Text("Serial: %s", d.getSerial().c_str()); + ImGui::Text("Description: %s", d.getDescription().c_str()); + ImGui::Text("Locked: %s", d.isLocked() ? "true" : "false"); + ImGui::Text("High Speed: %s", d.isHighSpeed() ? "true" : "false"); + ImGui::Separator(); + } + + ImGui::End(); +} diff --git a/src/gui/widgets/ftdi.h b/src/gui/widgets/ftdi.h new file mode 100644 index 000000000..db790929c --- /dev/null +++ b/src/gui/widgets/ftdi.h @@ -0,0 +1,38 @@ +/*************************************************************************** + * Copyright (C) 2020 PCSX-Redux authors * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#pragma once + +#include + +#include "imgui.h" + +namespace PCSX { +namespace Widgets { + +class FTDI { + public: + FTDI(bool& show) : m_show(show) {} + void draw(const char* title); + + bool& m_show; +}; + +} // namespace Widgets +} // namespace PCSX diff --git a/vsprojects/gui/gui.vcxproj b/vsprojects/gui/gui.vcxproj index f53bcfc4b..76e8aa086 100644 --- a/vsprojects/gui/gui.vcxproj +++ b/vsprojects/gui/gui.vcxproj @@ -142,6 +142,7 @@ + @@ -151,6 +152,7 @@ + diff --git a/vsprojects/gui/gui.vcxproj.filters b/vsprojects/gui/gui.vcxproj.filters index 69f2657a5..b32dd4e2f 100644 --- a/vsprojects/gui/gui.vcxproj.filters +++ b/vsprojects/gui/gui.vcxproj.filters @@ -42,6 +42,9 @@ Source Files\widgets + + Source Files\widgets + @@ -68,6 +71,9 @@ Header Files\widgets + + Header Files\widgets + From 20d51c36b37288a8e32b82aed1a8a3ef3e9bb4ca Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Sun, 5 Jan 2020 11:15:12 -0800 Subject: [PATCH 5/9] Adding libusb-posix skeleton. --- src/ftdi/abstract-libusb-posix.cc | 30 ++++++++++++++++++++++++++++ vsprojects/ftdi/ftdi.vcxproj | 1 + vsprojects/ftdi/ftdi.vcxproj.filters | 3 +++ 3 files changed, 34 insertions(+) create mode 100644 src/ftdi/abstract-libusb-posix.cc diff --git a/src/ftdi/abstract-libusb-posix.cc b/src/ftdi/abstract-libusb-posix.cc new file mode 100644 index 000000000..d9b320522 --- /dev/null +++ b/src/ftdi/abstract-libusb-posix.cc @@ -0,0 +1,30 @@ +/*************************************************************************** + * Copyright (C) 2019 PCSX-Redux authors * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef _WIN32 + +#include "ftdi/abstract.h" + +static std::vector s_devices; + +void PCSX::FTDI::DeviceList::scan() { abort(); } + +const std::vector& PCSX::FTDI::DeviceList::get() { return s_devices; } + +#endif diff --git a/vsprojects/ftdi/ftdi.vcxproj b/vsprojects/ftdi/ftdi.vcxproj index def6bb858..e2af83b39 100644 --- a/vsprojects/ftdi/ftdi.vcxproj +++ b/vsprojects/ftdi/ftdi.vcxproj @@ -149,6 +149,7 @@ + diff --git a/vsprojects/ftdi/ftdi.vcxproj.filters b/vsprojects/ftdi/ftdi.vcxproj.filters index 14e85ecbf..c3ce23f24 100644 --- a/vsprojects/ftdi/ftdi.vcxproj.filters +++ b/vsprojects/ftdi/ftdi.vcxproj.filters @@ -26,5 +26,8 @@ Source Files + + Source Files + \ No newline at end of file From 70ad10b1077158a654ac31805ae7d8edf125d6b7 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 6 Jan 2020 19:58:14 -0800 Subject: [PATCH 6/9] Adding polling thread. --- src/ftdi/abstract-ftd2xx-win32.cc | 44 +++++++++++++++++++++++++++++-- src/ftdi/abstract-libusb-posix.cc | 4 +-- src/ftdi/abstract.h | 8 +++--- src/gui/widgets/ftdi.cc | 4 +-- 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/ftdi/abstract-ftd2xx-win32.cc b/src/ftdi/abstract-ftd2xx-win32.cc index c702537a4..78589a421 100644 --- a/src/ftdi/abstract-ftd2xx-win32.cc +++ b/src/ftdi/abstract-ftd2xx-win32.cc @@ -20,12 +20,18 @@ #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN + +#include +#include + +#include + #include "ftd2xx.h" #include "ftdi/abstract.h" static std::vector s_devices; -void PCSX::FTDI::DeviceList::scan() { +void PCSX::FTDI::Devices::scan() { FT_STATUS status; DWORD numDevs = 0; @@ -55,6 +61,40 @@ void PCSX::FTDI::DeviceList::scan() { delete[] nodes; } -const std::vector& PCSX::FTDI::DeviceList::get() { return s_devices; } +const std::vector& PCSX::FTDI::Devices::get() { return s_devices; } + +static HANDLE s_thread = nullptr; +static HANDLE s_exitEvent = nullptr; +static bool s_threadRunning = false; + +static DWORD WINAPI threadProc(LPVOID parameter) { + bool exitting = false; + SetThreadDescription(GetCurrentThread(), L"abstract ftd2xx thread"); + while (!exitting) { + HANDLE objects[1]; + objects[0] = s_exitEvent; + DWORD idx = WaitForMultipleObjects(1, objects, FALSE, INFINITE); + exitting = idx == WAIT_OBJECT_0; + } + CloseHandle(s_exitEvent); + s_exitEvent = nullptr; + s_threadRunning = false; + return 0; +} + +void PCSX::FTDI::Devices::startThread() { + assert(!s_threadRunning); + s_exitEvent = CreateEvent(nullptr, FALSE, FALSE, L"abstract ftd2xx exit event"); + s_threadRunning = true; + s_thread = CreateThread(nullptr, 0, threadProc, nullptr, 0, nullptr); +} + +void PCSX::FTDI::Devices::stopThread() { + assert(s_threadRunning); + SetEvent(s_exitEvent); + WaitForSingleObject(s_thread, INFINITE); + s_thread = nullptr; + assert(!s_threadRunning); +} #endif diff --git a/src/ftdi/abstract-libusb-posix.cc b/src/ftdi/abstract-libusb-posix.cc index d9b320522..c041a5e39 100644 --- a/src/ftdi/abstract-libusb-posix.cc +++ b/src/ftdi/abstract-libusb-posix.cc @@ -23,8 +23,8 @@ static std::vector s_devices; -void PCSX::FTDI::DeviceList::scan() { abort(); } +void PCSX::FTDI::Devices::scan() { abort(); } -const std::vector& PCSX::FTDI::DeviceList::get() { return s_devices; } +const std::vector& PCSX::FTDI::Devices::get() { return s_devices; } #endif diff --git a/src/ftdi/abstract.h b/src/ftdi/abstract.h index 6d450d6b4..572fad372 100644 --- a/src/ftdi/abstract.h +++ b/src/ftdi/abstract.h @@ -28,7 +28,7 @@ namespace PCSX { namespace FTDI { -class DeviceList; +class Devices; class Device { public: bool isLocked() const { return m_locked; } @@ -49,13 +49,15 @@ class Device { std::string m_description = ""; void* m_handle = nullptr; - friend class DeviceList; + friend class Devices; }; -class DeviceList { +class Devices { public: static void scan(); static const std::vector& get(); + static void startThread(); + static void stopThread(); }; } // namespace FTDI diff --git a/src/gui/widgets/ftdi.cc b/src/gui/widgets/ftdi.cc index 17f6c8084..64c7d1130 100644 --- a/src/gui/widgets/ftdi.cc +++ b/src/gui/widgets/ftdi.cc @@ -28,9 +28,9 @@ void PCSX::Widgets::FTDI::draw(const char* title) { return; } - if (ImGui::Button(_("Scan"))) ::PCSX::FTDI::DeviceList::scan(); + if (ImGui::Button(_("Scan"))) ::PCSX::FTDI::Devices::scan(); - auto& devices = ::PCSX::FTDI::DeviceList::get(); + auto& devices = ::PCSX::FTDI::Devices::get(); ImGui::Text((std::to_string(devices.size()) + " devices detected").c_str()); ImGui::Separator(); From 720de96435209e2d2ae4a00fe0bcfd000f2a6bde Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Thu, 16 Jan 2020 23:36:12 -0800 Subject: [PATCH 7/9] Device opening / closing. --- src/ftdi/abstract-ftd2xx-win32.cc | 126 ++++++++++++++++++++++++++---- src/ftdi/abstract.h | 19 ++++- src/gui/gui.h | 11 +++ src/gui/widgets/assembly.cc | 28 +++---- src/gui/widgets/ftdi.cc | 18 ++++- src/main/main.cc | 1 - src/support/slice.h | 23 +++--- 7 files changed, 172 insertions(+), 54 deletions(-) diff --git a/src/ftdi/abstract-ftd2xx-win32.cc b/src/ftdi/abstract-ftd2xx-win32.cc index 78589a421..c42ccade0 100644 --- a/src/ftdi/abstract-ftd2xx-win32.cc +++ b/src/ftdi/abstract-ftd2xx-win32.cc @@ -24,17 +24,69 @@ #include #include +#include +#include #include +#include +#include #include "ftd2xx.h" #include "ftdi/abstract.h" +namespace PCSX { +namespace FTDI { +namespace Private { +class DeviceData { + public: + FT_HANDLE m_handle = nullptr; + HANDLE m_event = nullptr; + enum { + STATE_CLOSED, + STATE_OPEN_PENDING, + STATE_OPENED, + STATE_CLOSE_PENDING, + } m_state = STATE_CLOSED; +}; +} // namespace Private +} // namespace FTDI +} // namespace PCSX + static std::vector s_devices; +static HANDLE s_thread; +static std::atomic_bool s_exitThread; +static bool s_threadRunning = false; +static HANDLE s_kickEvent = nullptr; +static std::shared_mutex s_listLock; +static unsigned s_numOpened = 0; + +PCSX::FTDI::Device::~Device() { + assert(m_private->m_state == Private::DeviceData::STATE_CLOSED); + assert(!m_private->m_event); + assert(!m_private->m_handle); + delete m_private; +} + +void PCSX::FTDI::Device::open() { + std::shared_lock guard(s_listLock); + assert(m_private->m_state == Private::DeviceData::STATE_CLOSED); + m_private->m_state = Private::DeviceData::STATE_OPEN_PENDING; + SetEvent(s_kickEvent); +} +void PCSX::FTDI::Device::close() { + std::shared_lock guard(s_listLock); + assert(m_private->m_state == Private::DeviceData::STATE_OPENED); + m_private->m_state = Private::DeviceData::STATE_CLOSE_PENDING; + SetEvent(s_kickEvent); +} +bool PCSX::FTDI::Device::isOpened() const { return m_private->m_state == Private::DeviceData::STATE_OPENED; } void PCSX::FTDI::Devices::scan() { FT_STATUS status; DWORD numDevs = 0; + std::unique_lock guard(s_listLock); + if (s_numOpened != 0) return; + s_devices.clear(); status = FT_CreateDeviceInfoList(&numDevs); @@ -55,46 +107,86 @@ void PCSX::FTDI::Devices::scan() { s_devices[i].m_type = n->Type; s_devices[i].m_serial = n->SerialNumber; s_devices[i].m_description = n->Description; + s_devices[i].m_private = new Private::DeviceData(); } } delete[] nodes; } -const std::vector& PCSX::FTDI::Devices::get() { return s_devices; } - -static HANDLE s_thread = nullptr; -static HANDLE s_exitEvent = nullptr; -static bool s_threadRunning = false; +void PCSX::FTDI::Devices::iterate(std::function iter) { + std::shared_lock guard(s_listLock); + for (auto& d : s_devices) { + if (!iter(d)) break; + } +} -static DWORD WINAPI threadProc(LPVOID parameter) { - bool exitting = false; +void PCSX::FTDI::Devices::threadProc() { SetThreadDescription(GetCurrentThread(), L"abstract ftd2xx thread"); - while (!exitting) { - HANDLE objects[1]; - objects[0] = s_exitEvent; - DWORD idx = WaitForMultipleObjects(1, objects, FALSE, INFINITE); - exitting = idx == WAIT_OBJECT_0; + while (!s_exitThread) { + std::vector objects; + objects.push_back(s_kickEvent); + { + std::shared_lock guard(s_listLock); + + for (auto& device : s_devices) { + switch (device.m_private->m_state) { + case Private::DeviceData::STATE_OPEN_PENDING: + s_numOpened++; + FT_OpenEx(const_cast(device.m_serial.c_str()), FT_OPEN_BY_SERIAL_NUMBER, + &device.m_private->m_handle); + device.m_private->m_event = CreateEvent(nullptr, FALSE, FALSE, L"Event for FTDI device"); + FT_SetEventNotification(device.m_private->m_handle, + FT_EVENT_RXCHAR | FT_EVENT_MODEM_STATUS | FT_EVENT_LINE_STATUS, + device.m_private->m_event); + device.m_private->m_state = Private::DeviceData::STATE_OPENED; + case Private::DeviceData::STATE_OPENED: + objects.push_back(device.m_private->m_event); + break; + case Private::DeviceData::STATE_CLOSE_PENDING: + s_numOpened--; + FT_Close(device.m_private->m_handle); + CloseHandle(device.m_private->m_event); + device.m_private->m_handle = nullptr; + device.m_private->m_event = nullptr; + device.m_private->m_state = Private::DeviceData::STATE_CLOSED; + break; + } + } + } + DWORD idx; + do { + assert(objects.size() <= MAXIMUM_WAIT_OBJECTS); + idx = WaitForMultipleObjects(objects.size(), objects.data(), FALSE, INFINITE); + } while (idx != WAIT_OBJECT_0); } - CloseHandle(s_exitEvent); - s_exitEvent = nullptr; + CloseHandle(s_kickEvent); + s_kickEvent = nullptr; + s_exitThread = false; s_threadRunning = false; +} + +static DWORD WINAPI threadProcTrampoline(LPVOID parameter) { + PCSX::FTDI::Devices::threadProc(); return 0; } void PCSX::FTDI::Devices::startThread() { assert(!s_threadRunning); - s_exitEvent = CreateEvent(nullptr, FALSE, FALSE, L"abstract ftd2xx exit event"); + s_kickEvent = CreateEvent(nullptr, FALSE, FALSE, L"abstract ftd2xx kick event"); s_threadRunning = true; - s_thread = CreateThread(nullptr, 0, threadProc, nullptr, 0, nullptr); + s_thread = CreateThread(nullptr, 0, threadProcTrampoline, nullptr, 0, nullptr); } void PCSX::FTDI::Devices::stopThread() { assert(s_threadRunning); - SetEvent(s_exitEvent); + s_exitThread = true; + SetEvent(s_kickEvent); WaitForSingleObject(s_thread, INFINITE); s_thread = nullptr; assert(!s_threadRunning); } +bool PCSX::FTDI::Devices::isThreadRunning() { return s_threadRunning; } + #endif diff --git a/src/ftdi/abstract.h b/src/ftdi/abstract.h index 572fad372..7e24c40f5 100644 --- a/src/ftdi/abstract.h +++ b/src/ftdi/abstract.h @@ -21,6 +21,7 @@ #include +#include #include #include @@ -29,8 +30,12 @@ namespace PCSX { namespace FTDI { class Devices; +namespace Private { +class DeviceData; +} class Device { public: + ~Device(); bool isLocked() const { return m_locked; } bool isHighSpeed() const { return m_highSpeed; } uint16_t getVendorID() const { return m_vendorID; } @@ -39,6 +44,11 @@ class Device { const std::string& getSerial() const { return m_serial; } const std::string& getDescription() const { return m_description; } + bool isOpened() const; + + void open(); + void close(); + private: bool m_locked = false; bool m_highSpeed = false; @@ -47,7 +57,8 @@ class Device { uint32_t m_type = 0; std::string m_serial = ""; std::string m_description = ""; - void* m_handle = nullptr; + + Private::DeviceData* m_private; friend class Devices; }; @@ -55,9 +66,13 @@ class Device { class Devices { public: static void scan(); - static const std::vector& get(); + static void iterate(std::function); + static bool isThreadRunning(); static void startThread(); static void stopThread(); + + // technically private, but difficult to enforce properly + static void threadProc(); }; } // namespace FTDI diff --git a/src/gui/gui.h b/src/gui/gui.h index e6da5a54c..bea5d295c 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -49,6 +49,17 @@ namespace PCSX { class GUI final { public: + static void DButton(const char *label, bool enabled, std::function clicked) { + if (!enabled) { + const ImVec4 lolight = ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]; + ImGui::PushStyleColor(ImGuiCol_Button, lolight); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, lolight); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, lolight); + } + if (ImGui::Button(label) && enabled) clicked(); + if (!enabled) ImGui::PopStyleColor(3); + } + GUI(const flags::args &args) : m_args(args) {} void init(); void close(); diff --git a/src/gui/widgets/assembly.cc b/src/gui/widgets/assembly.cc index 750f07979..b3707756c 100644 --- a/src/gui/widgets/assembly.cc +++ b/src/gui/widgets/assembly.cc @@ -31,6 +31,7 @@ #include "core/disr3000a.h" #include "core/psxmem.h" #include "core/r3000a.h" +#include "gui/gui.h" #include "gui/widgets/assembly.h" #include "imgui_memory_editor/imgui_memory_editor.h" @@ -70,17 +71,6 @@ uint32_t virtToReal(uint32_t virt) { return pc; }; -void DButton(const char* label, bool enabled, std::function clicked) { - if (!enabled) { - const ImVec4 lolight = ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]; - ImGui::PushStyleColor(ImGuiCol_Button, lolight); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, lolight); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, lolight); - } - if (ImGui::Button(label) && enabled) clicked(); - if (!enabled) ImGui::PopStyleColor(3); -} - class DummyAsm : public PCSX::Disasm { virtual void Invalid() final {} virtual void OpCode(const char* str) final {} @@ -504,15 +494,15 @@ void PCSX::Widgets::Assembly::draw(psxRegisters* registers, Memory* memory, cons ImGui::SameLine(); ImGui::Checkbox(_("Follow PC"), &m_followPC); ImGui::SameLine(); - DButton(_("Pause"), g_system->running(), [&]() mutable { g_system->pause(); }); + GUI::DButton(_("Pause"), g_system->running(), [&]() mutable { g_system->pause(); }); ImGui::SameLine(); - DButton(_("Resume"), !g_system->running(), [&]() mutable { g_system->resume(); }); + GUI::DButton(_("Resume"), !g_system->running(), [&]() mutable { g_system->resume(); }); ImGui::SameLine(); - DButton(_("Step In"), !g_system->running(), [&]() mutable { g_emulator.m_debug->stepIn(); }); + GUI::DButton(_("Step In"), !g_system->running(), [&]() mutable { g_emulator.m_debug->stepIn(); }); ImGui::SameLine(); - DButton(_("Step Over"), !g_system->running(), [&]() mutable { g_emulator.m_debug->stepOver(); }); + GUI::DButton(_("Step Over"), !g_system->running(), [&]() mutable { g_emulator.m_debug->stepOver(); }); ImGui::SameLine(); - DButton(_("Step Out"), !g_system->running(), [&]() mutable { g_emulator.m_debug->stepOut(); }); + GUI::DButton(_("Step Out"), !g_system->running(), [&]() mutable { g_emulator.m_debug->stepOut(); }); if (!g_system->running()) { if (ImGui::IsKeyPressed(GLFW_KEY_F10)) { g_emulator.m_debug->stepOver(); @@ -693,17 +683,17 @@ void PCSX::Widgets::Assembly::draw(psxRegisters* registers, Memory* memory, cons std::string contextMenuTitle = "assembly address menu "; contextMenuTitle += dispAddr; if (ImGui::BeginPopupContextItem(contextMenuTitle.c_str())) { - DButton(_("Run to cursor"), !PCSX::g_system->running(), [&]() mutable { + GUI::DButton(_("Run to cursor"), !PCSX::g_system->running(), [&]() mutable { PCSX::g_emulator.m_debug->addBreakpoint(dispAddr, Debug::BE, true); ImGui::CloseCurrentPopup(); PCSX::g_system->resume(); }); - DButton(_("Set Breakpoint here"), !hasBP, [&]() mutable { + GUI::DButton(_("Set Breakpoint here"), !hasBP, [&]() mutable { PCSX::g_emulator.m_debug->addBreakpoint(dispAddr, Debug::BE); ImGui::CloseCurrentPopup(); hasBP = true; }); - DButton(_("Remove breakpoint from here"), hasBP, [&]() mutable { + GUI::DButton(_("Remove breakpoint from here"), hasBP, [&]() mutable { PCSX::g_emulator.m_debug->eraseBP(currentBP); ImGui::CloseCurrentPopup(); hasBP = false; diff --git a/src/gui/widgets/ftdi.cc b/src/gui/widgets/ftdi.cc index 64c7d1130..1a5b85d98 100644 --- a/src/gui/widgets/ftdi.cc +++ b/src/gui/widgets/ftdi.cc @@ -21,6 +21,7 @@ #include "core/system.h" #include "ftdi/abstract.h" +#include "gui/gui.h" void PCSX::Widgets::FTDI::draw(const char* title) { if (!ImGui::Begin(title, &m_show)) { @@ -30,11 +31,19 @@ void PCSX::Widgets::FTDI::draw(const char* title) { if (ImGui::Button(_("Scan"))) ::PCSX::FTDI::Devices::scan(); - auto& devices = ::PCSX::FTDI::Devices::get(); + bool isThreadRunning = ::PCSX::FTDI::Devices::isThreadRunning(); + GUI::DButton("Start Thread", !isThreadRunning, []() { ::PCSX::FTDI::Devices::startThread(); }); + GUI::DButton("Stop Thread", isThreadRunning, []() { ::PCSX::FTDI::Devices::stopThread(); }); - ImGui::Text((std::to_string(devices.size()) + " devices detected").c_str()); + unsigned count = 0; + ::PCSX::FTDI::Devices::iterate([&count](::PCSX::FTDI::Device& d) mutable { + count++; + return true; + }); + + ImGui::Text((std::to_string(count) + " devices detected").c_str()); ImGui::Separator(); - for (auto& d : devices) { + ::PCSX::FTDI::Devices::iterate([](::PCSX::FTDI::Device& d) { ImGui::Text("Vendor Id: %04x", d.getVendorID()); ImGui::Text("Device Id: %04x", d.getDeviceID()); ImGui::Text("Type: %i", d.getType()); @@ -43,7 +52,8 @@ void PCSX::Widgets::FTDI::draw(const char* title) { ImGui::Text("Locked: %s", d.isLocked() ? "true" : "false"); ImGui::Text("High Speed: %s", d.isHighSpeed() ? "true" : "false"); ImGui::Separator(); - } + return true; + }); ImGui::End(); } diff --git a/src/main/main.cc b/src/main/main.cc index 95bd2c633..da5f6cec1 100644 --- a/src/main/main.cc +++ b/src/main/main.cc @@ -169,7 +169,6 @@ using json = nlohmann::json; int main(int argc, char **argv) { const flags::args args(argc, argv); - PCSX::Slice slice; if (args.get("dumpproto")) { PCSX::SaveStates::ProtoFile::dumpSchema(std::cout); diff --git a/src/support/slice.h b/src/support/slice.h index 82e9f2a4e..16d27f492 100644 --- a/src/support/slice.h +++ b/src/support/slice.h @@ -26,25 +26,23 @@ namespace PCSX { class Slice { public: - Slice() : m_isInlined(false), m_isOwned(false), m_size(0) { - m_data.ptr = nullptr; - } + Slice() : m_isInlined(false), m_isOwned(false), m_size(0) { m_data.ptr = nullptr; } ~Slice() { maybeFree(); } - void copy(const void * data, uint32_t size) { + void copy(const void *data, uint32_t size) { assert(size < (1 << 30)); maybeFree(); m_size = size; m_isOwned = true; if (size > sizeof(m_data.inlined)) { m_isInlined = false; - m_data.ptr = (uint8_t *) malloc(size); + m_data.ptr = (uint8_t *)malloc(size); memcpy(m_data.ptr, data, size); } else { m_isInlined = true; memcpy(m_data.inlined, data, size); } } - void acquire(void * data, uint32_t size) { + void acquire(void *data, uint32_t size) { assert(size < (1 << 30)); maybeFree(); m_size = size; @@ -52,21 +50,24 @@ class Slice { m_isInlined = false; m_data.ptr = data; } - void borrow(const void * data, uint32_t size) { + void borrow(const void *data, uint32_t size) { assert(size < (1 << 30)); maybeFree(); m_size = size; m_isOwned = false; m_isInlined = false; - m_data.ptr = const_cast(data); + m_data.ptr = const_cast(data); } - const void * data() { return m_isInlined ? m_data.inlined : m_data.ptr; } + const void *data() { return m_isInlined ? m_data.inlined : m_data.ptr; } const uint32_t size() { return m_size; } + private: - void maybeFree() { if (m_isOwned && !m_isInlined) free(m_data.ptr); } + void maybeFree() { + if (m_isOwned && !m_isInlined) free(m_data.ptr); + } union { uint8_t inlined[24]; - void * ptr; + void *ptr; } m_data; bool m_isInlined : 1; bool m_isOwned : 1; From b351d89108bacd07f6b6029de9e7862b0b67c3ad Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 18 Jan 2020 15:57:34 -0800 Subject: [PATCH 8/9] LibUV glue. --- src/ftdi/abstract-ftd2xx-win32.cc | 49 ++++++++++++++++++++++++------- src/ftdi/abstract.h | 35 ++++++++++++++++++++-- src/gui/gui.h | 2 ++ src/main/main.cc | 2 ++ vsprojects/ftdi/ftdi.vcxproj | 24 ++++++++++----- vsprojects/includes.props | 2 ++ 6 files changed, 94 insertions(+), 20 deletions(-) diff --git a/src/ftdi/abstract-ftd2xx-win32.cc b/src/ftdi/abstract-ftd2xx-win32.cc index c42ccade0..e768f9f14 100644 --- a/src/ftdi/abstract-ftd2xx-win32.cc +++ b/src/ftdi/abstract-ftd2xx-win32.cc @@ -1,4 +1,4 @@ -/*************************************************************************** +/***s************************************************************************ * Copyright (C) 2019 PCSX-Redux authors * * * * This program is free software; you can redistribute it and/or modify * @@ -51,7 +51,8 @@ class DeviceData { } // namespace FTDI } // namespace PCSX -static std::vector s_devices; +static PCSX::FTDI::Device* s_devices = nullptr; +static unsigned s_numDevs = 0; static HANDLE s_thread; static std::atomic_bool s_exitThread; static bool s_threadRunning = false; @@ -59,21 +60,36 @@ static HANDLE s_kickEvent = nullptr; static std::shared_mutex s_listLock; static unsigned s_numOpened = 0; +static PCSX::GUI* s_gui = nullptr; + +static void asyncCallbackTrampoline(uv_async_t* handle) { + PCSX::FTDI::Device* device = (PCSX::FTDI::Device*)handle->data; + device->asyncCallback(); +} + +static void asyncCloseCallback(uv_handle_t* handle) {} + +PCSX::FTDI::Device::Device() { + uv_async_init(s_gui->loop(), &m_async, asyncCallbackTrampoline); + m_async.data = this; +} + PCSX::FTDI::Device::~Device() { assert(m_private->m_state == Private::DeviceData::STATE_CLOSED); assert(!m_private->m_event); assert(!m_private->m_handle); delete m_private; + uv_close(reinterpret_cast(&m_async), asyncCloseCallback); } void PCSX::FTDI::Device::open() { - std::shared_lock guard(s_listLock); + std::unique_lock guard(s_listLock); assert(m_private->m_state == Private::DeviceData::STATE_CLOSED); m_private->m_state = Private::DeviceData::STATE_OPEN_PENDING; SetEvent(s_kickEvent); } void PCSX::FTDI::Device::close() { - std::shared_lock guard(s_listLock); + std::unique_lock guard(s_listLock); assert(m_private->m_state == Private::DeviceData::STATE_OPENED); m_private->m_state = Private::DeviceData::STATE_CLOSE_PENDING; SetEvent(s_kickEvent); @@ -85,19 +101,22 @@ void PCSX::FTDI::Devices::scan() { DWORD numDevs = 0; std::unique_lock guard(s_listLock); - if (s_numOpened != 0) return; + // we can't modify the list if there's any device that's still opened + if (s_numDevs != 0) return; - s_devices.clear(); + delete[] s_devices; + s_numDevs = 0; status = FT_CreateDeviceInfoList(&numDevs); if (status != FT_OK || numDevs == 0) return; + s_numDevs = numDevs; FT_DEVICE_LIST_INFO_NODE* nodes = new FT_DEVICE_LIST_INFO_NODE[numDevs]; status = FT_GetDeviceInfoList(nodes, &numDevs); if (status == FT_OK && numDevs != 0) { - s_devices.resize(numDevs); + s_devices = new Device[numDevs]; for (DWORD i = 0; i < numDevs; i++) { const FT_DEVICE_LIST_INFO_NODE* n = nodes + i; s_devices[i].m_locked = n->Flags & FT_FLAGS_OPENED; @@ -116,8 +135,8 @@ void PCSX::FTDI::Devices::scan() { void PCSX::FTDI::Devices::iterate(std::function iter) { std::shared_lock guard(s_listLock); - for (auto& d : s_devices) { - if (!iter(d)) break; + for (unsigned i = 0; i < s_numDevs; i++) { + if (!iter(s_devices[i])) break; } } @@ -125,11 +144,14 @@ void PCSX::FTDI::Devices::threadProc() { SetThreadDescription(GetCurrentThread(), L"abstract ftd2xx thread"); while (!s_exitThread) { std::vector objects; + std::vector devices; objects.push_back(s_kickEvent); + devices.push_back(nullptr); { std::shared_lock guard(s_listLock); - for (auto& device : s_devices) { + for (unsigned i = 0; i < s_numDevs; i++) { + auto& device = s_devices[i]; switch (device.m_private->m_state) { case Private::DeviceData::STATE_OPEN_PENDING: s_numOpened++; @@ -142,6 +164,7 @@ void PCSX::FTDI::Devices::threadProc() { device.m_private->m_state = Private::DeviceData::STATE_OPENED; case Private::DeviceData::STATE_OPENED: objects.push_back(device.m_private->m_event); + devices.push_back(&device); break; case Private::DeviceData::STATE_CLOSE_PENDING: s_numOpened--; @@ -158,6 +181,10 @@ void PCSX::FTDI::Devices::threadProc() { do { assert(objects.size() <= MAXIMUM_WAIT_OBJECTS); idx = WaitForMultipleObjects(objects.size(), objects.data(), FALSE, INFINITE); + Device* device = devices[idx - WAIT_OBJECT_0]; + if (!device) continue; + DWORD events; + FT_GetEventStatus(device->m_private->m_handle, &events); } while (idx != WAIT_OBJECT_0); } CloseHandle(s_kickEvent); @@ -189,4 +216,6 @@ void PCSX::FTDI::Devices::stopThread() { bool PCSX::FTDI::Devices::isThreadRunning() { return s_threadRunning; } +void PCSX::FTDI::Devices::setGUI(GUI* gui) { s_gui = gui; } + #endif diff --git a/src/ftdi/abstract.h b/src/ftdi/abstract.h index 7e24c40f5..6a78467c5 100644 --- a/src/ftdi/abstract.h +++ b/src/ftdi/abstract.h @@ -21,9 +21,12 @@ #include +#include #include #include -#include + +#include "gui/gui.h" +#include "support/slice.h" namespace PCSX { @@ -35,6 +38,7 @@ class DeviceData; } class Device { public: + Device(); ~Device(); bool isLocked() const { return m_locked; } bool isHighSpeed() const { return m_highSpeed; } @@ -49,6 +53,9 @@ class Device { void open(); void close(); + // technically private, but difficult to enforce properly + void asyncCallback() {} + private: bool m_locked = false; bool m_highSpeed = false; @@ -58,7 +65,30 @@ class Device { std::string m_serial = ""; std::string m_description = ""; - Private::DeviceData* m_private; + Private::DeviceData* m_private = nullptr; + + static const unsigned SLICES_COUNT = 256; + Slice m_slices[SLICES_COUNT]; + std::atomic_uint16_t m_slicesIndexes = 0; + + uv_async_t m_async; + + unsigned usedSlices() { + uint16_t indexes = m_slicesIndexes.load(); + unsigned first = indexes & 0xff; + unsigned last = (indexes >> 8) & 0xff; + if (last < first) last += 256; + return last - first; + } + + unsigned availableSlices() { return 256 - usedSlices(); } + + Slice& allocateSlice() { + while (availableSlices() == 0) + ; + uint16_t indexes = m_slicesIndexes.fetch_add(0x100); + return m_slices[(indexes >> 8) & 0xff]; + } friend class Devices; }; @@ -70,6 +100,7 @@ class Devices { static bool isThreadRunning(); static void startThread(); static void stopThread(); + static void setGUI(GUI*); // technically private, but difficult to enforce properly static void threadProc(); diff --git a/src/gui/gui.h b/src/gui/gui.h index bea5d295c..e88ab07bb 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -105,6 +105,8 @@ class GUI final { } } + uv_loop_t *loop() { return &m_loop; } + private: GLFWwindow *m_window = nullptr; int &m_glfwPosX = settings.get().value; diff --git a/src/main/main.cc b/src/main/main.cc index da5f6cec1..74906a10d 100644 --- a/src/main/main.cc +++ b/src/main/main.cc @@ -30,6 +30,7 @@ #include "core/r3000a.h" #include "core/sstate.h" #include "flags.h" +#include "ftdi/abstract.h" #include "gui/gui.h" #include "spu/interface.h" #include "support/slice.h" @@ -197,6 +198,7 @@ int main(int argc, char **argv) { LoadPlugins(); PCSX::g_emulator.m_gpu->open(s_gui); PCSX::g_emulator.m_spu->open(); + PCSX::FTDI::Devices::setGUI(s_gui); PCSX::g_emulator.EmuInit(); PCSX::g_emulator.EmuReset(); diff --git a/vsprojects/ftdi/ftdi.vcxproj b/vsprojects/ftdi/ftdi.vcxproj index e2af83b39..1779a1dd4 100644 --- a/vsprojects/ftdi/ftdi.vcxproj +++ b/vsprojects/ftdi/ftdi.vcxproj @@ -58,15 +58,19 @@ + + + + @@ -85,9 +89,10 @@ Level3 true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - ..\..\src + ..\..\src;..\..\third_party;..\..\third_party\imgui;..\..\third_party\imgui_club;..\..\third_party\libuv\include + stdcpp17 Console @@ -98,9 +103,10 @@ Level3 true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - ..\..\src + ..\..\src;..\..\third_party;..\..\third_party\imgui;..\..\third_party\imgui_club;..\..\third_party\libuv\include + stdcpp17 Console @@ -113,9 +119,10 @@ true true true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true - ..\..\src + ..\..\src;..\..\third_party;..\..\third_party\imgui;..\..\third_party\imgui_club;..\..\third_party\libuv\include + stdcpp17 Console @@ -130,9 +137,10 @@ true true true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true - ..\..\src + ..\..\src;..\..\third_party;..\..\third_party\imgui;..\..\third_party\imgui_club;..\..\third_party\libuv\include + stdcpp17 Console diff --git a/vsprojects/includes.props b/vsprojects/includes.props index 1c325ade7..b6d6fafcd 100644 --- a/vsprojects/includes.props +++ b/vsprojects/includes.props @@ -8,6 +8,8 @@ true + + From 996c42b73f0eea808c128319372291e919c4dbbe Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 18 Jan 2020 20:28:06 -0800 Subject: [PATCH 9/9] Bit more proper closing sequence. --- src/ftdi/abstract-ftd2xx-win32.cc | 39 +++++++++++++++++++++++++++++-- src/ftdi/abstract.h | 4 ++++ src/gui/widgets/ftdi.cc | 20 ++++++++++++++-- src/main/main.cc | 2 ++ 4 files changed, 61 insertions(+), 4 deletions(-) diff --git a/src/ftdi/abstract-ftd2xx-win32.cc b/src/ftdi/abstract-ftd2xx-win32.cc index e768f9f14..2a6d0f6cc 100644 --- a/src/ftdi/abstract-ftd2xx-win32.cc +++ b/src/ftdi/abstract-ftd2xx-win32.cc @@ -67,7 +67,10 @@ static void asyncCallbackTrampoline(uv_async_t* handle) { device->asyncCallback(); } -static void asyncCloseCallback(uv_handle_t* handle) {} +static void asyncCloseCallbackTrampoline(uv_handle_t* handle) { + PCSX::FTDI::Device* device = reinterpret_cast(handle->data); + device->asyncCloseCallback(); +} PCSX::FTDI::Device::Device() { uv_async_init(s_gui->loop(), &m_async, asyncCallbackTrampoline); @@ -79,7 +82,9 @@ PCSX::FTDI::Device::~Device() { assert(!m_private->m_event); assert(!m_private->m_handle); delete m_private; - uv_close(reinterpret_cast(&m_async), asyncCloseCallback); + uv_loop_t* loop = m_async.loop; + uv_close(reinterpret_cast(&m_async), asyncCloseCallbackTrampoline); + while (!m_asyncClosed) uv_run(loop, UV_RUN_ONCE); } void PCSX::FTDI::Device::open() { @@ -95,6 +100,10 @@ void PCSX::FTDI::Device::close() { SetEvent(s_kickEvent); } bool PCSX::FTDI::Device::isOpened() const { return m_private->m_state == Private::DeviceData::STATE_OPENED; } +bool PCSX::FTDI::Device::isBusy() const { + return m_private->m_state == Private::DeviceData::STATE_CLOSE_PENDING || + m_private->m_state == Private::DeviceData::STATE_OPEN_PENDING; +} void PCSX::FTDI::Devices::scan() { FT_STATUS status; @@ -185,6 +194,7 @@ void PCSX::FTDI::Devices::threadProc() { if (!device) continue; DWORD events; FT_GetEventStatus(device->m_private->m_handle, &events); + printf("%i", events); } while (idx != WAIT_OBJECT_0); } CloseHandle(s_kickEvent); @@ -216,6 +226,31 @@ void PCSX::FTDI::Devices::stopThread() { bool PCSX::FTDI::Devices::isThreadRunning() { return s_threadRunning; } +void PCSX::FTDI::Devices::shutdown() { + if (!isThreadRunning()) startThread(); + { + bool run = true; + while (run) { + run = false; + std::unique_lock guard(s_listLock); + for (unsigned i = 0; i < s_numDevs; i++) { + auto& device = s_devices[i]; + switch (device.m_private->m_state) { + case Private::DeviceData::STATE_OPENED: + device.close(); + case Private::DeviceData::STATE_CLOSE_PENDING: + case Private::DeviceData::STATE_OPEN_PENDING: + run = true; + break; + } + } + } + } + stopThread(); + delete[] s_devices; + s_numDevs = 0; +} + void PCSX::FTDI::Devices::setGUI(GUI* gui) { s_gui = gui; } #endif diff --git a/src/ftdi/abstract.h b/src/ftdi/abstract.h index 6a78467c5..6e23e323e 100644 --- a/src/ftdi/abstract.h +++ b/src/ftdi/abstract.h @@ -49,12 +49,14 @@ class Device { const std::string& getDescription() const { return m_description; } bool isOpened() const; + bool isBusy() const; void open(); void close(); // technically private, but difficult to enforce properly void asyncCallback() {} + void asyncCloseCallback() { m_asyncClosed = true; } private: bool m_locked = false; @@ -72,6 +74,7 @@ class Device { std::atomic_uint16_t m_slicesIndexes = 0; uv_async_t m_async; + bool m_asyncClosed = false; unsigned usedSlices() { uint16_t indexes = m_slicesIndexes.load(); @@ -96,6 +99,7 @@ class Device { class Devices { public: static void scan(); + static void shutdown(); static void iterate(std::function); static bool isThreadRunning(); static void startThread(); diff --git a/src/gui/widgets/ftdi.cc b/src/gui/widgets/ftdi.cc index 1a5b85d98..5c55d1d12 100644 --- a/src/gui/widgets/ftdi.cc +++ b/src/gui/widgets/ftdi.cc @@ -43,7 +43,9 @@ void PCSX::Widgets::FTDI::draw(const char* title) { ImGui::Text((std::to_string(count) + " devices detected").c_str()); ImGui::Separator(); - ::PCSX::FTDI::Devices::iterate([](::PCSX::FTDI::Device& d) { + ::PCSX::FTDI::Device* devToClose = nullptr; + ::PCSX::FTDI::Device* devToOpen = nullptr; + ::PCSX::FTDI::Devices::iterate([&](::PCSX::FTDI::Device& d) mutable { ImGui::Text("Vendor Id: %04x", d.getVendorID()); ImGui::Text("Device Id: %04x", d.getDeviceID()); ImGui::Text("Type: %i", d.getType()); @@ -51,9 +53,23 @@ void PCSX::Widgets::FTDI::draw(const char* title) { ImGui::Text("Description: %s", d.getDescription().c_str()); ImGui::Text("Locked: %s", d.isLocked() ? "true" : "false"); ImGui::Text("High Speed: %s", d.isHighSpeed() ? "true" : "false"); + ImGui::Text("Opened: %s", d.isOpened() ? "true" : "false"); + if (d.isOpened() && !d.isBusy()) { + if (ImGui::Button("Close")) { + devToClose = &d; + } + } else if (!d.isBusy()) { + if (ImGui::Button("Open")) { + devToOpen = &d; + } + } else { + ImGui::Text("Device is busy"); + } ImGui::Separator(); return true; }); - ImGui::End(); + + if (devToClose) devToClose->close(); + if (devToOpen) devToOpen->open(); } diff --git a/src/main/main.cc b/src/main/main.cc index 74906a10d..5a8f639a6 100644 --- a/src/main/main.cc +++ b/src/main/main.cc @@ -227,6 +227,8 @@ int main(int argc, char **argv) { PCSX::g_emulator.m_gpu->shutdown(); PCSX::g_emulator.m_cdrom->m_iso.shutdown(); + PCSX::FTDI::Devices::shutdown(); + s_gui->close(); delete s_gui;