mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-04-02 11:01:52 -04:00
Compare commits
5 commits
Author | SHA1 | Date | |
---|---|---|---|
|
57ff99ce53 | ||
|
8b5cafa98e | ||
|
186e92221a | ||
|
31d2db6f78 | ||
|
ebb5ab53e2 |
11 changed files with 137 additions and 68 deletions
|
@ -8,6 +8,7 @@
|
||||||
#include "gui/debugger/DebuggerWindow2.h"
|
#include "gui/debugger/DebuggerWindow2.h"
|
||||||
|
|
||||||
#include "Cafe/OS/libs/coreinit/coreinit.h"
|
#include "Cafe/OS/libs/coreinit/coreinit.h"
|
||||||
|
#include "util/helpers/helpers.h"
|
||||||
|
|
||||||
#if BOOST_OS_WINDOWS
|
#if BOOST_OS_WINDOWS
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
@ -136,11 +137,6 @@ void debugger_createCodeBreakpoint(uint32 address, uint8 bpType)
|
||||||
debugger_updateExecutionBreakpoint(address);
|
debugger_updateExecutionBreakpoint(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void debugger_createExecuteBreakpoint(uint32 address)
|
|
||||||
{
|
|
||||||
debugger_createCodeBreakpoint(address, DEBUGGER_BP_T_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace coreinit
|
namespace coreinit
|
||||||
{
|
{
|
||||||
std::vector<std::thread::native_handle_type>& OSGetSchedulerThreads();
|
std::vector<std::thread::native_handle_type>& OSGetSchedulerThreads();
|
||||||
|
@ -294,8 +290,23 @@ void debugger_toggleExecuteBreakpoint(uint32 address)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// create new breakpoint
|
// create new execution breakpoint
|
||||||
debugger_createExecuteBreakpoint(address);
|
debugger_createCodeBreakpoint(address, DEBUGGER_BP_T_NORMAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void debugger_toggleLoggingBreakpoint(uint32 address)
|
||||||
|
{
|
||||||
|
auto existingBP = debugger_getFirstBP(address, DEBUGGER_BP_T_LOGGING);
|
||||||
|
if (existingBP)
|
||||||
|
{
|
||||||
|
// delete existing breakpoint
|
||||||
|
debugger_deleteBreakpoint(existingBP);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// create new logging breakpoint
|
||||||
|
debugger_createCodeBreakpoint(address, DEBUGGER_BP_T_LOGGING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -538,7 +549,48 @@ void debugger_enterTW(PPCInterpreter_t* hCPU)
|
||||||
{
|
{
|
||||||
if (bp->bpType == DEBUGGER_BP_T_LOGGING && bp->enabled)
|
if (bp->bpType == DEBUGGER_BP_T_LOGGING && bp->enabled)
|
||||||
{
|
{
|
||||||
std::string logName = !bp->comment.empty() ? "Breakpoint '"+boost::nowide::narrow(bp->comment)+"'" : fmt::format("Breakpoint at 0x{:08X} (no comment)", bp->address);
|
std::string comment = !bp->comment.empty() ? boost::nowide::narrow(bp->comment) : fmt::format("Breakpoint at 0x{:08X} (no comment)", bp->address);
|
||||||
|
|
||||||
|
auto replacePlaceholders = [&](const std::string& prefix, const auto& formatFunc)
|
||||||
|
{
|
||||||
|
size_t pos = 0;
|
||||||
|
while ((pos = comment.find(prefix, pos)) != std::string::npos)
|
||||||
|
{
|
||||||
|
size_t endPos = comment.find('}', pos);
|
||||||
|
if (endPos == std::string::npos)
|
||||||
|
break;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (int regNum = ConvertString<int>(comment.substr(pos + prefix.length(), endPos - pos - prefix.length())); regNum >= 0 && regNum < 32)
|
||||||
|
{
|
||||||
|
std::string replacement = formatFunc(regNum);
|
||||||
|
comment.replace(pos, endPos - pos + 1, replacement);
|
||||||
|
pos += replacement.length();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos = endPos + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
pos = endPos + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Replace integer register placeholders {rX}
|
||||||
|
replacePlaceholders("{r", [&](int regNum) {
|
||||||
|
return fmt::format("0x{:08X}", hCPU->gpr[regNum]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Replace floating point register placeholders {fX}
|
||||||
|
replacePlaceholders("{f", [&](int regNum) {
|
||||||
|
return fmt::format("{}", hCPU->fpr[regNum].fpr);
|
||||||
|
});
|
||||||
|
|
||||||
|
std::string logName = "Breakpoint '" + comment + "'";
|
||||||
std::string logContext = fmt::format("Thread: {:08x} LR: 0x{:08x}", MEMPTR<OSThread_t>(coreinit::OSGetCurrentThread()).GetMPTR(), hCPU->spr.LR, cemuLog_advancedPPCLoggingEnabled() ? " Stack Trace:" : "");
|
std::string logContext = fmt::format("Thread: {:08x} LR: 0x{:08x}", MEMPTR<OSThread_t>(coreinit::OSGetCurrentThread()).GetMPTR(), hCPU->spr.LR, cemuLog_advancedPPCLoggingEnabled() ? " Stack Trace:" : "");
|
||||||
cemuLog_log(LogType::Force, "[Debugger] {} was executed! {}", logName, logContext);
|
cemuLog_log(LogType::Force, "[Debugger] {} was executed! {}", logName, logContext);
|
||||||
if (cemuLog_advancedPPCLoggingEnabled())
|
if (cemuLog_advancedPPCLoggingEnabled())
|
||||||
|
|
|
@ -100,8 +100,8 @@ extern debuggerState_t debuggerState;
|
||||||
// new API
|
// new API
|
||||||
DebuggerBreakpoint* debugger_getFirstBP(uint32 address);
|
DebuggerBreakpoint* debugger_getFirstBP(uint32 address);
|
||||||
void debugger_createCodeBreakpoint(uint32 address, uint8 bpType);
|
void debugger_createCodeBreakpoint(uint32 address, uint8 bpType);
|
||||||
void debugger_createExecuteBreakpoint(uint32 address);
|
|
||||||
void debugger_toggleExecuteBreakpoint(uint32 address); // create/remove execute breakpoint
|
void debugger_toggleExecuteBreakpoint(uint32 address); // create/remove execute breakpoint
|
||||||
|
void debugger_toggleLoggingBreakpoint(uint32 address); // create/remove logging breakpoint
|
||||||
void debugger_toggleBreakpoint(uint32 address, bool state, DebuggerBreakpoint* bp);
|
void debugger_toggleBreakpoint(uint32 address, bool state, DebuggerBreakpoint* bp);
|
||||||
|
|
||||||
void debugger_createMemoryBreakpoint(uint32 address, bool onRead, bool onWrite);
|
void debugger_createMemoryBreakpoint(uint32 address, bool onRead, bool onWrite);
|
||||||
|
|
|
@ -187,8 +187,8 @@ std::string RendererOutputShader::GetOpenGlVertexSource(bool render_upside_down)
|
||||||
// vertex shader
|
// vertex shader
|
||||||
std::ostringstream vertex_source;
|
std::ostringstream vertex_source;
|
||||||
vertex_source <<
|
vertex_source <<
|
||||||
R"(#version 400
|
R"(#version 420
|
||||||
out vec2 passUV;
|
layout(location = 0) smooth out vec2 passUV;
|
||||||
|
|
||||||
out gl_PerVertex
|
out gl_PerVertex
|
||||||
{
|
{
|
||||||
|
@ -297,7 +297,7 @@ uniform vec2 nativeResolution;
|
||||||
uniform vec2 outputResolution;
|
uniform vec2 outputResolution;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
layout(location = 0) in vec2 passUV;
|
layout(location = 0) smooth in vec2 passUV;
|
||||||
layout(binding = 0) uniform sampler2D textureSrc;
|
layout(binding = 0) uniform sampler2D textureSrc;
|
||||||
layout(location = 0) out vec4 colorOut0;
|
layout(location = 0) out vec4 colorOut0;
|
||||||
)" + shaderSrc;
|
)" + shaderSrc;
|
||||||
|
|
|
@ -183,17 +183,17 @@ void CubebAPI::Destroy()
|
||||||
|
|
||||||
std::vector<IAudioAPI::DeviceDescriptionPtr> CubebAPI::GetDevices()
|
std::vector<IAudioAPI::DeviceDescriptionPtr> CubebAPI::GetDevices()
|
||||||
{
|
{
|
||||||
cubeb_device_collection devices;
|
|
||||||
if (cubeb_enumerate_devices(s_context, CUBEB_DEVICE_TYPE_OUTPUT, &devices) != CUBEB_OK)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
std::vector<DeviceDescriptionPtr> result;
|
std::vector<DeviceDescriptionPtr> result;
|
||||||
result.reserve(devices.count + 1); // Reserve space for the default device
|
|
||||||
|
|
||||||
// Add the default device to the list
|
// Add the default device to the list
|
||||||
auto defaultDevice = std::make_shared<CubebDeviceDescription>(nullptr, "default", L"Default Device");
|
auto defaultDevice = std::make_shared<CubebDeviceDescription>(nullptr, "default", L"Default Device");
|
||||||
result.emplace_back(defaultDevice);
|
result.emplace_back(defaultDevice);
|
||||||
|
|
||||||
|
cubeb_device_collection devices;
|
||||||
|
if (cubeb_enumerate_devices(s_context, CUBEB_DEVICE_TYPE_OUTPUT, &devices) != CUBEB_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
result.reserve(devices.count + 1); // The default device already occupies one element
|
||||||
|
|
||||||
for (size_t i = 0; i < devices.count; ++i)
|
for (size_t i = 0; i < devices.count; ++i)
|
||||||
{
|
{
|
||||||
// const auto& device = devices.device[i];
|
// const auto& device = devices.device[i];
|
||||||
|
|
|
@ -175,17 +175,17 @@ void CubebInputAPI::Destroy()
|
||||||
|
|
||||||
std::vector<IAudioInputAPI::DeviceDescriptionPtr> CubebInputAPI::GetDevices()
|
std::vector<IAudioInputAPI::DeviceDescriptionPtr> CubebInputAPI::GetDevices()
|
||||||
{
|
{
|
||||||
cubeb_device_collection devices;
|
|
||||||
if (cubeb_enumerate_devices(s_context, CUBEB_DEVICE_TYPE_INPUT, &devices) != CUBEB_OK)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
std::vector<DeviceDescriptionPtr> result;
|
std::vector<DeviceDescriptionPtr> result;
|
||||||
result.reserve(devices.count + 1); // Reserve space for the default device
|
|
||||||
|
|
||||||
// Add the default device to the list
|
// Add the default device to the list
|
||||||
auto defaultDevice = std::make_shared<CubebDeviceDescription>(nullptr, "default", L"Default Device");
|
auto defaultDevice = std::make_shared<CubebDeviceDescription>(nullptr, "default", L"Default Device");
|
||||||
result.emplace_back(defaultDevice);
|
result.emplace_back(defaultDevice);
|
||||||
|
|
||||||
|
cubeb_device_collection devices;
|
||||||
|
if (cubeb_enumerate_devices(s_context, CUBEB_DEVICE_TYPE_INPUT, &devices) != CUBEB_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
result.reserve(devices.count + 1); // The default device already occupies one element
|
||||||
|
|
||||||
for (size_t i = 0; i < devices.count; ++i)
|
for (size_t i = 0; i < devices.count; ++i)
|
||||||
{
|
{
|
||||||
// const auto& device = devices.device[i];
|
// const auto& device = devices.device[i];
|
||||||
|
|
|
@ -77,6 +77,7 @@ enum
|
||||||
MAINFRAME_MENU_ID_FILE_INSTALL_UPDATE,
|
MAINFRAME_MENU_ID_FILE_INSTALL_UPDATE,
|
||||||
MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER,
|
MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER,
|
||||||
MAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER,
|
MAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER,
|
||||||
|
MAINFRAME_MENU_ID_FILE_OPEN_SHADERCACHE_FOLDER,
|
||||||
MAINFRAME_MENU_ID_FILE_EXIT,
|
MAINFRAME_MENU_ID_FILE_EXIT,
|
||||||
MAINFRAME_MENU_ID_FILE_END_EMULATION,
|
MAINFRAME_MENU_ID_FILE_END_EMULATION,
|
||||||
MAINFRAME_MENU_ID_FILE_RECENT_0,
|
MAINFRAME_MENU_ID_FILE_RECENT_0,
|
||||||
|
@ -169,6 +170,7 @@ EVT_MENU(MAINFRAME_MENU_ID_FILE_LOAD, MainWindow::OnFileMenu)
|
||||||
EVT_MENU(MAINFRAME_MENU_ID_FILE_INSTALL_UPDATE, MainWindow::OnInstallUpdate)
|
EVT_MENU(MAINFRAME_MENU_ID_FILE_INSTALL_UPDATE, MainWindow::OnInstallUpdate)
|
||||||
EVT_MENU(MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER, MainWindow::OnOpenFolder)
|
EVT_MENU(MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER, MainWindow::OnOpenFolder)
|
||||||
EVT_MENU(MAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER, MainWindow::OnOpenFolder)
|
EVT_MENU(MAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER, MainWindow::OnOpenFolder)
|
||||||
|
EVT_MENU(MAINFRAME_MENU_ID_FILE_OPEN_SHADERCACHE_FOLDER, MainWindow::OnOpenFolder)
|
||||||
EVT_MENU(MAINFRAME_MENU_ID_FILE_EXIT, MainWindow::OnFileExit)
|
EVT_MENU(MAINFRAME_MENU_ID_FILE_EXIT, MainWindow::OnFileExit)
|
||||||
EVT_MENU(MAINFRAME_MENU_ID_FILE_END_EMULATION, MainWindow::OnFileMenu)
|
EVT_MENU(MAINFRAME_MENU_ID_FILE_END_EMULATION, MainWindow::OnFileMenu)
|
||||||
EVT_MENU_RANGE(MAINFRAME_MENU_ID_FILE_RECENT_0 + 0, MAINFRAME_MENU_ID_FILE_RECENT_LAST, MainWindow::OnFileMenu)
|
EVT_MENU_RANGE(MAINFRAME_MENU_ID_FILE_RECENT_0 + 0, MAINFRAME_MENU_ID_FILE_RECENT_LAST, MainWindow::OnFileMenu)
|
||||||
|
@ -673,10 +675,15 @@ void MainWindow::OnFileMenu(wxCommandEvent& event)
|
||||||
|
|
||||||
void MainWindow::OnOpenFolder(wxCommandEvent& event)
|
void MainWindow::OnOpenFolder(wxCommandEvent& event)
|
||||||
{
|
{
|
||||||
if(event.GetId() == MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER)
|
const auto id = event.GetId();
|
||||||
|
if(id == MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER)
|
||||||
wxLaunchDefaultApplication(wxHelper::FromPath(ActiveSettings::GetUserDataPath()));
|
wxLaunchDefaultApplication(wxHelper::FromPath(ActiveSettings::GetUserDataPath()));
|
||||||
else if(event.GetId() == MAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER)
|
else if(id == MAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER)
|
||||||
wxLaunchDefaultApplication(wxHelper::FromPath(ActiveSettings::GetMlcPath()));
|
wxLaunchDefaultApplication(wxHelper::FromPath(ActiveSettings::GetMlcPath()));
|
||||||
|
else if (id == MAINFRAME_MENU_ID_FILE_OPEN_SHADERCACHE_FOLDER)
|
||||||
|
wxLaunchDefaultApplication(wxHelper::FromPath(ActiveSettings::GetCachePath("shaderCache")));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::OnInstallUpdate(wxCommandEvent& event)
|
void MainWindow::OnInstallUpdate(wxCommandEvent& event)
|
||||||
|
@ -2099,6 +2106,7 @@ void MainWindow::RecreateMenu()
|
||||||
|
|
||||||
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER, _("&Open Cemu folder"));
|
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER, _("&Open Cemu folder"));
|
||||||
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER, _("&Open MLC folder"));
|
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER, _("&Open MLC folder"));
|
||||||
|
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_OPEN_SHADERCACHE_FOLDER, _("Open &shader cache folder"));
|
||||||
m_fileMenu->AppendSeparator();
|
m_fileMenu->AppendSeparator();
|
||||||
|
|
||||||
m_exitMenuItem = m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_EXIT, _("&Exit"));
|
m_exitMenuItem = m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_EXIT, _("&Exit"));
|
||||||
|
|
|
@ -202,14 +202,14 @@ void BreakpointWindow::OnLeftDClick(wxMouseEvent& event)
|
||||||
auto it = debuggerState.breakpoints.begin();
|
auto it = debuggerState.breakpoints.begin();
|
||||||
std::advance(it, index);
|
std::advance(it, index);
|
||||||
|
|
||||||
wxTextEntryDialog set_value_dialog(this, _("Enter a new comment."), wxString::Format(_("Set comment for breakpoint at address %08x"), address), (*it)->comment);
|
const wxString dialogTitle = (*it)->bpType == DEBUGGER_BP_T_LOGGING ? _("Enter a new logging message") : _("Enter a new comment");
|
||||||
if (set_value_dialog.ShowModal() == wxID_OK)
|
const wxString dialogMessage = (*it)->bpType == DEBUGGER_BP_T_LOGGING ? _("Set logging message when code at address %08x is ran.\nUse placeholders like {r3} or {f3} to log register values") : _("Set comment for breakpoint at address %08x");
|
||||||
|
wxTextEntryDialog set_comment_dialog(this, dialogMessage, dialogTitle, (*it)->comment);
|
||||||
|
if (set_comment_dialog.ShowModal() == wxID_OK)
|
||||||
{
|
{
|
||||||
(*it)->comment = set_value_dialog.GetValue().ToStdWstring();
|
(*it)->comment = set_comment_dialog.GetValue().ToStdWstring();
|
||||||
m_breakpoints->SetItem(index, ColumnComment, set_value_dialog.GetValue());
|
m_breakpoints->SetItem(index, ColumnComment, set_comment_dialog.GetValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -538,7 +538,7 @@ void DisasmCtrl::OnKeyPressed(sint32 key_code, const wxPoint& position)
|
||||||
auto optVirtualAddress = LinePixelPosToAddress(position.y);
|
auto optVirtualAddress = LinePixelPosToAddress(position.y);
|
||||||
switch (key_code)
|
switch (key_code)
|
||||||
{
|
{
|
||||||
case WXK_F9:
|
case WXK_F9:
|
||||||
{
|
{
|
||||||
if (optVirtualAddress)
|
if (optVirtualAddress)
|
||||||
{
|
{
|
||||||
|
@ -549,7 +549,7 @@ void DisasmCtrl::OnKeyPressed(sint32 key_code, const wxPoint& position)
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case 'G':
|
case 'G':
|
||||||
{
|
{
|
||||||
if(IsKeyDown(WXK_CONTROL))
|
if(IsKeyDown(WXK_CONTROL))
|
||||||
{
|
{
|
||||||
|
@ -686,6 +686,7 @@ void DisasmCtrl::OnContextMenu(const wxPoint& position, uint32 line)
|
||||||
// show dialog
|
// show dialog
|
||||||
wxMenu menu;
|
wxMenu menu;
|
||||||
menu.Append(IDContextMenu_ToggleBreakpoint, _("Toggle breakpoint"));
|
menu.Append(IDContextMenu_ToggleBreakpoint, _("Toggle breakpoint"));
|
||||||
|
menu.Append(IDContextMenu_ToggleLoggingBreakpoint, _("Toggle logging point"));
|
||||||
if(debugger_hasPatch(virtualAddress))
|
if(debugger_hasPatch(virtualAddress))
|
||||||
menu.Append(IDContextMenu_RestoreOriginalInstructions, _("Restore original instructions"));
|
menu.Append(IDContextMenu_RestoreOriginalInstructions, _("Restore original instructions"));
|
||||||
menu.AppendSeparator();
|
menu.AppendSeparator();
|
||||||
|
@ -707,6 +708,13 @@ void DisasmCtrl::OnContextMenuEntryClicked(wxCommandEvent& event)
|
||||||
wxPostEvent(this->m_parent, evt);
|
wxPostEvent(this->m_parent, evt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case IDContextMenu_ToggleLoggingBreakpoint:
|
||||||
|
{
|
||||||
|
debugger_toggleLoggingBreakpoint(m_contextMenuAddress);
|
||||||
|
wxCommandEvent evt(wxEVT_BREAKPOINT_CHANGE);
|
||||||
|
wxPostEvent(this->m_parent, evt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case IDContextMenu_RestoreOriginalInstructions:
|
case IDContextMenu_RestoreOriginalInstructions:
|
||||||
{
|
{
|
||||||
debugger_removePatch(m_contextMenuAddress);
|
debugger_removePatch(m_contextMenuAddress);
|
||||||
|
|
|
@ -8,6 +8,7 @@ class DisasmCtrl : public TextList
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
IDContextMenu_ToggleBreakpoint = wxID_HIGHEST + 1,
|
IDContextMenu_ToggleBreakpoint = wxID_HIGHEST + 1,
|
||||||
|
IDContextMenu_ToggleLoggingBreakpoint,
|
||||||
IDContextMenu_RestoreOriginalInstructions,
|
IDContextMenu_RestoreOriginalInstructions,
|
||||||
IDContextMenu_CopyAddress,
|
IDContextMenu_CopyAddress,
|
||||||
IDContextMenu_CopyUnrelocatedAddress,
|
IDContextMenu_CopyUnrelocatedAddress,
|
||||||
|
|
|
@ -23,15 +23,15 @@ static bool AttemptSetNonBlock(int sockFd)
|
||||||
return fcntl(sockFd, F_SETFL, fcntl(sockFd, F_GETFL) | O_NONBLOCK) == 0;
|
return fcntl(sockFd, F_SETFL, fcntl(sockFd, F_GETFL) | O_NONBLOCK) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
L2CapWiimote::L2CapWiimote(int recvFd, int sendFd, bdaddr_t addr)
|
L2CapWiimote::L2CapWiimote(int controlFd, int dataFd, bdaddr_t addr)
|
||||||
: m_recvFd(recvFd), m_sendFd(sendFd), m_addr(addr)
|
: m_controlFd(controlFd), m_dataFd(dataFd), m_addr(addr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
L2CapWiimote::~L2CapWiimote()
|
L2CapWiimote::~L2CapWiimote()
|
||||||
{
|
{
|
||||||
close(m_recvFd);
|
close(m_dataFd);
|
||||||
close(m_sendFd);
|
close(m_controlFd);
|
||||||
const auto& b = m_addr.b;
|
const auto& b = m_addr.b;
|
||||||
cemuLog_logDebug(LogType::Force, "Wiimote at {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x} disconnected", b[5], b[4], b[3], b[2], b[1], b[0]);
|
cemuLog_logDebug(LogType::Force, "Wiimote at {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x} disconnected", b[5], b[4], b[3], b[2], b[1], b[0]);
|
||||||
|
|
||||||
|
@ -61,51 +61,51 @@ std::vector<WiimoteDevicePtr> L2CapWiimote::get_devices()
|
||||||
std::vector<WiimoteDevicePtr> outDevices;
|
std::vector<WiimoteDevicePtr> outDevices;
|
||||||
for (const auto& addr : unconnected)
|
for (const auto& addr : unconnected)
|
||||||
{
|
{
|
||||||
// Socket for sending data to controller, PSM 0x11
|
// Control socket, PSM 0x11, needs to be open for the data socket to be opened
|
||||||
auto sendFd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
|
auto controlFd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
|
||||||
if (sendFd < 0)
|
if (controlFd < 0)
|
||||||
{
|
{
|
||||||
cemuLog_logDebug(LogType::Force, "Failed to open send socket: {}", strerror(errno));
|
cemuLog_logDebug(LogType::Force, "Failed to open control socket: {}", strerror(errno));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
sockaddr_l2 sendAddr{};
|
sockaddr_l2 controlAddr{};
|
||||||
sendAddr.l2_family = AF_BLUETOOTH;
|
controlAddr.l2_family = AF_BLUETOOTH;
|
||||||
sendAddr.l2_psm = htobs(0x11);
|
controlAddr.l2_psm = htobs(0x11);
|
||||||
sendAddr.l2_bdaddr = addr;
|
controlAddr.l2_bdaddr = addr;
|
||||||
|
|
||||||
if (!AttemptConnect(sendFd, sendAddr) || !AttemptSetNonBlock(sendFd))
|
if (!AttemptConnect(controlFd, controlAddr) || !AttemptSetNonBlock(controlFd))
|
||||||
{
|
{
|
||||||
const auto& b = addr.b;
|
const auto& b = addr.b;
|
||||||
cemuLog_logDebug(LogType::Force, "Failed to connect send socket to '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}': {}",
|
cemuLog_logDebug(LogType::Force, "Failed to connect control socket to '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}': {}",
|
||||||
b[5], b[4], b[3], b[2], b[1], b[0], strerror(errno));
|
b[5], b[4], b[3], b[2], b[1], b[0], strerror(errno));
|
||||||
close(sendFd);
|
close(controlFd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Socket for receiving data from controller, PSM 0x13
|
// Socket for sending and receiving data from controller, PSM 0x13
|
||||||
auto recvFd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
|
auto dataFd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
|
||||||
if (recvFd < 0)
|
if (dataFd < 0)
|
||||||
{
|
{
|
||||||
cemuLog_logDebug(LogType::Force, "Failed to open recv socket: {}", strerror(errno));
|
cemuLog_logDebug(LogType::Force, "Failed to open data socket: {}", strerror(errno));
|
||||||
close(sendFd);
|
close(controlFd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
sockaddr_l2 recvAddr{};
|
sockaddr_l2 dataAddr{};
|
||||||
recvAddr.l2_family = AF_BLUETOOTH;
|
dataAddr.l2_family = AF_BLUETOOTH;
|
||||||
recvAddr.l2_psm = htobs(0x13);
|
dataAddr.l2_psm = htobs(0x13);
|
||||||
recvAddr.l2_bdaddr = addr;
|
dataAddr.l2_bdaddr = addr;
|
||||||
|
|
||||||
if (!AttemptConnect(recvFd, recvAddr) || !AttemptSetNonBlock(recvFd))
|
if (!AttemptConnect(dataFd, dataAddr) || !AttemptSetNonBlock(dataFd))
|
||||||
{
|
{
|
||||||
const auto& b = addr.b;
|
const auto& b = addr.b;
|
||||||
cemuLog_logDebug(LogType::Force, "Failed to connect recv socket to '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}': {}",
|
cemuLog_logDebug(LogType::Force, "Failed to connect data socket to '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}': {}",
|
||||||
b[5], b[4], b[3], b[2], b[1], b[0], strerror(errno));
|
b[5], b[4], b[3], b[2], b[1], b[0], strerror(errno));
|
||||||
close(sendFd);
|
close(dataFd);
|
||||||
close(recvFd);
|
close(controlFd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
outDevices.emplace_back(std::make_shared<L2CapWiimote>(sendFd, recvFd, addr));
|
outDevices.emplace_back(std::make_shared<L2CapWiimote>(controlFd, dataFd, addr));
|
||||||
|
|
||||||
s_addressMutex.lock();
|
s_addressMutex.lock();
|
||||||
s_addresses[addr] = true;
|
s_addresses[addr] = true;
|
||||||
|
@ -123,13 +123,13 @@ bool L2CapWiimote::write_data(const std::vector<uint8>& data)
|
||||||
buffer[0] = 0xA2;
|
buffer[0] = 0xA2;
|
||||||
std::memcpy(buffer + 1, data.data(), size);
|
std::memcpy(buffer + 1, data.data(), size);
|
||||||
const auto outSize = size + 1;
|
const auto outSize = size + 1;
|
||||||
return send(m_sendFd, buffer, outSize, 0) == outSize;
|
return send(m_dataFd, buffer, outSize, 0) == outSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::vector<uint8>> L2CapWiimote::read_data()
|
std::optional<std::vector<uint8>> L2CapWiimote::read_data()
|
||||||
{
|
{
|
||||||
uint8 buffer[23];
|
uint8 buffer[23];
|
||||||
const auto nBytes = recv(m_sendFd, buffer, 23, 0);
|
const auto nBytes = recv(m_dataFd, buffer, 23, 0);
|
||||||
|
|
||||||
if (nBytes < 0 && errno == EWOULDBLOCK)
|
if (nBytes < 0 && errno == EWOULDBLOCK)
|
||||||
return std::vector<uint8>{};
|
return std::vector<uint8>{};
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
class L2CapWiimote : public WiimoteDevice
|
class L2CapWiimote : public WiimoteDevice
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
L2CapWiimote(int recvFd, int sendFd, bdaddr_t addr);
|
L2CapWiimote(int controlFd, int dataFd, bdaddr_t addr);
|
||||||
~L2CapWiimote() override;
|
~L2CapWiimote() override;
|
||||||
|
|
||||||
bool write_data(const std::vector<uint8>& data) override;
|
bool write_data(const std::vector<uint8>& data) override;
|
||||||
|
@ -15,8 +15,8 @@ class L2CapWiimote : public WiimoteDevice
|
||||||
static void AddCandidateAddress(bdaddr_t addr);
|
static void AddCandidateAddress(bdaddr_t addr);
|
||||||
static std::vector<WiimoteDevicePtr> get_devices();
|
static std::vector<WiimoteDevicePtr> get_devices();
|
||||||
private:
|
private:
|
||||||
int m_recvFd;
|
int m_controlFd;
|
||||||
int m_sendFd;
|
int m_dataFd;
|
||||||
bdaddr_t m_addr;
|
bdaddr_t m_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue