1 // Copyright 2010 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4
5 #include "Core/HW/WiimoteReal/WiimoteReal.h"
6
7 #include <algorithm>
8 #include <cstdlib>
9 #include <mutex>
10 #include <queue>
11 #include <unordered_set>
12
13 #include "Common/ChunkFile.h"
14 #include "Common/CommonTypes.h"
15 #include "Common/FileUtil.h"
16 #include "Common/IniFile.h"
17 #include "Common/Swap.h"
18 #include "Common/Thread.h"
19 #include "Core/ConfigManager.h"
20 #include "Core/Core.h"
21 #include "Core/HW/Wiimote.h"
22 #include "Core/HW/WiimoteCommon/DataReport.h"
23 #include "Core/HW/WiimoteCommon/WiimoteHid.h"
24 #include "Core/HW/WiimoteReal/IOAndroid.h"
25 #include "Core/HW/WiimoteReal/IOLinux.h"
26 #include "Core/HW/WiimoteReal/IOWin.h"
27 #include "Core/HW/WiimoteReal/IOdarwin.h"
28 #include "Core/HW/WiimoteReal/IOhidapi.h"
29 #include "InputCommon/ControllerInterface/Wiimote/Wiimote.h"
30 #include "InputCommon/InputConfig.h"
31
32 #include "SFML/Network.hpp"
33
34 namespace WiimoteReal
35 {
36 using namespace WiimoteCommon;
37
38 static void TryToConnectBalanceBoard(std::unique_ptr<Wiimote>);
39 static bool TryToConnectWiimoteToSlot(std::unique_ptr<Wiimote>&, unsigned int);
40 static void HandleWiimoteDisconnect(int index);
41
42 static bool g_real_wiimotes_initialized = false;
43
44 // This is used to store connected Wiimotes' IDs, so we don't connect
45 // more than once to the same device.
46 static std::unordered_set<std::string> s_known_ids;
47 static std::mutex s_known_ids_mutex;
48
49 std::recursive_mutex g_wiimotes_mutex;
50
51 // Real wii remotes assigned to a particular slot.
52 // Assignments must be done from the CPU thread with the above mutex held.
53 std::unique_ptr<Wiimote> g_wiimotes[MAX_BBMOTES];
54
55 struct WiimotePoolEntry
56 {
57 using Clock = std::chrono::steady_clock;
58
59 std::unique_ptr<Wiimote> wiimote;
60 Clock::time_point entry_time = Clock::now();
61
IsExpiredWiimoteReal::WiimotePoolEntry62 bool IsExpired() const
63 {
64 // Keep wii remotes in the pool for a bit before disconnecting them.
65 constexpr auto POOL_TIME = std::chrono::seconds{5};
66
67 return (Clock::now() - entry_time) > POOL_TIME;
68 }
69 };
70
71 // Connected wii remotes are placed here when no open slot is set to "Real".
72 // They are then automatically disconnected after some time.
73 static std::vector<WiimotePoolEntry> s_wiimote_pool;
74
75 static WiimoteScanner s_wiimote_scanner;
76
77 // Attempt to fill a real wiimote slot from the pool or by stealing from ControllerInterface.
TryToFillWiimoteSlot(u32 index)78 static void TryToFillWiimoteSlot(u32 index)
79 {
80 std::lock_guard lk(g_wiimotes_mutex);
81
82 if (g_wiimotes[index] || WiimoteCommon::GetSource(index) != WiimoteSource::Real)
83 return;
84
85 // If the pool is empty, attempt to steal from ControllerInterface.
86 if (s_wiimote_pool.empty())
87 {
88 ciface::Wiimote::ReleaseDevices(1);
89
90 // Still empty?
91 if (s_wiimote_pool.empty())
92 return;
93 }
94
95 if (TryToConnectWiimoteToSlot(s_wiimote_pool.front().wiimote, index))
96 s_wiimote_pool.erase(s_wiimote_pool.begin());
97 }
98
99 // Attempts to fill enabled real wiimote slots.
100 // Push/pull wiimotes to/from ControllerInterface as needed.
ProcessWiimotePool()101 void ProcessWiimotePool()
102 {
103 std::lock_guard lk(g_wiimotes_mutex);
104
105 for (u32 index = 0; index != MAX_WIIMOTES; ++index)
106 TryToFillWiimoteSlot(index);
107
108 if (SConfig::GetInstance().connect_wiimotes_for_ciface)
109 {
110 for (auto& entry : s_wiimote_pool)
111 ciface::Wiimote::AddDevice(std::move(entry.wiimote));
112
113 s_wiimote_pool.clear();
114 }
115 else
116 {
117 ciface::Wiimote::ReleaseDevices();
118 }
119 }
120
AddWiimoteToPool(std::unique_ptr<Wiimote> wiimote)121 void AddWiimoteToPool(std::unique_ptr<Wiimote> wiimote)
122 {
123 // Our real wiimote class requires an index.
124 // Within the pool it's only going to be used for logging purposes.
125 static constexpr int POOL_WIIMOTE_INDEX = 99;
126
127 if (!wiimote->Connect(POOL_WIIMOTE_INDEX))
128 {
129 ERROR_LOG(WIIMOTE, "Failed to connect real wiimote.");
130 return;
131 }
132
133 wiimote->EmuStop();
134
135 std::lock_guard lk(g_wiimotes_mutex);
136 s_wiimote_pool.emplace_back(WiimotePoolEntry{std::move(wiimote)});
137 }
138
139 Wiimote::Wiimote() = default;
140
Shutdown()141 void Wiimote::Shutdown()
142 {
143 std::lock_guard<std::mutex> lk(s_known_ids_mutex);
144 s_known_ids.erase(GetId());
145
146 StopThread();
147 ClearReadQueue();
148 m_write_reports.Clear();
149
150 NOTICE_LOG(WIIMOTE, "Disconnected real wiimote.");
151 }
152
153 // to be called from CPU thread
WriteReport(Report rpt)154 void Wiimote::WriteReport(Report rpt)
155 {
156 if (rpt.size() >= 3)
157 {
158 bool const new_rumble_state = (rpt[2] & 0x1) != 0;
159
160 switch (WiimoteCommon::OutputReportID(rpt[1]))
161 {
162 case OutputReportID::Rumble:
163 // If this is a rumble report and the rumble state didn't change, we can drop this report.
164 if (new_rumble_state == m_rumble_state)
165 return;
166 break;
167
168 case OutputReportID::SpeakerEnable:
169 m_speaker_enable = (rpt[2] & 0x4) != 0;
170 break;
171
172 case OutputReportID::SpeakerMute:
173 m_speaker_mute = (rpt[2] & 0x4) != 0;
174 break;
175
176 case OutputReportID::ReportMode:
177 // Force non-continuous reporting for less BT traffic.
178 // We duplicate reports to maintain 200hz anyways.
179 rpt[2] &= ~0x4;
180 break;
181
182 default:
183 break;
184 }
185
186 m_rumble_state = new_rumble_state;
187 }
188
189 m_write_reports.Push(std::move(rpt));
190 IOWakeup();
191 }
192
193 // to be called from CPU thread
QueueReport(WiimoteCommon::OutputReportID rpt_id,const void * data,unsigned int size)194 void Wiimote::QueueReport(WiimoteCommon::OutputReportID rpt_id, const void* data, unsigned int size)
195 {
196 auto const queue_data = static_cast<const u8*>(data);
197
198 Report rpt(size + 2);
199 rpt[0] = WR_SET_REPORT | BT_OUTPUT;
200 rpt[1] = u8(rpt_id);
201 std::copy_n(queue_data, size, rpt.begin() + 2);
202 WriteReport(std::move(rpt));
203 }
204
ResetDataReporting()205 void Wiimote::ResetDataReporting()
206 {
207 m_last_input_report.clear();
208
209 // "core" reporting in non-continuous mode is a wiimote's initial state.
210 // FYI: This also disables rumble.
211 OutputReportMode rpt = {};
212 rpt.mode = InputReportID::ReportCore;
213 rpt.continuous = 0;
214 QueueReport(rpt);
215 }
216
ClearReadQueue()217 void Wiimote::ClearReadQueue()
218 {
219 Report rpt;
220
221 // The "Clear" function isn't thread-safe :/
222 while (m_read_reports.Pop(rpt))
223 {
224 }
225 }
226
EventLinked()227 void Wiimote::EventLinked()
228 {
229 m_is_linked = true;
230
231 ClearReadQueue();
232 ResetDataReporting();
233 EnablePowerAssertionInternal();
234 }
235
EventUnlinked()236 void Wiimote::EventUnlinked()
237 {
238 if (m_really_disconnect)
239 DisconnectInternal();
240 else
241 EmuStop();
242 }
243
InterruptDataOutput(const u8 * data,const u32 size)244 void Wiimote::InterruptDataOutput(const u8* data, const u32 size)
245 {
246 Report rpt(size + REPORT_HID_HEADER_SIZE);
247 std::copy_n(data, size, rpt.data() + REPORT_HID_HEADER_SIZE);
248
249 // Convert output DATA packets to SET_REPORT packets.
250 // Nintendo Wiimotes work without this translation, but 3rd
251 // party ones don't.
252 rpt[0] = WR_SET_REPORT | BT_OUTPUT;
253
254 // Disallow games from turning off all of the LEDs.
255 // It makes Wiimote connection status confusing.
256 if (rpt[1] == u8(OutputReportID::LED))
257 {
258 auto& leds_rpt = *reinterpret_cast<OutputReportLeds*>(&rpt[2]);
259 if (0 == leds_rpt.leds)
260 {
261 // Turn on ALL of the LEDs.
262 leds_rpt.leds = 0xf;
263 }
264 }
265 else if (rpt[1] == u8(OutputReportID::SpeakerData) &&
266 (!SConfig::GetInstance().m_WiimoteEnableSpeaker || !m_speaker_enable || m_speaker_mute))
267 {
268 rpt.resize(3);
269 // Translate undesired speaker data reports into rumble reports.
270 rpt[1] = u8(OutputReportID::Rumble);
271 // Keep only the rumble bit.
272 rpt[2] &= 0x1;
273 }
274
275 WriteReport(std::move(rpt));
276 }
277
Read()278 void Wiimote::Read()
279 {
280 Report rpt(MAX_PAYLOAD);
281 auto const result = IORead(rpt.data());
282
283 // Drop the report if not connected.
284 if (!m_is_linked)
285 return;
286
287 if (result > 0)
288 {
289 if (SConfig::GetInstance().iBBDumpPort > 0 && m_index == WIIMOTE_BALANCE_BOARD)
290 {
291 static sf::UdpSocket Socket;
292 Socket.send((char*)rpt.data(), rpt.size(), sf::IpAddress::LocalHost,
293 SConfig::GetInstance().iBBDumpPort);
294 }
295
296 // Add it to queue
297 rpt.resize(result);
298 m_read_reports.Push(std::move(rpt));
299 }
300 else if (0 == result)
301 {
302 ERROR_LOG(WIIMOTE, "Wiimote::IORead failed. Disconnecting Wii Remote %d.", m_index + 1);
303 DisconnectInternal();
304 }
305 }
306
Write()307 bool Wiimote::Write()
308 {
309 // nothing written, but this is not an error
310 if (m_write_reports.Empty())
311 return true;
312
313 Report const& rpt = m_write_reports.Front();
314
315 if (SConfig::GetInstance().iBBDumpPort > 0 && m_index == WIIMOTE_BALANCE_BOARD)
316 {
317 static sf::UdpSocket Socket;
318 Socket.send((char*)rpt.data(), rpt.size(), sf::IpAddress::LocalHost,
319 SConfig::GetInstance().iBBDumpPort);
320 }
321 int ret = IOWrite(rpt.data(), rpt.size());
322
323 m_write_reports.Pop();
324
325 if (!m_write_reports.Empty())
326 IOWakeup();
327
328 return ret != 0;
329 }
330
IsBalanceBoard()331 bool Wiimote::IsBalanceBoard()
332 {
333 if (!ConnectInternal())
334 return false;
335 // Initialise the extension by writing 0x55 to 0xa400f0, then writing 0x00 to 0xa400fb.
336 // TODO: Use the structs for building these reports..
337 static const u8 init_extension_rpt1[MAX_PAYLOAD] = {
338 WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::WriteData), 0x04, 0xa4, 0x00, 0xf0, 0x01, 0x55};
339 static const u8 init_extension_rpt2[MAX_PAYLOAD] = {
340 WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::WriteData), 0x04, 0xa4, 0x00, 0xfb, 0x01, 0x00};
341 static const u8 status_report[] = {WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::RequestStatus),
342 0};
343 if (!IOWrite(init_extension_rpt1, sizeof(init_extension_rpt1)) ||
344 !IOWrite(init_extension_rpt2, sizeof(init_extension_rpt2)))
345 {
346 ERROR_LOG(WIIMOTE, "IsBalanceBoard(): Failed to initialise extension.");
347 return false;
348 }
349
350 int ret = IOWrite(status_report, sizeof(status_report));
351 u8 buf[MAX_PAYLOAD];
352 while (ret != 0)
353 {
354 ret = IORead(buf);
355 if (ret == -1)
356 continue;
357
358 switch (InputReportID(buf[1]))
359 {
360 case InputReportID::Status:
361 {
362 const auto* status = reinterpret_cast<InputReportStatus*>(&buf[2]);
363 // A Balance Board has a Balance Board extension.
364 if (!status->extension)
365 return false;
366 // Read two bytes from 0xa400fe to identify the extension.
367 static const u8 identify_ext_rpt[] = {WR_SET_REPORT | BT_OUTPUT,
368 u8(OutputReportID::ReadData),
369 0x04,
370 0xa4,
371 0x00,
372 0xfe,
373 0x02,
374 0x00};
375 ret = IOWrite(identify_ext_rpt, sizeof(identify_ext_rpt));
376 break;
377 }
378 case InputReportID::ReadDataReply:
379 {
380 const auto* reply = reinterpret_cast<InputReportReadDataReply*>(&buf[2]);
381 if (Common::swap16(reply->address) != 0x00fe)
382 {
383 ERROR_LOG(WIIMOTE, "IsBalanceBoard(): Received unexpected data reply for address %X",
384 Common::swap16(reply->address));
385 return false;
386 }
387 // A Balance Board ext can be identified by checking for 0x0402.
388 return reply->data[0] == 0x04 && reply->data[1] == 0x02;
389 }
390 case InputReportID::Ack:
391 {
392 const auto* ack = reinterpret_cast<InputReportAck*>(&buf[2]);
393 if (ack->rpt_id == OutputReportID::ReadData && ack->error_code != ErrorCode::Success)
394 {
395 WARN_LOG(WIIMOTE, "Failed to read from 0xa400fe, assuming Wiimote is not a Balance Board.");
396 return false;
397 }
398 }
399 default:
400 break;
401 }
402 }
403 return false;
404 }
405
IsDataReport(const Report & rpt)406 static bool IsDataReport(const Report& rpt)
407 {
408 return rpt.size() >= 2 && rpt[1] >= u8(InputReportID::ReportCore);
409 }
410
GetNextReport(Report * report)411 bool Wiimote::GetNextReport(Report* report)
412 {
413 return m_read_reports.Pop(*report);
414 }
415
416 // Returns the next report that should be sent
ProcessReadQueue()417 Report& Wiimote::ProcessReadQueue()
418 {
419 // Pop through the queued reports
420 while (GetNextReport(&m_last_input_report))
421 {
422 if (!IsDataReport(m_last_input_report))
423 {
424 // A non-data report, use it.
425 return m_last_input_report;
426
427 // Forget the last data report as it may be of the wrong type
428 // or contain outdated button data
429 // or it's not supposed to be sent at this time
430 // It's just easier to be correct this way and it's probably not horrible.
431 }
432 }
433
434 // If the last report wasn't a data report it's irrelevant.
435 if (!IsDataReport(m_last_input_report))
436 m_last_input_report.clear();
437
438 // If it was a data report, we repeat that until something else comes in.
439 return m_last_input_report;
440 }
441
Update()442 void Wiimote::Update()
443 {
444 // Pop through the queued reports
445 const Report& rpt = ProcessReadQueue();
446
447 // Send the report
448 if (!rpt.empty())
449 InterruptCallback(rpt.front(), rpt.data() + REPORT_HID_HEADER_SIZE,
450 u32(rpt.size() - REPORT_HID_HEADER_SIZE));
451 }
452
IsButtonPressed()453 bool Wiimote::IsButtonPressed()
454 {
455 Report& rpt = m_last_input_report;
456 if (rpt.size() >= 4)
457 {
458 const auto mode = InputReportID(rpt[1]);
459
460 // TODO: Button data could also be pulled out of non-data reports if really wanted.
461 if (DataReportBuilder::IsValidMode(mode))
462 {
463 auto builder = MakeDataReportManipulator(mode, rpt.data() + 2);
464 ButtonData buttons = {};
465 builder->GetCoreData(&buttons);
466
467 return buttons.hex != 0;
468 }
469 }
470 return false;
471 }
472
Prepare()473 void Wiimote::Prepare()
474 {
475 m_need_prepare.Set();
476 IOWakeup();
477 }
478
PrepareOnThread()479 bool Wiimote::PrepareOnThread()
480 {
481 // Set reporting mode to non-continuous core buttons and turn on rumble.
482 u8 static const mode_report[] = {WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::ReportMode), 1,
483 u8(InputReportID::ReportCore)};
484
485 // Request status and turn off rumble.
486 u8 static const req_status_report[] = {WR_SET_REPORT | BT_OUTPUT,
487 u8(OutputReportID::RequestStatus), 0};
488
489 return IOWrite(mode_report, sizeof(mode_report)) &&
490 (Common::SleepCurrentThread(200), IOWrite(req_status_report, sizeof(req_status_report)));
491 }
492
EmuStop()493 void Wiimote::EmuStop()
494 {
495 m_is_linked = false;
496
497 ResetDataReporting();
498 DisablePowerAssertionInternal();
499 }
500
EmuResume()501 void Wiimote::EmuResume()
502 {
503 EnablePowerAssertionInternal();
504 }
505
EmuPause()506 void Wiimote::EmuPause()
507 {
508 DisablePowerAssertionInternal();
509 }
510
CalculateWantedWiimotes()511 static unsigned int CalculateWantedWiimotes()
512 {
513 std::lock_guard lk(g_wiimotes_mutex);
514 // Figure out how many real Wiimotes are required
515 unsigned int wanted_wiimotes = 0;
516 for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
517 if (WiimoteCommon::GetSource(i) == WiimoteSource::Real && !g_wiimotes[i])
518 ++wanted_wiimotes;
519 return wanted_wiimotes;
520 }
521
CalculateWantedBB()522 static unsigned int CalculateWantedBB()
523 {
524 std::lock_guard lk(g_wiimotes_mutex);
525 unsigned int wanted_bb = 0;
526 if (WiimoteCommon::GetSource(WIIMOTE_BALANCE_BOARD) == WiimoteSource::Real &&
527 !g_wiimotes[WIIMOTE_BALANCE_BOARD])
528 ++wanted_bb;
529 return wanted_bb;
530 }
531
StartThread()532 void WiimoteScanner::StartThread()
533 {
534 if (m_scan_thread_running.IsSet())
535 return;
536 m_scan_thread_running.Set();
537 m_scan_thread = std::thread(&WiimoteScanner::ThreadFunc, this);
538 }
539
StopThread()540 void WiimoteScanner::StopThread()
541 {
542 if (m_scan_thread_running.TestAndClear())
543 {
544 SetScanMode(WiimoteScanMode::DO_NOT_SCAN);
545 m_scan_thread.join();
546 }
547 }
548
SetScanMode(WiimoteScanMode scan_mode)549 void WiimoteScanner::SetScanMode(WiimoteScanMode scan_mode)
550 {
551 m_scan_mode.store(scan_mode);
552 m_scan_mode_changed_event.Set();
553 }
554
IsReady() const555 bool WiimoteScanner::IsReady() const
556 {
557 std::lock_guard<std::mutex> lg(m_backends_mutex);
558 return std::any_of(m_backends.begin(), m_backends.end(),
559 [](const auto& backend) { return backend->IsReady(); });
560 }
561
CheckForDisconnectedWiimotes()562 static void CheckForDisconnectedWiimotes()
563 {
564 std::lock_guard lk(g_wiimotes_mutex);
565 for (unsigned int i = 0; i < MAX_BBMOTES; ++i)
566 if (g_wiimotes[i] && !g_wiimotes[i]->IsConnected())
567 HandleWiimoteDisconnect(i);
568 }
569
PoolThreadFunc()570 void WiimoteScanner::PoolThreadFunc()
571 {
572 Common::SetCurrentThreadName("Wiimote Pool Thread");
573
574 // Toggle between 1010 and 0101.
575 u8 led_value = 0b1010;
576
577 auto next_time = std::chrono::steady_clock::now();
578
579 while (m_scan_thread_running.IsSet())
580 {
581 std::this_thread::sleep_until(next_time);
582 next_time += std::chrono::milliseconds(250);
583
584 std::lock_guard lk(g_wiimotes_mutex);
585
586 // Remove stale pool entries.
587 for (auto it = s_wiimote_pool.begin(); it != s_wiimote_pool.end();)
588 {
589 if (!it->wiimote->IsConnected())
590 {
591 INFO_LOG(WIIMOTE, "Removing disconnected wiimote pool entry.");
592 it = s_wiimote_pool.erase(it);
593 }
594 else if (it->IsExpired())
595 {
596 INFO_LOG(WIIMOTE, "Removing expired wiimote pool entry.");
597 it = s_wiimote_pool.erase(it);
598 }
599 else
600 {
601 ++it;
602 }
603 }
604
605 // Make wiimote pool LEDs dance.
606 for (auto& wiimote : s_wiimote_pool)
607 {
608 OutputReportLeds leds = {};
609 leds.leds = led_value;
610 wiimote.wiimote->QueueReport(leds);
611 }
612
613 led_value ^= 0b1111;
614 }
615 }
616
ThreadFunc()617 void WiimoteScanner::ThreadFunc()
618 {
619 std::thread pool_thread(&WiimoteScanner::PoolThreadFunc, this);
620
621 Common::SetCurrentThreadName("Wiimote Scanning Thread");
622
623 NOTICE_LOG(WIIMOTE, "Wiimote scanning thread has started.");
624
625 // Create and destroy scanner backends here to ensure all operations stay on the same thread. The
626 // HIDAPI backend on macOS has an error condition when IOHIDManagerCreate and IOHIDManagerClose
627 // are called on different threads (and so reference different CFRunLoops) which can cause an
628 // EXC_BAD_ACCES crash.
629 {
630 std::lock_guard<std::mutex> lg(m_backends_mutex);
631
632 m_backends.emplace_back(std::make_unique<WiimoteScannerLinux>());
633 m_backends.emplace_back(std::make_unique<WiimoteScannerAndroid>());
634 m_backends.emplace_back(std::make_unique<WiimoteScannerWindows>());
635 m_backends.emplace_back(std::make_unique<WiimoteScannerDarwin>());
636 m_backends.emplace_back(std::make_unique<WiimoteScannerHidapi>());
637 }
638
639 while (m_scan_thread_running.IsSet())
640 {
641 m_scan_mode_changed_event.WaitFor(std::chrono::milliseconds(500));
642
643 // Does stuff needed to detect disconnects on Windows
644 for (const auto& backend : m_backends)
645 backend->Update();
646
647 CheckForDisconnectedWiimotes();
648
649 if (m_scan_mode.load() == WiimoteScanMode::DO_NOT_SCAN)
650 continue;
651
652 // If we don't want Wiimotes in ControllerInterface, we may not need them at all.
653 if (!SConfig::GetInstance().connect_wiimotes_for_ciface)
654 {
655 // We don't want any remotes in passthrough mode or running in GC mode.
656 const bool core_running = Core::GetState() != Core::State::Uninitialized;
657 if (SConfig::GetInstance().m_bt_passthrough_enabled ||
658 (core_running && !SConfig::GetInstance().bWii))
659 continue;
660
661 // We don't want any remotes if we already connected everything we need.
662 if (0 == CalculateWantedWiimotes() && 0 == CalculateWantedBB())
663 continue;
664 }
665
666 for (const auto& backend : m_backends)
667 {
668 std::vector<Wiimote*> found_wiimotes;
669 Wiimote* found_board = nullptr;
670 backend->FindWiimotes(found_wiimotes, found_board);
671 {
672 std::unique_lock wm_lk(g_wiimotes_mutex);
673
674 for (auto* wiimote : found_wiimotes)
675 {
676 {
677 std::lock_guard<std::mutex> lk(s_known_ids_mutex);
678 s_known_ids.insert(wiimote->GetId());
679 }
680
681 AddWiimoteToPool(std::unique_ptr<Wiimote>(wiimote));
682 ProcessWiimotePool();
683 }
684
685 if (found_board)
686 {
687 {
688 std::lock_guard<std::mutex> lk(s_known_ids_mutex);
689 s_known_ids.insert(found_board->GetId());
690 }
691
692 TryToConnectBalanceBoard(std::unique_ptr<Wiimote>(found_board));
693 }
694 }
695 }
696
697 // Stop scanning if not in continous mode.
698 auto scan_mode = WiimoteScanMode::SCAN_ONCE;
699 m_scan_mode.compare_exchange_strong(scan_mode, WiimoteScanMode::DO_NOT_SCAN);
700 }
701
702 {
703 std::lock_guard<std::mutex> lg(m_backends_mutex);
704 m_backends.clear();
705 }
706
707 pool_thread.join();
708
709 NOTICE_LOG(WIIMOTE, "Wiimote scanning thread has stopped.");
710 }
711
Connect(int index)712 bool Wiimote::Connect(int index)
713 {
714 m_index = index;
715
716 if (!m_run_thread.IsSet())
717 {
718 m_need_prepare.Set();
719 m_run_thread.Set();
720 StartThread();
721 m_thread_ready_event.Wait();
722 }
723
724 return IsConnected();
725 }
726
StartThread()727 void Wiimote::StartThread()
728 {
729 m_wiimote_thread = std::thread(&Wiimote::ThreadFunc, this);
730 }
731
StopThread()732 void Wiimote::StopThread()
733 {
734 if (!m_run_thread.TestAndClear())
735 return;
736 IOWakeup();
737 m_wiimote_thread.join();
738 }
739
ThreadFunc()740 void Wiimote::ThreadFunc()
741 {
742 Common::SetCurrentThreadName("Wiimote Device Thread");
743
744 bool ok = ConnectInternal();
745
746 if (!ok)
747 {
748 // try again, it might take a moment to settle
749 Common::SleepCurrentThread(100);
750 ok = ConnectInternal();
751 }
752
753 m_thread_ready_event.Set();
754
755 if (!ok)
756 {
757 return;
758 }
759
760 // main loop
761 while (IsConnected() && m_run_thread.IsSet())
762 {
763 if (m_need_prepare.TestAndClear() && !PrepareOnThread())
764 {
765 ERROR_LOG(WIIMOTE, "Wiimote::PrepareOnThread failed. Disconnecting Wiimote %d.",
766 m_index + 1);
767 break;
768 }
769 if (!Write())
770 {
771 ERROR_LOG(WIIMOTE, "Wiimote::Write failed. Disconnecting Wiimote %d.", m_index + 1);
772 break;
773 }
774 Read();
775 }
776
777 DisconnectInternal();
778 }
779
GetIndex() const780 int Wiimote::GetIndex() const
781 {
782 return m_index;
783 }
784
LoadSettings()785 void LoadSettings()
786 {
787 std::string ini_filename = File::GetUserPath(D_CONFIG_IDX) + WIIMOTE_INI_NAME ".ini";
788
789 IniFile inifile;
790 inifile.Load(ini_filename);
791
792 for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
793 {
794 std::string secname("Wiimote");
795 secname += static_cast<char>('1' + i);
796 IniFile::Section& sec = *inifile.GetOrCreateSection(secname);
797
798 unsigned int source = 0;
799 sec.Get("Source", &source, i ? int(WiimoteSource::None) : int(WiimoteSource::Emulated));
800 WiimoteCommon::SetSource(i, WiimoteSource(source));
801 }
802
803 std::string secname("BalanceBoard");
804 IniFile::Section& sec = *inifile.GetOrCreateSection(secname);
805
806 unsigned int bb_source = 0;
807 sec.Get("Source", &bb_source, int(WiimoteSource::None));
808 WiimoteCommon::SetSource(WIIMOTE_BALANCE_BOARD, WiimoteSource(bb_source));
809 }
810
811 // config dialog calls this when some settings change
Initialize(::Wiimote::InitializeMode init_mode)812 void Initialize(::Wiimote::InitializeMode init_mode)
813 {
814 if (!g_real_wiimotes_initialized)
815 {
816 s_wiimote_scanner.StartThread();
817 }
818
819 if (SConfig::GetInstance().m_WiimoteContinuousScanning)
820 s_wiimote_scanner.SetScanMode(WiimoteScanMode::CONTINUOUSLY_SCAN);
821 else
822 s_wiimote_scanner.SetScanMode(WiimoteScanMode::DO_NOT_SCAN);
823
824 // wait for connection because it should exist before state load
825 if (init_mode == ::Wiimote::InitializeMode::DO_WAIT_FOR_WIIMOTES)
826 {
827 int timeout = 100;
828 s_wiimote_scanner.SetScanMode(WiimoteScanMode::SCAN_ONCE);
829 while (CalculateWantedWiimotes() && timeout)
830 {
831 Common::SleepCurrentThread(100);
832 timeout--;
833 }
834 }
835
836 if (g_real_wiimotes_initialized)
837 return;
838
839 NOTICE_LOG(WIIMOTE, "WiimoteReal::Initialize");
840
841 g_real_wiimotes_initialized = true;
842 }
843
844 // called on emulation shutdown
Stop()845 void Stop()
846 {
847 for (auto& wiimote : g_wiimotes)
848 if (wiimote && wiimote->IsConnected())
849 wiimote->EmuStop();
850 }
851
852 // called when the Dolphin app exits
Shutdown()853 void Shutdown()
854 {
855 g_real_wiimotes_initialized = false;
856 s_wiimote_scanner.StopThread();
857
858 NOTICE_LOG(WIIMOTE, "WiimoteReal::Shutdown");
859
860 std::lock_guard lk(g_wiimotes_mutex);
861 for (unsigned int i = 0; i < MAX_BBMOTES; ++i)
862 HandleWiimoteDisconnect(i);
863
864 // Release remotes from ControllerInterface and empty the pool.
865 ciface::Wiimote::ReleaseDevices();
866 s_wiimote_pool.clear();
867 }
868
Resume()869 void Resume()
870 {
871 for (auto& wiimote : g_wiimotes)
872 if (wiimote && wiimote->IsConnected())
873 wiimote->EmuResume();
874 }
875
Pause()876 void Pause()
877 {
878 for (auto& wiimote : g_wiimotes)
879 if (wiimote && wiimote->IsConnected())
880 wiimote->EmuPause();
881 }
882
883 // Called from the Wiimote scanner thread (or UI thread on source change)
TryToConnectWiimoteToSlot(std::unique_ptr<Wiimote> & wm,unsigned int i)884 static bool TryToConnectWiimoteToSlot(std::unique_ptr<Wiimote>& wm, unsigned int i)
885 {
886 if (WiimoteCommon::GetSource(i) != WiimoteSource::Real || g_wiimotes[i])
887 return false;
888
889 if (!wm->Connect(i))
890 {
891 ERROR_LOG(WIIMOTE, "Failed to connect real wiimote.");
892 return false;
893 }
894
895 wm->Prepare();
896
897 // Set LEDs.
898 OutputReportLeds led_report = {};
899 led_report.leds = u8(1 << (i % WIIMOTE_BALANCE_BOARD));
900 wm->QueueReport(led_report);
901
902 Core::RunAsCPUThread([i, &wm] {
903 g_wiimotes[i] = std::move(wm);
904 WiimoteCommon::UpdateSource(i);
905 });
906
907 NOTICE_LOG(WIIMOTE, "Connected real wiimote to slot %i.", i + 1);
908
909 return true;
910 }
911
TryToConnectBalanceBoard(std::unique_ptr<Wiimote> wm)912 static void TryToConnectBalanceBoard(std::unique_ptr<Wiimote> wm)
913 {
914 if (TryToConnectWiimoteToSlot(wm, WIIMOTE_BALANCE_BOARD))
915 return;
916
917 NOTICE_LOG(WIIMOTE, "No open slot for real balance board.");
918 }
919
HandleWiimoteDisconnect(int index)920 static void HandleWiimoteDisconnect(int index)
921 {
922 Core::RunAsCPUThread([index] {
923 g_wiimotes[index] = nullptr;
924 WiimoteCommon::UpdateSource(index);
925 });
926 }
927
928 // This is called from the GUI thread
Refresh()929 void Refresh()
930 {
931 if (!SConfig::GetInstance().m_WiimoteContinuousScanning)
932 s_wiimote_scanner.SetScanMode(WiimoteScanMode::SCAN_ONCE);
933 }
934
IsValidDeviceName(const std::string & name)935 bool IsValidDeviceName(const std::string& name)
936 {
937 return "Nintendo RVL-CNT-01" == name || "Nintendo RVL-CNT-01-TR" == name ||
938 IsBalanceBoardName(name);
939 }
940
IsBalanceBoardName(const std::string & name)941 bool IsBalanceBoardName(const std::string& name)
942 {
943 return "Nintendo RVL-WBC-01" == name;
944 }
945
946 // This is called from the scanner backends (currently on the scanner thread).
IsNewWiimote(const std::string & identifier)947 bool IsNewWiimote(const std::string& identifier)
948 {
949 std::lock_guard<std::mutex> lk(s_known_ids_mutex);
950 return s_known_ids.count(identifier) == 0;
951 }
952
HandleWiimoteSourceChange(unsigned int index)953 void HandleWiimoteSourceChange(unsigned int index)
954 {
955 std::lock_guard wm_lk(g_wiimotes_mutex);
956
957 Core::RunAsCPUThread([index] {
958 if (auto removed_wiimote = std::move(g_wiimotes[index]))
959 AddWiimoteToPool(std::move(removed_wiimote));
960 });
961 ProcessWiimotePool();
962 }
963
HandleWiimotesInControllerInterfaceSettingChange()964 void HandleWiimotesInControllerInterfaceSettingChange()
965 {
966 ProcessWiimotePool();
967 }
968
969 } // namespace WiimoteReal
970