Skip to content

Commit 720de96

Browse files
committed
Device opening / closing.
1 parent e89a687 commit 720de96

File tree

7 files changed

+172
-54
lines changed

7 files changed

+172
-54
lines changed

src/ftdi/abstract-ftd2xx-win32.cc

Lines changed: 109 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,69 @@
2424
#include <assert.h>
2525
#include <windows.h>
2626

27+
#include <atomic>
28+
#include <condition_variable>
2729
#include <mutex>
30+
#include <shared_mutex>
31+
#include <thread>
2832

2933
#include "ftd2xx.h"
3034
#include "ftdi/abstract.h"
3135

36+
namespace PCSX {
37+
namespace FTDI {
38+
namespace Private {
39+
class DeviceData {
40+
public:
41+
FT_HANDLE m_handle = nullptr;
42+
HANDLE m_event = nullptr;
43+
enum {
44+
STATE_CLOSED,
45+
STATE_OPEN_PENDING,
46+
STATE_OPENED,
47+
STATE_CLOSE_PENDING,
48+
} m_state = STATE_CLOSED;
49+
};
50+
} // namespace Private
51+
} // namespace FTDI
52+
} // namespace PCSX
53+
3254
static std::vector<PCSX::FTDI::Device> s_devices;
55+
static HANDLE s_thread;
56+
static std::atomic_bool s_exitThread;
57+
static bool s_threadRunning = false;
58+
static HANDLE s_kickEvent = nullptr;
59+
static std::shared_mutex s_listLock;
60+
static unsigned s_numOpened = 0;
61+
62+
PCSX::FTDI::Device::~Device() {
63+
assert(m_private->m_state == Private::DeviceData::STATE_CLOSED);
64+
assert(!m_private->m_event);
65+
assert(!m_private->m_handle);
66+
delete m_private;
67+
}
68+
69+
void PCSX::FTDI::Device::open() {
70+
std::shared_lock<std::shared_mutex> guard(s_listLock);
71+
assert(m_private->m_state == Private::DeviceData::STATE_CLOSED);
72+
m_private->m_state = Private::DeviceData::STATE_OPEN_PENDING;
73+
SetEvent(s_kickEvent);
74+
}
75+
void PCSX::FTDI::Device::close() {
76+
std::shared_lock<std::shared_mutex> guard(s_listLock);
77+
assert(m_private->m_state == Private::DeviceData::STATE_OPENED);
78+
m_private->m_state = Private::DeviceData::STATE_CLOSE_PENDING;
79+
SetEvent(s_kickEvent);
80+
}
81+
bool PCSX::FTDI::Device::isOpened() const { return m_private->m_state == Private::DeviceData::STATE_OPENED; }
3382

3483
void PCSX::FTDI::Devices::scan() {
3584
FT_STATUS status;
3685
DWORD numDevs = 0;
3786

87+
std::unique_lock<std::shared_mutex> guard(s_listLock);
88+
if (s_numOpened != 0) return;
89+
3890
s_devices.clear();
3991
status = FT_CreateDeviceInfoList(&numDevs);
4092

@@ -55,46 +107,86 @@ void PCSX::FTDI::Devices::scan() {
55107
s_devices[i].m_type = n->Type;
56108
s_devices[i].m_serial = n->SerialNumber;
57109
s_devices[i].m_description = n->Description;
110+
s_devices[i].m_private = new Private::DeviceData();
58111
}
59112
}
60113

61114
delete[] nodes;
62115
}
63116

64-
const std::vector<PCSX::FTDI::Device>& PCSX::FTDI::Devices::get() { return s_devices; }
65-
66-
static HANDLE s_thread = nullptr;
67-
static HANDLE s_exitEvent = nullptr;
68-
static bool s_threadRunning = false;
117+
void PCSX::FTDI::Devices::iterate(std::function<bool(Device&)> iter) {
118+
std::shared_lock<std::shared_mutex> guard(s_listLock);
119+
for (auto& d : s_devices) {
120+
if (!iter(d)) break;
121+
}
122+
}
69123

70-
static DWORD WINAPI threadProc(LPVOID parameter) {
71-
bool exitting = false;
124+
void PCSX::FTDI::Devices::threadProc() {
72125
SetThreadDescription(GetCurrentThread(), L"abstract ftd2xx thread");
73-
while (!exitting) {
74-
HANDLE objects[1];
75-
objects[0] = s_exitEvent;
76-
DWORD idx = WaitForMultipleObjects(1, objects, FALSE, INFINITE);
77-
exitting = idx == WAIT_OBJECT_0;
126+
while (!s_exitThread) {
127+
std::vector<HANDLE> objects;
128+
objects.push_back(s_kickEvent);
129+
{
130+
std::shared_lock<std::shared_mutex> guard(s_listLock);
131+
132+
for (auto& device : s_devices) {
133+
switch (device.m_private->m_state) {
134+
case Private::DeviceData::STATE_OPEN_PENDING:
135+
s_numOpened++;
136+
FT_OpenEx(const_cast<char*>(device.m_serial.c_str()), FT_OPEN_BY_SERIAL_NUMBER,
137+
&device.m_private->m_handle);
138+
device.m_private->m_event = CreateEvent(nullptr, FALSE, FALSE, L"Event for FTDI device");
139+
FT_SetEventNotification(device.m_private->m_handle,
140+
FT_EVENT_RXCHAR | FT_EVENT_MODEM_STATUS | FT_EVENT_LINE_STATUS,
141+
device.m_private->m_event);
142+
device.m_private->m_state = Private::DeviceData::STATE_OPENED;
143+
case Private::DeviceData::STATE_OPENED:
144+
objects.push_back(device.m_private->m_event);
145+
break;
146+
case Private::DeviceData::STATE_CLOSE_PENDING:
147+
s_numOpened--;
148+
FT_Close(device.m_private->m_handle);
149+
CloseHandle(device.m_private->m_event);
150+
device.m_private->m_handle = nullptr;
151+
device.m_private->m_event = nullptr;
152+
device.m_private->m_state = Private::DeviceData::STATE_CLOSED;
153+
break;
154+
}
155+
}
156+
}
157+
DWORD idx;
158+
do {
159+
assert(objects.size() <= MAXIMUM_WAIT_OBJECTS);
160+
idx = WaitForMultipleObjects(objects.size(), objects.data(), FALSE, INFINITE);
161+
} while (idx != WAIT_OBJECT_0);
78162
}
79-
CloseHandle(s_exitEvent);
80-
s_exitEvent = nullptr;
163+
CloseHandle(s_kickEvent);
164+
s_kickEvent = nullptr;
165+
s_exitThread = false;
81166
s_threadRunning = false;
167+
}
168+
169+
static DWORD WINAPI threadProcTrampoline(LPVOID parameter) {
170+
PCSX::FTDI::Devices::threadProc();
82171
return 0;
83172
}
84173

85174
void PCSX::FTDI::Devices::startThread() {
86175
assert(!s_threadRunning);
87-
s_exitEvent = CreateEvent(nullptr, FALSE, FALSE, L"abstract ftd2xx exit event");
176+
s_kickEvent = CreateEvent(nullptr, FALSE, FALSE, L"abstract ftd2xx kick event");
88177
s_threadRunning = true;
89-
s_thread = CreateThread(nullptr, 0, threadProc, nullptr, 0, nullptr);
178+
s_thread = CreateThread(nullptr, 0, threadProcTrampoline, nullptr, 0, nullptr);
90179
}
91180

92181
void PCSX::FTDI::Devices::stopThread() {
93182
assert(s_threadRunning);
94-
SetEvent(s_exitEvent);
183+
s_exitThread = true;
184+
SetEvent(s_kickEvent);
95185
WaitForSingleObject(s_thread, INFINITE);
96186
s_thread = nullptr;
97187
assert(!s_threadRunning);
98188
}
99189

190+
bool PCSX::FTDI::Devices::isThreadRunning() { return s_threadRunning; }
191+
100192
#endif

src/ftdi/abstract.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include <stdint.h>
2323

24+
#include <functional>
2425
#include <string>
2526
#include <vector>
2627

@@ -29,8 +30,12 @@ namespace PCSX {
2930
namespace FTDI {
3031

3132
class Devices;
33+
namespace Private {
34+
class DeviceData;
35+
}
3236
class Device {
3337
public:
38+
~Device();
3439
bool isLocked() const { return m_locked; }
3540
bool isHighSpeed() const { return m_highSpeed; }
3641
uint16_t getVendorID() const { return m_vendorID; }
@@ -39,6 +44,11 @@ class Device {
3944
const std::string& getSerial() const { return m_serial; }
4045
const std::string& getDescription() const { return m_description; }
4146

47+
bool isOpened() const;
48+
49+
void open();
50+
void close();
51+
4252
private:
4353
bool m_locked = false;
4454
bool m_highSpeed = false;
@@ -47,17 +57,22 @@ class Device {
4757
uint32_t m_type = 0;
4858
std::string m_serial = "";
4959
std::string m_description = "";
50-
void* m_handle = nullptr;
60+
61+
Private::DeviceData* m_private;
5162

5263
friend class Devices;
5364
};
5465

5566
class Devices {
5667
public:
5768
static void scan();
58-
static const std::vector<Device>& get();
69+
static void iterate(std::function<bool(Device&)>);
70+
static bool isThreadRunning();
5971
static void startThread();
6072
static void stopThread();
73+
74+
// technically private, but difficult to enforce properly
75+
static void threadProc();
6176
};
6277

6378
} // namespace FTDI

src/gui/gui.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,17 @@ namespace PCSX {
4949

5050
class GUI final {
5151
public:
52+
static void DButton(const char *label, bool enabled, std::function<void(void)> clicked) {
53+
if (!enabled) {
54+
const ImVec4 lolight = ImGui::GetStyle().Colors[ImGuiCol_TextDisabled];
55+
ImGui::PushStyleColor(ImGuiCol_Button, lolight);
56+
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, lolight);
57+
ImGui::PushStyleColor(ImGuiCol_ButtonActive, lolight);
58+
}
59+
if (ImGui::Button(label) && enabled) clicked();
60+
if (!enabled) ImGui::PopStyleColor(3);
61+
}
62+
5263
GUI(const flags::args &args) : m_args(args) {}
5364
void init();
5465
void close();

src/gui/widgets/assembly.cc

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "core/disr3000a.h"
3232
#include "core/psxmem.h"
3333
#include "core/r3000a.h"
34+
#include "gui/gui.h"
3435
#include "gui/widgets/assembly.h"
3536

3637
#include "imgui_memory_editor/imgui_memory_editor.h"
@@ -70,17 +71,6 @@ uint32_t virtToReal(uint32_t virt) {
7071
return pc;
7172
};
7273

73-
void DButton(const char* label, bool enabled, std::function<void(void)> clicked) {
74-
if (!enabled) {
75-
const ImVec4 lolight = ImGui::GetStyle().Colors[ImGuiCol_TextDisabled];
76-
ImGui::PushStyleColor(ImGuiCol_Button, lolight);
77-
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, lolight);
78-
ImGui::PushStyleColor(ImGuiCol_ButtonActive, lolight);
79-
}
80-
if (ImGui::Button(label) && enabled) clicked();
81-
if (!enabled) ImGui::PopStyleColor(3);
82-
}
83-
8474
class DummyAsm : public PCSX::Disasm {
8575
virtual void Invalid() final {}
8676
virtual void OpCode(const char* str) final {}
@@ -504,15 +494,15 @@ void PCSX::Widgets::Assembly::draw(psxRegisters* registers, Memory* memory, cons
504494
ImGui::SameLine();
505495
ImGui::Checkbox(_("Follow PC"), &m_followPC);
506496
ImGui::SameLine();
507-
DButton(_("Pause"), g_system->running(), [&]() mutable { g_system->pause(); });
497+
GUI::DButton(_("Pause"), g_system->running(), [&]() mutable { g_system->pause(); });
508498
ImGui::SameLine();
509-
DButton(_("Resume"), !g_system->running(), [&]() mutable { g_system->resume(); });
499+
GUI::DButton(_("Resume"), !g_system->running(), [&]() mutable { g_system->resume(); });
510500
ImGui::SameLine();
511-
DButton(_("Step In"), !g_system->running(), [&]() mutable { g_emulator.m_debug->stepIn(); });
501+
GUI::DButton(_("Step In"), !g_system->running(), [&]() mutable { g_emulator.m_debug->stepIn(); });
512502
ImGui::SameLine();
513-
DButton(_("Step Over"), !g_system->running(), [&]() mutable { g_emulator.m_debug->stepOver(); });
503+
GUI::DButton(_("Step Over"), !g_system->running(), [&]() mutable { g_emulator.m_debug->stepOver(); });
514504
ImGui::SameLine();
515-
DButton(_("Step Out"), !g_system->running(), [&]() mutable { g_emulator.m_debug->stepOut(); });
505+
GUI::DButton(_("Step Out"), !g_system->running(), [&]() mutable { g_emulator.m_debug->stepOut(); });
516506
if (!g_system->running()) {
517507
if (ImGui::IsKeyPressed(GLFW_KEY_F10)) {
518508
g_emulator.m_debug->stepOver();
@@ -693,17 +683,17 @@ void PCSX::Widgets::Assembly::draw(psxRegisters* registers, Memory* memory, cons
693683
std::string contextMenuTitle = "assembly address menu ";
694684
contextMenuTitle += dispAddr;
695685
if (ImGui::BeginPopupContextItem(contextMenuTitle.c_str())) {
696-
DButton(_("Run to cursor"), !PCSX::g_system->running(), [&]() mutable {
686+
GUI::DButton(_("Run to cursor"), !PCSX::g_system->running(), [&]() mutable {
697687
PCSX::g_emulator.m_debug->addBreakpoint(dispAddr, Debug::BE, true);
698688
ImGui::CloseCurrentPopup();
699689
PCSX::g_system->resume();
700690
});
701-
DButton(_("Set Breakpoint here"), !hasBP, [&]() mutable {
691+
GUI::DButton(_("Set Breakpoint here"), !hasBP, [&]() mutable {
702692
PCSX::g_emulator.m_debug->addBreakpoint(dispAddr, Debug::BE);
703693
ImGui::CloseCurrentPopup();
704694
hasBP = true;
705695
});
706-
DButton(_("Remove breakpoint from here"), hasBP, [&]() mutable {
696+
GUI::DButton(_("Remove breakpoint from here"), hasBP, [&]() mutable {
707697
PCSX::g_emulator.m_debug->eraseBP(currentBP);
708698
ImGui::CloseCurrentPopup();
709699
hasBP = false;

src/gui/widgets/ftdi.cc

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include "core/system.h"
2323
#include "ftdi/abstract.h"
24+
#include "gui/gui.h"
2425

2526
void PCSX::Widgets::FTDI::draw(const char* title) {
2627
if (!ImGui::Begin(title, &m_show)) {
@@ -30,11 +31,19 @@ void PCSX::Widgets::FTDI::draw(const char* title) {
3031

3132
if (ImGui::Button(_("Scan"))) ::PCSX::FTDI::Devices::scan();
3233

33-
auto& devices = ::PCSX::FTDI::Devices::get();
34+
bool isThreadRunning = ::PCSX::FTDI::Devices::isThreadRunning();
35+
GUI::DButton("Start Thread", !isThreadRunning, []() { ::PCSX::FTDI::Devices::startThread(); });
36+
GUI::DButton("Stop Thread", isThreadRunning, []() { ::PCSX::FTDI::Devices::stopThread(); });
3437

35-
ImGui::Text((std::to_string(devices.size()) + " devices detected").c_str());
38+
unsigned count = 0;
39+
::PCSX::FTDI::Devices::iterate([&count](::PCSX::FTDI::Device& d) mutable {
40+
count++;
41+
return true;
42+
});
43+
44+
ImGui::Text((std::to_string(count) + " devices detected").c_str());
3645
ImGui::Separator();
37-
for (auto& d : devices) {
46+
::PCSX::FTDI::Devices::iterate([](::PCSX::FTDI::Device& d) {
3847
ImGui::Text("Vendor Id: %04x", d.getVendorID());
3948
ImGui::Text("Device Id: %04x", d.getDeviceID());
4049
ImGui::Text("Type: %i", d.getType());
@@ -43,7 +52,8 @@ void PCSX::Widgets::FTDI::draw(const char* title) {
4352
ImGui::Text("Locked: %s", d.isLocked() ? "true" : "false");
4453
ImGui::Text("High Speed: %s", d.isHighSpeed() ? "true" : "false");
4554
ImGui::Separator();
46-
}
55+
return true;
56+
});
4757

4858
ImGui::End();
4959
}

src/main/main.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,6 @@ using json = nlohmann::json;
169169

170170
int main(int argc, char **argv) {
171171
const flags::args args(argc, argv);
172-
PCSX::Slice slice;
173172

174173
if (args.get<bool>("dumpproto")) {
175174
PCSX::SaveStates::ProtoFile::dumpSchema(std::cout);

0 commit comments

Comments
 (0)