diff --git a/Source/Core/Common/Src/FifoQueue.h b/Source/Core/Common/Src/FifoQueue.h index 2060ceee92..01f0e4dd3c 100644 --- a/Source/Core/Common/Src/FifoQueue.h +++ b/Source/Core/Common/Src/FifoQueue.h @@ -36,15 +36,16 @@ public: return (0 == m_size); } - const T& Front() const + T& Front() const { return *m_read_ptr->current; } - void Push(const T& t) + template + void Push(Arg&& t) { // create the element, add it to the queue - m_write_ptr->current = new T(t); + m_write_ptr->current = new T(std::forward(t)); // set the next pointer to a new element ptr // then advance the write pointer m_write_ptr = m_write_ptr->next = new ElementPtr(); @@ -67,7 +68,7 @@ public: if (Empty()) return false; - t = Front(); + t = std::move(Front()); Pop(); return true; diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp index 92018f7c21..1c3e306498 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp @@ -707,10 +707,10 @@ void Wiimote::Update() std::lock_guard lk(g_refresh_lock); if (g_wiimotes[m_index]) { - Report rpt = g_wiimotes[m_index]->ProcessReadQueue(); - const u8 *real_data = rpt.first; - if (real_data) + const Report& rpt = g_wiimotes[m_index]->ProcessReadQueue(); + if (!rpt.empty()) { + const u8 *real_data = rpt.data(); switch (real_data[1]) { // use data reports @@ -770,13 +770,9 @@ void Wiimote::Update() // copy over report from real-wiimote if (-1 == rptf_size) { - memcpy(data, real_data, rpt.second); - rptf_size = rpt.second; + std::copy(rpt.begin(), rpt.end(), data); + rptf_size = rpt.size(); } - - if (real_data != g_wiimotes[m_index]->\ - m_last_data_report.first) - delete[] real_data; } } } diff --git a/Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp b/Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp index 164281e515..b86abb7ef2 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp +++ b/Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp @@ -370,73 +370,55 @@ bool Wiimote::IsConnected() const // zero = error int Wiimote::IORead(u8* buf) { - // used below for a warning - *buf = 0; + // Add data report indicator byte (here, 0xa1) + buf[0] = 0xa1; + // Used below for a warning + buf[1] = 0; - DWORD bytes; + DWORD bytes = 0; ResetEvent(hid_overlap_read.hEvent); - if (!ReadFile(dev_handle, buf, MAX_PAYLOAD - 1, &bytes, &hid_overlap_read)) + if (!ReadFile(dev_handle, buf + 1, MAX_PAYLOAD - 1, &bytes, &hid_overlap_read)) { - auto const err = GetLastError(); + auto const read_err = GetLastError(); - if (ERROR_IO_PENDING == err) + if (ERROR_IO_PENDING == read_err) { - auto const r = WaitForSingleObject(hid_overlap_read.hEvent, WIIMOTE_DEFAULT_TIMEOUT); - if (WAIT_TIMEOUT == r) + auto const wait_result = WaitForSingleObject(hid_overlap_read.hEvent, WIIMOTE_DEFAULT_TIMEOUT); + if (WAIT_TIMEOUT == wait_result) { - // Timeout - cancel and continue - if (*buf) - WARN_LOG(WIIMOTE, "Packet ignored. This may indicate a problem (timeout is %i ms).", - WIIMOTE_DEFAULT_TIMEOUT); - CancelIo(dev_handle); - bytes = -1; } - else if (WAIT_FAILED == r) + else if (WAIT_FAILED == wait_result) { WARN_LOG(WIIMOTE, "A wait error occurred on reading from Wiimote %i.", index + 1); - bytes = 0; + CancelIo(dev_handle); } - else if (WAIT_OBJECT_0 == r) + + if (!GetOverlappedResult(dev_handle, &hid_overlap_read, &bytes, TRUE)) { - if (!GetOverlappedResult(dev_handle, &hid_overlap_read, &bytes, TRUE)) + auto const overlapped_err = GetLastError(); + + if (ERROR_OPERATION_ABORTED == overlapped_err) { - WARN_LOG(WIIMOTE, "GetOverlappedResult failed on Wiimote %i.", index + 1); - bytes = 0; + if (buf[1] != 0) + WARN_LOG(WIIMOTE, "Packet ignored. This may indicate a problem (timeout is %i ms).", + WIIMOTE_DEFAULT_TIMEOUT); + + return -1; } + + WARN_LOG(WIIMOTE, "GetOverlappedResult error %d on Wiimote %i.", overlapped_err, index + 1); + return 0; } - else - { - bytes = 0; - } - } - else if (ERROR_HANDLE_EOF == err) - { - // Remote disconnect - bytes = 0; - } - else if (ERROR_DEVICE_NOT_CONNECTED == err) - { - // Remote disconnect - bytes = 0; } else { - bytes = 0; + WARN_LOG(WIIMOTE, "ReadFile error %d on Wiimote %i.", read_err, index + 1); + return 0; } } - if (bytes > 0) - { - // Move the data over one, so we can add back in data report indicator byte (here, 0xa1) - std::copy_n(buf, MAX_PAYLOAD - 1, buf + 1); - buf[0] = 0xa1; - - // TODO: is this really needed? - bytes = MAX_PAYLOAD; - } - - return bytes; + return bytes + 1; } int Wiimote::IOWrite(const u8* buf, int len) diff --git a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp index f1bb39061c..9decc4f674 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp +++ b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp @@ -57,7 +57,7 @@ Wiimote::Wiimote() #elif defined(_WIN32) , dev_handle(0), stack(MSBT_STACK_UNKNOWN) #endif - , m_last_data_report(Report((u8 *)NULL, 0)) + , m_last_input_report() , m_channel(0), m_run_thread(false) { #if defined(__linux__) && HAVE_BLUEZ @@ -73,11 +73,7 @@ Wiimote::~Wiimote() Disconnect(); ClearReadQueue(); - - // clear write queue - Report rpt; - while (m_write_reports.Pop(rpt)) - delete[] rpt.first; + m_write_reports.Clear(); } // to be called from CPU thread @@ -85,17 +81,18 @@ void Wiimote::QueueReport(u8 rpt_id, const void* _data, unsigned int size) { auto const data = static_cast(_data); - Report rpt; - rpt.second = size + 2; - rpt.first = new u8[rpt.second]; - rpt.first[0] = WM_SET_REPORT | WM_BT_OUTPUT; - rpt.first[1] = rpt_id; - std::copy(data, data + size, rpt.first + 2); - m_write_reports.Push(rpt); + Report rpt(size + 2); + rpt[0] = WM_SET_REPORT | WM_BT_OUTPUT; + rpt[1] = rpt_id; + std::copy_n(data, size, rpt.begin() + 2); + m_write_reports.Push(std::move(rpt)); } void Wiimote::DisableDataReporting() { + m_last_input_report.clear(); + + // This probably accomplishes nothing. wm_report_mode rpt = {}; rpt.mode = WM_REPORT_CORE; rpt.all_the_time = 0; @@ -107,15 +104,10 @@ void Wiimote::DisableDataReporting() void Wiimote::ClearReadQueue() { Report rpt; - - if (m_last_data_report.first) - { - delete[] m_last_data_report.first; - m_last_data_report.first = NULL; - } - + + // The "Clear" function isn't thread-safe :/ while (m_read_reports.Pop(rpt)) - delete[] rpt.first; + {} } void Wiimote::ControlChannel(const u16 channel, const void* const data, const u32 size) @@ -148,65 +140,58 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const _data, const } auto const data = static_cast(_data); - - Report rpt; - rpt.first = new u8[size]; - rpt.second = (u8)size; - std::copy(data, data + size, rpt.first); + Report rpt(data, data + size); // Convert output DATA packets to SET_REPORT packets. // Nintendo Wiimotes work without this translation, but 3rd // party ones don't. - if (rpt.first[0] == 0xa2) + if (rpt[0] == 0xa2) { - rpt.first[0] = WM_SET_REPORT | WM_BT_OUTPUT; + rpt[0] = WM_SET_REPORT | WM_BT_OUTPUT; } // Disallow games from turning off all of the LEDs. // It makes Wiimote connection status confusing. - if (rpt.first[1] == WM_LEDS) + if (rpt[1] == WM_LEDS) { - auto& leds_rpt = *reinterpret_cast(&rpt.first[2]); + auto& leds_rpt = *reinterpret_cast(&rpt[2]); if (0 == leds_rpt.leds) { // Turn on ALL of the LEDs. leds_rpt.leds = 0xf; } } - else if (rpt.first[1] == WM_WRITE_SPEAKER_DATA + else if (rpt[1] == WM_WRITE_SPEAKER_DATA && !SConfig::GetInstance().m_WiimoteEnableSpeaker) { // Translate speaker data reports into rumble reports. - rpt.first[1] = WM_CMD_RUMBLE; + rpt[1] = WM_RUMBLE; // Keep only the rumble bit. - rpt.first[2] &= 0x1; - rpt.second = 3; + rpt[2] &= 0x1; + rpt.resize(3); } - m_write_reports.Push(rpt); + m_write_reports.Push(std::move(rpt)); } bool Wiimote::Read() { - Report rpt; - - rpt.first = new unsigned char[MAX_PAYLOAD]; - rpt.second = IORead(rpt.first); + Report rpt(MAX_PAYLOAD); + auto const result = IORead(rpt.data()); - if (0 == rpt.second) + if (result > 0 && m_channel > 0) + { + // Add it to queue + rpt.resize(result); + m_read_reports.Push(std::move(rpt)); + return true; + } + else if (0 == result) { WARN_LOG(WIIMOTE, "Wiimote::IORead failed. Disconnecting Wiimote %d.", index + 1); Disconnect(); } - if (rpt.second > 0 && m_channel > 0) - { - // Add it to queue - m_read_reports.Push(rpt); - return true; - } - - delete[] rpt.first; return false; } @@ -216,16 +201,15 @@ bool Wiimote::Write() { Report const& rpt = m_write_reports.Front(); - bool const is_speaker_data = rpt.first[1] == WM_WRITE_SPEAKER_DATA; + bool const is_speaker_data = rpt[1] == WM_WRITE_SPEAKER_DATA; if (!is_speaker_data || m_last_audio_report.GetTimeDifference() > 5) { - IOWrite(rpt.first, rpt.second); + IOWrite(rpt.data(), rpt.size()); if (is_speaker_data) m_last_audio_report.Update(); - delete[] rpt.first; m_write_reports.Pop(); return true; } @@ -234,23 +218,35 @@ bool Wiimote::Write() return false; } +bool IsDataReport(const Report& rpt) +{ + return rpt.size() >= 2 && rpt[1] >= WM_REPORT_CORE; +} + // Returns the next report that should be sent -Report Wiimote::ProcessReadQueue() +const Report& Wiimote::ProcessReadQueue() { // Pop through the queued reports - Report rpt = m_last_data_report; - while (m_read_reports.Pop(rpt)) + while (m_read_reports.Pop(m_last_input_report)) { - if (rpt.first[1] >= WM_REPORT_CORE) - // A data report - m_last_data_report = rpt; - else - // Some other kind of report - return rpt; + if (!IsDataReport(m_last_input_report)) + { + // A non-data report, use it. + return m_last_input_report; + + // Forget the last data report as it may be of the wrong type + // or contain outdated button data + // or it's not supposed to be sent at this time + // It's just easier to be correct this way and it's probably not horrible. + } } - // The queue was empty, or there were only data reports - return rpt; + // If the last report wasn't a data report it's irrelevant. + if (!IsDataReport(m_last_input_report)) + m_last_input_report.clear(); + + // If it was a data report, we repeat that until something else comes in. + return m_last_input_report; } void Wiimote::Update() @@ -262,16 +258,12 @@ void Wiimote::Update() } // Pop through the queued reports - Report const rpt = ProcessReadQueue(); + const Report& rpt = ProcessReadQueue(); // Send the report - if (rpt.first != NULL && m_channel > 0) + if (!rpt.empty() && m_channel > 0) Core::Callback_WiimoteInterruptChannel(index, m_channel, - rpt.first, rpt.second); - - // Delete the data if it isn't also the last data rpt - if (rpt != m_last_data_report) - delete[] rpt.first; + rpt.data(), rpt.size()); } bool Wiimote::Prepare(int _index) @@ -279,13 +271,13 @@ bool Wiimote::Prepare(int _index) index = _index; // core buttons, no continuous reporting - u8 const mode_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_REPORT_TYPE, 0, 0x30}; + u8 const mode_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REPORT_MODE, 0, WM_REPORT_CORE}; // Set the active LEDs and turn on rumble. - u8 const led_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_LED, u8(WIIMOTE_LED_1 << index | 0x1)}; + u8 const led_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_LEDS, u8(WIIMOTE_LED_1 << index | 0x1)}; // Turn off rumble - u8 rumble_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_RUMBLE, 0}; + u8 rumble_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_RUMBLE, 0}; // Request status report u8 const req_status_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REQUEST_STATUS, 0}; diff --git a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h index cfc66106b4..771cf7498d 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h +++ b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h @@ -33,8 +33,7 @@ #include "../../InputCommon/Src/InputConfig.h" -// Pointer to data, and size of data -typedef std::pair Report; +typedef std::vector Report; namespace WiimoteReal { @@ -50,7 +49,7 @@ public: void InterruptChannel(const u16 channel, const void* const data, const u32 size); void Update(); - Report ProcessReadQueue(); + const Report& ProcessReadQueue(); bool Read(); bool Write(); @@ -99,7 +98,7 @@ public: #endif protected: - Report m_last_data_report; + Report m_last_input_report; u16 m_channel; private: diff --git a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteRealBase.h b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteRealBase.h index 1a1f6676cf..e2b1a8db03 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteRealBase.h +++ b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteRealBase.h @@ -41,20 +41,6 @@ #define WM_SET_REPORT 0xA0 #endif -// TODO: duplicated in WiimoteHid.h -// Commands -#define WM_CMD_RUMBLE 0x10 -#define WM_CMD_LED 0x11 -#define WM_CMD_REPORT_TYPE 0x12 -#define WM_CMD_IR 0x13 -#define WM_CMD_SPEAKER_ENABLE 0x14 -#define WM_CMD_CTRL_STATUS 0x15 -#define WM_CMD_WRITE_DATA 0x16 -#define WM_CMD_READ_DATA 0x17 -#define WM_CMD_SPEAKER_DATA 0x18 -#define WM_CMD_SPEAKER_MUTE 0x19 -#define WM_CMD_IR_2 0x1A - #define WM_BT_INPUT 0x01 #define WM_BT_OUTPUT 0x02 @@ -73,12 +59,12 @@ #ifdef _WIN32 // Available bluetooth stacks for Windows. -typedef enum win_bt_stack_t +enum win_bt_stack_t { MSBT_STACK_UNKNOWN, MSBT_STACK_MS, MSBT_STACK_BLUESOLEIL -} win_bt_stack_t; +}; #endif #endif // WIIMOTE_COMM_H