Make the refresh button on the Wiimote New plugin add new wiimotes in linux, instead...
[dolphin.git] / Source / Plugins / Plugin_WiimoteNew / Src / WiimoteReal / WiimoteReal.cpp
blob0c88f4b4f42e05492343233d8bdd16aa0099943d
1 // Copyright (C) 2003 Dolphin Project.
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0.
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official SVN repository and contact information can be found at
16 // http://code.google.com/p/dolphin-emu/
18 #include <queue>
20 #include "Common.h"
21 #include "IniFile.h"
22 #include "Thread.h"
23 #include "StringUtil.h"
24 #include "Timer.h"
25 #include "pluginspecs_wiimote.h"
27 #include "wiiuse.h"
28 #include "WiimoteReal.h"
30 #include "../WiimoteEmu/WiimoteHid.h"
32 unsigned int g_wiimote_sources[MAX_WIIMOTES];
34 namespace WiimoteReal
37 bool g_real_wiimotes_initialized = false;
38 wiimote_t** g_wiimotes_from_wiiuse = NULL;
39 unsigned int g_wiimotes_found = 0;
41 volatile bool g_run_wiimote_thread = false;
42 Common::Thread *g_wiimote_thread = NULL;
43 Common::CriticalSection g_wiimote_critsec;
45 THREAD_RETURN WiimoteThreadFunc(void* arg);
47 // silly, copying data n stuff, o well, don't use this too often
48 void SendPacket(wiimote_t* const wm, const u8 rpt_id, const void* const data, const unsigned int size)
50 u8* const rpt = new u8[size + 2];
51 rpt[0] = 0xA1;
52 rpt[1] = rpt_id;
53 memcpy(rpt + 2, data, size);
54 wiiuse_io_write(wm, (byte*)rpt, size + 2);
55 delete[] rpt;
58 class Wiimote
60 public:
61 Wiimote(wiimote_t* const wm, const unsigned int index);
62 ~Wiimote();
64 void ControlChannel(const u16 channel, const void* const data, const u32 size);
65 void InterruptChannel(const u16 channel, const void* const data, const u32 size);
66 void Update();
68 void Read();
69 void Disconnect();
70 void DisableDataReporting();
72 private:
73 void ClearReports();
75 wiimote_t* const m_wiimote;
76 const unsigned int m_index;
78 u16 m_channel;
79 u8 m_last_data_report[MAX_PAYLOAD];
80 bool m_last_data_report_valid;
82 std::queue<u8*> m_reports;
85 Wiimote::Wiimote(wiimote_t* const wm, const unsigned int index)
86 : m_wiimote(wm)
87 , m_index(index)
88 , m_channel(0)
89 , m_last_data_report_valid(false)
91 // disable reporting
92 DisableDataReporting();
94 // clear all msgs, silly maybe
95 // - cleared on first InterruptChannel call
96 //while (wiiuse_io_read(m_wiimote));
98 //{
99 // LEDs test
100 //wm_leds rpt = wm_leds();
101 //rpt.leds = 1 << i;
102 //SendPacket(g_wiimotes_from_wiiuse[i], WM_LEDS, &rpt, sizeof(rpt));
105 // Rumble briefly
106 wiiuse_rumble(m_wiimote, 1);
107 SLEEP(200);
108 wiiuse_rumble(m_wiimote, 0);
110 // set LEDs
111 wiiuse_set_leds(m_wiimote, WIIMOTE_LED_1 << m_index);
113 // TODO: make Dolphin connect wiimote, maybe
116 Wiimote::~Wiimote()
118 ClearReports();
120 // disable reporting / wiiuse might do this on shutdown anyway, o well, don't know for sure
121 DisableDataReporting();
123 // send disconnect message to wii, maybe, i hope, naw shit messes up on emu-stop
124 //if (g_WiimoteInitialize.pWiimoteInterruptChannel)
126 // //u8* const rpt = new u8[2];
127 // //rpt[0] = 0XA1; rpt[1] = 0x15;
128 // //m_reports.push(rpt);
129 // //Update();
131 // const u8 rpt[] = { 0xA1, 0x15 };
132 // g_WiimoteInitialize.pWiimoteInterruptChannel(m_index, m_channel, rpt, sizeof(rpt));
136 void Wiimote::DisableDataReporting()
138 wm_report_mode rpt = wm_report_mode();
139 rpt.mode = WM_REPORT_CORE;
140 SendPacket(m_wiimote, WM_REPORT_MODE, &rpt, sizeof(rpt));
143 void Wiimote::ClearReports()
145 m_last_data_report_valid = false;
146 while (m_reports.size())
148 delete[] m_reports.front();
149 m_reports.pop();
153 void Wiimote::ControlChannel(const u16 channel, const void* const data, const u32 size)
155 // Check for custom communication
156 if (99 == channel)
157 Disconnect();
158 else
159 InterruptChannel(channel, data, size);
162 void Wiimote::InterruptChannel(const u16 channel, const void* const data, const u32 size)
164 if (0 == m_channel) // first interrupt/control channel sent
166 // clear all msgs, silly maybe
167 while (wiiuse_io_read(m_wiimote));
169 // request status
170 wm_request_status rpt = wm_request_status();
171 SendPacket(m_wiimote, WM_REQUEST_STATUS, &rpt, sizeof(rpt));
174 m_channel = channel;
175 wiiuse_io_write(m_wiimote, (byte*)data, size);
178 void Wiimote::Read()
180 // if not connected to Dolphin, don't do anything, to keep sanchez happy :p
181 if (0 == m_channel)
182 return;
184 if (wiiuse_io_read(m_wiimote))
186 // a data report, save it
187 if (m_wiimote->event_buf[1] >= 0x30)
189 memcpy(m_last_data_report, m_wiimote->event_buf, MAX_PAYLOAD);
190 m_last_data_report_valid = true;
192 else
194 // some other report, add it to queue
195 u8* const rpt = new u8[MAX_PAYLOAD];
196 memcpy(rpt, m_wiimote->event_buf, MAX_PAYLOAD);
197 m_reports.push(rpt);
202 void Wiimote::Update()
204 // do we have some queued reports
205 if (m_reports.size())
207 u8* const rpt = m_reports.front();
208 m_reports.pop();
209 g_WiimoteInitialize.pWiimoteInterruptChannel(m_index, m_channel, rpt, MAX_PAYLOAD);
210 delete[] rpt;
212 else if (m_last_data_report_valid)
214 // otherwise send the last data report, if there is one
215 g_WiimoteInitialize.pWiimoteInterruptChannel(m_index, m_channel, m_last_data_report, MAX_PAYLOAD);
219 void Wiimote::Disconnect()
221 m_channel = 0;
223 // disable reporting
224 DisableDataReporting();
226 // clear queue
227 ClearReports();
229 // clear out wiiuse queue, or maybe not, silly? idk
230 while (wiiuse_io_read(m_wiimote));
233 Wiimote* g_wiimotes[4];
235 void LoadSettings()
237 std::string ini_filename = (std::string(File::GetUserPath(D_CONFIG_IDX)) + g_plugin.ini_name + ".ini" );
239 IniFile inifile;
240 inifile.Load(ini_filename);
242 for (unsigned int i=0; i<MAX_WIIMOTES; ++i)
244 std::string secname("Wiimote");
245 secname += (char)('1' + i);
246 IniFile::Section& sec = *inifile.GetOrCreateSection(secname.c_str());
248 sec.Get("Source", &g_wiimote_sources[i], WIIMOTE_SRC_EMU);
252 unsigned int Initialize()
254 // return if already initialized
255 if (g_real_wiimotes_initialized)
256 return g_wiimotes_found;
258 memset(g_wiimotes, 0, sizeof(g_wiimotes));
260 // only call wiiuse_find with the number of slots configured for real wiimotes
261 unsigned int wanted_wiimotes = 0;
262 for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
263 if (WIIMOTE_SRC_REAL == g_wiimote_sources[i])
264 ++wanted_wiimotes;
266 // don't bother initializing wiiuse if we don't want any real wiimotes
267 if (0 == wanted_wiimotes)
269 g_wiimotes_found = 0;
270 return 0;
273 // initialized
274 g_real_wiimotes_initialized = true;
276 // Call Wiiuse.dll
277 g_wiimotes_from_wiiuse = wiiuse_init(MAX_WIIMOTES);
278 g_wiimotes_found = wiiuse_find(g_wiimotes_from_wiiuse, wanted_wiimotes, 5);
280 DEBUG_LOG(WIIMOTE, "Found %i Real Wiimotes, %i wanted", g_wiimotes_found, wanted_wiimotes);
282 g_wiimotes_found =
283 wiiuse_connect(g_wiimotes_from_wiiuse, g_wiimotes_found);
285 DEBUG_LOG(WIIMOTE, "Connected to %i Real Wiimotes", g_wiimotes_found);
287 g_wiimote_critsec.Enter(); // enter
289 // create real wiimote class instances, assign wiimotes
291 for (unsigned int i = 0, w = 0; i<MAX_WIIMOTES && w<g_wiimotes_found; ++i)
293 if (WIIMOTE_SRC_REAL != g_wiimote_sources[i])
294 continue;
296 // create/assign wiimote
297 g_wiimotes[i] = new Wiimote(g_wiimotes_from_wiiuse[w++], i);
300 g_wiimote_critsec.Leave(); // leave
302 // start wiimote thread
303 g_run_wiimote_thread = true;
304 g_wiimote_thread = new Common::Thread(WiimoteThreadFunc, 0);
306 return g_wiimotes_found;
309 void Shutdown(void)
311 if (false == g_real_wiimotes_initialized)
312 return;
314 // Uninitialized
315 g_real_wiimotes_initialized = false;
317 // stop wiimote thread
318 if (g_wiimote_thread)
320 g_run_wiimote_thread = false;
321 g_wiimote_thread->WaitForDeath();
322 delete g_wiimote_thread;
323 g_wiimote_thread = NULL;
326 g_wiimote_critsec.Enter(); // enter
328 // delete wiimotes
329 for (unsigned int i=0; i<MAX_WIIMOTES; ++i)
330 if (g_wiimotes[i])
332 delete g_wiimotes[i];
333 g_wiimotes[i] = NULL;
336 g_wiimote_critsec.Leave(); // leave
338 // set all LEDs on, idk
339 //for (unsigned int i=0; i<g_wiimotes_found; ++i)
341 // wiiuse_set_leds(g_wiimotes_from_wiiuse[i], 0xF0);
344 // Clean up wiiuse
345 wiiuse_cleanup(g_wiimotes_from_wiiuse, MAX_WIIMOTES);
348 #ifdef __linux__
349 void Refresh()
351 // find the number of slots configured for real wiimotes
352 unsigned int wanted_wiimotes = 0;
353 for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
354 if (g_wiimote_sources[i] == WIIMOTE_SRC_REAL)
355 ++wanted_wiimotes;
357 // don't scan for wiimotes if we don't want any more
358 if (wanted_wiimotes <= g_wiimotes_found)
359 return;
361 // scan for wiimotes
362 unsigned int num_wiimotes = wiiuse_find_more(g_wiimotes_from_wiiuse, wanted_wiimotes, 5);
364 DEBUG_LOG(WIIMOTE, "Found %i Real Wiimotes, %i wanted", num_wiimotes, wanted_wiimotes);
366 int num_new_wiimotes = wiiuse_connect(g_wiimotes_from_wiiuse, num_wiimotes);
368 DEBUG_LOG(WIIMOTE, "Connected to %i additional Real Wiimotes", num_new_wiimotes);
370 g_wiimote_critsec.Enter(); // enter
372 // create real wiimote class instances, and assign wiimotes for the new wiimotes
373 for (unsigned int i = g_wiimotes_found, w = g_wiimotes_found;
374 i < MAX_WIIMOTES && w < num_wiimotes; ++i)
376 if (g_wiimote_sources[i] != WIIMOTE_SRC_REAL || g_wiimotes[i] != NULL)
377 continue;
379 // create/assign wiimote
380 g_wiimotes[i] = new Wiimote(g_wiimotes_from_wiiuse[w++], i);
382 g_wiimotes_found = num_wiimotes;
384 g_wiimote_critsec.Leave(); // leave
386 return;
388 #else
389 void Refresh()
391 // should be fine i think
392 Shutdown();
393 Initialize();
395 #endif
397 void InterruptChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size)
399 g_wiimote_critsec.Enter(); // enter
401 u8* data = (u8*)_pData;
403 // some hax, since we just send the last data report to Dolphin on each Update() call
404 // , make the wiimote only send updated data reports when data changes
405 // == less bt traffic, eliminates some unneeded packets
406 if (WM_REPORT_MODE == ((u8*)_pData)[1])
408 // I dont wanna write on the const *_pData
409 data = new u8[_Size];
410 memcpy(data, _pData, _Size);
412 // nice var names :p, this seems to be this one
413 ((wm_report_mode*)(data + 2))->all_the_time = false;
414 //((wm_report_mode*)(data + 2))->continuous = false;
417 if (g_wiimotes[_WiimoteNumber])
418 g_wiimotes[_WiimoteNumber]->InterruptChannel(_channelID, data, _Size);
420 g_wiimote_critsec.Leave(); // leave
422 if (data != _pData)
423 delete[] data;
426 void ControlChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size)
428 g_wiimote_critsec.Enter(); // enter
430 if (g_wiimotes[_WiimoteNumber])
431 g_wiimotes[_WiimoteNumber]->ControlChannel(_channelID, _pData, _Size);
433 g_wiimote_critsec.Leave(); // leave
437 // Read the Wiimote once
438 void Update(int _WiimoteNumber)
440 g_wiimote_critsec.Enter(); // enter
442 if (g_wiimotes[_WiimoteNumber])
443 g_wiimotes[_WiimoteNumber]->Update();
445 g_wiimote_critsec.Leave(); // leave
448 void StateChange(PLUGIN_EMUSTATE newState)
450 g_wiimote_critsec.Enter(); // enter
452 // TODO: disable/enable auto reporting, maybe
454 g_wiimote_critsec.Leave(); // leave
457 THREAD_RETURN WiimoteThreadFunc(void* arg)
459 Common::SetCurrentThreadName("Wiimote Read");
461 while (g_run_wiimote_thread)
463 g_wiimote_critsec.Enter(); // enter
465 for (unsigned int i=0; i<MAX_WIIMOTES; ++i)
466 if (g_wiimotes[i])
467 g_wiimotes[i]->Read();
469 g_wiimote_critsec.Leave(); // leave
471 // hmmm, i get occasional lockups without this :/
472 Common::SleepCurrentThread(1);
475 return 0;
478 }; // end of namespace