PageRenderTime 147ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 1ms

/wii_yourself/wiimote.cpp

https://bitbucket.org/lrsschtz/powerwall-viewer
C++ | 2819 lines | 2033 code | 322 blank | 464 comment | 394 complexity | ebb8705c75be2892e483e026066c312d MD5 | raw file
  1. // _______________________________________________________________________________
  2. //
  3. // - WiiYourself! - native C++ Wiimote library v1.15
  4. // (c) gl.tter 2007-10 - http://gl.tter.org
  5. //
  6. // see License.txt for conditions of use. see History.txt for change log.
  7. // _______________________________________________________________________________
  8. //
  9. // wiimote.cpp (tab = 4 spaces)
  10. // VC-specifics:
  11. #ifdef _MSC_VER
  12. // disable warning "C++ exception handler used, but unwind semantics are not enabled."
  13. // in <xstring> (I don't use it - or just enable C++ exceptions)
  14. # pragma warning(disable: 4530)
  15. // auto-link with the necessary libs
  16. # pragma comment(lib, "setupapi.lib")
  17. # pragma comment(lib, "hid.lib") // for HID API (from DDK)
  18. # pragma comment(lib, "winmm.lib") // for timeGetTime()
  19. #endif // _MSC_VER
  20. #include "wiimote.h"
  21. #include <setupapi.h>
  22. extern "C" {
  23. # ifdef __MINGW32__
  24. # include <ddk/hidsdi.h>// from WinDDK
  25. # else
  26. # include <hidsdi.h>
  27. # endif
  28. }
  29. #include <sys/types.h> // for _stat
  30. #include <sys/stat.h> // "
  31. #include <process.h> // for _beginthreadex()
  32. #ifdef __BORLANDC__
  33. # include <cmath.h> // for orientation
  34. #else
  35. # include <math.h> // "
  36. #endif
  37. #include <mmreg.h> // for WAVEFORMATEXTENSIBLE
  38. #include <mmsystem.h> // for timeGetTime()
  39. // apparently not defined in some compilers:
  40. #ifndef min
  41. # define min(a,b) (((a) < (b)) ? (a) : (b))
  42. #endif
  43. // ------------------------------------------------------------------------------------
  44. // helpers
  45. // ------------------------------------------------------------------------------------
  46. template<class T> inline T sign (const T& val) { return (val<0)? T(-1) : T(1); }
  47. template<class T> inline T square(const T& val) { return val*val; }
  48. #define ARRAY_ENTRIES(array) (sizeof(array)/sizeof(array[0]))
  49. // ------------------------------------------------------------------------------------
  50. // Tracing & Debugging
  51. // ------------------------------------------------------------------------------------
  52. #define PREFIX _T("WiiYourself! : ")
  53. // comment these to auto-strip their code from the library:
  54. // (they currently use OutputDebugString() via _TRACE() - change to suit)
  55. #if (_MSC_VER >= 1400) // VC 2005+ (earlier versions don't support variable args)
  56. # define TRACE(fmt, ...) _TRACE(PREFIX fmt _T("\n"), __VA_ARGS__)
  57. # define WARN(fmt, ...) _TRACE(PREFIX _T("* ") fmt _T(" *") _T("\n"), __VA_ARGS__)
  58. #elif defined(__MINGW32__)
  59. # define TRACE(fmt, ...) _TRACE(PREFIX fmt _T("\n") , ##__VA_ARGS__)
  60. # define WARN(fmt, ...) _TRACE(PREFIX _T("* ") fmt _T(" *") _T("\n") , ##__VA_ARGS__)
  61. #endif
  62. // uncomment any of these for deeper debugging:
  63. //#define DEEP_TRACE(fmt, ...) _TRACE(PREFIX _T("|") fmt _T("\n"), __VA_ARGS__) // VC 2005+
  64. //#define DEEP_TRACE(fmt, ...) _TRACE(PREFIX _T("|") fmt _T("\n") , ##__VA_ARGS__) // mingw
  65. //#define BEEP_DEBUG_READS
  66. //#define BEEP_DEBUG_WRITES
  67. //#define BEEP_ON_ORIENTATION_ESTIMATE
  68. //#define BEEP_ON_PERIODIC_STATUSREFRESH
  69. // internals: auto-strip code from the macros if they weren't defined
  70. #ifndef TRACE
  71. # define TRACE
  72. #endif
  73. #ifndef DEEP_TRACE
  74. # define DEEP_TRACE
  75. #endif
  76. #ifndef WARN
  77. # define WARN
  78. #endif
  79. // ------------------------------------------------------------------------------------
  80. static void _cdecl _TRACE (const TCHAR* fmt, ...)
  81. {
  82. static TCHAR buffer[256];
  83. if (!fmt) return;
  84. va_list argptr;
  85. va_start (argptr, fmt);
  86. #if (_MSC_VER >= 1400) // VC 2005+
  87. _vsntprintf_s(buffer, ARRAY_ENTRIES(buffer), _TRUNCATE, fmt, argptr);
  88. #else
  89. _vsntprintf (buffer, ARRAY_ENTRIES(buffer), fmt, argptr);
  90. #endif
  91. va_end (argptr);
  92. OutputDebugString(buffer);
  93. }
  94. // ------------------------------------------------------------------------------------
  95. // wiimote
  96. // ------------------------------------------------------------------------------------
  97. // class statics
  98. HMODULE wiimote::HidDLL = NULL;
  99. unsigned wiimote::_TotalCreated = 0;
  100. unsigned wiimote::_TotalConnected = 0;
  101. hidwrite_ptr wiimote::_HidD_SetOutputReport = NULL;
  102. // (keep in sync with 'speaker_freq'):
  103. const unsigned wiimote::FreqLookup [TOTAL_FREQUENCIES] =
  104. { 0, 4200, 3920, 3640, 3360,
  105. 3130, 2940, 2760, 2610, 2470 };
  106. const TCHAR* wiimote::ButtonNameFromBit [TOTAL_BUTTON_BITS] =
  107. { _T("Left") , _T("Right"), _T("Down"), _T("Up"),
  108. _T("Plus") , _T("??") , _T("??") , _T("??") ,
  109. _T("Two") , _T("One") , _T("B") , _T("A") ,
  110. _T("Minus"), _T("??") , _T("??") , _T("Home") };
  111. const TCHAR* wiimote::ClassicButtonNameFromBit [TOTAL_BUTTON_BITS] =
  112. { _T("??") , _T("TrigR") , _T("Plus") , _T("Home"),
  113. _T("Minus"), _T("TrigL") , _T("Down") , _T("Right") ,
  114. _T("Up") , _T("Left") , _T("ZR") , _T("X") ,
  115. _T("A") , _T("Y") , _T("B") , _T("ZL") };
  116. // ------------------------------------------------------------------------------------
  117. wiimote::wiimote ()
  118. :
  119. DataRead (CreateEvent(NULL, FALSE, FALSE, NULL)),
  120. Handle (INVALID_HANDLE_VALUE),
  121. ReportType (IN_BUTTONS),
  122. bStatusReceived (false), // for output method detection
  123. bConnectInProgress (true ),
  124. bInitInProgress (false),
  125. bEnablingMotionPlus (false),
  126. bConnectionLost (false), // set if write fails after connection
  127. bMotionPlusDetected (false),
  128. bMotionPlusEnabled (false),
  129. bMotionPlusExtension (false),
  130. bCalibrateAtRest (false),
  131. bUseHIDwrite (false), // if OS supports it
  132. ChangedCallback (NULL),
  133. CallbackTriggerFlags (CHANGED_ALL),
  134. InternalChanged (NO_CHANGE),
  135. CurrentSample (NULL),
  136. HIDwriteThread (NULL),
  137. ReadParseThread (NULL),
  138. SampleThread (NULL),
  139. AsyncRumbleThread (NULL),
  140. AsyncRumbleTimeout (0),
  141. UniqueID (0) // not _guaranteed_ unique, see comments in header
  142. #ifdef ID2_FROM_DEVICEPATH // (see comments in header)
  143. // UniqueID2 (0)
  144. #endif
  145. {
  146. _ASSERT(DataRead != INVALID_HANDLE_VALUE);
  147. // if this is the first wiimote object, detect & enable HID write support
  148. if(++_TotalCreated == 1)
  149. {
  150. HidDLL = LoadLibrary(_T("hid.dll"));
  151. _ASSERT(HidDLL);
  152. if(!HidDLL)
  153. WARN(_T("Couldn't load hid.dll - shouldn't happen!"));
  154. else{
  155. _HidD_SetOutputReport = (hidwrite_ptr)
  156. GetProcAddress(HidDLL, "HidD_SetOutputReport");
  157. if(_HidD_SetOutputReport)
  158. TRACE(_T("OS supports HID writes."));
  159. else
  160. TRACE(_T("OS doesn't support HID writes."));
  161. }
  162. }
  163. // clear our public and private state data completely (including deadzones)
  164. Clear (true);
  165. Internal.Clear(true);
  166. // and the state recording vars
  167. memset(&Recording, 0, sizeof(Recording));
  168. // for overlapped IO (Read/WriteFile)
  169. memset(&Overlapped, 0, sizeof(Overlapped));
  170. Overlapped.hEvent = DataRead;
  171. Overlapped.Offset =
  172. Overlapped.OffsetHigh = 0;
  173. // for async HID output method
  174. InitializeCriticalSection(&HIDwriteQueueLock);
  175. // for polling
  176. InitializeCriticalSection(&StateLock);
  177. // request millisecond timer accuracy
  178. timeBeginPeriod(1);
  179. }
  180. // ------------------------------------------------------------------------------------
  181. wiimote::~wiimote ()
  182. {
  183. Disconnect();
  184. // events & critical sections are kept open for the lifetime of the object,
  185. // so tidy them up here:
  186. if(DataRead != INVALID_HANDLE_VALUE)
  187. CloseHandle(DataRead);
  188. DeleteCriticalSection(&HIDwriteQueueLock);
  189. DeleteCriticalSection(&StateLock);
  190. // tidy up timer accuracy request
  191. timeEndPeriod(1);
  192. // release HID DLL (for dynamic HID write method)
  193. if((--_TotalCreated == 0) && HidDLL)
  194. {
  195. FreeLibrary(HidDLL);
  196. HidDLL = NULL;
  197. _HidD_SetOutputReport = NULL;
  198. }
  199. }
  200. // ------------------------------------------------------------------------------------
  201. bool wiimote::Connect (unsigned wiimote_index, bool force_hidwrites)
  202. {
  203. if(wiimote_index == FIRST_AVAILABLE)
  204. TRACE(_T("Connecting first available Wiimote:"));
  205. else
  206. TRACE(_T("Connecting Wiimote %u:"), wiimote_index);
  207. // auto-disconnect if user is being naughty
  208. if(IsConnected())
  209. Disconnect();
  210. // get the GUID of the HID class
  211. GUID guid;
  212. HidD_GetHidGuid(&guid);
  213. // get a handle to all devices that are part of the HID class
  214. // Brian: Fun fact: DIGCF_PRESENT worked on my machine just fine. I reinstalled
  215. // Vista, and now it no longer finds the Wiimote with that parameter enabled...
  216. HDEVINFO dev_info = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_DEVICEINTERFACE);// | DIGCF_PRESENT);
  217. if(!dev_info) {
  218. WARN(_T("couldn't get device info"));
  219. return false;
  220. }
  221. // enumerate the devices
  222. SP_DEVICE_INTERFACE_DATA didata;
  223. didata.cbSize = sizeof(didata);
  224. unsigned index = 0;
  225. unsigned wiimotes_found = 0;
  226. while(SetupDiEnumDeviceInterfaces(dev_info, NULL, &guid, index, &didata))
  227. {
  228. // get the buffer size for this device detail instance
  229. DWORD req_size = 0;
  230. SetupDiGetDeviceInterfaceDetail(dev_info, &didata, NULL, 0, &req_size, NULL);
  231. // (bizarre way of doing it) create a buffer large enough to hold the
  232. // fixed-size detail struct components, and the variable string size
  233. SP_DEVICE_INTERFACE_DETAIL_DATA *didetail =
  234. (SP_DEVICE_INTERFACE_DETAIL_DATA*) new BYTE[req_size];
  235. _ASSERT(didetail);
  236. didetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
  237. // now actually get the detail struct
  238. if(!SetupDiGetDeviceInterfaceDetail(dev_info, &didata, didetail,
  239. req_size, &req_size, NULL)) {
  240. WARN(_T("couldn't get devinterface info for %u"), index);
  241. break;
  242. }
  243. // open a shared handle to the device to query it (this will succeed even
  244. // if the wiimote is already Connect()'ed)
  245. DEEP_TRACE(_T(".. querying device %s"), didetail->DevicePath);
  246. Handle = CreateFile(didetail->DevicePath, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
  247. NULL, OPEN_EXISTING, 0, NULL);
  248. if(Handle == INVALID_HANDLE_VALUE) {
  249. DEEP_TRACE(_T(".... failed with err %x (probably harmless)."),
  250. GetLastError());
  251. goto skip;
  252. }
  253. // get the device attributes
  254. HIDD_ATTRIBUTES attrib;
  255. attrib.Size = sizeof(attrib);
  256. if(HidD_GetAttributes(Handle, &attrib))
  257. {
  258. // is this a wiimote?
  259. if((attrib.VendorID != VID) || (attrib.ProductID != PID))
  260. goto skip;
  261. // yes, but is it the one we're interested in?
  262. ++wiimotes_found;
  263. if((wiimote_index != FIRST_AVAILABLE) &&
  264. (wiimote_index != wiimotes_found))
  265. goto skip;
  266. // the wiimote is installed, but it may not be currently paired:
  267. if(wiimote_index == FIRST_AVAILABLE)
  268. TRACE(_T(".. opening Wiimote %u:"), wiimotes_found);
  269. else
  270. TRACE(_T(".. opening:"));
  271. // re-open the handle, but this time we don't allow write sharing
  272. // (that way subsequent calls can still _discover_ wiimotes above, but
  273. // will correctly fail here if they're already connected)
  274. CloseHandle(Handle);
  275. // note this also means that if another application has already opened
  276. // the device, the library can no longer connect it (this may happen
  277. // with software that enumerates all joysticks in the system, because
  278. // even though the wiimote is not a standard joystick (and can't
  279. // be read as such), it unfortunately announces itself to the OS
  280. // as one. The SDL library was known to do grab wiimotes like this.
  281. // If you cannot stop the application from doing it, you may change the
  282. // call below to open the device in full shared mode - but then the
  283. // library can no longer detect if you've already connected a device
  284. // and will allow you to connect it twice! So be careful ...
  285. Handle = CreateFile(didetail->DevicePath, GENERIC_READ|GENERIC_WRITE,
  286. FILE_SHARE_READ,
  287. NULL, OPEN_EXISTING,
  288. FILE_FLAG_OVERLAPPED, NULL);
  289. if(Handle == INVALID_HANDLE_VALUE) {
  290. TRACE(_T(".... failed with err %x"), GetLastError());
  291. goto skip;
  292. }
  293. // clear the wiimote state & buffers
  294. Clear (false); // preserves existing deadzones
  295. Internal.Clear(false); // "
  296. InternalChanged = NO_CHANGE;
  297. memset(ReadBuff , 0, sizeof(ReadBuff));
  298. bConnectionLost = false;
  299. bConnectInProgress = true; // don't parse extensions or request regular
  300. // updates until complete
  301. // enable async reading
  302. BeginAsyncRead();
  303. // autodetect which write method the Bluetooth stack supports,
  304. // by requesting the wiimote status report:
  305. if(force_hidwrites && !_HidD_SetOutputReport) {
  306. TRACE(_T(".. can't force HID writes (not supported)"));
  307. force_hidwrites = false;
  308. }
  309. if(force_hidwrites)
  310. TRACE(_T(".. (HID writes forced)"));
  311. else{
  312. // - try WriteFile() first as it's the most efficient (it uses
  313. // harware interrupts where possible and is async-capable):
  314. bUseHIDwrite = false;
  315. RequestStatusReport();
  316. // and wait for the report to arrive:
  317. DWORD last_time = timeGetTime();
  318. while(!bStatusReceived && ((timeGetTime()-last_time) < 500))
  319. Sleep(10);
  320. TRACE(_T(".. WriteFile() %s."), bStatusReceived? _T("succeeded") :
  321. _T("failed"));
  322. }
  323. // try HID write method (if supported)
  324. if(!bStatusReceived && _HidD_SetOutputReport)
  325. {
  326. bUseHIDwrite = true;
  327. RequestStatusReport();
  328. // wait for the report to arrive:
  329. DWORD last_time = timeGetTime();
  330. while(!bStatusReceived && ((timeGetTime()-last_time) < 500))
  331. Sleep(10);
  332. // did we get it?
  333. TRACE(_T(".. HID write %s."), bStatusReceived? _T("succeeded") :
  334. _T("failed"));
  335. }
  336. // still failed?
  337. if(!bStatusReceived) {
  338. WARN(_T("output failed - wiimote is not connected (or confused)."));
  339. Disconnect();
  340. goto skip;
  341. }
  342. //Sleep(500);
  343. // reset it
  344. Reset();
  345. // read the wiimote calibration info
  346. ReadCalibration();
  347. // allow the result(s) to come in (so that the caller can immediately test
  348. //MotionPlusConnected();
  349. Sleep(300); // note, don't need it on my system, better to be safe though
  350. // connected succesfully:
  351. _TotalConnected++;
  352. // use the first incomding analogue sensor values as the 'at rest'
  353. // offsets (only supports the Balance Board currently)
  354. bCalibrateAtRest = true;
  355. // refresh the public state from the internal one (so that everything
  356. // is available straight away
  357. RefreshState();
  358. // attempt to construct a unique hardware ID from the calibration
  359. // data bytes (this is obviously not guaranteed to be unique across
  360. // all devices, but may work fairly well in practice... ?)
  361. memcpy(&UniqueID, &CalibrationInfo, sizeof(CalibrationInfo));
  362. _ASSERT(UniqueID != 0); // if this fires, the calibration data didn't
  363. // arrive - this shouldn't happen
  364. #ifdef ID2_FROM_DEVICEPATH // (see comments in header)
  365. // create a 2nd alternative id by simply adding all the characters
  366. // in the device path to create a single number
  367. UniqueID2 = 0;
  368. for(unsigned index=0; index<_tcslen(didetail->DevicePath); index++)
  369. UniqueID2 += didetail->DevicePath[index];
  370. #endif
  371. // and show when we want to trigger the next periodic status request
  372. // (for battery level and connection loss detection)
  373. NextStatusTime = timeGetTime() + REQUEST_STATUS_EVERY_MS;
  374. NextMPlusDetectTime = timeGetTime() + DETECT_MPLUS_EVERY_MS;
  375. MPlusDetectCount = DETECT_MPLUS_COUNT;
  376. // tidy up
  377. delete[] (BYTE*)didetail;
  378. break;
  379. }
  380. skip:
  381. // tidy up
  382. delete[] (BYTE*)didetail;
  383. if(Handle != INVALID_HANDLE_VALUE) {
  384. CloseHandle(Handle);
  385. Handle = INVALID_HANDLE_VALUE;
  386. }
  387. // if this was the specified wiimote index, abort
  388. if((wiimote_index != FIRST_AVAILABLE) &&
  389. (wiimote_index == (wiimotes_found-1)))
  390. break;
  391. index++;
  392. }
  393. // clean up our list
  394. SetupDiDestroyDeviceInfoList(dev_info);
  395. bConnectInProgress = false;
  396. if(IsConnected()) {
  397. TRACE(_T(".. connected!"));
  398. // notify the callbacks (if requested to do so)
  399. if(CallbackTriggerFlags & WII_CONNECTED)
  400. {
  401. ChangedNotifier(WII_CONNECTED, Internal);
  402. if(ChangedCallback)
  403. ChangedCallback(*this, WII_CONNECTED, Internal);
  404. }
  405. return true;
  406. }
  407. TRACE(_T(".. connection failed."));
  408. return false;
  409. }
  410. // ------------------------------------------------------------------------------------
  411. void wiimote::CalibrateAtRest ()
  412. {
  413. _ASSERT(IsConnected());
  414. if(!IsConnected())
  415. return;
  416. // the app calls this to remove 'at rest' offsets from the analogue sensor
  417. // values (currently only works for the Balance Board):
  418. if(IsBalanceBoard()) {
  419. TRACE(_T(".. removing 'at rest' BBoard offsets."));
  420. Internal.BalanceBoard.AtRestKg = Internal.BalanceBoard.Kg;
  421. RefreshState();
  422. }
  423. }
  424. // ------------------------------------------------------------------------------------
  425. void wiimote::Disconnect ()
  426. {
  427. if(Handle == INVALID_HANDLE_VALUE)
  428. return;
  429. TRACE(_T("Disconnect()."));
  430. if(IsConnected())
  431. {
  432. _ASSERT(_TotalConnected > 0); // sanity
  433. _TotalConnected--;
  434. if(!bConnectionLost)
  435. Reset();
  436. }
  437. CloseHandle(Handle);
  438. Handle = INVALID_HANDLE_VALUE;
  439. UniqueID = 0;
  440. #ifdef ID2_FROM_DEVICEPATH // (see comments in header)
  441. UniqueID2 = 0;
  442. #endif
  443. // close the read thread
  444. if(ReadParseThread) {
  445. // unblock it so it can realise we're closing and exit straight away
  446. SetEvent(DataRead);
  447. WaitForSingleObject(ReadParseThread, 3000);
  448. CloseHandle(ReadParseThread);
  449. ReadParseThread = NULL;
  450. }
  451. // close the rumble thread
  452. if(AsyncRumbleThread) {
  453. WaitForSingleObject(AsyncRumbleThread, 3000);
  454. CloseHandle(AsyncRumbleThread);
  455. AsyncRumbleThread = NULL;
  456. AsyncRumbleTimeout = 0;
  457. }
  458. // and the sample streaming thread
  459. if(SampleThread) {
  460. WaitForSingleObject(SampleThread, 3000);
  461. CloseHandle(SampleThread);
  462. SampleThread = NULL;
  463. }
  464. #ifndef USE_DYNAMIC_HIDQUEUE
  465. HID.Deallocate();
  466. #endif
  467. bStatusReceived = false;
  468. // and clear the state
  469. Clear (false); // (preserves deadzones)
  470. Internal.Clear(false); // "
  471. InternalChanged = NO_CHANGE;
  472. }
  473. // ------------------------------------------------------------------------------------
  474. void wiimote::Reset ()
  475. {
  476. TRACE(_T("Resetting wiimote."));
  477. if(bMotionPlusEnabled)
  478. DisableMotionPlus();
  479. // stop updates (by setting report type to non-continuous, buttons-only)
  480. if(IsBalanceBoard())
  481. SetReportType(IN_BUTTONS_BALANCE_BOARD, false);
  482. else
  483. SetReportType(IN_BUTTONS, false);
  484. SetRumble (false);
  485. SetLEDs (0x00);
  486. // MuteSpeaker (true);
  487. EnableSpeaker(false);
  488. Sleep(150); // avoids loosing the extension calibration data on Connect()
  489. }
  490. // ------------------------------------------------------------------------------------
  491. unsigned __stdcall wiimote::ReadParseThreadfunc (void* param)
  492. {
  493. // this thread waits for the async ReadFile() to deliver data & parses it.
  494. // it also requests periodic status updates, deals with connection loss
  495. // and ends state recordings with a specific duration:
  496. _ASSERT(param);
  497. wiimote &remote = *(wiimote*)param;
  498. OVERLAPPED &overlapped = remote.Overlapped;
  499. unsigned exit_code = 0; // (success)
  500. while(1)
  501. {
  502. // wait until the overlapped read completes, or the timeout is reached:
  503. DWORD wait = WaitForSingleObject(overlapped.hEvent, 500);
  504. // before we deal with the result, let's do some housekeeping:
  505. // if we were recently Disconect()ed, exit now
  506. if(remote.Handle == INVALID_HANDLE_VALUE) {
  507. DEEP_TRACE(_T("read thread: wiimote was disconnected"));
  508. break;
  509. }
  510. // ditto if the connection was lost (eg. through a failed write)
  511. if(remote.bConnectionLost)
  512. {
  513. connection_lost:
  514. TRACE(_T("read thread: connection to wiimote was lost"));
  515. remote.Disconnect();
  516. remote.InternalChanged = (state_change_flags)
  517. (remote.InternalChanged | CONNECTION_LOST);
  518. // report via the callback (if any)
  519. if(remote.CallbackTriggerFlags & CONNECTION_LOST)
  520. {
  521. remote.ChangedNotifier(CONNECTION_LOST, remote.Internal);
  522. if(remote.ChangedCallback)
  523. remote.ChangedCallback(remote, CONNECTION_LOST, remote.Internal);
  524. }
  525. break;
  526. }
  527. DWORD time = timeGetTime();
  528. // periodic events (but not if we're streaming audio,
  529. // we don't want to cause a glitch)
  530. if(remote.IsConnected() && !remote.bInitInProgress &&
  531. !remote.IsPlayingAudio())
  532. {
  533. // status request due?
  534. if(time > remote.NextStatusTime)
  535. {
  536. #ifdef BEEP_ON_PERIODIC_STATUSREFRESH
  537. Beep(2000,50);
  538. #endif
  539. remote.RequestStatusReport();
  540. // and schedule the next one
  541. remote.NextStatusTime = time + REQUEST_STATUS_EVERY_MS;
  542. }
  543. // motion plus detection due?
  544. if(!remote.IsBalanceBoard() &&
  545. // !remote.bConnectInProgress &&
  546. !remote.bMotionPlusExtension &&
  547. (remote.Internal.ExtensionType != MOTION_PLUS) &&
  548. (remote.Internal.ExtensionType != PARTIALLY_INSERTED) &&
  549. (time > remote.NextMPlusDetectTime))
  550. {
  551. remote.DetectMotionPlusExtensionAsync();
  552. // we try several times in quick succession before the next
  553. // delay:
  554. if(--remote.MPlusDetectCount == 0) {
  555. remote.NextMPlusDetectTime = time + DETECT_MPLUS_EVERY_MS;
  556. remote.MPlusDetectCount = DETECT_MPLUS_COUNT;
  557. #ifdef _DEBUG
  558. TRACE(_T("--"));
  559. #endif
  560. }
  561. }
  562. }
  563. // if we're state recording and have reached the specified duration, stop
  564. if(remote.Recording.bEnabled && (remote.Recording.EndTimeMS != UNTIL_STOP) &&
  565. (time >= remote.Recording.EndTimeMS))
  566. remote.Recording.bEnabled = false;
  567. // now handle the wait result:
  568. // did the wait time out?
  569. if(wait == WAIT_TIMEOUT) {
  570. DEEP_TRACE(_T("read thread: timed out"));
  571. continue; // wait again
  572. }
  573. // did an error occurr?
  574. if(wait != WAIT_OBJECT_0) {
  575. DEEP_TRACE(_T("read thread: error waiting!"));
  576. remote.bConnectionLost = true;
  577. // deal with it straight away to avoid a longer delay
  578. goto connection_lost;
  579. }
  580. // data was received:
  581. #ifdef BEEP_DEBUG_READS
  582. Beep(500,1);
  583. #endif
  584. DWORD read = 0;
  585. // get the data read result
  586. GetOverlappedResult(remote.Handle, &overlapped, &read, TRUE);
  587. // if we read data, parse it
  588. if(read) {
  589. DEEP_TRACE(_T("read thread: parsing data"));
  590. remote.OnReadData(read);
  591. }
  592. else
  593. DEEP_TRACE(_T("read thread: didn't get any data??"));
  594. }
  595. TRACE(_T("(ending read thread)"));
  596. #ifdef BEEP_DEBUG_READS
  597. if(exit_code != 0)
  598. Beep(200,1000);
  599. #endif
  600. return exit_code;
  601. }
  602. // ------------------------------------------------------------------------------------
  603. bool wiimote::BeginAsyncRead ()
  604. {
  605. // (this is also called before we're fully connected)
  606. if(Handle == INVALID_HANDLE_VALUE)
  607. return false;
  608. DEEP_TRACE(_T(".. starting async read"));
  609. #ifdef BEEP_DEBUG_READS
  610. Beep(1000,1);
  611. #endif
  612. DWORD read;
  613. if (!ReadFile(Handle, ReadBuff, REPORT_LENGTH, &read, &Overlapped)) {
  614. DWORD err = GetLastError();
  615. if(err != ERROR_IO_PENDING) {
  616. DEEP_TRACE(_T(".... ** ReadFile() failed! **"));
  617. return false;
  618. }
  619. }
  620. // launch the completion wait/callback thread
  621. if(!ReadParseThread) {
  622. ReadParseThread = (HANDLE)_beginthreadex(NULL, 0, ReadParseThreadfunc,
  623. this, 0, NULL);
  624. DEEP_TRACE(_T(".... creating read thread"));
  625. _ASSERT(ReadParseThread);
  626. if(!ReadParseThread)
  627. return false;
  628. SetThreadPriority(ReadParseThread, WORKER_THREAD_PRIORITY);
  629. }
  630. // if ReadFile completed while we called, signal the thread to proceed
  631. if(read) {
  632. DEEP_TRACE(_T(".... got data right away"));
  633. SetEvent(DataRead);
  634. }
  635. return true;
  636. }
  637. // ------------------------------------------------------------------------------------
  638. void wiimote::OnReadData (DWORD bytes_read)
  639. {
  640. _ASSERT(bytes_read == REPORT_LENGTH);
  641. // copy our input buffer
  642. BYTE buff [REPORT_LENGTH];
  643. memcpy(buff, ReadBuff, bytes_read);
  644. // start reading again
  645. BeginAsyncRead();
  646. // parse it
  647. ParseInput(buff);
  648. }
  649. // ------------------------------------------------------------------------------------
  650. void wiimote::SetReportType (input_report type, bool continuous)
  651. {
  652. _ASSERT(IsConnected());
  653. if(!IsConnected())
  654. return;
  655. // the balance board only uses one type of report
  656. _ASSERT(!IsBalanceBoard() || type == IN_BUTTONS_BALANCE_BOARD);
  657. if(IsBalanceBoard() && (type != IN_BUTTONS_BALANCE_BOARD))
  658. return;
  659. #ifdef TRACE
  660. #define TYPE2NAME(_type) (type==_type)? _T(#_type)
  661. const TCHAR* name = TYPE2NAME(IN_BUTTONS) :
  662. TYPE2NAME(IN_BUTTONS_ACCEL_IR) :
  663. TYPE2NAME(IN_BUTTONS_ACCEL_EXT) :
  664. TYPE2NAME(IN_BUTTONS_ACCEL_IR_EXT) :
  665. TYPE2NAME(IN_BUTTONS_BALANCE_BOARD) :
  666. _T("(unknown??)");
  667. TRACE(_T("ReportType: %s (%s)"), name, (continuous? _T("continuous") :
  668. _T("non-continuous")));
  669. #endif
  670. ReportType = type;
  671. switch(type)
  672. {
  673. case IN_BUTTONS_ACCEL_IR:
  674. EnableIR(wiimote_state::ir::EXTENDED);
  675. break;
  676. case IN_BUTTONS_ACCEL_IR_EXT:
  677. EnableIR(wiimote_state::ir::BASIC);
  678. break;
  679. default:
  680. DisableIR();
  681. break;
  682. }
  683. BYTE buff [REPORT_LENGTH] = {0};
  684. buff[0] = OUT_TYPE;
  685. buff[1] = (continuous ? 0x04 : 0x00) | GetRumbleBit();
  686. buff[2] = (BYTE)type;
  687. WriteReport(buff);
  688. // Sleep(15);
  689. }
  690. // ------------------------------------------------------------------------------------
  691. void wiimote::SetLEDs (BYTE led_bits)
  692. {
  693. _ASSERT(IsConnected());
  694. if(!IsConnected() || bInitInProgress)
  695. return;
  696. _ASSERT(led_bits <= 0x0f);
  697. led_bits &= 0xf;
  698. BYTE buff [REPORT_LENGTH] = {0};
  699. buff[0] = OUT_LEDs;
  700. buff[1] = (led_bits<<4) | GetRumbleBit();
  701. WriteReport(buff);
  702. Internal.LED.Bits = led_bits;
  703. }
  704. // ------------------------------------------------------------------------------------
  705. void wiimote::SetRumble (bool on)
  706. {
  707. _ASSERT(IsConnected());
  708. if(!IsConnected())
  709. return;
  710. if(Internal.bRumble == on)
  711. return;
  712. Internal.bRumble = on;
  713. // if we're streaming audio, we don't need to send a report (sending it makes
  714. // the audio glitch, and the rumble bit is sent with every report anyway)
  715. if(IsPlayingAudio())
  716. return;
  717. BYTE buff [REPORT_LENGTH] = {0};
  718. buff[0] = OUT_STATUS;
  719. buff[1] = on? 0x01 : 0x00;
  720. WriteReport(buff);
  721. }
  722. // ------------------------------------------------------------------------------------
  723. unsigned __stdcall wiimote::AsyncRumbleThreadfunc (void* param)
  724. {
  725. // auto-disables rumble after x milliseconds:
  726. _ASSERT(param);
  727. wiimote &remote = *(wiimote*)param;
  728. while(remote.IsConnected())
  729. {
  730. if(remote.AsyncRumbleTimeout)
  731. {
  732. DWORD current_time = timeGetTime();
  733. if(current_time >= remote.AsyncRumbleTimeout)
  734. {
  735. if(remote.Internal.bRumble)
  736. remote.SetRumble(false);
  737. remote.AsyncRumbleTimeout = 0;
  738. }
  739. Sleep(1);
  740. }
  741. else
  742. Sleep(4);
  743. }
  744. return 0;
  745. }
  746. // ------------------------------------------------------------------------------------
  747. void wiimote::RumbleForAsync (unsigned milliseconds)
  748. {
  749. // rumble for a fixed amount of time
  750. _ASSERT(IsConnected());
  751. if(!IsConnected())
  752. return;
  753. SetRumble(true);
  754. // show how long thread should wait to disable rumble again
  755. // (it it's currently rumbling it will just extend the time)
  756. AsyncRumbleTimeout = timeGetTime() + milliseconds;
  757. // create the thread?
  758. if(AsyncRumbleThread)
  759. return;
  760. AsyncRumbleThread = (HANDLE)_beginthreadex(NULL, 0, AsyncRumbleThreadfunc, this,
  761. 0, NULL);
  762. _ASSERT(AsyncRumbleThread);
  763. if(!AsyncRumbleThread) {
  764. WARN(_T("couldn't create rumble thread!"));
  765. return;
  766. }
  767. SetThreadPriority(AsyncRumbleThread, WORKER_THREAD_PRIORITY);
  768. }
  769. // ------------------------------------------------------------------------------------
  770. void wiimote::RequestStatusReport ()
  771. {
  772. // (this can be called before we're fully connected)
  773. _ASSERT(Handle != INVALID_HANDLE_VALUE);
  774. if(Handle == INVALID_HANDLE_VALUE)
  775. return;
  776. BYTE buff [REPORT_LENGTH] = {0};
  777. buff[0] = OUT_STATUS;
  778. buff[1] = GetRumbleBit();
  779. WriteReport(buff);
  780. }
  781. // ------------------------------------------------------------------------------------
  782. bool wiimote::ReadAddress (int address, short size)
  783. {
  784. // asynchronous
  785. BYTE buff [REPORT_LENGTH] = {0};
  786. buff[0] = OUT_READMEMORY;
  787. buff[1] = (BYTE)(((address & 0xff000000) >> 24) | GetRumbleBit());
  788. buff[2] = (BYTE)( (address & 0x00ff0000) >> 16);
  789. buff[3] = (BYTE)( (address & 0x0000ff00) >> 8);
  790. buff[4] = (BYTE)( (address & 0x000000ff));
  791. buff[5] = (BYTE)( (size & 0xff00 ) >> 8);
  792. buff[6] = (BYTE)( (size & 0xff));
  793. return WriteReport(buff);
  794. }
  795. // ------------------------------------------------------------------------------------
  796. void wiimote::WriteData (int address, BYTE size, const BYTE* buff)
  797. {
  798. // asynchronous
  799. BYTE write [REPORT_LENGTH] = {0};
  800. write[0] = OUT_WRITEMEMORY;
  801. write[1] = (BYTE)(((address & 0xff000000) >> 24) | GetRumbleBit());
  802. write[2] = (BYTE)( (address & 0x00ff0000) >> 16);
  803. write[3] = (BYTE)( (address & 0x0000ff00) >> 8);
  804. write[4] = (BYTE)( (address & 0x000000ff));
  805. write[5] = size;
  806. memcpy(write+6, buff, size);
  807. WriteReport(write);
  808. }
  809. // ------------------------------------------------------------------------------------
  810. int wiimote::ParseInput (BYTE* buff)
  811. {
  812. int changed = 0;
  813. // lock our internal state (so RefreshState() is blocked until we're done
  814. EnterCriticalSection(&StateLock);
  815. switch(buff[0])
  816. {
  817. case IN_BUTTONS:
  818. DEEP_TRACE(_T(".. parsing buttons."));
  819. changed |= ParseButtons(buff);
  820. break;
  821. case IN_BUTTONS_ACCEL:
  822. DEEP_TRACE(_T(".. parsing buttons/accel."));
  823. changed |= ParseButtons(buff);
  824. if(!IsBalanceBoard())
  825. changed |= ParseAccel(buff);
  826. break;
  827. case IN_BUTTONS_ACCEL_EXT:
  828. DEEP_TRACE(_T(".. parsing extenion/accel."));
  829. changed |= ParseButtons(buff);
  830. changed |= ParseExtension(buff, 6);
  831. if(!IsBalanceBoard())
  832. changed |= ParseAccel(buff);
  833. break;
  834. case IN_BUTTONS_ACCEL_IR:
  835. DEEP_TRACE(_T(".. parsing ir/accel."));
  836. changed |= ParseButtons(buff);
  837. if(!IsBalanceBoard()) {
  838. changed |= ParseAccel(buff);
  839. changed |= ParseIR(buff);
  840. }
  841. break;
  842. case IN_BUTTONS_ACCEL_IR_EXT:
  843. DEEP_TRACE(_T(".. parsing ir/extenion/accel."));
  844. changed |= ParseButtons(buff);
  845. changed |= ParseExtension(buff, 16);
  846. if(!IsBalanceBoard()) {
  847. changed |= ParseAccel(buff);
  848. changed |= ParseIR (buff);
  849. }
  850. break;
  851. case IN_BUTTONS_BALANCE_BOARD:
  852. DEEP_TRACE(_T(".. parsing buttson/balance."));
  853. changed |= ParseButtons(buff);
  854. changed |= ParseExtension(buff, 3);
  855. break;
  856. case IN_READADDRESS:
  857. DEEP_TRACE(_T(".. parsing read address."));
  858. changed |= ParseButtons (buff);
  859. changed |= ParseReadAddress(buff);
  860. break;
  861. case IN_STATUS:
  862. DEEP_TRACE(_T(".. parsing status."));
  863. changed |= ParseStatus(buff);
  864. // show that we received the status report (used for output method
  865. // detection during Connect())
  866. bStatusReceived = true;
  867. break;
  868. default:
  869. DEEP_TRACE(_T(".. ** unknown input ** (happens)."));
  870. ///_ASSERT(0);
  871. //Debug.WriteLine("Unknown report type: " + type.ToString());
  872. LeaveCriticalSection(&StateLock);
  873. return false;
  874. }
  875. // if we're recording and some state we care about has changed, insert it into
  876. // the state history
  877. if(Recording.bEnabled && (changed & Recording.TriggerFlags))
  878. {
  879. DEEP_TRACE(_T(".. adding state to history"));
  880. state_event event;
  881. event.time_ms = timeGetTime();
  882. event.state = *(wiimote_state*)this;
  883. Recording.StateHistory->push_back(event);
  884. }
  885. // for polling: show which state has changed since the last RefreshState()
  886. InternalChanged = (state_change_flags)(InternalChanged | changed);
  887. LeaveCriticalSection(&StateLock);
  888. // callbacks: call it (if set & state the app is interested in has changed)
  889. if(changed & CallbackTriggerFlags)
  890. {
  891. DEEP_TRACE(_T(".. calling state change callback"));
  892. ChangedNotifier((state_change_flags)changed, Internal);
  893. if(ChangedCallback)
  894. ChangedCallback(*this, (state_change_flags)changed, Internal);
  895. }
  896. DEEP_TRACE(_T(".. parse complete."));
  897. return true;
  898. }
  899. // ------------------------------------------------------------------------------------
  900. state_change_flags wiimote::RefreshState ()
  901. {
  902. // nothing changed since the last call?
  903. if(InternalChanged == NO_CHANGE)
  904. return NO_CHANGE;
  905. // copy the internal state to our public data members:
  906. // synchronise the interal state with the read/parse thread (we don't want
  907. // values changing during the copy)
  908. EnterCriticalSection(&StateLock);
  909. // remember which state changed since the last call
  910. state_change_flags changed = InternalChanged;
  911. // preserve the application-set deadzones (if any)
  912. joystick::deadzone nunchuk_deadzone = Nunchuk.Joystick.DeadZone;
  913. joystick::deadzone classic_joyl_deadzone = ClassicController.JoystickL.DeadZone;
  914. joystick::deadzone classic_joyr_deadzone = ClassicController.JoystickR.DeadZone;
  915. // copy the internal state to the public one
  916. *(wiimote_state*)this = Internal;
  917. InternalChanged = NO_CHANGE;
  918. // restore the application-set deadzones
  919. Nunchuk.Joystick.DeadZone = nunchuk_deadzone;
  920. ClassicController.JoystickL.DeadZone = classic_joyl_deadzone;
  921. ClassicController.JoystickR.DeadZone = classic_joyr_deadzone;
  922. LeaveCriticalSection(&StateLock);
  923. return changed;
  924. }
  925. // ------------------------------------------------------------------------------------
  926. void wiimote::DetectMotionPlusExtensionAsync ()
  927. {
  928. #ifdef _DEBUG
  929. TRACE(_T("(looking for motion plus)"));
  930. #endif
  931. // show that we're expecting the result shortly
  932. MotionPlusDetectCount++;
  933. // MotionPLus reports at a different address than other extensions (until
  934. // activated, when it maps itself into the usual extension registers), so
  935. // try to detect it first:
  936. ReadAddress(REGISTER_MOTIONPLUS_DETECT, 6);
  937. }
  938. // ------------------------------------------------------------------------------------
  939. bool wiimote::EnableMotionPlus ()
  940. {
  941. TRACE(_T("Enabling Motion Plus:"));
  942. bMotionPlusExtension = false;
  943. bInitInProgress = true;
  944. bEnablingMotionPlus = true;
  945. // Initialize it:
  946. WriteData(REGISTER_MOTIONPLUS_INIT , 0x55);
  947. // Sleep(50);
  948. // Enable it (this maps it to the standard extension port):
  949. WriteData(REGISTER_MOTIONPLUS_ENABLE, 0x04);
  950. // Sleep(50);
  951. Sleep(500);
  952. return true;
  953. }
  954. // ------------------------------------------------------------------------------------
  955. bool wiimote::DisableMotionPlus ()
  956. {
  957. if(!bMotionPlusDetected || !bMotionPlusEnabled)
  958. return false;
  959. TRACE(_T("Disabling Motion Plus:"));
  960. // disable it (this makes standard extensions visible again)
  961. WriteData(REGISTER_EXTENSION_INIT1, 0x55);
  962. return true;
  963. }
  964. // ------------------------------------------------------------------------------------
  965. void wiimote::InitializeExtension ()
  966. {
  967. TRACE(_T("Initialising Extension."));
  968. // wibrew.org: The new way to initialize the extension is by writing 0x55 to
  969. // 0x(4)A400F0, then writing 0x00 to 0x(4)A400FB. It works on all extensions, and
  970. // makes the extension type bytes unencrypted. This means that you no longer have
  971. // to decrypt the extension bytes using the transform listed above.
  972. bInitInProgress = true;
  973. _ASSERT(Internal.bExtension);
  974. // only initialize if it's not a MotionPlus
  975. if(!bEnablingMotionPlus) {
  976. WriteData (REGISTER_EXTENSION_INIT1, 0x55);
  977. WriteData (REGISTER_EXTENSION_INIT2, 0x00);
  978. }
  979. else
  980. bEnablingMotionPlus = false;
  981. ReadAddress(REGISTER_EXTENSION_TYPE , 6);
  982. }
  983. // ------------------------------------------------------------------------------------
  984. int wiimote::ParseStatus (BYTE* buff)
  985. {
  986. // parse the buttons
  987. int changed = ParseButtons(buff);
  988. // get the battery level
  989. BYTE battery_raw = buff[6];
  990. if(Internal.BatteryRaw != battery_raw)
  991. changed |= BATTERY_CHANGED;
  992. Internal.BatteryRaw = battery_raw;
  993. // it is estimated that ~200 is the maximum battery level
  994. Internal.BatteryPercent = battery_raw / 2;
  995. // there is also a flag that shows if the battery is nearly empty
  996. bool drained = buff[3] & 0x01;
  997. if(drained != bBatteryDrained)
  998. {
  999. bBatteryDrained = drained;
  1000. if(drained)
  1001. changed |= BATTERY_DRAINED;
  1002. }
  1003. // leds
  1004. BYTE leds = buff[3] >> 4;
  1005. if(leds != Internal.LED.Bits)
  1006. changed |= LEDS_CHANGED;
  1007. Internal.LED.Bits = leds;
  1008. // don't handle extensions until a connection is complete
  1009. // if(bConnectInProgress)
  1010. // return changed;
  1011. bool extension = ((buff[3] & 0x02) != 0);
  1012. // TRACE(_T("(extension = %s)"), (extension? _T("TRUE") : _T("false")));
  1013. if(extension != Internal.bExtension)
  1014. {
  1015. if(!Internal.bExtension)
  1016. {
  1017. TRACE(_T("Extension connected:"));
  1018. Internal.bExtension = true;
  1019. InitializeExtension();
  1020. }
  1021. else{
  1022. TRACE(_T("Extension disconnected."));
  1023. Internal.bExtension = false;
  1024. Internal.ExtensionType = wiimote_state::NONE;
  1025. bMotionPlusEnabled = false;
  1026. bMotionPlusExtension = false;
  1027. bMotionPlusDetected = false;
  1028. bInitInProgress = false;
  1029. bEnablingMotionPlus = false;
  1030. changed |= EXTENSION_DISCONNECTED;
  1031. // renable reports
  1032. // SetReportType(ReportType);
  1033. }
  1034. }
  1035. return changed;
  1036. }
  1037. // ------------------------------------------------------------------------------------
  1038. int wiimote::ParseButtons (BYTE* buff)
  1039. {
  1040. int changed = 0;
  1041. // WORD bits = *(WORD*)(buff+1);
  1042. WORD bits = *(WORD*)(buff+1) & Button.ALL;
  1043. if(bits != Internal.Button.Bits)
  1044. changed |= BUTTONS_CHANGED;
  1045. Internal.Button.Bits = bits;
  1046. return changed;
  1047. }
  1048. // ------------------------------------------------------------------------------------
  1049. bool wiimote::EstimateOrientationFrom (wiimote_state::acceleration &accel)
  1050. {
  1051. // Orientation estimate from acceleration data (shared between wiimote and nunchuk)
  1052. // return true if the orientation was updated
  1053. // assume the controller is stationary if the acceleration vector is near
  1054. // 1g for several updates (this may not always be correct)
  1055. float length_sq = square(accel.X) + square(accel.Y) + square(accel.Z);
  1056. // TODO: as I'm comparing _squared_ length, I really need different
  1057. // min/max epsilons...
  1058. #define DOT(x1,y1,z1, x2,y2,z2) ((x1*x2) + (y1*y2) + (z1*z2))
  1059. static const float epsilon = 0.2f;
  1060. if((length_sq >= (1.f-epsilon)) && (length_sq <= (1.f+epsilon)))
  1061. {
  1062. if(++WiimoteNearGUpdates < 2)
  1063. return false;
  1064. // wiimote seems to be stationary: normalize the current acceleration
  1065. // (ie. the assumed gravity vector)
  1066. float inv_len = 1.f / sqrt(length_sq);
  1067. float x = accel.X * inv_len;
  1068. float y = accel.Y * inv_len;
  1069. float z = accel.Z * inv_len;
  1070. // copy the values
  1071. accel.Orientation.X = x;
  1072. accel.Orientation.Y = y;
  1073. accel.Orientation.Z = z;
  1074. // and extract pitch & roll from them:
  1075. // (may not be optimal)
  1076. float pitch = -asin(y) * 57.2957795f;
  1077. // float roll = asin(x) * 57.2957795f;
  1078. float roll = atan2(x,z) * 57.2957795f;
  1079. if(z < 0) {
  1080. pitch = (y < 0)? 180 - pitch : -180 - pitch;
  1081. roll = (x < 0)? -180 - roll : 180 - roll;
  1082. }
  1083. accel.Orientation.Pitch = pitch;
  1084. accel.Orientation.Roll = roll;
  1085. // show that we just updated orientation
  1086. accel.Orientation.UpdateAge = 0;
  1087. #ifdef BEEP_ON_ORIENTATION_ESTIMATE
  1088. Beep(2000, 1);
  1089. #endif
  1090. return true; // updated
  1091. }
  1092. // not updated this time:
  1093. WiimoteNearGUpdates = 0;
  1094. // age the last orientation update
  1095. accel.Orientation.UpdateAge++;
  1096. return false;
  1097. }
  1098. // ------------------------------------------------------------------------------------
  1099. void wiimote::ApplyJoystickDeadZones (wiimote_state::joystick &joy)
  1100. {
  1101. // apply the deadzones to each axis (if set)
  1102. if((joy.DeadZone.X > 0.f) && (joy.DeadZone.X <= 1.f))
  1103. {
  1104. if(fabs(joy.X) <= joy.DeadZone.X)
  1105. joy.X = 0;
  1106. else{
  1107. joy.X -= joy.DeadZone.X * sign(joy.X);
  1108. joy.X /= 1.f - joy.DeadZone.X;
  1109. }
  1110. }
  1111. if((joy.DeadZone.Y > 0.f) && (joy.DeadZone.Y <= 1.f))
  1112. {
  1113. if(fabs(joy.Y) <= joy.DeadZone.Y)
  1114. joy.Y = 0;
  1115. else{
  1116. joy.Y -= joy.DeadZone.Y * sign(joy.Y);
  1117. joy.Y /= 1.f - joy.DeadZone.Y;
  1118. }
  1119. }
  1120. }
  1121. // ------------------------------------------------------------------------------------
  1122. int wiimote::ParseAccel (BYTE* buff)
  1123. {
  1124. int changed = 0;
  1125. BYTE raw_x = buff[3];
  1126. BYTE raw_y = buff[4];
  1127. BYTE raw_z = buff[5];
  1128. if((raw_x != Internal.Acceleration.RawX) ||
  1129. (raw_y != Internal.Acceleration.RawY) ||
  1130. (raw_z != Internal.Acceleration.RawZ))
  1131. changed |= ACCEL_CHANGED;
  1132. Internal.Acceleration.RawX = raw_x;
  1133. Internal.Acceleration.RawY = raw_y;
  1134. Internal.Acceleration.RawZ = raw_z;
  1135. // avoid / 0.0 when calibration data hasn't arrived yet
  1136. if(Internal.CalibrationInfo.X0)
  1137. {
  1138. Internal.Acceleration.X =
  1139. ((float)Internal.Acceleration.RawX - Internal.CalibrationInfo.X0) /
  1140. ((float)Internal.CalibrationInfo.XG - Internal.CalibrationInfo.X0);
  1141. Internal.Acceleration.Y =
  1142. ((float)Internal.Acceleration.RawY - Internal.CalibrationInfo.Y0) /
  1143. ((float)Internal.CalibrationInfo.YG - Internal.CalibrationInfo.Y0);
  1144. Internal.Acceleration.Z =
  1145. ((float)Internal.Acceleration.RawZ - Internal.CalibrationInfo.Z0) /
  1146. ((float)Internal.CalibrationInfo.ZG - Internal.CalibrationInfo.Z0);
  1147. }
  1148. else{
  1149. Internal.Acceleration.X =
  1150. Internal.Acceleration.Y =
  1151. Internal.Acceleration.Z = 0.f;
  1152. }
  1153. // see if we can estimate the orientation from the current values
  1154. if(EstimateOrientationFrom(Internal.Acceleration))
  1155. changed |= ORIENTATION_CHANGED;
  1156. return changed;
  1157. }
  1158. // ------------------------------------------------------------------------------------
  1159. int wiimote::ParseIR (BYTE* buff)
  1160. {
  1161. if(Internal.IR.Mode == wiimote_state::ir::OFF)
  1162. return NO_CHANGE;
  1163. // avoid garbage values when the MotionPlus is enabled, but the app is
  1164. // still using the extended IR report type
  1165. if(bMotionPlusEnabled && (Internal.IR.Mode == wiimote_state::ir::EXTENDED))
  1166. return NO_CHANGE;
  1167. // take a copy of the existing IR state (so we can detect changes)
  1168. wiimote_state::ir prev_ir = Internal.IR;
  1169. // only updates the other values if the dots are visible (so that the last
  1170. // valid values stay unmodified)
  1171. switch(Internal.IR.Mode)
  1172. {
  1173. case wiimote_state::ir::BASIC:
  1174. // 2 dots are encoded in 5 bytes, so read 2 at a time
  1175. for(unsigned step=0; step<2; step++)
  1176. {
  1177. ir::dot &dot0 = Internal.IR.Dot[step*2 ];
  1178. ir::dot &dot1 = Internal.IR.Dot[step*2+1];
  1179. const unsigned offs = 6 + (step*5); // 5 bytes for 2 dots
  1180. dot0.bVisible = !(buff[offs ] == 0xff && buff[offs+1] == 0xff);
  1181. dot1.bVisible = !(buff[offs+3] == 0xff && buff[offs+4] == 0xff);
  1182. if(dot0.bVisible) {
  1183. dot0.RawX = buff[offs ] | ((buff[offs+2] >> 4) & 0x03) << 8;;
  1184. dot0.RawY = buff[offs+1] | ((buff[offs+2] >> 6) & 0x03) << 8;;
  1185. dot0.X = 1.f - (dot0.RawX / (float)wiimote_state::ir::MAX_RAW_X);
  1186. dot0.Y = (dot0.RawY / (float)wiimote_state::ir::MAX_RAW_Y);
  1187. }
  1188. if(dot1.bVisible) {
  1189. dot1.RawX = buff[offs+3] | ((buff[offs+2] >> 0) & 0x03) << 8;
  1190. dot1.RawY = buff[offs+4] | ((buff[offs+2] >> 2) & 0x03) << 8;
  1191. dot1.X = 1.f - (dot1.RawX / (float)wiimote_state::ir::MAX_RAW_X);
  1192. dot1.Y = (dot1.RawY / (float)wiimote_state::ir::MAX_RAW_Y);
  1193. }
  1194. }
  1195. break;
  1196. case wiimote_state::ir::EXTENDED:
  1197. // each dot is encoded into 3 bytes
  1198. for(unsigned index=0; index<4; index++)
  1199. {
  1200. ir::dot &dot = Internal.IR.Dot[index];
  1201. const unsigned offs = 6 + (index * 3);
  1202. dot.bVisible = !(buff[offs ]==0xff && buff[offs+1]==0xff &&
  1203. buff[offs+2]==0xff);
  1204. if(dot.bVisible) {
  1205. dot.RawX = buff[offs ] | ((buff[offs+2] >> 4) & 0x03) << 8;
  1206. dot.RawY = buff[offs+1] | ((buff[offs+2] >> 6) & 0x03) << 8;
  1207. dot.X = 1.f - (dot.RawX / (float)wiimote_state::ir::MAX_RAW_X);
  1208. dot.Y = (dot.RawY / (float)wiimote_state::ir::MAX_RAW_Y);
  1209. dot.Size = buff[offs+2] & 0x0f;
  1210. }
  1211. }
  1212. break;
  1213. case wiimote_state::ir::FULL:
  1214. _ASSERT(0); // not supported yet;
  1215. break;
  1216. }
  1217. return memcmp(&prev_ir, &Internal.IR, sizeof(Internal.IR))? IR_CHANGED : 0;
  1218. }
  1219. // ------------------------------------------------------------------------------------
  1220. inline float wiimote::GetBalanceValue (short sensor, short min, short mid, short max)
  1221. {
  1222. if(max == mid || mid == min)
  1223. return 0;
  1224. float val = (sensor < mid)?
  1225. 68.0f * ((float)(sensor - min) / (mid - min)) :
  1226. 68.0f * ((float)(sensor - mid) / (max - mid)) + 68.0f;
  1227. // divide by four (so that each sensor is correct)
  1228. return val * 0.25f;
  1229. }
  1230. // ------------------------------------------------------------------------------------
  1231. int wiimote::ParseExtension (BYTE *buff, unsigned offset)
  1232. {
  1233. int changed = 0;
  1234. switch(Internal.ExtensionType)
  1235. {
  1236. case wiimote_state::NUNCHUK:
  1237. {
  1238. // buttons
  1239. bool c = (buff[offset+5] & 0x02) == 0;
  1240. bool z = (buff[offset+5] & 0x01) == 0;
  1241. if((c != Internal.Nunchuk.C) || (z != Internal.Nunchuk.Z))
  1242. changed |= NUNCHUK_BUTTONS_CHANGED;
  1243. Internal.Nunchuk.C = c;
  1244. Internal.Nunchuk.Z = z;
  1245. // acceleration
  1246. {
  1247. wiimote_state::acceleration &accel = Internal.Nunchuk.Acceleration;
  1248. BYTE raw_x = buff[offset+2];
  1249. BYTE raw_y = buff[offset+3];
  1250. BYTE raw_z = buff[offset+4];
  1251. if((raw_x != accel.RawX) || (raw_y != accel.RawY) || (raw_z != accel.RawZ))
  1252. changed |= NUNCHUK_ACCEL_CHANGED;
  1253. accel.RawX = raw_x;
  1254. accel.RawY = raw_y;
  1255. accel.RawZ = raw_z;
  1256. wiimote_state::nunchuk::calibration_info &calib =
  1257. Internal.Nunchuk.CalibrationInfo;
  1258. accel.X = ((float)raw_x - calib.X0) / ((float)calib.XG - calib.X0);
  1259. accel.Y = ((float)raw_y - calib.Y0) / ((float)calib.YG - calib.Y0);
  1260. accel.Z = ((float)raw_z - calib.Z0) / ((float)calib.ZG - calib.Z0);
  1261. // try to extract orientation from the accel:
  1262. if(EstimateOrientationFrom(accel))
  1263. changed |= NUNCHUK_ORIENTATION_CHANGED;
  1264. }
  1265. {
  1266. // joystick:
  1267. wiimote_state::joystick &joy = Internal.Nunchuk.Joystick;
  1268. float raw_x = buff[offset+0];
  1269. float raw_y = buff[offset+1];
  1270. if((raw_x != joy.RawX) || (raw_y != joy.RawY))
  1271. changed |= NUNCHUK_JOYSTICK_CHANGED;
  1272. joy.RawX = raw_x;
  1273. joy.RawY = raw_y;
  1274. // apply the calibration data
  1275. wiimote_state::nunchuk::calibration_info &calib =
  1276. Internal.Nunchuk.CalibrationInfo;
  1277. if(Internal.Nunchuk.CalibrationInfo.MaxX != 0x00)
  1278. joy.X = ((float)raw_x - calib.MidX) / ((float)calib.MaxX - calib.MinX);
  1279. if(calib.MaxY != 0x00)
  1280. joy.Y = ((float)raw_y - calib.MidY) / ((float)calib.MaxY - calib.MinY);
  1281. // i prefer the outputs to range -1 - +1 (note this also affects the
  1282. // deadzone calculations)
  1283. joy.X *= 2; joy.Y *= 2;
  1284. // apply the public deadzones to the internal state (if set)
  1285. joy.DeadZone = Nunchuk.Joystick.DeadZone;
  1286. ApplyJoystickDeadZones(joy);
  1287. }
  1288. }
  1289. break;
  1290. case wiimote_state::CLASSIC:
  1291. case wiimote_state::GH3_GHWT_GUITAR:
  1292. case wiimote_state::GHWT_DRUMS:
  1293. {
  1294. // buttons:
  1295. WORD bits = *(WORD*)(buff+offset+4);
  1296. bits = ~bits; // need to invert bits since 0 is down, and 1 is up
  1297. if(bits != Internal.ClassicController.Button.Bits)
  1298. changed |= CLASSIC_BUTTONS_CHANGED;
  1299. Internal.ClassicController.Button.Bits = bits;
  1300. // joysticks:
  1301. wiimote_state::joystick &joyL = Internal.ClassicController.JoystickL;
  1302. wiimote_state::joystick &joyR = Internal.ClassicController.JoystickR;
  1303. float l_raw_x = (float) (buff[offset+0] & 0x3f);
  1304. float l_raw_y = (float) (buff[offset+1] & 0x3f);
  1305. float r_raw_x = (float)((buff[offset+2] >> 7) |
  1306. ((buff[offset+1] & 0xc0) >> 5) |
  1307. ((buff[offset+0] & 0xc0) >> 3));
  1308. float r_raw_y = (float) (buff[offset+2] & 0x1f);
  1309. if((joyL.RawX != l_raw_x) || (joyL.RawY != l_raw_y))
  1310. changed |= CLASSIC_JOYSTICK_L_CHANGED;
  1311. if((joyR.RawX != r_raw_x) || (joyR.RawY != r_raw_y))
  1312. changed |= CLASSIC_JOYSTICK_R_CHANGED;
  1313. joyL.RawX = l_raw_x; joyL.RawY = l_raw_y;
  1314. joyR.RawX = r_raw_x; joyR.RawY = r_raw_y;
  1315. // apply calibration
  1316. wiimote_state::classic_controller::calibration_info &calib =
  1317. Internal.ClassicController.CalibrationInfo;
  1318. if(calib.MaxXL != 0x00)
  1319. joyL.X = (joyL.RawX - calib.MidXL) / ((float)calib.MaxXL - calib.MinXL);
  1320. if(calib.MaxYL != 0x00)
  1321. joyL.Y = (joyL.RawY - calib.MidYL) / ((float)calib.MaxYL - calib.MinYL);
  1322. if(calib.MaxXR != 0x00)
  1323. joyR.X = (joyR.RawX - calib.MidXR) / ((float)calib.MaxXR - calib.MinXR);
  1324. if(calib.MaxYR != 0x00)
  1325. joyR.Y = (joyR.RawY - calib.MidYR) / ((float)calib.MaxYR - calib.MinYR);
  1326. // i prefer the joystick outputs to range -1 - +1 (note this also affects
  1327. // the deadzone calculations)
  1328. joyL.X *= 2; joyL.Y *= 2; joyR.X *= 2; joyR.Y *= 2;
  1329. // apply the public deadzones to the internal state (if set)
  1330. joyL.DeadZone = ClassicController.JoystickL.DeadZone;
  1331. joyR.DeadZone = ClassicController.JoystickR.DeadZone;
  1332. ApplyJoystickDeadZones(joyL);
  1333. ApplyJoystickDeadZones(joyR);
  1334. // triggers
  1335. BYTE raw_trigger_l = ((buff[offset+2] & 0x60) >> 2) |
  1336. (buff[offset+3] >> 5);
  1337. BYTE raw_trigger_r = buff[offset+3] & 0x1f;
  1338. if((raw_trigger_l != Internal.ClassicController.RawTriggerL) ||
  1339. (raw_trigger_r != Internal.ClassicController.RawTriggerR))
  1340. changed |= CLASSIC_TRIGGERS_CHANGED;
  1341. Internal.ClassicController.RawTriggerL = raw_trigger_l;
  1342. Internal.ClassicController.RawTriggerR = raw_trigger_r;
  1343. if(calib.MaxTriggerL != 0x00)
  1344. Internal.ClassicController.TriggerL =
  1345. (float)Internal.ClassicController.RawTriggerL /
  1346. ((float)calib.MaxTriggerL - calib.MinTriggerL);
  1347. if(calib.MaxTriggerR != 0x00)
  1348. Internal.ClassicController.TriggerR =
  1349. (float)Internal.ClassicController.RawTriggerR /
  1350. ((float)calib.MaxTriggerR - calib.MinTriggerR);
  1351. }
  1352. break;
  1353. case BALANCE_BOARD:
  1354. {
  1355. wiimote_state::balance_board::sensors_raw prev_raw =
  1356. Internal.BalanceBoard.Raw;
  1357. Internal.BalanceBoard.Raw.TopR =
  1358. (short)((short)buff[offset+0] << 8 | buff[offset+1]);
  1359. Internal.BalanceBoard.Raw.BottomR =
  1360. (short)((short)buff[offset+2] << 8 | buff[offset+3]);
  1361. Internal.BalanceBoard.Raw.TopL =
  1362. (short)((short)buff[offset+4] << 8 | buff[offset+5]);
  1363. Internal.BalanceBoard.Raw.BottomL =
  1364. (short)((short)buff[offset+6] << 8 | buff[offset+7]);
  1365. if((Internal.BalanceBoard.Raw.TopL != prev_raw.TopL) ||
  1366. (Internal.BalanceBoard.Raw.TopR != prev_raw.TopR) ||
  1367. (Internal.BalanceBoard.Raw.BottomL != prev_raw.BottomL) ||
  1368. (Internal.BalanceBoard.Raw.BottomR != prev_raw.BottomR))
  1369. changed |= BALANCE_WEIGHT_CHANGED;
  1370. Internal.BalanceBoard.Kg.TopL =
  1371. GetBalanceValue(Internal.BalanceBoard.Raw.TopL,
  1372. Internal.BalanceBoard.CalibrationInfo.Kg0 .TopL,
  1373. Internal.BalanceBoard.CalibrationInfo.Kg17.TopL,
  1374. Internal.BalanceBoard.CalibrationInfo.Kg34.TopL);
  1375. Internal.BalanceBoard.Kg.TopR =
  1376. GetBalanceValue(Internal.BalanceBoard.Raw.TopR,
  1377. Internal.BalanceBoard.CalibrationInfo.Kg0 .TopR,
  1378. Internal.BalanceBoard.CalibrationInfo.Kg17.TopR,
  1379. Internal.BalanceBoard.CalibrationInfo.Kg34.TopR);
  1380. Internal.BalanceBoard.Kg.BottomL =
  1381. GetBalanceValue(Internal.BalanceBoard.Raw.BottomL,
  1382. Internal.BalanceBoard.CalibrationInfo.Kg0 .BottomL,
  1383. Internal.BalanceBoard.CalibrationInfo.Kg17.BottomL,
  1384. Internal.BalanceBoard.CalibrationInfo.Kg34.BottomL);
  1385. Internal.BalanceBoard.Kg.BottomR =
  1386. GetBalanceValue(Internal.BalanceBoard.Raw.BottomR,
  1387. Internal.BalanceBoard.CalibrationInfo.Kg0 .BottomR,
  1388. Internal.BalanceBoard.CalibrationInfo.Kg17.BottomR,
  1389. Internal.BalanceBoard.CalibrationInfo.Kg34.BottomR);
  1390. // uses these as the 'at rest' offsets? (immediately after Connect(),
  1391. // or if the app called CalibrateAtRest())
  1392. if(bCalibrateAtRest) {
  1393. bCalibrateAtRest = false;
  1394. TRACE(_T(".. Auto-removing 'at rest' BBoard offsets."));
  1395. Internal.BalanceBoard.AtRestKg = Internal.BalanceBoard.Kg;
  1396. }
  1397. // remove the 'at rest' offsets
  1398. Internal.BalanceBoard.Kg.TopL -= BalanceBoard.AtRestKg.TopL;
  1399. Internal.BalanceBoard.Kg.TopR -= BalanceBoard.AtRestKg.TopR;
  1400. Internal.BalanceBoard.Kg.BottomL -= BalanceBoard.AtRestKg.BottomL;
  1401. Internal.BalanceBoard.Kg.BottomR -= BalanceBoard.AtRestKg.BottomR;
  1402. // compute the average
  1403. Internal.BalanceBoard.Kg.Total = Internal.BalanceBoard.Kg.TopL +
  1404. Internal.BalanceBoard.Kg.TopR +
  1405. Internal.BalanceBoard.Kg.BottomL +
  1406. Internal.BalanceBoard.Kg.BottomR;
  1407. // and convert to Lbs
  1408. const float KG2LB = 2.20462262f;
  1409. Internal.BalanceBoard.Lb = Internal.BalanceBoard.Kg;
  1410. Internal.BalanceBoard.Lb.TopL *= KG2LB;
  1411. Internal.BalanceBoard.Lb.TopR *= KG2LB;
  1412. Internal.BalanceBoard.Lb.BottomL *= KG2LB;
  1413. Internal.BalanceBoard.Lb.BottomR *= KG2LB;
  1414. Internal.BalanceBoard.Lb.Total *= KG2LB;
  1415. }
  1416. break;
  1417. case MOTION_PLUS:
  1418. {
  1419. bMotionPlusDetected = true;
  1420. bMotionPlusEnabled = true;
  1421. short yaw = ((unsigned short)buff[offset+3] & 0xFC)<<6 |
  1422. (unsigned short)buff[offset+0];
  1423. short pitch = ((unsigned short)buff[offset+5] & 0xFC)<<6 |
  1424. (unsigned short)buff[offset+2];
  1425. short roll = ((unsigned short)buff[offset+4] & 0xFC)<<6 |
  1426. (unsigned short)buff[offset+1];
  1427. // we get one set of bogus values when the MotionPlus is disconnected,
  1428. // so ignore them
  1429. if((yaw != 0x3fff) || (pitch != 0x3fff) || (roll != 0x3fff))
  1430. {
  1431. wiimote_state::motion_plus::sensors_raw &raw = Internal.MotionPlus.Raw;
  1432. if((raw.Yaw != yaw) || (raw.Pitch != pitch) || (raw.Roll != roll))
  1433. changed |= MOTIONPLUS_SPEED_CHANGED;
  1434. raw.Yaw = yaw;
  1435. raw.Pitch = pitch;
  1436. raw.Roll = roll;
  1437. // convert to float values
  1438. bool yaw_slow = (buff[offset+3] & 0x2) == 0x2;
  1439. bool pitch_slow = (buff[offset+3] & 0x1) == 0x1;
  1440. bool roll_slow = (buff[offset+4] & 0x2) == 0x2;
  1441. // Mingyu: try to use the scale on Wiki (too fast!!)
  1442. //float y_scale = yaw_slow ? 0.07263f : 0.33014f; // 595 deg/s -> 8192, times 2000/440 for the fast mode
  1443. //float p_scale = pitch_slow? 0.07263f : 0.33014f;
  1444. //float r_scale = roll_slow ? 0.07263f : 0.33014f;
  1445. float y_scale = yaw_slow? 0.05f : 0.25f;
  1446. float p_scale = pitch_slow? 0.05f : 0.25f;
  1447. float r_scale = roll_slow? 0.05f : 0.25f;
  1448. Internal.MotionPlus.Speed.Yaw = -(raw.Yaw - 0x1F7F) * y_scale;
  1449. Internal.MotionPlus.Speed.Pitch = -(raw.Pitch - 0x1F7F) * p_scale;
  1450. Internal.MotionPlus.Speed.Roll = -(raw.Roll - 0x1F7F) * r_scale;
  1451. // show if there's an extension plugged into the MotionPlus:
  1452. bool extension = buff[offset+4] & 1;
  1453. if(extension != bMotionPlusExtension)
  1454. {
  1455. if(extension) {
  1456. TRACE(_T(".. MotionPlus extension found."));
  1457. changed |= MOTIONPLUS_EXTENSION_CONNECTED;
  1458. }
  1459. else{
  1460. TRACE(_T(".. MotionPlus' extension disconnected."));
  1461. changed |= MOTIONPLUS_EXTENSION_DISCONNECTED;
  1462. }
  1463. }
  1464. bMotionPlusExtension = extension;
  1465. }
  1466. // while we're getting data, the plus is obviously detected/enabled
  1467. // bMotionPlusDetected = bMotionPlusEnabled = true;
  1468. }
  1469. break;
  1470. }
  1471. return changed;
  1472. }
  1473. // ------------------------------------------------------------------------------------
  1474. int wiimote::ParseReadAddress (BYTE* buff)
  1475. {
  1476. // decode the address that was queried:
  1477. int address = buff[4]<<8 | buff[5];
  1478. int size = buff[3] >> 4;
  1479. int changed = 0;
  1480. if((buff[3] & 0x08) != 0) {
  1481. WARN(_T("error: read address not valid."));
  1482. _ASSERT(0);
  1483. return NO_CHANGE;
  1484. }
  1485. // address read failed (write-only)?
  1486. else if((buff[3] & 0x07) != 0)
  1487. {
  1488. // this also happens when attempting to detect a non-existant MotionPlus
  1489. if(MotionPlusDetectCount)
  1490. {
  1491. --MotionPlusDetectCount;
  1492. if(Internal.ExtensionType == MOTION_PLUS)
  1493. {
  1494. if(bMotionPlusDetected)
  1495. TRACE(_T(".. MotionPlus removed."));
  1496. bMotionPlusDetected = false;
  1497. bMotionPlusEnabled = false;
  1498. // the MotionPlus can sometimes get confused - initializing
  1499. // extenions fixes it:
  1500. // if(address == 0xfa)
  1501. // InitializeExtension();
  1502. }
  1503. }
  1504. else
  1505. WARN(_T("error: attempt to read from write-only register 0x%X."), buff[3]);
  1506. return NO_CHANGE;
  1507. }
  1508. // *NOTE*: this is a major (but convenient) hack! The returned data only
  1509. // contains the lower two bytes of the address that was queried.
  1510. // as these don't collide between any of the addresses/registers
  1511. // we currently read, it's OK to match just those two bytes
  1512. // skip the header
  1513. buff += 6;
  1514. switch(address)
  1515. {
  1516. case (REGISTER_CALIBRATION & 0xffff):
  1517. {
  1518. _ASSERT(size == 6);
  1519. TRACE(_T(".. got wiimote calibration."));
  1520. Internal.CalibrationInfo.X0 = buff[0];
  1521. Internal.CalibrationInfo.Y0 = buff[1];
  1522. Internal.CalibrationInfo.Z0 = buff[2];
  1523. Internal.CalibrationInfo.XG = buff[4];
  1524. Internal.CalibrationInfo.YG = buff[5];
  1525. Internal.CalibrationInfo.ZG = buff[6];
  1526. //changed |= CALIBRATION_CHANGED;
  1527. }
  1528. break;
  1529. // note: this covers both the normal extension and motion plus extension
  1530. // addresses (0x4a400fa / 0x4a600fa)
  1531. case (REGISTER_EXTENSION_TYPE & 0xffff):
  1532. {
  1533. _ASSERT(size == 5);
  1534. QWORD type = *(QWORD*)buff;
  1535. // TRACE(_T("(found extension 0x%I64x)"), type);
  1536. static const QWORD NUNCHUK = 0x000020A40000ULL;
  1537. static const QWORD CLASSIC = 0x010120A40000ULL;
  1538. static const QWORD GH3_GHWT_GUITAR = 0x030120A40000ULL;
  1539. static const QWORD GHWT_DRUMS = 0x030120A40001ULL;
  1540. static const QWORD BALANCE_BOARD = 0x020420A40000ULL;
  1541. static const QWORD MOTION_PLUS = 0x050420A40000ULL;
  1542. static const QWORD MOTION_PLUS_EMBED = 0x050420a40001ULL;
  1543. static const QWORD MOTION_PLUS_DETECT = 0x050020a60000ULL;
  1544. static const QWORD MOTION_PLUS_DETECT2 = 0x050420a60000ULL;
  1545. static const QWORD MOTION_PLUS_EMBED_DETECT = 0x050020a60001ULL; // Mingyu
  1546. static const QWORD MOTION_PLUS_EMBED_DETECT2 = 0x050420a60001ULL; // Mingyu
  1547. static const QWORD PARTIALLY_INSERTED = 0xffffffffffffULL;
  1548. // MotionPlus: _before_ it's been activated
  1549. //if((type == MOTION_PLUS_DETECT) || (type == MOTION_PLUS_DETECT2))
  1550. if ((type == MOTION_PLUS_DETECT) || (type == MOTION_PLUS_DETECT2) ||
  1551. (type == MOTION_PLUS_EMBED_DETECT) || (type == MOTION_PLUS_EMBED_DETECT2))
  1552. {
  1553. if(!bMotionPlusDetected) {
  1554. TRACE(_T("Motion Plus detected!"));
  1555. changed |= MOTIONPLUS_DETECTED;
  1556. }
  1557. bMotionPlusDetected = true;
  1558. --MotionPlusDetectCount;
  1559. break;
  1560. }
  1561. #define IF_TYPE(id) if(type == id) { \
  1562. /* sometimes it comes in more than once */ \
  1563. if(Internal.ExtensionType == wiimote_state::id)\
  1564. break; \
  1565. Internal.ExtensionType = wiimote_state::id;
  1566. // MotionPlus: once it's activated & mapped to the standard ext. port
  1567. IF_TYPE(MOTION_PLUS)
  1568. TRACE(_T(".. Motion Plus!"));
  1569. // and start a query for the calibration data
  1570. ReadAddress(REGISTER_EXTENSION_CALIBRATION, 16);
  1571. bMotionPlusDetected = true;
  1572. }
  1573. else IF_TYPE(NUNCHUK)
  1574. TRACE(_T(".. Nunchuk!"));
  1575. bMotionPlusEnabled = false;
  1576. // and start a query for the calibration data
  1577. ReadAddress(REGISTER_EXTENSION_CALIBRATION, 16);
  1578. }
  1579. else IF_TYPE(CLASSIC)
  1580. TRACE(_T(".. Classic Controller!"));
  1581. bMotionPlusEnabled = false;
  1582. // and start a query for the calibration data
  1583. ReadAddress(REGISTER_EXTENSION_CALIBRATION, 16);
  1584. }
  1585. else IF_TYPE(GH3_GHWT_GUITAR)
  1586. // sometimes it comes in more than once?
  1587. TRACE(_T(".. GH3/GHWT Guitar Controller!"));
  1588. bMotionPlusEnabled = false;
  1589. // and start a query for the calibration data
  1590. ReadAddress(REGISTER_EXTENSION_CALIBRATION, 16);
  1591. }
  1592. else IF_TYPE(GHWT_DRUMS)
  1593. TRACE(_T(".. GHWT Drums!"));
  1594. bMotionPlusEnabled = false;
  1595. // and start a query for the calibration data
  1596. ReadAddress(REGISTER_EXTENSION_CALIBRATION, 16);
  1597. }
  1598. else IF_TYPE(BALANCE_BOARD)
  1599. TRACE(_T(".. Balance Board!"));
  1600. bMotionPlusEnabled = false;
  1601. // and start a query for the calibration data
  1602. ReadAddress(REGISTER_BALANCE_CALIBRATION, 24);
  1603. }
  1604. else if(type == MOTION_PLUS_EMBED) {
  1605. if(Internal.ExtensionType == wiimote_state::MOTION_PLUS)
  1606. break;
  1607. Internal.ExtensionType = wiimote_state::MOTION_PLUS;
  1608. TRACE(_T(".. Motion Plus Embedded!"));
  1609. ReadAddress(REGISTER_EXTENSION_CALIBRATION, 16);
  1610. bMotionPlusDetected = true;
  1611. }
  1612. else if(type == PARTIALLY_INSERTED) {
  1613. // sometimes it comes in more than once?
  1614. if(Internal.ExtensionType == wiimote_state::PARTIALLY_INSERTED)
  1615. Sleep(50);
  1616. TRACE(_T(".. partially inserted!"));
  1617. bMotionPlusEnabled = false;
  1618. Internal.ExtensionType = wiimote_state::PARTIALLY_INSERTED;
  1619. changed |= EXTENSION_PARTIALLY_INSERTED;
  1620. // try initializing the extension again by requesting another
  1621. // status report (this usually fixes it)
  1622. Internal.bExtension = false;
  1623. RequestStatusReport();
  1624. }
  1625. else{
  1626. TRACE(_T("unknown extension controller found (0x%I64x)"), type);
  1627. }
  1628. }
  1629. break;
  1630. case (REGISTER_EXTENSION_CALIBRATION & 0xffff):
  1631. case (REGISTER_BALANCE_CALIBRATION & 0xffff):
  1632. {
  1633. // _ASSERT(((Internal.ExtensionType == BALANCE_BOARD) && (size == 31)) ||
  1634. // ((Internal.ExtensionType != BALANCE_BOARD) && (size == 15)));
  1635. switch(Internal.ExtensionType)
  1636. {
  1637. case wiimote_state::NUNCHUK:
  1638. {
  1639. wiimote_state::nunchuk::calibration_info
  1640. &calib = Internal.Nunchuk.CalibrationInfo;
  1641. calib.X0 = buff[ 0];
  1642. calib.Y0 = buff[ 1];
  1643. calib.Z0 = buff[ 2];
  1644. calib.XG = buff[ 4];
  1645. calib.YG = buff[ 5];
  1646. calib.ZG = buff[ 6];
  1647. calib.MaxX = buff[ 8];
  1648. calib.MinX = buff[ 9];
  1649. calib.MidX = buff[10];
  1650. calib.MaxY = buff[11];
  1651. calib.MinY = buff[12];
  1652. calib.MidY = buff[13];
  1653. changed |= NUNCHUK_CONNECTED;//|NUNCHUK_CALIBRATION_CHANGED;
  1654. // reenable reports
  1655. // SetReportType(ReportType);
  1656. }
  1657. break;
  1658. case wiimote_state::CLASSIC:
  1659. case wiimote_state::GH3_GHWT_GUITAR:
  1660. case wiimote_state::GHWT_DRUMS:
  1661. {
  1662. wiimote_state::classic_controller::calibration_info
  1663. &calib = Internal.ClassicController.CalibrationInfo;
  1664. calib.MaxXL = buff[ 0] >> 2;
  1665. calib.MinXL = buff[ 1] >> 2;
  1666. calib.MidXL = buff[ 2] >> 2;
  1667. calib.MaxYL = buff[ 3] >> 2;
  1668. calib.MinYL = buff[ 4] >> 2;
  1669. calib.MidYL = buff[ 5] >> 2;
  1670. calib.MaxXR = buff[ 6] >> 3;
  1671. calib.MinXR = buff[ 7] >> 3;
  1672. calib.MidXR = buff[ 8] >> 3;
  1673. calib.MaxYR = buff[ 9] >> 3;
  1674. calib.MinYR = buff[10] >> 3;
  1675. calib.MidYR = buff[11] >> 3;
  1676. // this doesn't seem right...
  1677. // calib.MinTriggerL = buff[12] >> 3;
  1678. // calib.MaxTriggerL = buff[14] >> 3;
  1679. // calib.MinTriggerR = buff[13] >> 3;
  1680. // calib.MaxTriggerR = buff[15] >> 3;
  1681. calib.MinTriggerL = 0;
  1682. calib.MaxTriggerL = 31;
  1683. calib.MinTriggerR = 0;
  1684. calib.MaxTriggerR = 31;
  1685. changed |= CLASSIC_CONNECTED;//|CLASSIC_CALIBRATION_CHANGED;
  1686. // reenable reports
  1687. // SetReportType(ReportType);
  1688. }
  1689. break;
  1690. case BALANCE_BOARD:
  1691. {
  1692. // first part, 0 & 17kg calibration values
  1693. wiimote_state::balance_board::calibration_info
  1694. &calib = Internal.BalanceBoard.CalibrationInfo;
  1695. calib.Kg0 .TopR = (short)((short)buff[0] << 8 | buff[1]);
  1696. calib.Kg0 .BottomR = (short)((short)buff[2] << 8 | buff[3]);
  1697. calib.Kg0 .TopL = (short)((short)buff[4] << 8 | buff[5]);
  1698. calib.Kg0 .BottomL = (short)((short)buff[6] << 8 | buff[7]);
  1699. calib.Kg17.TopR = (short)((short)buff[8] << 8 | buff[9]);
  1700. calib.Kg17.BottomR = (short)((short)buff[10] << 8 | buff[11]);
  1701. calib.Kg17.TopL = (short)((short)buff[12] << 8 | buff[13]);
  1702. calib.Kg17.BottomL = (short)((short)buff[14] << 8 | buff[15]);
  1703. // 2nd part is scanned above
  1704. }
  1705. break;
  1706. case MOTION_PLUS:
  1707. {
  1708. // TODO: not known how the calibration values work
  1709. changed |= MOTIONPLUS_ENABLED;
  1710. bMotionPlusEnabled = true;
  1711. bInitInProgress = false;
  1712. // reenable reports
  1713. // SetReportType(ReportType);
  1714. }
  1715. break;
  1716. }
  1717. case 0x34:
  1718. {
  1719. if(Internal.ExtensionType == BALANCE_BOARD)
  1720. {
  1721. wiimote_state::balance_board::calibration_info
  1722. &calib = Internal.BalanceBoard.CalibrationInfo;
  1723. // 2nd part of the balance board calibration,
  1724. // 34kg calibration values
  1725. calib.Kg34.TopR = (short)((short)buff[0] << 8 | buff[1]);
  1726. calib.Kg34.BottomR = (short)((short)buff[2] << 8 | buff[3]);
  1727. calib.Kg34.TopL = (short)((short)buff[4] << 8 | buff[5]);
  1728. calib.Kg34.BottomL = (short)((short)buff[6] << 8 | buff[7]);
  1729. changed |= BALANCE_CONNECTED;
  1730. // reenable reports
  1731. SetReportType(IN_BUTTONS_BALANCE_BOARD);
  1732. }
  1733. // else unknown what these are for
  1734. }
  1735. bInitInProgress = false;
  1736. }
  1737. break;
  1738. default:
  1739. // _ASSERT(0); // shouldn't happen
  1740. break;
  1741. }
  1742. return changed;
  1743. }
  1744. // ------------------------------------------------------------------------------------
  1745. void wiimote::ReadCalibration ()
  1746. {
  1747. TRACE(_T("Requestion wiimote calibration:"));
  1748. // this appears to change the report type to 0x31
  1749. ReadAddress(REGISTER_CALIBRATION, 7);
  1750. }
  1751. // ------------------------------------------------------------------------------------
  1752. void wiimote::EnableIR (wiimote_state::ir::mode mode)
  1753. {
  1754. Internal.IR.Mode = mode;
  1755. BYTE buff [REPORT_LENGTH] = {0};
  1756. buff[0] = OUT_IR;
  1757. buff[1] = 0x04 | GetRumbleBit();
  1758. WriteReport(buff);
  1759. memset(buff, 0, REPORT_LENGTH);
  1760. buff[0] = OUT_IR2;
  1761. buff[1] = 0x04 | GetRumbleBit();
  1762. WriteReport(buff);
  1763. static const BYTE ir_sens1[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00,
  1764. 0xc0};
  1765. static const BYTE ir_sens2[] = {0x40, 0x00};
  1766. WriteData(REGISTER_IR, 0x08);
  1767. Sleep(25); // wait a little to make IR more reliable (for some)
  1768. WriteData(REGISTER_IR_SENSITIVITY_1, sizeof(ir_sens1), ir_sens1);
  1769. WriteData(REGISTER_IR_SENSITIVITY_2, sizeof(ir_sens2), ir_sens2);
  1770. WriteData(REGISTER_IR_MODE, (BYTE)mode);
  1771. }
  1772. // ------------------------------------------------------------------------------------
  1773. void wiimote::DisableIR ()
  1774. {
  1775. Internal.IR.Mode = wiimote_state::ir::OFF;
  1776. BYTE buff [REPORT_LENGTH] = {0};
  1777. buff[0] = OUT_IR;
  1778. buff[1] = GetRumbleBit();
  1779. WriteReport(buff);
  1780. memset(buff, 0, REPORT_LENGTH);
  1781. buff[0] = OUT_IR2;
  1782. buff[1] = GetRumbleBit();
  1783. WriteReport(buff);
  1784. }
  1785. // ------------------------------------------------------------------------------------
  1786. unsigned __stdcall wiimote::HIDwriteThreadfunc (void* param)
  1787. {
  1788. _ASSERT(param);
  1789. TRACE(_T("(starting HID write thread)"));
  1790. wiimote &remote = *(wiimote*)param;
  1791. while(remote.Handle != INVALID_HANDLE_VALUE)
  1792. {
  1793. // try to write the oldest entry in the queue
  1794. #ifdef USE_DYNAMIC_HIDQUEUE
  1795. if(!remote.HIDwriteQueue.empty())
  1796. #else
  1797. if(!remote.HID.IsEmpty())
  1798. #endif
  1799. {
  1800. #ifdef BEEP_DEBUG_WRITES
  1801. Beep(1500,1);
  1802. #endif
  1803. EnterCriticalSection(&remote.HIDwriteQueueLock);
  1804. #ifdef USE_DYNAMIC_HIDQUEUE
  1805. BYTE *buff = remote.HIDwriteQueue.front();
  1806. _ASSERT(buff);
  1807. #else
  1808. BYTE *buff = remote.HID.Queue[remote.HID.ReadIndex].Report;
  1809. #endif
  1810. LeaveCriticalSection(&remote.HIDwriteQueueLock);
  1811. if(!_HidD_SetOutputReport(remote.Handle, buff, REPORT_LENGTH))
  1812. {
  1813. DWORD err = GetLastError();
  1814. if(err==ERROR_BUSY)
  1815. TRACE(_T("**** HID WRITE: BUSY ****"));
  1816. else if(err == ERROR_NOT_READY)
  1817. TRACE(_T("**** HID WRITE: NOT READY ****"));
  1818. if((err != ERROR_BUSY) && // "the requested resource is in use"
  1819. (err != ERROR_NOT_READY)) // "the device is not ready"
  1820. {
  1821. if(err == ERROR_NOT_SUPPORTED) {
  1822. WARN(_T("BT Stack doesn't suport HID writes!"));
  1823. goto remove_entry;
  1824. }
  1825. else{
  1826. DEEP_TRACE(_T("HID write failed (err %u)! - "), err);
  1827. // if this worked previously, the connection was probably lost
  1828. if(remote.IsConnected())
  1829. remote.bConnectionLost = true;
  1830. }
  1831. //_T("aborting write thread"), err);
  1832. //return 911;
  1833. }
  1834. }
  1835. else{
  1836. remove_entry:
  1837. EnterCriticalSection(&remote.HIDwriteQueueLock);
  1838. #ifdef USE_DYNAMIC_HIDQUEUE
  1839. remote.HIDwriteQueue.pop();
  1840. delete[] buff;
  1841. #else
  1842. remote.HID.ReadIndex++;
  1843. remote.HID.ReadIndex &= (hid::MAX_QUEUE_ENTRIES-1);
  1844. #endif
  1845. LeaveCriticalSection(&remote.HIDwriteQueueLock);
  1846. }
  1847. }
  1848. Sleep(1);
  1849. }
  1850. TRACE(_T("ending HID write thread"));
  1851. return 0;
  1852. }
  1853. // ------------------------------------------------------------------------------------
  1854. bool wiimote::WriteReport (BYTE *buff)
  1855. {
  1856. #ifdef BEEP_DEBUG_WRITES
  1857. Beep(2000,1);
  1858. #endif
  1859. #ifdef _DEBUG
  1860. #define DEEP_TRACE_TYPE(type) case OUT_##type: DEEP_TRACE(_T("WriteReport: ")\
  1861. _T(#type)); break
  1862. switch(buff[0])
  1863. {
  1864. DEEP_TRACE_TYPE(NONE);
  1865. DEEP_TRACE_TYPE(LEDs);
  1866. DEEP_TRACE_TYPE(TYPE);
  1867. DEEP_TRACE_TYPE(IR);
  1868. DEEP_TRACE_TYPE(SPEAKER_ENABLE);
  1869. DEEP_TRACE_TYPE(STATUS);
  1870. DEEP_TRACE_TYPE(WRITEMEMORY);
  1871. DEEP_TRACE_TYPE(READMEMORY);
  1872. DEEP_TRACE_TYPE(SPEAKER_DATA);
  1873. DEEP_TRACE_TYPE(SPEAKER_MUTE);
  1874. DEEP_TRACE_TYPE(IR2);
  1875. default:
  1876. TRACE(_T("WriteReport: type [%02x][%02x]"), buff[1], buff[2]);
  1877. }
  1878. #endif
  1879. if(bUseHIDwrite)
  1880. {
  1881. // HidD_SetOutputReport: +: works on MS Bluetooth stacks (WriteFile doesn't).
  1882. // -: is synchronous, so make it async
  1883. if(!HIDwriteThread)
  1884. {
  1885. HIDwriteThread = (HANDLE)_beginthreadex(NULL, 0, HIDwriteThreadfunc,
  1886. this, 0, NULL);
  1887. _ASSERT(HIDwriteThread);
  1888. if(!HIDwriteThread) {
  1889. WARN(_T("couldn't create HID write thread!"));
  1890. return false;
  1891. }
  1892. SetThreadPriority(HIDwriteThread, WORKER_THREAD_PRIORITY);
  1893. }
  1894. // insert the write request into the thread's queue
  1895. #ifdef USE_DYNAMIC_HIDQUEUE
  1896. EnterCriticalSection(&HIDwriteQueueLock);
  1897. BYTE *buff_copy = new BYTE[REPORT_LENGTH];
  1898. #else
  1899. // allocate the HID write queue once
  1900. if(!HID.Queue && !HID.Allocate())
  1901. return false;
  1902. EnterCriticalSection(&HIDwriteQueueLock);
  1903. BYTE *buff_copy = HID.Queue[HID.WriteIndex].Report;
  1904. #endif
  1905. memcpy(buff_copy, buff, REPORT_LENGTH);
  1906. #ifdef USE_DYNAMIC_HIDQUEUE
  1907. HIDwriteQueue.push(buff_copy);
  1908. #else
  1909. HID.WriteIndex++;
  1910. HID.WriteIndex &= (HID.MAX_QUEUE_ENTRIES-1);
  1911. // check if the fixed report queue has overflown:
  1912. // if this ASSERT triggers, the HID write queue (that stores reports
  1913. // for asynchronous output by HIDwriteThreadfunc) has overflown.
  1914. // this can happen if the connection with the wiimote has been lost
  1915. // and in that case is harmless.
  1916. //
  1917. // if it happens during normal operation though you need to increase
  1918. // hid::MAX_QUEUE_ENTRIES to the next power-of-2 (see comments)
  1919. // _and_ email me the working setting so I can update the next release
  1920. _ASSERT(HID.WriteIndex != HID.ReadIndex);
  1921. #endif
  1922. LeaveCriticalSection(&HIDwriteQueueLock);
  1923. return true;
  1924. }
  1925. // WriteFile:
  1926. DWORD written;
  1927. if(!WriteFile(Handle, buff, REPORT_LENGTH, &written, &Overlapped))
  1928. {
  1929. DWORD error = GetLastError();
  1930. if(error != ERROR_IO_PENDING) {
  1931. TRACE(_T("WriteFile failed, err: %u!"), error);
  1932. // if it worked previously, assume we lost the connection
  1933. if(IsConnected())
  1934. bConnectionLost = true;
  1935. #ifndef USE_DYNAMIC_HIDQUEUE
  1936. HID.Deallocate();
  1937. #endif
  1938. return false;
  1939. }
  1940. }
  1941. return true;
  1942. }
  1943. // ------------------------------------------------------------------------------------
  1944. // experimental speaker support:
  1945. // ------------------------------------------------------------------------------------
  1946. bool wiimote::MuteSpeaker (bool on)
  1947. {
  1948. _ASSERT(IsConnected());
  1949. if(!IsConnected())
  1950. return false;
  1951. if(Internal.Speaker.bMuted == on)
  1952. return true;
  1953. if(on) TRACE(_T("muting speaker." ));
  1954. else TRACE(_T("unmuting speaker."));
  1955. BYTE buff [REPORT_LENGTH] = {0};
  1956. buff[0] = OUT_SPEAKER_MUTE;
  1957. buff[1] = (on? 0x04 : 0x00) | GetRumbleBit();
  1958. if(!WriteReport(buff))
  1959. return false;
  1960. Sleep(1);
  1961. Internal.Speaker.bMuted = on;
  1962. return true;
  1963. }
  1964. // ------------------------------------------------------------------------------------
  1965. bool wiimote::EnableSpeaker (bool on)
  1966. {
  1967. _ASSERT(IsConnected());
  1968. if(!IsConnected())
  1969. return false;
  1970. if(Internal.Speaker.bEnabled == on)
  1971. return true;
  1972. if(on) TRACE(_T("enabling speaker.")); else TRACE(_T("disabling speaker."));
  1973. BYTE buff [REPORT_LENGTH] = {0};
  1974. buff[0] = OUT_SPEAKER_ENABLE;
  1975. buff[1] = (on? 0x04 : 0x00) | GetRumbleBit();
  1976. if(!WriteReport(buff))
  1977. return false;
  1978. if(!on) {
  1979. Internal.Speaker.Freq = FREQ_NONE;
  1980. Internal.Speaker.Volume = 0;
  1981. MuteSpeaker(true);
  1982. }
  1983. Internal.Speaker.bEnabled = on;
  1984. return true;
  1985. }
  1986. // ------------------------------------------------------------------------------------
  1987. #ifdef TR4 // TEMP, ignore
  1988. extern int hzinc;
  1989. #endif
  1990. // ------------------------------------------------------------------------------------
  1991. unsigned __stdcall wiimote::SampleStreamThreadfunc (void* param)
  1992. {
  1993. TRACE(_T("(starting sample thread)"));
  1994. // sends a simple square wave sample stream
  1995. wiimote &remote = *(wiimote*)param;
  1996. static BYTE squarewave_report[REPORT_LENGTH] =
  1997. { OUT_SPEAKER_DATA, 20<<3, 0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,
  1998. 0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3, };
  1999. static BYTE sample_report [REPORT_LENGTH] =
  2000. { OUT_SPEAKER_DATA, 0 };
  2001. bool last_playing = false;
  2002. DWORD frame = 0;
  2003. DWORD frame_start = 0;
  2004. unsigned total_samples = 0;
  2005. unsigned sample_index = 0;
  2006. wiimote_sample *current_sample = NULL;
  2007. // TODO: duration!!
  2008. while(remote.IsConnected())
  2009. {
  2010. bool playing = remote.IsPlayingAudio();
  2011. if(!playing)
  2012. Sleep(1);
  2013. else{
  2014. const unsigned freq_hz = FreqLookup[remote.Internal.Speaker.Freq];
  2015. #ifdef TR4
  2016. const float frame_ms = 1000 / ((freq_hz+hzinc) / 40.f); // 20bytes = 40 samples per write
  2017. #else
  2018. const float frame_ms = 1000 / (freq_hz / 40.f); // 20bytes = 40 samples per write
  2019. #endif
  2020. // has the sample just changed?
  2021. bool sample_changed = (current_sample != remote.CurrentSample);
  2022. current_sample = (wiimote_sample*)remote.CurrentSample;
  2023. // (attempts to minimise glitches, doesn't seem to help though)
  2024. //#define FIRSTFRAME_IS_SILENT // send all-zero for first frame
  2025. #ifdef FIRSTFRAME_IS_SILENT
  2026. bool silent_frame = false;
  2027. #endif
  2028. if(!last_playing || sample_changed) {
  2029. frame = 0;
  2030. frame_start = timeGetTime();
  2031. total_samples = current_sample? current_sample->length : 0;
  2032. sample_index = 0;
  2033. #ifdef FIRSTFRAME_IS_SILENT
  2034. silent_frame = true;
  2035. #endif
  2036. }
  2037. // are we streaming a sample?
  2038. if(current_sample)
  2039. {
  2040. if(sample_index < current_sample->length)
  2041. {
  2042. // (remember that samples are 4bit, ie. 2 per byte)
  2043. unsigned samples_left = (current_sample->length - sample_index);
  2044. unsigned report_samples = min(samples_left, (unsigned)40);
  2045. // round the entries up to the nearest multiple of 2
  2046. unsigned report_entries = (report_samples+1) >> 1;
  2047. sample_report[1] = (BYTE)((report_entries<<3) |
  2048. remote.GetRumbleBit());
  2049. #ifdef FIRSTFRAME_IS_SILENT
  2050. if(silent_frame) {
  2051. // send all-zeroes
  2052. for(unsigned index=0; index<report_entries; index++)
  2053. sample_report[2+index] = 0;
  2054. remote.WriteReport(sample_report);
  2055. }
  2056. else
  2057. #endif
  2058. {
  2059. for(unsigned index=0; index<report_entries; index++)
  2060. sample_report[2+index] =
  2061. current_sample->samples[(sample_index>>1)+index];
  2062. remote.WriteReport(sample_report);
  2063. sample_index += report_samples;
  2064. }
  2065. }
  2066. else{
  2067. // we reached the sample end
  2068. remote.CurrentSample = NULL;
  2069. current_sample = NULL;
  2070. remote.Internal.Speaker.Freq = FREQ_NONE;
  2071. remote.Internal.Speaker.Volume = 0;
  2072. }
  2073. }
  2074. // no, a squarewave
  2075. else{
  2076. squarewave_report[1] = (20<<3) | remote.GetRumbleBit();
  2077. remote.WriteReport(squarewave_report);
  2078. #if 0
  2079. // verify that we're sending at the correct rate (we are)
  2080. DWORD elapsed = (timeGetTime()-frame_start);
  2081. unsigned total_samples = frame * 40;
  2082. float elapsed_secs = elapsed / 1000.f;
  2083. float sent_persec = total_samples / elapsed_secs;
  2084. #endif
  2085. }
  2086. frame++;
  2087. // send the first two buffers immediately? (attempts to lessen startup
  2088. // startup glitches by assuming we're filling a small sample
  2089. // (or general input) buffer on the wiimote) - doesn't seem to help
  2090. // if(frame > 2) {
  2091. while((timeGetTime()-frame_start) < (unsigned)(frame*frame_ms))
  2092. Sleep(1);
  2093. // }
  2094. }
  2095. last_playing = playing;
  2096. }
  2097. TRACE(_T("(ending sample thread)"));
  2098. return 0;
  2099. }
  2100. // ------------------------------------------------------------------------------------
  2101. bool wiimote::Load16bitMonoSampleWAV (const TCHAR* filepath, wiimote_sample &out)
  2102. {
  2103. // converts unsigned 16bit mono .wav audio data to the 4bit ADPCM variant
  2104. // used by the Wiimote (at least the closest match so far), and returns
  2105. // the data in a BYTE array (caller must delete[] it when no longer needed):
  2106. memset(&out, 0, sizeof(out));
  2107. TRACE(_T("Loading '%s'"), filepath);
  2108. FILE *file;
  2109. #if (_MSC_VER >= 1400) // VC 2005+
  2110. _tfopen_s(&file, filepath, _T("rb"));
  2111. #else
  2112. file = _tfopen(filepath, _T("rb"));
  2113. #endif
  2114. _ASSERT(file);
  2115. if(!file) {
  2116. WARN(_T("Couldn't open '%s"), filepath);
  2117. return false;
  2118. }
  2119. // parse the .wav file
  2120. struct riff_chunkheader {
  2121. char ckID [4];
  2122. DWORD ckSize;
  2123. char formType [4];
  2124. };
  2125. struct chunk_header {
  2126. char ckID [4];
  2127. DWORD ckSize;
  2128. };
  2129. union {
  2130. WAVEFORMATEX x;
  2131. WAVEFORMATEXTENSIBLE xe;
  2132. } wf = {0};
  2133. riff_chunkheader riff_chunkheader;
  2134. chunk_header chunk_header;
  2135. speaker_freq freq = FREQ_NONE;
  2136. #define READ(data) if(fread(&data, sizeof(data), 1, file) != 1) { \
  2137. TRACE(_T(".wav file corrupt")); \
  2138. fclose(file); \
  2139. return false; \
  2140. }
  2141. #define READ_SIZE(ptr,size) if(fread(ptr, size, 1, file) != 1) { \
  2142. TRACE(_T(".wav file corrupt")); \
  2143. fclose(file); \
  2144. return false; \
  2145. }
  2146. // read the riff chunk header
  2147. READ(riff_chunkheader);
  2148. // valid RIFF file?
  2149. _ASSERT(!strncmp(riff_chunkheader.ckID, "RIFF", 4));
  2150. if(strncmp(riff_chunkheader.ckID, "RIFF", 4))
  2151. goto unsupported; // nope
  2152. // valid WAV variant?
  2153. _ASSERT(!strncmp(riff_chunkheader.formType, "WAVE", 4));
  2154. if(strncmp(riff_chunkheader.formType, "WAVE", 4))
  2155. goto unsupported; // nope
  2156. // find the format & data chunks
  2157. while(1)
  2158. {
  2159. READ(chunk_header);
  2160. if(!strncmp(chunk_header.ckID, "fmt ", 4))
  2161. {
  2162. // not a valid .wav file?
  2163. if(chunk_header.ckSize < 16 ||
  2164. chunk_header.ckSize > sizeof(WAVEFORMATEXTENSIBLE))
  2165. goto unsupported;
  2166. READ_SIZE((BYTE*)&wf.x, chunk_header.ckSize);
  2167. // now we know it's true wav file
  2168. bool extensible = (wf.x.wFormatTag == WAVE_FORMAT_EXTENSIBLE);
  2169. int format = extensible? wf.xe.SubFormat.Data1 :
  2170. wf.x .wFormatTag;
  2171. // must be uncompressed PCM (the format comparisons also work on
  2172. // the 'extensible' header, even though they're named differently)
  2173. if(format != WAVE_FORMAT_PCM) {
  2174. TRACE(_T(".. not uncompressed PCM"));
  2175. goto unsupported;
  2176. }
  2177. // must be mono, 16bit
  2178. if((wf.x.nChannels != 1) || (wf.x.wBitsPerSample != 16)) {
  2179. TRACE(_T(".. %d bit, %d channel%s"), wf.x.wBitsPerSample,
  2180. wf.x.nChannels,
  2181. (wf.x.nChannels>1? _T("s"):_T("")));
  2182. goto unsupported;
  2183. }
  2184. // must be _near_ a supported speaker frequency range (but allow some
  2185. // tolerance, especially as the speaker freq values aren't final yet):
  2186. unsigned sample_freq = wf.x.nSamplesPerSec;
  2187. const unsigned epsilon = 100; // for now
  2188. for(unsigned index=1; index<ARRAY_ENTRIES(FreqLookup); index++)
  2189. {
  2190. if((sample_freq+epsilon) >= FreqLookup[index] &&
  2191. (sample_freq-epsilon) <= FreqLookup[index]) {
  2192. freq = (speaker_freq)index;
  2193. TRACE(_T(".. using speaker freq %u"), FreqLookup[index]);
  2194. break;
  2195. }
  2196. }
  2197. if(freq == FREQ_NONE) {
  2198. WARN(_T("Couldn't (loosely) match .wav samplerate %u Hz to speaker"),
  2199. sample_freq);
  2200. goto unsupported;
  2201. }
  2202. }
  2203. else if(!strncmp(chunk_header.ckID, "data", 4))
  2204. {
  2205. // make sure we got a valid fmt chunk first
  2206. if(!wf.x.nBlockAlign)
  2207. goto corrupt_file;
  2208. // grab the data
  2209. unsigned total_samples = chunk_header.ckSize / wf.x.nBlockAlign;
  2210. if(total_samples == 0)
  2211. goto corrupt_file;
  2212. short *samples = new short[total_samples];
  2213. size_t read = fread(samples, 2, total_samples, file);
  2214. fclose(file);
  2215. if(read != total_samples)
  2216. {
  2217. if(read == 0) {
  2218. delete[] samples;
  2219. goto corrupt_file;
  2220. }
  2221. // got a different number, but use them anyway
  2222. WARN(_T("found %s .wav audio data than expected (%u/%u samples)"),
  2223. ((read < total_samples)? _T("less") : _T("more")),
  2224. read, total_samples);
  2225. total_samples = read;
  2226. }
  2227. // and convert them
  2228. bool res = Convert16bitMonoSamples(samples, true, total_samples, freq,
  2229. out);
  2230. delete[] samples;
  2231. return res;
  2232. }
  2233. else{
  2234. // unknown chunk, skip its data
  2235. DWORD chunk_bytes = (chunk_header.ckSize + 1) & ~1L;
  2236. if(fseek(file, chunk_bytes, SEEK_CUR))
  2237. goto corrupt_file;
  2238. }
  2239. }
  2240. corrupt_file:
  2241. WARN(_T(".wav file is corrupt"));
  2242. fclose(file);
  2243. return false;
  2244. unsupported:
  2245. WARN(_T(".wav file format not supported (must be mono 16bit PCM)"));
  2246. fclose(file);
  2247. return false;
  2248. }
  2249. // ------------------------------------------------------------------------------------
  2250. bool wiimote::Load16BitMonoSampleRAW (const TCHAR* filepath,
  2251. bool _signed,
  2252. speaker_freq freq,
  2253. wiimote_sample &out)
  2254. {
  2255. // converts (.wav style) unsigned 16bit mono raw data to the 4bit ADPCM variant
  2256. // used by the Wiimote, and returns the data in a BYTE array (caller must
  2257. // delete[] it when no longer needed):
  2258. memset(&out, 0, sizeof(out));
  2259. // get the length of the file
  2260. struct _stat file_info;
  2261. if(_tstat(filepath, &file_info)) {
  2262. WARN(_T("couldn't get filesize for '%s'"), filepath);
  2263. return false;
  2264. }
  2265. DWORD len = file_info.st_size;
  2266. _ASSERT(len);
  2267. if(!len) {
  2268. WARN(_T("zero-size sample file '%s'"), filepath);
  2269. return false;
  2270. }
  2271. unsigned total_samples = (len+1) / 2; // round up just in case file is corrupt
  2272. // allocate a buffer to hold the samples to convert
  2273. short *samples = new short[total_samples];
  2274. _ASSERT(samples);
  2275. if(!samples) {
  2276. TRACE(_T("Couldn't open '%s"), filepath);
  2277. return false;
  2278. }
  2279. // load them
  2280. FILE *file;
  2281. bool res;
  2282. #if (_MSC_VER >= 1400) // VC 2005+
  2283. _tfopen_s(&file, filepath, _T("rb"));
  2284. #else
  2285. file = _tfopen(filepath, _T("rb"));
  2286. #endif
  2287. _ASSERT(file);
  2288. if(!file) {
  2289. TRACE(_T("Couldn't open '%s"), filepath);
  2290. goto error;
  2291. }
  2292. res = (fread(samples, 1, len, file) == len);
  2293. fclose(file);
  2294. if(!res) {
  2295. WARN(_T("Couldn't load file '%s'"), filepath);
  2296. goto error;
  2297. }
  2298. // and convert them
  2299. res = Convert16bitMonoSamples(samples, _signed, total_samples, freq, out);
  2300. delete[] samples;
  2301. return res;
  2302. error:
  2303. delete[] samples;
  2304. return false;
  2305. }
  2306. // ------------------------------------------------------------------------------------
  2307. bool wiimote::Convert16bitMonoSamples (const short* samples,
  2308. bool _signed,
  2309. DWORD length,
  2310. speaker_freq freq,
  2311. wiimote_sample &out)
  2312. {
  2313. // converts 16bit mono sample data to the native 4bit format used by the Wiimote,
  2314. // and returns the data in a BYTE array (caller must delete[] when no
  2315. // longer needed):
  2316. memset(&out, 0, sizeof(0));
  2317. _ASSERT(samples && length);
  2318. if(!samples || !length)
  2319. return false;
  2320. // allocate the output buffer
  2321. out.samples = new BYTE[length];
  2322. _ASSERT(out.samples);
  2323. if(!out.samples)
  2324. return false;
  2325. // clear it
  2326. memset(out.samples, 0, length);
  2327. out.length = length;
  2328. out.freq = freq;
  2329. // ADPCM code, adapted from
  2330. // http://www.wiindows.org/index.php/Talk:Wiimote#Input.2FOutput_Reports
  2331. static const int index_table[16] = { -1, -1, -1, -1, 2, 4, 6, 8,
  2332. -1, -1, -1, -1, 2, 4, 6, 8 };
  2333. static const int diff_table [16] = { 1, 3, 5, 7, 9, 11, 13, 15,
  2334. -1, -3, -5, -7, -9, -11, -13, 15 };
  2335. static const int step_scale [16] = { 230, 230, 230, 230, 307, 409, 512, 614,
  2336. 230, 230, 230, 230, 307, 409, 512, 614 };
  2337. // Encode to ADPCM, on initialization set adpcm_prev_value to 0 and adpcm_step
  2338. // to 127 (these variables must be preserved across reports)
  2339. int adpcm_prev_value = 0;
  2340. int adpcm_step = 127;
  2341. for(size_t i=0; i<length; i++)
  2342. {
  2343. // convert to 16bit signed
  2344. int value = samples[i];// (8bit) << 8);// | samples[i]; // dither it?
  2345. if(!_signed)
  2346. value -= 32768;
  2347. // encode:
  2348. int diff = value - adpcm_prev_value;
  2349. BYTE encoded_val = 0;
  2350. if(diff < 0) {
  2351. encoded_val |= 8;
  2352. diff = -diff;
  2353. }
  2354. diff = (diff << 2) / adpcm_step;
  2355. if (diff > 7)
  2356. diff = 7;
  2357. encoded_val |= diff;
  2358. adpcm_prev_value += ((adpcm_step * diff_table[encoded_val]) / 8);
  2359. if(adpcm_prev_value > 0x7fff)
  2360. adpcm_prev_value = 0x7fff;
  2361. if(adpcm_prev_value < -0x8000)
  2362. adpcm_prev_value = -0x8000;
  2363. adpcm_step = (adpcm_step * step_scale[encoded_val]) >> 8;
  2364. if(adpcm_step < 127)
  2365. adpcm_step = 127;
  2366. if(adpcm_step > 24567)
  2367. adpcm_step = 24567;
  2368. if(i & 1)
  2369. out.samples[i>>1] |= encoded_val;
  2370. else
  2371. out.samples[i>>1] |= encoded_val << 4;
  2372. }
  2373. return true;
  2374. }
  2375. // ------------------------------------------------------------------------------------
  2376. bool wiimote::PlaySample (const wiimote_sample &sample, BYTE volume,
  2377. speaker_freq freq_override)
  2378. {
  2379. _ASSERT(IsConnected());
  2380. if(!IsConnected())
  2381. return false;
  2382. speaker_freq freq = freq_override? freq_override : sample.freq;
  2383. TRACE(_T("playing sample."));
  2384. EnableSpeaker(true);
  2385. MuteSpeaker (true);
  2386. #if 0
  2387. // combine everything into one write - faster, seems to work?
  2388. BYTE bytes[9] = { 0x00, 0x00, 0x00, 10+freq, vol, 0x00, 0x00, 0x01, 0x01 };
  2389. WriteData(0x04a20001, sizeof(bytes), bytes);
  2390. #else
  2391. // Write 0x01 to register 0x04a20009
  2392. WriteData(0x04a20009, 0x01);
  2393. // Write 0x08 to register 0x04a20001
  2394. WriteData(0x04a20001, 0x08);
  2395. // Write 7-byte configuration to registers 0x04a20001-0x04a20008
  2396. BYTE bytes[7] = { 0x00, 0x00, 0x00, 10+(BYTE)freq, volume, 0x00, 0x00 };
  2397. WriteData(0x04a20001, sizeof(bytes), bytes);
  2398. // + Write 0x01 to register 0x04a20008
  2399. WriteData(0x04a20008, 0x01);
  2400. #endif
  2401. Internal.Speaker.Freq = freq;
  2402. Internal.Speaker.Volume = volume;
  2403. CurrentSample = &sample;
  2404. MuteSpeaker(false);
  2405. return StartSampleThread();
  2406. }
  2407. // ------------------------------------------------------------------------------------
  2408. bool wiimote::StartSampleThread ()
  2409. {
  2410. if(SampleThread)
  2411. return true;
  2412. SampleThread = (HANDLE)_beginthreadex(NULL, 0, SampleStreamThreadfunc,
  2413. this, 0, NULL);
  2414. _ASSERT(SampleThread);
  2415. if(!SampleThread) {
  2416. WARN(_T("couldn't create sample thread!"));
  2417. MuteSpeaker (true);
  2418. EnableSpeaker(false);
  2419. return false;
  2420. }
  2421. SetThreadPriority(SampleThread, WORKER_THREAD_PRIORITY);
  2422. return true;
  2423. }
  2424. // ------------------------------------------------------------------------------------
  2425. bool wiimote::PlaySquareWave (speaker_freq freq, BYTE volume)
  2426. {
  2427. _ASSERT(IsConnected());
  2428. if(!IsConnected())
  2429. return false;
  2430. // if we're already playing a sample, stop it first
  2431. if(IsPlayingSample())
  2432. CurrentSample = NULL;
  2433. // if we're already playing a square wave at this freq and volume, return
  2434. else if(IsPlayingAudio() && (Internal.Speaker.Freq == freq) &&
  2435. (Internal.Speaker.Volume == volume))
  2436. return true;
  2437. TRACE(_T("playing square wave."));
  2438. // stop playing samples
  2439. CurrentSample = 0;
  2440. EnableSpeaker(true);
  2441. MuteSpeaker (true);
  2442. #if 0
  2443. // combined everything into one write - much faster, seems to work?
  2444. BYTE bytes[9] = { 0x00, 0x00, 0x00, freq, volume, 0x00, 0x00, 0x01, 0x1 };
  2445. WriteData(0x04a20001, sizeof(bytes), bytes);
  2446. #else
  2447. // write 0x01 to register 0xa20009
  2448. WriteData(0x04a20009, 0x01);
  2449. // write 0x08 to register 0xa20001
  2450. WriteData(0x04a20001, 0x08);
  2451. // write default sound mode (4bit ADPCM, we assume) 7-byte configuration
  2452. // to registers 0xa20001-0xa20008
  2453. BYTE bytes[7] = { 0x00, 0x00, 0x00, 10+(BYTE)freq, volume, 0x00, 0x00 };
  2454. WriteData(0x04a20001, sizeof(bytes), bytes);
  2455. // write 0x01 to register 0xa20008
  2456. WriteData(0x04a20008, 0x01);
  2457. #endif
  2458. Internal.Speaker.Freq = freq;
  2459. Internal.Speaker.Volume = volume;
  2460. MuteSpeaker(false);
  2461. return StartSampleThread();
  2462. }
  2463. // ------------------------------------------------------------------------------------
  2464. void wiimote::RecordState (state_history &events_out,
  2465. unsigned max_time_ms,
  2466. state_change_flags change_trigger)
  2467. {
  2468. // user being naughty?
  2469. if(Recording.bEnabled)
  2470. StopRecording();
  2471. // clear the list
  2472. if(!events_out.empty())
  2473. events_out.clear();
  2474. // start recording
  2475. Recording.StateHistory = &events_out;
  2476. Recording.StartTimeMS = timeGetTime();
  2477. Recording.EndTimeMS = Recording.StartTimeMS + max_time_ms;
  2478. Recording.TriggerFlags = change_trigger;
  2479. // as this call happens outside the read/parse thread, set the boolean
  2480. // which will enable reocrding last, so that all params are in place.
  2481. // TODO: * stricly speaking this only works on VC2005+ or better, as it
  2482. // automatically places a memory barrier on volatile variables - earlier/
  2483. // other compilers may reorder the assignments!). *
  2484. Recording.bEnabled = true;
  2485. }
  2486. // ------------------------------------------------------------------------------------
  2487. void wiimote::StopRecording ()
  2488. {
  2489. if(!Recording.bEnabled)
  2490. return;
  2491. Recording.bEnabled = false;
  2492. // make sure the read/parse thread has time to notice the change (else it might
  2493. // still write one more state to the list)
  2494. Sleep(10); // too much?
  2495. }
  2496. // ------------------------------------------------------------------------------------
  2497. // ------------------------------------------------------------------------------------