00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #ifdef _MSC_VER
00013
00014
00015 # pragma warning(disable: 4530)
00016
00017 # pragma comment(lib, "setupapi.lib")
00018 # pragma comment(lib, "hid.lib") // for HID API (from DDK)
00019 # pragma comment(lib, "winmm.lib") // for timeGetTime()
00020 #endif // _MSC_VER
00021
00022 #include "wiimote.h"
00023 #include <setupapi.h>
00024 extern "C" {
00025 # ifdef __MINGW32__
00026 # include <ddk/hidsdi.h>
00027 # else
00028 # include <hidsdi.h>
00029 # endif
00030 }
00031 #include <sys/types.h>
00032 #include <sys/stat.h>
00033 #include <process.h>
00034 #ifdef __BORLANDC__
00035 # include <cmath.h>
00036 #else
00037 # include <math.h>
00038 #endif
00039 #include <mmreg.h>
00040 #include <mmsystem.h>
00041
00042
00043 #ifndef min
00044 # define min(a,b) (((a) < (b)) ? (a) : (b))
00045 #endif
00046
00047
00048
00049 template<class T> inline T sign (const T& val) { return (val<0)? T(-1) : T(1); }
00050 template<class T> inline T square(const T& val) { return val*val; }
00051 #define ARRAY_ENTRIES(array) (sizeof(array)/sizeof(array[0]))
00052
00053
00054
00055
00056 #define PREFIX _T("WiiYourself! : ")
00057
00058
00059
00060 #if (_MSC_VER >= 1400) // VC 2005+ (earlier versions don't support variable args)
00061 # define TRACE(fmt, ...) _TRACE(PREFIX fmt _T("\n"), __VA_ARGS__)
00062 # define WARN(fmt, ...) _TRACE(PREFIX _T("* ") fmt _T(" *") _T("\n"), __VA_ARGS__)
00063 #elif defined(__MINGW32__)
00064 # define TRACE(fmt, ...) _TRACE(PREFIX fmt _T("\n") , ##__VA_ARGS__)
00065 # define WARN(fmt, ...) _TRACE(PREFIX _T("* ") fmt _T(" *") _T("\n") , ##__VA_ARGS__)
00066 #endif
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076 #ifndef TRACE
00077 # define TRACE
00078 #endif
00079 #ifndef DEEP_TRACE
00080 # define DEEP_TRACE
00081 #endif
00082 #ifndef WARN
00083 # define WARN
00084 #endif
00085
00086 static void _cdecl _TRACE (const TCHAR* fmt, ...)
00087 {
00088 static TCHAR buffer[256];
00089 if (!fmt) return;
00090
00091 va_list argptr;
00092 va_start (argptr, fmt);
00093 #if (_MSC_VER >= 1400) // VC 2005+
00094 _vsntprintf_s(buffer, ARRAY_ENTRIES(buffer), _TRUNCATE, fmt, argptr);
00095 #else
00096 _vsntprintf (buffer, ARRAY_ENTRIES(buffer), fmt, argptr);
00097 #endif
00098 va_end (argptr);
00099
00100 OutputDebugString(buffer);
00101 }
00102
00103
00104
00105
00106
00107 HMODULE wiimote::HidDLL = NULL;
00108 unsigned wiimote::_TotalCreated = 0;
00109 unsigned wiimote::_TotalConnected = 0;
00110 hidwrite_ptr wiimote::_HidD_SetOutputReport = NULL;
00111
00112
00113 const unsigned wiimote::FreqLookup [TOTAL_FREQUENCIES] =
00114 { 0, 4200, 3920, 3640, 3360,
00115 3130, 2940, 2760, 2610, 2470 };
00116
00117 const TCHAR* wiimote::ButtonNameFromBit [TOTAL_BUTTON_BITS] =
00118 { _T("Left") , _T("Right"), _T("Down"), _T("Up"),
00119 _T("Plus") , _T("??") , _T("??") , _T("??") ,
00120 _T("Two") , _T("One") , _T("B") , _T("A") ,
00121 _T("Minus"), _T("??") , _T("??") , _T("Home") };
00122
00123 const TCHAR* wiimote::ClassicButtonNameFromBit [TOTAL_BUTTON_BITS] =
00124 { _T("??") , _T("TrigR") , _T("Plus") , _T("Home"),
00125 _T("Minus"), _T("TrigL") , _T("Down") , _T("Right") ,
00126 _T("Up") , _T("Left") , _T("ZR") , _T("X") ,
00127 _T("A") , _T("Y") , _T("B") , _T("ZL") };
00128
00129 wiimote::wiimote ()
00130 :
00131 DataRead (CreateEvent(NULL, FALSE, FALSE, NULL)),
00132 Handle (INVALID_HANDLE_VALUE),
00133 ReportType (IN_BUTTONS),
00134 bStatusReceived (false),
00135 bConnectInProgress (true ),
00136 bInitInProgress (false),
00137 bEnablingMotionPlus (false),
00138 bConnectionLost (false),
00139 bMotionPlusDetected (false),
00140 bMotionPlusEnabled (false),
00141 bMotionPlusExtension (false),
00142 bCalibrateAtRest (false),
00143 bUseHIDwrite (false),
00144 ChangedCallback (NULL),
00145 CallbackTriggerFlags (CHANGED_ALL),
00146 InternalChanged (NO_CHANGE),
00147 CurrentSample (NULL),
00148 HIDwriteThread (NULL),
00149 ReadParseThread (NULL),
00150 SampleThread (NULL),
00151 AsyncRumbleThread (NULL),
00152 AsyncRumbleTimeout (0),
00153 UniqueID (0)
00154 #ifdef ID2_FROM_DEVICEPATH
00155
00156 #endif
00157 {
00158 _ASSERT(DataRead != INVALID_HANDLE_VALUE);
00159
00160
00161 if(++_TotalCreated == 1)
00162 {
00163 HidDLL = LoadLibrary(_T("hid.dll"));
00164 _ASSERT(HidDLL);
00165 if(!HidDLL)
00166 WARN(_T("Couldn't load hid.dll - shouldn't happen!"));
00167 else{
00168 _HidD_SetOutputReport = (hidwrite_ptr)
00169 GetProcAddress(HidDLL, "HidD_SetOutputReport");
00170 if(_HidD_SetOutputReport)
00171 TRACE(_T("OS supports HID writes."));
00172 else
00173 TRACE(_T("OS doesn't support HID writes."));
00174 }
00175 }
00176
00177
00178 Clear (true);
00179 Internal.Clear(true);
00180
00181
00182 memset(&Recording, 0, sizeof(Recording));
00183
00184
00185 memset(&Overlapped, 0, sizeof(Overlapped));
00186 Overlapped.hEvent = DataRead;
00187 Overlapped.Offset =
00188 Overlapped.OffsetHigh = 0;
00189
00190
00191 InitializeCriticalSection(&HIDwriteQueueLock);
00192
00193 InitializeCriticalSection(&StateLock);
00194
00195
00196 timeBeginPeriod(1);
00197 }
00198
00199 wiimote::~wiimote ()
00200 {
00201 Disconnect();
00202
00203
00204
00205 if(DataRead != INVALID_HANDLE_VALUE)
00206 CloseHandle(DataRead);
00207
00208 DeleteCriticalSection(&HIDwriteQueueLock);
00209 DeleteCriticalSection(&StateLock);
00210
00211
00212 timeEndPeriod(1);
00213
00214
00215 if((--_TotalCreated == 0) && HidDLL)
00216 {
00217 FreeLibrary(HidDLL);
00218 HidDLL = NULL;
00219 _HidD_SetOutputReport = NULL;
00220 }
00221 }
00222
00223
00224 bool wiimote::Connect (unsigned wiimote_index, bool force_hidwrites)
00225 {
00226 if(wiimote_index == FIRST_AVAILABLE)
00227 TRACE(_T("Connecting first available Wiimote:"));
00228 else
00229 TRACE(_T("Connecting Wiimote %u:"), wiimote_index);
00230
00231
00232 if(IsConnected())
00233 Disconnect();
00234
00235
00236 GUID guid;
00237 HidD_GetHidGuid(&guid);
00238
00239
00240
00241
00242 HDEVINFO dev_info = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_DEVICEINTERFACE);
00243 if(!dev_info) {
00244 WARN(_T("couldn't get device info"));
00245 return false;
00246 }
00247
00248
00249 SP_DEVICE_INTERFACE_DATA didata;
00250 didata.cbSize = sizeof(didata);
00251
00252 unsigned index = 0;
00253 unsigned wiimotes_found = 0;
00254 while(SetupDiEnumDeviceInterfaces(dev_info, NULL, &guid, index, &didata))
00255 {
00256
00257 DWORD req_size = 0;
00258 SetupDiGetDeviceInterfaceDetail(dev_info, &didata, NULL, 0, &req_size, NULL);
00259
00260
00261
00262 SP_DEVICE_INTERFACE_DETAIL_DATA *didetail =
00263 (SP_DEVICE_INTERFACE_DETAIL_DATA*) new BYTE[req_size];
00264 _ASSERT(didetail);
00265 didetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
00266
00267
00268 if(!SetupDiGetDeviceInterfaceDetail(dev_info, &didata, didetail,
00269 req_size, &req_size, NULL)) {
00270 WARN(_T("couldn't get devinterface info for %u"), index);
00271 break;
00272 }
00273
00274
00275
00276 DEEP_TRACE(_T(".. querying device %s"), didetail->DevicePath);
00277 Handle = CreateFile(didetail->DevicePath, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
00278 NULL, OPEN_EXISTING, 0, NULL);
00279 if(Handle == INVALID_HANDLE_VALUE) {
00280 DEEP_TRACE(_T(".... failed with err %x (probably harmless)."),
00281 GetLastError());
00282 goto skip;
00283 }
00284
00285
00286 HIDD_ATTRIBUTES attrib;
00287 attrib.Size = sizeof(attrib);
00288 if(HidD_GetAttributes(Handle, &attrib))
00289 {
00290
00291 if((attrib.VendorID != VID) || (attrib.ProductID != PID))
00292 goto skip;
00293
00294
00295 ++wiimotes_found;
00296 if((wiimote_index != FIRST_AVAILABLE) &&
00297 (wiimote_index != wiimotes_found))
00298 goto skip;
00299
00300
00301 if(wiimote_index == FIRST_AVAILABLE)
00302 TRACE(_T(".. opening Wiimote %u:"), wiimotes_found);
00303 else
00304 TRACE(_T(".. opening:"));
00305
00306
00307
00308
00309
00310 CloseHandle(Handle);
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322 Handle = CreateFile(didetail->DevicePath, GENERIC_READ|GENERIC_WRITE,
00323 FILE_SHARE_READ,
00324 NULL, OPEN_EXISTING,
00325 FILE_FLAG_OVERLAPPED, NULL);
00326 if(Handle == INVALID_HANDLE_VALUE) {
00327 TRACE(_T(".... failed with err %x"), GetLastError());
00328 goto skip;
00329 }
00330
00331
00332 Clear (false);
00333 Internal.Clear(false);
00334 InternalChanged = NO_CHANGE;
00335 memset(ReadBuff , 0, sizeof(ReadBuff));
00336 bConnectionLost = false;
00337 bConnectInProgress = true;
00338
00339
00340 BeginAsyncRead();
00341
00342
00343
00344 if(force_hidwrites && !_HidD_SetOutputReport) {
00345 TRACE(_T(".. can't force HID writes (not supported)"));
00346 force_hidwrites = false;
00347 }
00348
00349 if(force_hidwrites)
00350 TRACE(_T(".. (HID writes forced)"));
00351 else{
00352
00353
00354 bUseHIDwrite = false;
00355 RequestStatusReport();
00356
00357 DWORD last_time = timeGetTime();
00358 while(!bStatusReceived && ((timeGetTime()-last_time) < 500))
00359 Sleep(10);
00360 TRACE(_T(".. WriteFile() %s."), bStatusReceived? _T("succeeded") :
00361 _T("failed"));
00362 }
00363
00364
00365 if(!bStatusReceived && _HidD_SetOutputReport)
00366 {
00367 bUseHIDwrite = true;
00368 RequestStatusReport();
00369
00370 DWORD last_time = timeGetTime();
00371 while(!bStatusReceived && ((timeGetTime()-last_time) < 500))
00372 Sleep(10);
00373
00374 TRACE(_T(".. HID write %s."), bStatusReceived? _T("succeeded") :
00375 _T("failed"));
00376 }
00377
00378
00379 if(!bStatusReceived) {
00380 WARN(_T("output failed - wiimote is not connected (or confused)."));
00381 Disconnect();
00382 goto skip;
00383 }
00384
00385
00386
00387 Reset();
00388
00389
00390 ReadCalibration();
00391
00392
00393
00394 Sleep(300);
00395
00396
00397 _TotalConnected++;
00398
00399
00400
00401 bCalibrateAtRest = true;
00402
00403
00404
00405 RefreshState();
00406
00407
00408
00409
00410 memcpy(&UniqueID, &CalibrationInfo, sizeof(CalibrationInfo));
00411
00412 _ASSERT(UniqueID != 0);
00413
00414
00415 #ifdef ID2_FROM_DEVICEPATH // (see comments in header)
00416
00417
00418 UniqueID2 = 0;
00419 for(unsigned index=0; index<_tcslen(didetail->DevicePath); index++)
00420 UniqueID2 += didetail->DevicePath[index];
00421 #endif
00422
00423
00424 NextStatusTime = timeGetTime() + REQUEST_STATUS_EVERY_MS;
00425 NextMPlusDetectTime = timeGetTime() + DETECT_MPLUS_EVERY_MS;
00426 MPlusDetectCount = DETECT_MPLUS_COUNT;
00427
00428
00429 delete[] (BYTE*)didetail;
00430 break;
00431 }
00432 skip:
00433
00434 delete[] (BYTE*)didetail;
00435
00436 if(Handle != INVALID_HANDLE_VALUE) {
00437 CloseHandle(Handle);
00438 Handle = INVALID_HANDLE_VALUE;
00439 }
00440
00441 if((wiimote_index != FIRST_AVAILABLE) &&
00442 (wiimote_index == (wiimotes_found-1)))
00443 break;
00444
00445 index++;
00446 }
00447
00448
00449 SetupDiDestroyDeviceInfoList(dev_info);
00450
00451 bConnectInProgress = false;
00452 if(IsConnected()) {
00453 TRACE(_T(".. connected!"));
00454
00455 if(CallbackTriggerFlags & CONNECTED)
00456 {
00457 ChangedNotifier(CONNECTED, Internal);
00458 if(ChangedCallback)
00459 ChangedCallback(*this, CONNECTED, Internal);
00460 }
00461 return true;
00462 }
00463 TRACE(_T(".. connection failed."));
00464 return false;
00465 }
00466
00467 void wiimote::CalibrateAtRest ()
00468 {
00469 _ASSERT(IsConnected());
00470 if(!IsConnected())
00471 return;
00472
00473
00474
00475 if(IsBalanceBoard()) {
00476 TRACE(_T(".. removing 'at rest' BBoard offsets."));
00477 Internal.BalanceBoard.AtRestKg = Internal.BalanceBoard.Kg;
00478 RefreshState();
00479 }
00480 }
00481
00482 void wiimote::Disconnect ()
00483 {
00484 if(Handle == INVALID_HANDLE_VALUE)
00485 return;
00486
00487 TRACE(_T("Disconnect()."));
00488
00489 if(IsConnected())
00490 {
00491 _ASSERT(_TotalConnected > 0);
00492 _TotalConnected--;
00493
00494 if(!bConnectionLost)
00495 Reset();
00496 }
00497
00498 CloseHandle(Handle);
00499 Handle = INVALID_HANDLE_VALUE;
00500 UniqueID = 0;
00501 #ifdef ID2_FROM_DEVICEPATH // (see comments in header)
00502 UniqueID2 = 0;
00503 #endif
00504
00505
00506 if(ReadParseThread) {
00507
00508 SetEvent(DataRead);
00509 WaitForSingleObject(ReadParseThread, 3000);
00510 CloseHandle(ReadParseThread);
00511 ReadParseThread = NULL;
00512 }
00513
00514 if(AsyncRumbleThread) {
00515 WaitForSingleObject(AsyncRumbleThread, 3000);
00516 CloseHandle(AsyncRumbleThread);
00517 AsyncRumbleThread = NULL;
00518 AsyncRumbleTimeout = 0;
00519 }
00520
00521 if(SampleThread) {
00522 WaitForSingleObject(SampleThread, 3000);
00523 CloseHandle(SampleThread);
00524 SampleThread = NULL;
00525 }
00526
00527 #ifndef USE_DYNAMIC_HIDQUEUE
00528 HID.Deallocate();
00529 #endif
00530
00531 bStatusReceived = false;
00532
00533
00534 Clear (false);
00535 Internal.Clear(false);
00536 InternalChanged = NO_CHANGE;
00537 }
00538
00539 void wiimote::Reset ()
00540 {
00541 TRACE(_T("Resetting wiimote."));
00542
00543 if(bMotionPlusEnabled)
00544 DisableMotionPlus();
00545
00546
00547 if(IsBalanceBoard())
00548 SetReportType(IN_BUTTONS_BALANCE_BOARD, false);
00549 else
00550 SetReportType(IN_BUTTONS, false);
00551
00552 SetRumble (false);
00553 SetLEDs (0x00);
00554
00555 EnableSpeaker(false);
00556
00557 Sleep(150);
00558 }
00559
00560 unsigned __stdcall wiimote::ReadParseThreadfunc (void* param)
00561 {
00562
00563
00564
00565 _ASSERT(param);
00566 wiimote &remote = *(wiimote*)param;
00567 OVERLAPPED &overlapped = remote.Overlapped;
00568 unsigned exit_code = 0;
00569
00570 while(1)
00571 {
00572
00573 DWORD wait = WaitForSingleObject(overlapped.hEvent, 500);
00574
00575
00576
00577
00578 if(remote.Handle == INVALID_HANDLE_VALUE) {
00579 DEEP_TRACE(_T("read thread: wiimote was disconnected"));
00580 break;
00581 }
00582
00583 if(remote.bConnectionLost)
00584 {
00585 connection_lost:
00586 TRACE(_T("read thread: connection to wiimote was lost"));
00587 remote.Disconnect();
00588 remote.InternalChanged = (state_change_flags)
00589 (remote.InternalChanged | CONNECTION_LOST);
00590
00591 if(remote.CallbackTriggerFlags & CONNECTION_LOST)
00592 {
00593 remote.ChangedNotifier(CONNECTION_LOST, remote.Internal);
00594 if(remote.ChangedCallback)
00595 remote.ChangedCallback(remote, CONNECTION_LOST, remote.Internal);
00596 }
00597 break;
00598 }
00599
00600 DWORD time = timeGetTime();
00601
00602
00603 if(remote.IsConnected() && !remote.bInitInProgress &&
00604 !remote.IsPlayingAudio())
00605 {
00606
00607 if(time > remote.NextStatusTime)
00608 {
00609 #ifdef BEEP_ON_PERIODIC_STATUSREFRESH
00610 Beep(2000,50);
00611 #endif
00612 remote.RequestStatusReport();
00613
00614 remote.NextStatusTime = time + REQUEST_STATUS_EVERY_MS;
00615 }
00616
00617 if(!remote.IsBalanceBoard() &&
00618
00619 !remote.bMotionPlusExtension &&
00620 (remote.Internal.ExtensionType != MOTION_PLUS) &&
00621 (remote.Internal.ExtensionType != PARTIALLY_INSERTED) &&
00622 (time > remote.NextMPlusDetectTime))
00623 {
00624 remote.DetectMotionPlusExtensionAsync();
00625
00626
00627 if(--remote.MPlusDetectCount == 0) {
00628 remote.NextMPlusDetectTime = time + DETECT_MPLUS_EVERY_MS;
00629 remote.MPlusDetectCount = DETECT_MPLUS_COUNT;
00630 #ifdef _DEBUG
00631 TRACE(_T("--"));
00632 #endif
00633 }
00634 }
00635 }
00636
00637
00638 if(remote.Recording.bEnabled && (remote.Recording.EndTimeMS != UNTIL_STOP) &&
00639 (time >= remote.Recording.EndTimeMS))
00640 remote.Recording.bEnabled = false;
00641
00642
00643
00644 if(wait == WAIT_TIMEOUT) {
00645 DEEP_TRACE(_T("read thread: timed out"));
00646 continue;
00647 }
00648
00649 if(wait != WAIT_OBJECT_0) {
00650 DEEP_TRACE(_T("read thread: error waiting!"));
00651 remote.bConnectionLost = true;
00652
00653 goto connection_lost;
00654 }
00655
00656
00657 #ifdef BEEP_DEBUG_READS
00658 Beep(500,1);
00659 #endif
00660 DWORD read = 0;
00661
00662 GetOverlappedResult(remote.Handle, &overlapped, &read, TRUE);
00663
00664 if(read) {
00665 DEEP_TRACE(_T("read thread: parsing data"));
00666 remote.OnReadData(read);
00667 }
00668 else
00669 DEEP_TRACE(_T("read thread: didn't get any data??"));
00670 }
00671
00672 TRACE(_T("(ending read thread)"));
00673 #ifdef BEEP_DEBUG_READS
00674 if(exit_code != 0)
00675 Beep(200,1000);
00676 #endif
00677 return exit_code;
00678 }
00679
00680 bool wiimote::BeginAsyncRead ()
00681 {
00682
00683 if(Handle == INVALID_HANDLE_VALUE)
00684 return false;
00685
00686 DEEP_TRACE(_T(".. starting async read"));
00687 #ifdef BEEP_DEBUG_READS
00688 Beep(1000,1);
00689 #endif
00690
00691 DWORD read;
00692 if (!ReadFile(Handle, ReadBuff, REPORT_LENGTH, &read, &Overlapped)) {
00693 DWORD err = GetLastError();
00694 if(err != ERROR_IO_PENDING) {
00695 DEEP_TRACE(_T(".... ** ReadFile() failed! **"));
00696 return false;
00697 }
00698 }
00699
00700
00701 if(!ReadParseThread) {
00702 ReadParseThread = (HANDLE)_beginthreadex(NULL, 0, ReadParseThreadfunc,
00703 this, 0, NULL);
00704 DEEP_TRACE(_T(".... creating read thread"));
00705 _ASSERT(ReadParseThread);
00706 if(!ReadParseThread)
00707 return false;
00708 SetThreadPriority(ReadParseThread, WORKER_THREAD_PRIORITY);
00709 }
00710
00711
00712 if(read) {
00713 DEEP_TRACE(_T(".... got data right away"));
00714 SetEvent(DataRead);
00715 }
00716 return true;
00717 }
00718
00719 void wiimote::OnReadData (DWORD bytes_read)
00720 {
00721 _ASSERT(bytes_read == REPORT_LENGTH);
00722
00723
00724 BYTE buff [REPORT_LENGTH];
00725 memcpy(buff, ReadBuff, bytes_read);
00726
00727
00728 BeginAsyncRead();
00729
00730
00731 ParseInput(buff);
00732 }
00733
00734 void wiimote::SetReportType (input_report type, bool continuous)
00735 {
00736 _ASSERT(IsConnected());
00737 if(!IsConnected())
00738 return;
00739
00740
00741 _ASSERT(!IsBalanceBoard() || type == IN_BUTTONS_BALANCE_BOARD);
00742 if(IsBalanceBoard() && (type != IN_BUTTONS_BALANCE_BOARD))
00743 return;
00744
00745 #ifdef TRACE
00746 #define TYPE2NAME(_type) (type==_type)? _T(#_type)
00747 const TCHAR* name = TYPE2NAME(IN_BUTTONS) :
00748 TYPE2NAME(IN_BUTTONS_ACCEL_IR) :
00749 TYPE2NAME(IN_BUTTONS_ACCEL_EXT) :
00750 TYPE2NAME(IN_BUTTONS_ACCEL_IR_EXT) :
00751 TYPE2NAME(IN_BUTTONS_BALANCE_BOARD) :
00752 _T("(unknown??)");
00753 TRACE(_T("ReportType: %s (%s)"), name, (continuous? _T("continuous") :
00754 _T("non-continuous")));
00755 #endif
00756 ReportType = type;
00757
00758 switch(type)
00759 {
00760 case IN_BUTTONS_ACCEL_IR:
00761 EnableIR(wiimote_state::ir::EXTENDED);
00762 break;
00763 case IN_BUTTONS_ACCEL_IR_EXT:
00764 EnableIR(wiimote_state::ir::BASIC);
00765 break;
00766 default:
00767 DisableIR();
00768 break;
00769 }
00770
00771 BYTE buff [REPORT_LENGTH] = {0};
00772 buff[0] = OUT_TYPE;
00773 buff[1] = (continuous ? 0x04 : 0x00) | GetRumbleBit();
00774 buff[2] = (BYTE)type;
00775 WriteReport(buff);
00776
00777 }
00778
00779 void wiimote::SetLEDs (BYTE led_bits)
00780 {
00781 _ASSERT(IsConnected());
00782 if(!IsConnected() || bInitInProgress)
00783 return;
00784
00785 _ASSERT(led_bits <= 0x0f);
00786 led_bits &= 0xf;
00787
00788 BYTE buff [REPORT_LENGTH] = {0};
00789 buff[0] = OUT_LEDs;
00790 buff[1] = (led_bits<<4) | GetRumbleBit();
00791 WriteReport(buff);
00792
00793 Internal.LED.Bits = led_bits;
00794 }
00795
00796 void wiimote::SetRumble (bool on)
00797 {
00798 _ASSERT(IsConnected());
00799 if(!IsConnected())
00800 return;
00801
00802 if(Internal.bRumble == on)
00803 return;
00804
00805 Internal.bRumble = on;
00806
00807
00808
00809 if(IsPlayingAudio())
00810 return;
00811
00812 BYTE buff [REPORT_LENGTH] = {0};
00813 buff[0] = OUT_STATUS;
00814 buff[1] = on? 0x01 : 0x00;
00815 WriteReport(buff);
00816 }
00817
00818 unsigned __stdcall wiimote::AsyncRumbleThreadfunc (void* param)
00819 {
00820
00821 _ASSERT(param);
00822 wiimote &remote = *(wiimote*)param;
00823
00824 while(remote.IsConnected())
00825 {
00826 if(remote.AsyncRumbleTimeout)
00827 {
00828 DWORD current_time = timeGetTime();
00829 if(current_time >= remote.AsyncRumbleTimeout)
00830 {
00831 if(remote.Internal.bRumble)
00832 remote.SetRumble(false);
00833 remote.AsyncRumbleTimeout = 0;
00834 }
00835 Sleep(1);
00836 }
00837 else
00838 Sleep(4);
00839 }
00840 return 0;
00841 }
00842
00843 void wiimote::RumbleForAsync (unsigned milliseconds)
00844 {
00845
00846 _ASSERT(IsConnected());
00847 if(!IsConnected())
00848 return;
00849
00850 SetRumble(true);
00851
00852
00853
00854 AsyncRumbleTimeout = timeGetTime() + milliseconds;
00855
00856
00857 if(AsyncRumbleThread)
00858 return;
00859
00860 AsyncRumbleThread = (HANDLE)_beginthreadex(NULL, 0, AsyncRumbleThreadfunc, this,
00861 0, NULL);
00862 _ASSERT(AsyncRumbleThread);
00863 if(!AsyncRumbleThread) {
00864 WARN(_T("couldn't create rumble thread!"));
00865 return;
00866 }
00867 SetThreadPriority(AsyncRumbleThread, WORKER_THREAD_PRIORITY);
00868 }
00869
00870 void wiimote::RequestStatusReport ()
00871 {
00872
00873 _ASSERT(Handle != INVALID_HANDLE_VALUE);
00874 if(Handle == INVALID_HANDLE_VALUE)
00875 return;
00876
00877 BYTE buff [REPORT_LENGTH] = {0};
00878 buff[0] = OUT_STATUS;
00879 buff[1] = GetRumbleBit();
00880 WriteReport(buff);
00881 }
00882
00883 bool wiimote::ReadAddress (int address, short size)
00884 {
00885
00886 BYTE buff [REPORT_LENGTH] = {0};
00887 buff[0] = OUT_READMEMORY;
00888 buff[1] = (BYTE)(((address & 0xff000000) >> 24) | GetRumbleBit());
00889 buff[2] = (BYTE)( (address & 0x00ff0000) >> 16);
00890 buff[3] = (BYTE)( (address & 0x0000ff00) >> 8);
00891 buff[4] = (BYTE)( (address & 0x000000ff));
00892 buff[5] = (BYTE)( (size & 0xff00 ) >> 8);
00893 buff[6] = (BYTE)( (size & 0xff));
00894 return WriteReport(buff);
00895 }
00896
00897 void wiimote::WriteData (int address, BYTE size, const BYTE* buff)
00898 {
00899
00900 BYTE write [REPORT_LENGTH] = {0};
00901 write[0] = OUT_WRITEMEMORY;
00902 write[1] = (BYTE)(((address & 0xff000000) >> 24) | GetRumbleBit());
00903 write[2] = (BYTE)( (address & 0x00ff0000) >> 16);
00904 write[3] = (BYTE)( (address & 0x0000ff00) >> 8);
00905 write[4] = (BYTE)( (address & 0x000000ff));
00906 write[5] = size;
00907 memcpy(write+6, buff, size);
00908 WriteReport(write);
00909 }
00910
00911 int wiimote::ParseInput (BYTE* buff)
00912 {
00913 int changed = 0;
00914
00915
00916 EnterCriticalSection(&StateLock);
00917
00918 switch(buff[0])
00919 {
00920 case IN_BUTTONS:
00921 DEEP_TRACE(_T(".. parsing buttons."));
00922 changed |= ParseButtons(buff);
00923 break;
00924
00925 case IN_BUTTONS_ACCEL:
00926 DEEP_TRACE(_T(".. parsing buttons/accel."));
00927 changed |= ParseButtons(buff);
00928 if(!IsBalanceBoard())
00929 changed |= ParseAccel(buff);
00930 break;
00931
00932 case IN_BUTTONS_ACCEL_EXT:
00933 DEEP_TRACE(_T(".. parsing extenion/accel."));
00934 changed |= ParseButtons(buff);
00935 changed |= ParseExtension(buff, 6);
00936 if(!IsBalanceBoard())
00937 changed |= ParseAccel(buff);
00938 break;
00939
00940 case IN_BUTTONS_ACCEL_IR:
00941 DEEP_TRACE(_T(".. parsing ir/accel."));
00942 changed |= ParseButtons(buff);
00943 if(!IsBalanceBoard()) {
00944 changed |= ParseAccel(buff);
00945 changed |= ParseIR(buff);
00946 }
00947 break;
00948
00949 case IN_BUTTONS_ACCEL_IR_EXT:
00950 DEEP_TRACE(_T(".. parsing ir/extenion/accel."));
00951 changed |= ParseButtons(buff);
00952 changed |= ParseExtension(buff, 16);
00953 if(!IsBalanceBoard()) {
00954 changed |= ParseAccel(buff);
00955 changed |= ParseIR (buff);
00956 }
00957 break;
00958
00959 case IN_BUTTONS_BALANCE_BOARD:
00960 DEEP_TRACE(_T(".. parsing buttson/balance."));
00961 changed |= ParseButtons(buff);
00962 changed |= ParseExtension(buff, 3);
00963 break;
00964
00965 case IN_READADDRESS:
00966 DEEP_TRACE(_T(".. parsing read address."));
00967 changed |= ParseButtons (buff);
00968 changed |= ParseReadAddress(buff);
00969 break;
00970
00971 case IN_STATUS:
00972 DEEP_TRACE(_T(".. parsing status."));
00973 changed |= ParseStatus(buff);
00974
00975
00976 bStatusReceived = true;
00977 break;
00978
00979 default:
00980 DEEP_TRACE(_T(".. ** unknown input ** (happens)."));
00982
00983 LeaveCriticalSection(&StateLock);
00984 return false;
00985 }
00986
00987
00988
00989 if(Recording.bEnabled && (changed & Recording.TriggerFlags))
00990 {
00991 DEEP_TRACE(_T(".. adding state to history"));
00992 state_event event;
00993 event.time_ms = timeGetTime();
00994 event.state = *(wiimote_state*)this;
00995 Recording.StateHistory->push_back(event);
00996 }
00997
00998
00999 InternalChanged = (state_change_flags)(InternalChanged | changed);
01000
01001 LeaveCriticalSection(&StateLock);
01002
01003
01004 if(changed & CallbackTriggerFlags)
01005 {
01006 DEEP_TRACE(_T(".. calling state change callback"));
01007 ChangedNotifier((state_change_flags)changed, Internal);
01008 if(ChangedCallback)
01009 ChangedCallback(*this, (state_change_flags)changed, Internal);
01010 }
01011
01012 DEEP_TRACE(_T(".. parse complete."));
01013 return true;
01014 }
01015
01016 state_change_flags wiimote::RefreshState ()
01017 {
01018
01019 if(InternalChanged == NO_CHANGE)
01020 return NO_CHANGE;
01021
01022
01023
01024
01025 EnterCriticalSection(&StateLock);
01026
01027
01028 state_change_flags changed = InternalChanged;
01029
01030
01031 joystick::deadzone nunchuk_deadzone = Nunchuk.Joystick.DeadZone;
01032 joystick::deadzone classic_joyl_deadzone = ClassicController.JoystickL.DeadZone;
01033 joystick::deadzone classic_joyr_deadzone = ClassicController.JoystickR.DeadZone;
01034
01035
01036 *(wiimote_state*)this = Internal;
01037 InternalChanged = NO_CHANGE;
01038
01039
01040 Nunchuk.Joystick.DeadZone = nunchuk_deadzone;
01041 ClassicController.JoystickL.DeadZone = classic_joyl_deadzone;
01042 ClassicController.JoystickR.DeadZone = classic_joyr_deadzone;
01043
01044 LeaveCriticalSection(&StateLock);
01045
01046 return changed;
01047 }
01048
01049 void wiimote::DetectMotionPlusExtensionAsync ()
01050 {
01051 #ifdef _DEBUG
01052 TRACE(_T("(looking for motion plus)"));
01053 #endif
01054
01055 MotionPlusDetectCount++;
01056
01057
01058
01059 ReadAddress(REGISTER_MOTIONPLUS_DETECT, 6);
01060 }
01061
01062 bool wiimote::EnableMotionPlus ()
01063 {
01064 _ASSERT(bMotionPlusDetected);
01065 if(!bMotionPlusDetected)
01066 return false;
01067 if(bMotionPlusEnabled)
01068 return true;
01069
01070 TRACE(_T("Enabling Motion Plus:"));
01071
01072 bMotionPlusExtension = false;
01073 bInitInProgress = true;
01074 bEnablingMotionPlus = true;
01075
01076
01077 WriteData(REGISTER_MOTIONPLUS_INIT , 0x55);
01078
01079
01080 WriteData(REGISTER_MOTIONPLUS_ENABLE, 0x04);
01081
01082 Sleep(500);
01083 return true;
01084 }
01085
01086 bool wiimote::DisableMotionPlus ()
01087 {
01088 if(!bMotionPlusDetected || !bMotionPlusEnabled)
01089 return false;
01090
01091 TRACE(_T("Disabling Motion Plus:"));
01092
01093
01094 WriteData(REGISTER_EXTENSION_INIT1, 0x55);
01095 return true;
01096 }
01097
01098 void wiimote::InitializeExtension ()
01099 {
01100 TRACE(_T("Initialising Extension."));
01101
01102
01103
01104
01105 bInitInProgress = true;
01106 _ASSERT(Internal.bExtension);
01107
01108 if(!bEnablingMotionPlus) {
01109 WriteData (REGISTER_EXTENSION_INIT1, 0x55);
01110 WriteData (REGISTER_EXTENSION_INIT2, 0x00);
01111 }
01112 else
01113 bEnablingMotionPlus = false;
01114
01115 ReadAddress(REGISTER_EXTENSION_TYPE , 6);
01116 }
01117
01118 int wiimote::ParseStatus (BYTE* buff)
01119 {
01120
01121 int changed = ParseButtons(buff);
01122
01123
01124 BYTE battery_raw = buff[6];
01125 if(Internal.BatteryRaw != battery_raw)
01126 changed |= BATTERY_CHANGED;
01127 Internal.BatteryRaw = battery_raw;
01128
01129 Internal.BatteryPercent = battery_raw / 2;
01130
01131
01132 bool drained = buff[3] & 0x01;
01133 if(drained != bBatteryDrained)
01134 {
01135 bBatteryDrained = drained;
01136 if(drained)
01137 changed |= BATTERY_DRAINED;
01138 }
01139
01140
01141 BYTE leds = buff[3] >> 4;
01142 if(leds != Internal.LED.Bits)
01143 changed |= LEDS_CHANGED;
01144 Internal.LED.Bits = leds;
01145
01146
01147
01148
01149
01150 bool extension = ((buff[3] & 0x02) != 0);
01151
01152
01153 if(extension != Internal.bExtension)
01154 {
01155 if(!Internal.bExtension)
01156 {
01157 TRACE(_T("Extension connected:"));
01158 Internal.bExtension = true;
01159 InitializeExtension();
01160 }
01161 else{
01162 TRACE(_T("Extension disconnected."));
01163 Internal.bExtension = false;
01164 Internal.ExtensionType = wiimote_state::NONE;
01165 bMotionPlusEnabled = false;
01166 bMotionPlusExtension = false;
01167 bMotionPlusDetected = false;
01168 bInitInProgress = false;
01169 bEnablingMotionPlus = false;
01170 changed |= EXTENSION_DISCONNECTED;
01171
01172
01173 }
01174 }
01175
01176 return changed;
01177 }
01178
01179 int wiimote::ParseButtons (BYTE* buff)
01180 {
01181 int changed = 0;
01182
01183
01184 WORD bits = *(WORD*)(buff+1) & Button.ALL;
01185
01186 if(bits != Internal.Button.Bits)
01187 changed |= BUTTONS_CHANGED;
01188 Internal.Button.Bits = bits;
01189
01190 return changed;
01191 }
01192
01193 bool wiimote::EstimateOrientationFrom (wiimote_state::acceleration &accel)
01194 {
01195
01196
01197
01198
01199
01200 float length_sq = square(accel.X) + square(accel.Y) + square(accel.Z);
01201
01202
01203
01204 #define DOT(x1,y1,z1, x2,y2,z2) ((x1*x2) + (y1*y2) + (z1*z2))
01205
01206 static const float epsilon = 0.2f;
01207 if((length_sq >= (1.f-epsilon)) && (length_sq <= (1.f+epsilon)))
01208 {
01209 if(++WiimoteNearGUpdates < 2)
01210 return false;
01211
01212
01213
01214 float inv_len = 1.f / sqrt(length_sq);
01215 float x = accel.X * inv_len;
01216 float y = accel.Y * inv_len;
01217 float z = accel.Z * inv_len;
01218
01219
01220 accel.Orientation.X = x;
01221 accel.Orientation.Y = y;
01222 accel.Orientation.Z = z;
01223
01224
01225
01226 float pitch = -asin(y) * 57.2957795f;
01227
01228 float roll = atan2(x,z) * 57.2957795f;
01229 if(z < 0) {
01230 pitch = (y < 0)? 180 - pitch : -180 - pitch;
01231 roll = (x < 0)? -180 - roll : 180 - roll;
01232 }
01233
01234 accel.Orientation.Pitch = pitch;
01235 accel.Orientation.Roll = roll;
01236
01237
01238 accel.Orientation.UpdateAge = 0;
01239 #ifdef BEEP_ON_ORIENTATION_ESTIMATE
01240 Beep(2000, 1);
01241 #endif
01242 return true;
01243 }
01244
01245
01246 WiimoteNearGUpdates = 0;
01247
01248 accel.Orientation.UpdateAge++;
01249 return false;
01250 }
01251
01252 void wiimote::ApplyJoystickDeadZones (wiimote_state::joystick &joy)
01253 {
01254
01255 if((joy.DeadZone.X > 0.f) && (joy.DeadZone.X <= 1.f))
01256 {
01257 if(fabs(joy.X) <= joy.DeadZone.X)
01258 joy.X = 0;
01259 else{
01260 joy.X -= joy.DeadZone.X * sign(joy.X);
01261 joy.X /= 1.f - joy.DeadZone.X;
01262 }
01263 }
01264 if((joy.DeadZone.Y > 0.f) && (joy.DeadZone.Y <= 1.f))
01265 {
01266 if(fabs(joy.Y) <= joy.DeadZone.Y)
01267 joy.Y = 0;
01268 else{
01269 joy.Y -= joy.DeadZone.Y * sign(joy.Y);
01270 joy.Y /= 1.f - joy.DeadZone.Y;
01271 }
01272 }
01273 }
01274
01275 int wiimote::ParseAccel (BYTE* buff)
01276 {
01277 int changed = 0;
01278
01279 BYTE raw_x = buff[3];
01280 BYTE raw_y = buff[4];
01281 BYTE raw_z = buff[5];
01282
01283 if((raw_x != Internal.Acceleration.RawX) ||
01284 (raw_y != Internal.Acceleration.RawY) ||
01285 (raw_z != Internal.Acceleration.RawZ))
01286 changed |= ACCEL_CHANGED;
01287
01288 Internal.Acceleration.RawX = raw_x;
01289 Internal.Acceleration.RawY = raw_y;
01290 Internal.Acceleration.RawZ = raw_z;
01291
01292
01293 if(Internal.CalibrationInfo.X0)
01294 {
01295 Internal.Acceleration.X =
01296 ((float)Internal.Acceleration.RawX - Internal.CalibrationInfo.X0) /
01297 ((float)Internal.CalibrationInfo.XG - Internal.CalibrationInfo.X0);
01298 Internal.Acceleration.Y =
01299 ((float)Internal.Acceleration.RawY - Internal.CalibrationInfo.Y0) /
01300 ((float)Internal.CalibrationInfo.YG - Internal.CalibrationInfo.Y0);
01301 Internal.Acceleration.Z =
01302 ((float)Internal.Acceleration.RawZ - Internal.CalibrationInfo.Z0) /
01303 ((float)Internal.CalibrationInfo.ZG - Internal.CalibrationInfo.Z0);
01304 }
01305 else{
01306 Internal.Acceleration.X =
01307 Internal.Acceleration.Y =
01308 Internal.Acceleration.Z = 0.f;
01309 }
01310
01311
01312 if(EstimateOrientationFrom(Internal.Acceleration))
01313 changed |= ORIENTATION_CHANGED;
01314
01315 return changed;
01316 }
01317
01318 int wiimote::ParseIR (BYTE* buff)
01319 {
01320 if(Internal.IR.Mode == wiimote_state::ir::OFF)
01321 return NO_CHANGE;
01322
01323
01324
01325 if(bMotionPlusEnabled && (Internal.IR.Mode == wiimote_state::ir::EXTENDED))
01326 return NO_CHANGE;
01327
01328
01329 wiimote_state::ir prev_ir = Internal.IR;
01330
01331
01332
01333 switch(Internal.IR.Mode)
01334 {
01335 case wiimote_state::ir::BASIC:
01336
01337 for(unsigned step=0; step<2; step++)
01338 {
01339 ir::dot &dot0 = Internal.IR.Dot[step*2 ];
01340 ir::dot &dot1 = Internal.IR.Dot[step*2+1];
01341 const unsigned offs = 6 + (step*5);
01342
01343 dot0.bVisible = !(buff[offs ] == 0xff && buff[offs+1] == 0xff);
01344 dot1.bVisible = !(buff[offs+3] == 0xff && buff[offs+4] == 0xff);
01345
01346 if(dot0.bVisible) {
01347 dot0.RawX = buff[offs ] | ((buff[offs+2] >> 4) & 0x03) << 8;;
01348 dot0.RawY = buff[offs+1] | ((buff[offs+2] >> 6) & 0x03) << 8;;
01349 dot0.X = 1.f - (dot0.RawX / (float)wiimote_state::ir::MAX_RAW_X);
01350 dot0.Y = (dot0.RawY / (float)wiimote_state::ir::MAX_RAW_Y);
01351 }
01352 if(dot1.bVisible) {
01353 dot1.RawX = buff[offs+3] | ((buff[offs+2] >> 0) & 0x03) << 8;
01354 dot1.RawY = buff[offs+4] | ((buff[offs+2] >> 2) & 0x03) << 8;
01355 dot1.X = 1.f - (dot1.RawX / (float)wiimote_state::ir::MAX_RAW_X);
01356 dot1.Y = (dot1.RawY / (float)wiimote_state::ir::MAX_RAW_Y);
01357 }
01358 }
01359 break;
01360
01361 case wiimote_state::ir::EXTENDED:
01362
01363 for(unsigned index=0; index<4; index++)
01364 {
01365 ir::dot &dot = Internal.IR.Dot[index];
01366 const unsigned offs = 6 + (index * 3);
01367
01368 dot.bVisible = !(buff[offs ]==0xff && buff[offs+1]==0xff &&
01369 buff[offs+2]==0xff);
01370 if(dot.bVisible) {
01371 dot.RawX = buff[offs ] | ((buff[offs+2] >> 4) & 0x03) << 8;
01372 dot.RawY = buff[offs+1] | ((buff[offs+2] >> 6) & 0x03) << 8;
01373 dot.X = 1.f - (dot.RawX / (float)wiimote_state::ir::MAX_RAW_X);
01374 dot.Y = (dot.RawY / (float)wiimote_state::ir::MAX_RAW_Y);
01375 dot.Size = buff[offs+2] & 0x0f;
01376 }
01377 }
01378 break;
01379
01380 case wiimote_state::ir::FULL:
01381 _ASSERT(0);
01382 break;
01383 }
01384
01385 return memcmp(&prev_ir, &Internal.IR, sizeof(Internal.IR))? IR_CHANGED : 0;
01386 }
01387
01388 inline float wiimote::GetBalanceValue (short sensor, short min, short mid, short max)
01389 {
01390 if(max == mid || mid == min)
01391 return 0;
01392
01393 float val = (sensor < mid)?
01394 68.0f * ((float)(sensor - min) / (mid - min)) :
01395 68.0f * ((float)(sensor - mid) / (max - mid)) + 68.0f;
01396
01397
01398 return val * 0.25f;
01399 }
01400
01401 int wiimote::ParseExtension (BYTE *buff, unsigned offset)
01402 {
01403 int changed = 0;
01404
01405 switch(Internal.ExtensionType)
01406 {
01407 case wiimote_state::NUNCHUK:
01408 {
01409
01410 bool c = (buff[offset+5] & 0x02) == 0;
01411 bool z = (buff[offset+5] & 0x01) == 0;
01412
01413 if((c != Internal.Nunchuk.C) || (z != Internal.Nunchuk.Z))
01414 changed |= NUNCHUK_BUTTONS_CHANGED;
01415
01416 Internal.Nunchuk.C = c;
01417 Internal.Nunchuk.Z = z;
01418
01419
01420 {
01421 wiimote_state::acceleration &accel = Internal.Nunchuk.Acceleration;
01422
01423 BYTE raw_x = buff[offset+2];
01424 BYTE raw_y = buff[offset+3];
01425 BYTE raw_z = buff[offset+4];
01426 if((raw_x != accel.RawX) || (raw_y != accel.RawY) || (raw_z != accel.RawZ))
01427 changed |= NUNCHUK_ACCEL_CHANGED;
01428
01429 accel.RawX = raw_x;
01430 accel.RawY = raw_y;
01431 accel.RawZ = raw_z;
01432
01433 wiimote_state::nunchuk::calibration_info &calib =
01434 Internal.Nunchuk.CalibrationInfo;
01435 accel.X = ((float)raw_x - calib.X0) / ((float)calib.XG - calib.X0);
01436 accel.Y = ((float)raw_y - calib.Y0) / ((float)calib.YG - calib.Y0);
01437 accel.Z = ((float)raw_z - calib.Z0) / ((float)calib.ZG - calib.Z0);
01438
01439
01440 if(EstimateOrientationFrom(accel))
01441 changed |= NUNCHUK_ORIENTATION_CHANGED;
01442 }
01443 {
01444
01445 wiimote_state::joystick &joy = Internal.Nunchuk.Joystick;
01446
01447 float raw_x = buff[offset+0];
01448 float raw_y = buff[offset+1];
01449
01450 if((raw_x != joy.RawX) || (raw_y != joy.RawY))
01451 changed |= NUNCHUK_JOYSTICK_CHANGED;
01452
01453 joy.RawX = raw_x;
01454 joy.RawY = raw_y;
01455
01456
01457 wiimote_state::nunchuk::calibration_info &calib =
01458 Internal.Nunchuk.CalibrationInfo;
01459 if(Internal.Nunchuk.CalibrationInfo.MaxX != 0x00)
01460 joy.X = ((float)raw_x - calib.MidX) / ((float)calib.MaxX - calib.MinX);
01461 if(calib.MaxY != 0x00)
01462 joy.Y = ((float)raw_y - calib.MidY) / ((float)calib.MaxY - calib.MinY);
01463
01464
01465
01466 joy.X *= 2; joy.Y *= 2;
01467
01468
01469 joy.DeadZone = Nunchuk.Joystick.DeadZone;
01470 ApplyJoystickDeadZones(joy);
01471 }
01472 }
01473 break;
01474
01475 case wiimote_state::CLASSIC:
01476 case wiimote_state::GH3_GHWT_GUITAR:
01477 case wiimote_state::GHWT_DRUMS:
01478 {
01479
01480 WORD bits = *(WORD*)(buff+offset+4);
01481 bits = ~bits;
01482
01483 if(bits != Internal.ClassicController.Button.Bits)
01484 changed |= CLASSIC_BUTTONS_CHANGED;
01485
01486 Internal.ClassicController.Button.Bits = bits;
01487
01488
01489 wiimote_state::joystick &joyL = Internal.ClassicController.JoystickL;
01490 wiimote_state::joystick &joyR = Internal.ClassicController.JoystickR;
01491
01492 float l_raw_x = (float) (buff[offset+0] & 0x3f);
01493 float l_raw_y = (float) (buff[offset+1] & 0x3f);
01494 float r_raw_x = (float)((buff[offset+2] >> 7) |
01495 ((buff[offset+1] & 0xc0) >> 5) |
01496 ((buff[offset+0] & 0xc0) >> 3));
01497 float r_raw_y = (float) (buff[offset+2] & 0x1f);
01498
01499 if((joyL.RawX != l_raw_x) || (joyL.RawY != l_raw_y))
01500 changed |= CLASSIC_JOYSTICK_L_CHANGED;
01501 if((joyR.RawX != r_raw_x) || (joyR.RawY != r_raw_y))
01502 changed |= CLASSIC_JOYSTICK_R_CHANGED;
01503
01504 joyL.RawX = l_raw_x; joyL.RawY = l_raw_y;
01505 joyR.RawX = r_raw_x; joyR.RawY = r_raw_y;
01506
01507
01508 wiimote_state::classic_controller::calibration_info &calib =
01509 Internal.ClassicController.CalibrationInfo;
01510 if(calib.MaxXL != 0x00)
01511 joyL.X = (joyL.RawX - calib.MidXL) / ((float)calib.MaxXL - calib.MinXL);
01512 if(calib.MaxYL != 0x00)
01513 joyL.Y = (joyL.RawY - calib.MidYL) / ((float)calib.MaxYL - calib.MinYL);
01514 if(calib.MaxXR != 0x00)
01515 joyR.X = (joyR.RawX - calib.MidXR) / ((float)calib.MaxXR - calib.MinXR);
01516 if(calib.MaxYR != 0x00)
01517 joyR.Y = (joyR.RawY - calib.MidYR) / ((float)calib.MaxYR - calib.MinYR);
01518
01519
01520
01521 joyL.X *= 2; joyL.Y *= 2; joyR.X *= 2; joyR.Y *= 2;
01522
01523
01524 joyL.DeadZone = ClassicController.JoystickL.DeadZone;
01525 joyR.DeadZone = ClassicController.JoystickR.DeadZone;
01526 ApplyJoystickDeadZones(joyL);
01527 ApplyJoystickDeadZones(joyR);
01528
01529
01530 BYTE raw_trigger_l = ((buff[offset+2] & 0x60) >> 2) |
01531 (buff[offset+3] >> 5);
01532 BYTE raw_trigger_r = buff[offset+3] & 0x1f;
01533
01534 if((raw_trigger_l != Internal.ClassicController.RawTriggerL) ||
01535 (raw_trigger_r != Internal.ClassicController.RawTriggerR))
01536 changed |= CLASSIC_TRIGGERS_CHANGED;
01537
01538 Internal.ClassicController.RawTriggerL = raw_trigger_l;
01539 Internal.ClassicController.RawTriggerR = raw_trigger_r;
01540
01541 if(calib.MaxTriggerL != 0x00)
01542 Internal.ClassicController.TriggerL =
01543 (float)Internal.ClassicController.RawTriggerL /
01544 ((float)calib.MaxTriggerL - calib.MinTriggerL);
01545 if(calib.MaxTriggerR != 0x00)
01546 Internal.ClassicController.TriggerR =
01547 (float)Internal.ClassicController.RawTriggerR /
01548 ((float)calib.MaxTriggerR - calib.MinTriggerR);
01549 }
01550 break;
01551
01552 case BALANCE_BOARD:
01553 {
01554 wiimote_state::balance_board::sensors_raw prev_raw =
01555 Internal.BalanceBoard.Raw;
01556 Internal.BalanceBoard.Raw.TopR =
01557 (short)((short)buff[offset+0] << 8 | buff[offset+1]);
01558 Internal.BalanceBoard.Raw.BottomR =
01559 (short)((short)buff[offset+2] << 8 | buff[offset+3]);
01560 Internal.BalanceBoard.Raw.TopL =
01561 (short)((short)buff[offset+4] << 8 | buff[offset+5]);
01562 Internal.BalanceBoard.Raw.BottomL =
01563 (short)((short)buff[offset+6] << 8 | buff[offset+7]);
01564
01565 if((Internal.BalanceBoard.Raw.TopL != prev_raw.TopL) ||
01566 (Internal.BalanceBoard.Raw.TopR != prev_raw.TopR) ||
01567 (Internal.BalanceBoard.Raw.BottomL != prev_raw.BottomL) ||
01568 (Internal.BalanceBoard.Raw.BottomR != prev_raw.BottomR))
01569 changed |= BALANCE_WEIGHT_CHANGED;
01570
01571 Internal.BalanceBoard.Kg.TopL =
01572 GetBalanceValue(Internal.BalanceBoard.Raw.TopL,
01573 Internal.BalanceBoard.CalibrationInfo.Kg0 .TopL,
01574 Internal.BalanceBoard.CalibrationInfo.Kg17.TopL,
01575 Internal.BalanceBoard.CalibrationInfo.Kg34.TopL);
01576 Internal.BalanceBoard.Kg.TopR =
01577 GetBalanceValue(Internal.BalanceBoard.Raw.TopR,
01578 Internal.BalanceBoard.CalibrationInfo.Kg0 .TopR,
01579 Internal.BalanceBoard.CalibrationInfo.Kg17.TopR,
01580 Internal.BalanceBoard.CalibrationInfo.Kg34.TopR);
01581 Internal.BalanceBoard.Kg.BottomL =
01582 GetBalanceValue(Internal.BalanceBoard.Raw.BottomL,
01583 Internal.BalanceBoard.CalibrationInfo.Kg0 .BottomL,
01584 Internal.BalanceBoard.CalibrationInfo.Kg17.BottomL,
01585 Internal.BalanceBoard.CalibrationInfo.Kg34.BottomL);
01586 Internal.BalanceBoard.Kg.BottomR =
01587 GetBalanceValue(Internal.BalanceBoard.Raw.BottomR,
01588 Internal.BalanceBoard.CalibrationInfo.Kg0 .BottomR,
01589 Internal.BalanceBoard.CalibrationInfo.Kg17.BottomR,
01590 Internal.BalanceBoard.CalibrationInfo.Kg34.BottomR);
01591
01592
01593
01594 if(bCalibrateAtRest) {
01595 bCalibrateAtRest = false;
01596 TRACE(_T(".. Auto-removing 'at rest' BBoard offsets."));
01597 Internal.BalanceBoard.AtRestKg = Internal.BalanceBoard.Kg;
01598 }
01599
01600
01601 Internal.BalanceBoard.Kg.TopL -= BalanceBoard.AtRestKg.TopL;
01602 Internal.BalanceBoard.Kg.TopR -= BalanceBoard.AtRestKg.TopR;
01603 Internal.BalanceBoard.Kg.BottomL -= BalanceBoard.AtRestKg.BottomL;
01604 Internal.BalanceBoard.Kg.BottomR -= BalanceBoard.AtRestKg.BottomR;
01605
01606
01607 Internal.BalanceBoard.Kg.Total = Internal.BalanceBoard.Kg.TopL +
01608 Internal.BalanceBoard.Kg.TopR +
01609 Internal.BalanceBoard.Kg.BottomL +
01610 Internal.BalanceBoard.Kg.BottomR;
01611
01612 const float KG2LB = 2.20462262f;
01613 Internal.BalanceBoard.Lb = Internal.BalanceBoard.Kg;
01614 Internal.BalanceBoard.Lb.TopL *= KG2LB;
01615 Internal.BalanceBoard.Lb.TopR *= KG2LB;
01616 Internal.BalanceBoard.Lb.BottomL *= KG2LB;
01617 Internal.BalanceBoard.Lb.BottomR *= KG2LB;
01618 Internal.BalanceBoard.Lb.Total *= KG2LB;
01619 }
01620 break;
01621
01622 case MOTION_PLUS:
01623 {
01624 bMotionPlusDetected = true;
01625 bMotionPlusEnabled = true;
01626
01627 short yaw = ((unsigned short)buff[offset+3] & 0xFC)<<6 |
01628 (unsigned short)buff[offset+0];
01629 short pitch = ((unsigned short)buff[offset+5] & 0xFC)<<6 |
01630 (unsigned short)buff[offset+2];
01631 short roll = ((unsigned short)buff[offset+4] & 0xFC)<<6 |
01632 (unsigned short)buff[offset+1];
01633
01634
01635
01636 if((yaw != 0x3fff) || (pitch != 0x3fff) || (roll != 0x3fff))
01637 {
01638 wiimote_state::motion_plus::sensors_raw &raw = Internal.MotionPlus.Raw;
01639
01640 if((raw.Yaw != yaw) || (raw.Pitch != pitch) || (raw.Roll != roll))
01641 changed |= MOTIONPLUS_SPEED_CHANGED;
01642
01643 raw.Yaw = yaw;
01644 raw.Pitch = pitch;
01645 raw.Roll = roll;
01646
01647
01648 bool yaw_slow = (buff[offset+3] & 0x2) == 0x2;
01649 bool pitch_slow = (buff[offset+3] & 0x1) == 0x1;
01650 bool roll_slow = (buff[offset+4] & 0x2) == 0x2;
01651 float y_scale = yaw_slow? 0.05f : 0.25f;
01652 float p_scale = pitch_slow? 0.05f : 0.25f;
01653 float r_scale = roll_slow? 0.05f : 0.25f;
01654
01655 Internal.MotionPlus.Speed.Yaw = -(raw.Yaw - 0x1F7F) * y_scale;
01656 Internal.MotionPlus.Speed.Pitch = -(raw.Pitch - 0x1F7F) * p_scale;
01657 Internal.MotionPlus.Speed.Roll = -(raw.Roll - 0x1F7F) * r_scale;
01658
01659
01660 bool extension = buff[offset+4] & 1;
01661 if(extension != bMotionPlusExtension)
01662 {
01663 if(extension) {
01664 TRACE(_T(".. MotionPlus extension found."));
01665 changed |= MOTIONPLUS_EXTENSION_CONNECTED;
01666 }
01667 else{
01668 TRACE(_T(".. MotionPlus' extension disconnected."));
01669 changed |= MOTIONPLUS_EXTENSION_DISCONNECTED;
01670 }
01671 }
01672 bMotionPlusExtension = extension;
01673 }
01674
01675
01676 }
01677 break;
01678 }
01679
01680 return changed;
01681 }
01682
01683 int wiimote::ParseReadAddress (BYTE* buff)
01684 {
01685
01686 int address = buff[4]<<8 | buff[5];
01687 int size = buff[3] >> 4;
01688 int changed = 0;
01689
01690 if((buff[3] & 0x08) != 0) {
01691 WARN(_T("error: read address not valid."));
01692 _ASSERT(0);
01693 return NO_CHANGE;
01694 }
01695
01696 else if((buff[3] & 0x07) != 0)
01697 {
01698
01699 if(MotionPlusDetectCount)
01700 {
01701 --MotionPlusDetectCount;
01702 if(Internal.ExtensionType == MOTION_PLUS)
01703 {
01704 if(bMotionPlusDetected)
01705 TRACE(_T(".. MotionPlus removed."));
01706 bMotionPlusDetected = false;
01707 bMotionPlusEnabled = false;
01708
01709
01710
01711
01712 }
01713 }
01714 else
01715 WARN(_T("error: attempt to read from write-only register 0x%X."), buff[3]);
01716
01717 return NO_CHANGE;
01718 }
01719
01720
01721
01722
01723
01724
01725
01726 buff += 6;
01727
01728 switch(address)
01729 {
01730 case (REGISTER_CALIBRATION & 0xffff):
01731 {
01732 _ASSERT(size == 6);
01733 TRACE(_T(".. got wiimote calibration."));
01734 Internal.CalibrationInfo.X0 = buff[0];
01735 Internal.CalibrationInfo.Y0 = buff[1];
01736 Internal.CalibrationInfo.Z0 = buff[2];
01737 Internal.CalibrationInfo.XG = buff[4];
01738 Internal.CalibrationInfo.YG = buff[5];
01739 Internal.CalibrationInfo.ZG = buff[6];
01740
01741 }
01742 break;
01743
01744
01745
01746 case (REGISTER_EXTENSION_TYPE & 0xffff):
01747 {
01748 _ASSERT(size == 5);
01749 QWORD type = *(QWORD*)buff;
01750
01751
01752
01753 static const QWORD NUNCHUK = 0x000020A40000ULL;
01754 static const QWORD CLASSIC = 0x010120A40000ULL;
01755 static const QWORD GH3_GHWT_GUITAR = 0x030120A40000ULL;
01756 static const QWORD GHWT_DRUMS = 0x030120A40001ULL;
01757 static const QWORD BALANCE_BOARD = 0x020420A40000ULL;
01758 static const QWORD MOTION_PLUS = 0x050420A40000ULL;
01759 static const QWORD MOTION_PLUS_DETECT = 0x050020a60000ULL;
01760 static const QWORD MOTION_PLUS_DETECT2 = 0x050420a60000ULL;
01761 static const QWORD PARTIALLY_INSERTED = 0xffffffffffffULL;
01762
01763
01764 if((type == MOTION_PLUS_DETECT) || (type == MOTION_PLUS_DETECT2))
01765 {
01766 if(!bMotionPlusDetected) {
01767 TRACE(_T("Motion Plus detected!"));
01768 changed |= MOTIONPLUS_DETECTED;
01769 }
01770 bMotionPlusDetected = true;
01771 --MotionPlusDetectCount;
01772 break;
01773 }
01774
01775 #define IF_TYPE(id) if(type == id) { \
01776 \
01777 if(Internal.ExtensionType == wiimote_state::id)\
01778 break; \
01779 Internal.ExtensionType = wiimote_state::id;
01780
01781
01782 IF_TYPE(MOTION_PLUS)
01783 TRACE(_T(".. Motion Plus!"));
01784
01785 ReadAddress(REGISTER_EXTENSION_CALIBRATION, 16);
01786 bMotionPlusDetected = true;
01787 }
01788 else IF_TYPE(NUNCHUK)
01789 TRACE(_T(".. Nunchuk!"));
01790 bMotionPlusEnabled = false;
01791
01792 ReadAddress(REGISTER_EXTENSION_CALIBRATION, 16);
01793 }
01794 else IF_TYPE(CLASSIC)
01795 TRACE(_T(".. Classic Controller!"));
01796 bMotionPlusEnabled = false;
01797
01798 ReadAddress(REGISTER_EXTENSION_CALIBRATION, 16);
01799 }
01800 else IF_TYPE(GH3_GHWT_GUITAR)
01801
01802 TRACE(_T(".. GH3/GHWT Guitar Controller!"));
01803 bMotionPlusEnabled = false;
01804
01805 ReadAddress(REGISTER_EXTENSION_CALIBRATION, 16);
01806 }
01807 else IF_TYPE(GHWT_DRUMS)
01808 TRACE(_T(".. GHWT Drums!"));
01809 bMotionPlusEnabled = false;
01810
01811 ReadAddress(REGISTER_EXTENSION_CALIBRATION, 16);
01812 }
01813 else IF_TYPE(BALANCE_BOARD)
01814 TRACE(_T(".. Balance Board!"));
01815 bMotionPlusEnabled = false;
01816
01817 ReadAddress(REGISTER_BALANCE_CALIBRATION, 24);
01818 }
01819 else if(type == PARTIALLY_INSERTED) {
01820
01821 if(Internal.ExtensionType == wiimote_state::PARTIALLY_INSERTED)
01822 Sleep(50);
01823 TRACE(_T(".. partially inserted!"));
01824 bMotionPlusEnabled = false;
01825 Internal.ExtensionType = wiimote_state::PARTIALLY_INSERTED;
01826 changed |= EXTENSION_PARTIALLY_INSERTED;
01827
01828
01829 Internal.bExtension = false;
01830 RequestStatusReport();
01831 }
01832 else{
01833 TRACE(_T("unknown extension controller found (0x%I64x)"), type);
01834 }
01835 }
01836 break;
01837
01838 case (REGISTER_EXTENSION_CALIBRATION & 0xffff):
01839 case (REGISTER_BALANCE_CALIBRATION & 0xffff):
01840 {
01841
01842
01843
01844 switch(Internal.ExtensionType)
01845 {
01846 case wiimote_state::NUNCHUK:
01847 {
01848 wiimote_state::nunchuk::calibration_info
01849 &calib = Internal.Nunchuk.CalibrationInfo;
01850
01851 calib.X0 = buff[ 0];
01852 calib.Y0 = buff[ 1];
01853 calib.Z0 = buff[ 2];
01854 calib.XG = buff[ 4];
01855 calib.YG = buff[ 5];
01856 calib.ZG = buff[ 6];
01857 calib.MaxX = buff[ 8];
01858 calib.MinX = buff[ 9];
01859 calib.MidX = buff[10];
01860 calib.MaxY = buff[11];
01861 calib.MinY = buff[12];
01862 calib.MidY = buff[13];
01863
01864 changed |= NUNCHUK_CONNECTED;
01865
01866
01867 }
01868 break;
01869
01870 case wiimote_state::CLASSIC:
01871 case wiimote_state::GH3_GHWT_GUITAR:
01872 case wiimote_state::GHWT_DRUMS:
01873 {
01874 wiimote_state::classic_controller::calibration_info
01875 &calib = Internal.ClassicController.CalibrationInfo;
01876
01877 calib.MaxXL = buff[ 0] >> 2;
01878 calib.MinXL = buff[ 1] >> 2;
01879 calib.MidXL = buff[ 2] >> 2;
01880 calib.MaxYL = buff[ 3] >> 2;
01881 calib.MinYL = buff[ 4] >> 2;
01882 calib.MidYL = buff[ 5] >> 2;
01883 calib.MaxXR = buff[ 6] >> 3;
01884 calib.MinXR = buff[ 7] >> 3;
01885 calib.MidXR = buff[ 8] >> 3;
01886 calib.MaxYR = buff[ 9] >> 3;
01887 calib.MinYR = buff[10] >> 3;
01888 calib.MidYR = buff[11] >> 3;
01889
01890
01891
01892
01893
01894 calib.MinTriggerL = 0;
01895 calib.MaxTriggerL = 31;
01896 calib.MinTriggerR = 0;
01897 calib.MaxTriggerR = 31;
01898
01899 changed |= CLASSIC_CONNECTED;
01900
01901
01902 }
01903 break;
01904
01905 case BALANCE_BOARD:
01906 {
01907
01908 wiimote_state::balance_board::calibration_info
01909 &calib = Internal.BalanceBoard.CalibrationInfo;
01910
01911 calib.Kg0 .TopR = (short)((short)buff[0] << 8 | buff[1]);
01912 calib.Kg0 .BottomR = (short)((short)buff[2] << 8 | buff[3]);
01913 calib.Kg0 .TopL = (short)((short)buff[4] << 8 | buff[5]);
01914 calib.Kg0 .BottomL = (short)((short)buff[6] << 8 | buff[7]);
01915
01916 calib.Kg17.TopR = (short)((short)buff[8] << 8 | buff[9]);
01917 calib.Kg17.BottomR = (short)((short)buff[10] << 8 | buff[11]);
01918 calib.Kg17.TopL = (short)((short)buff[12] << 8 | buff[13]);
01919 calib.Kg17.BottomL = (short)((short)buff[14] << 8 | buff[15]);
01920
01921
01922 }
01923 break;
01924
01925 case MOTION_PLUS:
01926 {
01927
01928 changed |= MOTIONPLUS_ENABLED;
01929 bMotionPlusEnabled = true;
01930 bInitInProgress = false;
01931
01932
01933 }
01934 break;
01935 }
01936 case 0x34:
01937 {
01938 if(Internal.ExtensionType == BALANCE_BOARD)
01939 {
01940 wiimote_state::balance_board::calibration_info
01941 &calib = Internal.BalanceBoard.CalibrationInfo;
01942
01943
01944
01945 calib.Kg34.TopR = (short)((short)buff[0] << 8 | buff[1]);
01946 calib.Kg34.BottomR = (short)((short)buff[2] << 8 | buff[3]);
01947 calib.Kg34.TopL = (short)((short)buff[4] << 8 | buff[5]);
01948 calib.Kg34.BottomL = (short)((short)buff[6] << 8 | buff[7]);
01949
01950 changed |= BALANCE_CONNECTED;
01951
01952 SetReportType(IN_BUTTONS_BALANCE_BOARD);
01953 }
01954
01955 }
01956 bInitInProgress = false;
01957 }
01958 break;
01959
01960 default:
01961
01962 break;
01963 }
01964
01965 return changed;
01966 }
01967
01968 void wiimote::ReadCalibration ()
01969 {
01970 TRACE(_T("Requestion wiimote calibration:"));
01971
01972 ReadAddress(REGISTER_CALIBRATION, 7);
01973 }
01974
01975 void wiimote::EnableIR (wiimote_state::ir::mode mode)
01976 {
01977 Internal.IR.Mode = mode;
01978
01979 BYTE buff [REPORT_LENGTH] = {0};
01980 buff[0] = OUT_IR;
01981 buff[1] = 0x04 | GetRumbleBit();
01982 WriteReport(buff);
01983
01984 memset(buff, 0, REPORT_LENGTH);
01985 buff[0] = OUT_IR2;
01986 buff[1] = 0x04 | GetRumbleBit();
01987 WriteReport(buff);
01988
01989 static const BYTE ir_sens1[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00,
01990 0xc0};
01991 static const BYTE ir_sens2[] = {0x40, 0x00};
01992
01993 WriteData(REGISTER_IR, 0x08);
01994 Sleep(25);
01995 WriteData(REGISTER_IR_SENSITIVITY_1, sizeof(ir_sens1), ir_sens1);
01996 WriteData(REGISTER_IR_SENSITIVITY_2, sizeof(ir_sens2), ir_sens2);
01997 WriteData(REGISTER_IR_MODE, (BYTE)mode);
01998 }
01999
02000 void wiimote::DisableIR ()
02001 {
02002 Internal.IR.Mode = wiimote_state::ir::OFF;
02003
02004 BYTE buff [REPORT_LENGTH] = {0};
02005 buff[0] = OUT_IR;
02006 buff[1] = GetRumbleBit();
02007 WriteReport(buff);
02008
02009 memset(buff, 0, REPORT_LENGTH);
02010 buff[0] = OUT_IR2;
02011 buff[1] = GetRumbleBit();
02012 WriteReport(buff);
02013 }
02014
02015 unsigned __stdcall wiimote::HIDwriteThreadfunc (void* param)
02016 {
02017 _ASSERT(param);
02018 TRACE(_T("(starting HID write thread)"));
02019 wiimote &remote = *(wiimote*)param;
02020
02021 while(remote.Handle != INVALID_HANDLE_VALUE)
02022 {
02023
02024 #ifdef USE_DYNAMIC_HIDQUEUE
02025 if(!remote.HIDwriteQueue.empty())
02026 #else
02027 if(!remote.HID.IsEmpty())
02028 #endif
02029 {
02030 #ifdef BEEP_DEBUG_WRITES
02031 Beep(1500,1);
02032 #endif
02033 EnterCriticalSection(&remote.HIDwriteQueueLock);
02034 #ifdef USE_DYNAMIC_HIDQUEUE
02035 BYTE *buff = remote.HIDwriteQueue.front();
02036 _ASSERT(buff);
02037 #else
02038 BYTE *buff = remote.HID.Queue[remote.HID.ReadIndex].Report;
02039 #endif
02040 LeaveCriticalSection(&remote.HIDwriteQueueLock);
02041
02042 if(!_HidD_SetOutputReport(remote.Handle, buff, REPORT_LENGTH))
02043 {
02044 DWORD err = GetLastError();
02045 if(err==ERROR_BUSY)
02046 TRACE(_T("**** HID WRITE: BUSY ****"));
02047 else if(err == ERROR_NOT_READY)
02048 TRACE(_T("**** HID WRITE: NOT READY ****"));
02049
02050 if((err != ERROR_BUSY) &&
02051 (err != ERROR_NOT_READY))
02052 {
02053 if(err == ERROR_NOT_SUPPORTED) {
02054 WARN(_T("BT Stack doesn't suport HID writes!"));
02055 goto remove_entry;
02056 }
02057 else{
02058 DEEP_TRACE(_T("HID write failed (err %u)! - "), err);
02059
02060 if(remote.IsConnected())
02061 remote.bConnectionLost = true;
02062 }
02063
02064
02065 }
02066 }
02067 else{
02068 remove_entry:
02069 EnterCriticalSection(&remote.HIDwriteQueueLock);
02070 #ifdef USE_DYNAMIC_HIDQUEUE
02071 remote.HIDwriteQueue.pop();
02072 delete[] buff;
02073 #else
02074 remote.HID.ReadIndex++;
02075 remote.HID.ReadIndex &= (hid::MAX_QUEUE_ENTRIES-1);
02076 #endif
02077 LeaveCriticalSection(&remote.HIDwriteQueueLock);
02078 }
02079 }
02080 Sleep(1);
02081 }
02082
02083 TRACE(_T("ending HID write thread"));
02084 return 0;
02085 }
02086
02087 bool wiimote::WriteReport (BYTE *buff)
02088 {
02089 #ifdef BEEP_DEBUG_WRITES
02090 Beep(2000,1);
02091 #endif
02092
02093 #ifdef _DEBUG
02094 #define DEEP_TRACE_TYPE(type) case OUT_##type: DEEP_TRACE(_T("WriteReport: ")\
02095 _T(#type)); break
02096 switch(buff[0])
02097 {
02098 DEEP_TRACE_TYPE(NONE);
02099 DEEP_TRACE_TYPE(LEDs);
02100 DEEP_TRACE_TYPE(TYPE);
02101 DEEP_TRACE_TYPE(IR);
02102 DEEP_TRACE_TYPE(SPEAKER_ENABLE);
02103 DEEP_TRACE_TYPE(STATUS);
02104 DEEP_TRACE_TYPE(WRITEMEMORY);
02105 DEEP_TRACE_TYPE(READMEMORY);
02106 DEEP_TRACE_TYPE(SPEAKER_DATA);
02107 DEEP_TRACE_TYPE(SPEAKER_MUTE);
02108 DEEP_TRACE_TYPE(IR2);
02109 default:
02110 TRACE(_T("WriteReport: type [%02x][%02x]"), buff[1], buff[2]);
02111 }
02112 #endif
02113
02114 if(bUseHIDwrite)
02115 {
02116
02117
02118 if(!HIDwriteThread)
02119 {
02120 HIDwriteThread = (HANDLE)_beginthreadex(NULL, 0, HIDwriteThreadfunc,
02121 this, 0, NULL);
02122 _ASSERT(HIDwriteThread);
02123 if(!HIDwriteThread) {
02124 WARN(_T("couldn't create HID write thread!"));
02125 return false;
02126 }
02127 SetThreadPriority(HIDwriteThread, WORKER_THREAD_PRIORITY);
02128 }
02129
02130
02131 #ifdef USE_DYNAMIC_HIDQUEUE
02132 EnterCriticalSection(&HIDwriteQueueLock);
02133 BYTE *buff_copy = new BYTE[REPORT_LENGTH];
02134 #else
02135
02136 if(!HID.Queue && !HID.Allocate())
02137 return false;
02138
02139 EnterCriticalSection(&HIDwriteQueueLock);
02140 BYTE *buff_copy = HID.Queue[HID.WriteIndex].Report;
02141 #endif
02142 memcpy(buff_copy, buff, REPORT_LENGTH);
02143
02144 #ifdef USE_DYNAMIC_HIDQUEUE
02145 HIDwriteQueue.push(buff_copy);
02146 #else
02147 HID.WriteIndex++;
02148 HID.WriteIndex &= (HID.MAX_QUEUE_ENTRIES-1);
02149
02150
02151
02152
02153
02154
02155
02156
02157
02158
02159 _ASSERT(HID.WriteIndex != HID.ReadIndex);
02160 #endif
02161 LeaveCriticalSection(&HIDwriteQueueLock);
02162 return true;
02163 }
02164
02165
02166 DWORD written;
02167 if(!WriteFile(Handle, buff, REPORT_LENGTH, &written, &Overlapped))
02168 {
02169 DWORD error = GetLastError();
02170 if(error != ERROR_IO_PENDING) {
02171 TRACE(_T("WriteFile failed, err: %u!"), error);
02172
02173 if(IsConnected())
02174 bConnectionLost = true;
02175 #ifndef USE_DYNAMIC_HIDQUEUE
02176 HID.Deallocate();
02177 #endif
02178 return false;
02179 }
02180 }
02181 return true;
02182 }
02183
02184
02185
02186 bool wiimote::MuteSpeaker (bool on)
02187 {
02188 _ASSERT(IsConnected());
02189 if(!IsConnected())
02190 return false;
02191
02192 if(Internal.Speaker.bMuted == on)
02193 return true;
02194
02195 if(on) TRACE(_T("muting speaker." ));
02196 else TRACE(_T("unmuting speaker."));
02197
02198 BYTE buff [REPORT_LENGTH] = {0};
02199 buff[0] = OUT_SPEAKER_MUTE;
02200 buff[1] = (on? 0x04 : 0x00) | GetRumbleBit();
02201 if(!WriteReport(buff))
02202 return false;
02203 Sleep(1);
02204 Internal.Speaker.bMuted = on;
02205 return true;
02206 }
02207
02208 bool wiimote::EnableSpeaker (bool on)
02209 {
02210 _ASSERT(IsConnected());
02211 if(!IsConnected())
02212 return false;
02213
02214 if(Internal.Speaker.bEnabled == on)
02215 return true;
02216
02217 if(on) TRACE(_T("enabling speaker.")); else TRACE(_T("disabling speaker."));
02218
02219 BYTE buff [REPORT_LENGTH] = {0};
02220 buff[0] = OUT_SPEAKER_ENABLE;
02221 buff[1] = (on? 0x04 : 0x00) | GetRumbleBit();
02222 if(!WriteReport(buff))
02223 return false;
02224
02225 if(!on) {
02226 Internal.Speaker.Freq = FREQ_NONE;
02227 Internal.Speaker.Volume = 0;
02228 MuteSpeaker(true);
02229 }
02230
02231 Internal.Speaker.bEnabled = on;
02232 return true;
02233 }
02234
02235 #ifdef TR4 // TEMP, ignore
02236 extern int hzinc;
02237 #endif
02238
02239 unsigned __stdcall wiimote::SampleStreamThreadfunc (void* param)
02240 {
02241 TRACE(_T("(starting sample thread)"));
02242
02243 wiimote &remote = *(wiimote*)param;
02244
02245 static BYTE squarewave_report[REPORT_LENGTH] =
02246 { OUT_SPEAKER_DATA, 20<<3, 0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,
02247 0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3, };
02248 static BYTE sample_report [REPORT_LENGTH] =
02249 { OUT_SPEAKER_DATA, 0 };
02250
02251 bool last_playing = false;
02252 DWORD frame = 0;
02253 DWORD frame_start = 0;
02254 unsigned total_samples = 0;
02255 unsigned sample_index = 0;
02256 wiimote_sample *current_sample = NULL;
02257
02258
02259 while(remote.IsConnected())
02260 {
02261 bool playing = remote.IsPlayingAudio();
02262
02263 if(!playing)
02264 Sleep(1);
02265 else{
02266 const unsigned freq_hz = FreqLookup[remote.Internal.Speaker.Freq];
02267 #ifdef TR4
02268 const float frame_ms = 1000 / ((freq_hz+hzinc) / 40.f);
02269 #else
02270 const float frame_ms = 1000 / (freq_hz / 40.f);
02271 #endif
02272
02273
02274 bool sample_changed = (current_sample != remote.CurrentSample);
02275 current_sample = (wiimote_sample*)remote.CurrentSample;
02276
02277
02278
02279
02280 #ifdef FIRSTFRAME_IS_SILENT
02281 bool silent_frame = false;
02282 #endif
02283 if(!last_playing || sample_changed) {
02284 frame = 0;
02285 frame_start = timeGetTime();
02286 total_samples = current_sample? current_sample->length : 0;
02287 sample_index = 0;
02288 #ifdef FIRSTFRAME_IS_SILENT
02289 silent_frame = true;
02290 #endif
02291 }
02292
02293
02294 if(current_sample)
02295 {
02296 if(sample_index < current_sample->length)
02297 {
02298
02299 unsigned samples_left = (current_sample->length - sample_index);
02300 unsigned report_samples = min(samples_left, (unsigned)40);
02301
02302 unsigned report_entries = (report_samples+1) >> 1;
02303
02304 sample_report[1] = (BYTE)((report_entries<<3) |
02305 remote.GetRumbleBit());
02306 #ifdef FIRSTFRAME_IS_SILENT
02307 if(silent_frame) {
02308
02309 for(unsigned index=0; index<report_entries; index++)
02310 sample_report[2+index] = 0;
02311 remote.WriteReport(sample_report);
02312 }
02313 else
02314 #endif
02315 {
02316 for(unsigned index=0; index<report_entries; index++)
02317 sample_report[2+index] =
02318 current_sample->samples[(sample_index>>1)+index];
02319 remote.WriteReport(sample_report);
02320 sample_index += report_samples;
02321 }
02322 }
02323 else{
02324
02325 remote.CurrentSample = NULL;
02326 current_sample = NULL;
02327 remote.Internal.Speaker.Freq = FREQ_NONE;
02328 remote.Internal.Speaker.Volume = 0;
02329 }
02330 }
02331
02332 else{
02333 squarewave_report[1] = (20<<3) | remote.GetRumbleBit();
02334 remote.WriteReport(squarewave_report);
02335 #if 0
02336
02337 DWORD elapsed = (timeGetTime()-frame_start);
02338 unsigned total_samples = frame * 40;
02339 float elapsed_secs = elapsed / 1000.f;
02340 float sent_persec = total_samples / elapsed_secs;
02341 #endif
02342 }
02343
02344 frame++;
02345
02346
02347
02348
02349
02350 while((timeGetTime()-frame_start) < (unsigned)(frame*frame_ms))
02351 Sleep(1);
02352
02353 }
02354
02355 last_playing = playing;
02356 }
02357
02358 TRACE(_T("(ending sample thread)"));
02359 return 0;
02360 }
02361
02362 bool wiimote::Load16bitMonoSampleWAV (const TCHAR* filepath, wiimote_sample &out)
02363 {
02364
02365
02366
02367 memset(&out, 0, sizeof(out));
02368
02369 TRACE(_T("Loading '%s'"), filepath);
02370
02371 FILE *file;
02372 #if (_MSC_VER >= 1400) // VC 2005+
02373 _tfopen_s(&file, filepath, _T("rb"));
02374 #else
02375 file = _tfopen(filepath, _T("rb"));
02376 #endif
02377 _ASSERT(file);
02378 if(!file) {
02379 WARN(_T("Couldn't open '%s"), filepath);
02380 return false;
02381 }
02382
02383
02384 struct riff_chunkheader {
02385 char ckID [4];
02386 DWORD ckSize;
02387 char formType [4];
02388 };
02389 struct chunk_header {
02390 char ckID [4];
02391 DWORD ckSize;
02392 };
02393 union {
02394 WAVEFORMATEX x;
02395 WAVEFORMATEXTENSIBLE xe;
02396 } wf = {0};
02397
02398 riff_chunkheader riff_chunkheader;
02399 chunk_header chunk_header;
02400 speaker_freq freq = FREQ_NONE;
02401
02402 #define READ(data) if(fread(&data, sizeof(data), 1, file) != 1) { \
02403 TRACE(_T(".wav file corrupt")); \
02404 fclose(file); \
02405 return false; \
02406 }
02407 #define READ_SIZE(ptr,size) if(fread(ptr, size, 1, file) != 1) { \
02408 TRACE(_T(".wav file corrupt")); \
02409 fclose(file); \
02410 return false; \
02411 }
02412
02413 READ(riff_chunkheader);
02414
02415
02416 _ASSERT(!strncmp(riff_chunkheader.ckID, "RIFF", 4));
02417 if(strncmp(riff_chunkheader.ckID, "RIFF", 4))
02418 goto unsupported;
02419
02420 _ASSERT(!strncmp(riff_chunkheader.formType, "WAVE", 4));
02421 if(strncmp(riff_chunkheader.formType, "WAVE", 4))
02422 goto unsupported;
02423
02424
02425 while(1)
02426 {
02427 READ(chunk_header);
02428
02429 if(!strncmp(chunk_header.ckID, "fmt ", 4))
02430 {
02431
02432 if(chunk_header.ckSize < 16 ||
02433 chunk_header.ckSize > sizeof(WAVEFORMATEXTENSIBLE))
02434 goto unsupported;
02435
02436 READ_SIZE((BYTE*)&wf.x, chunk_header.ckSize);
02437
02438
02439 bool extensible = (wf.x.wFormatTag == WAVE_FORMAT_EXTENSIBLE);
02440 int format = extensible? wf.xe.SubFormat.Data1 :
02441 wf.x .wFormatTag;
02442
02443
02444 if(format != WAVE_FORMAT_PCM) {
02445 TRACE(_T(".. not uncompressed PCM"));
02446 goto unsupported;
02447 }
02448
02449
02450 if((wf.x.nChannels != 1) || (wf.x.wBitsPerSample != 16)) {
02451 TRACE(_T(".. %d bit, %d channel%s"), wf.x.wBitsPerSample,
02452 wf.x.nChannels,
02453 (wf.x.nChannels>1? _T("s"):_T("")));
02454 goto unsupported;
02455 }
02456
02457
02458
02459 unsigned sample_freq = wf.x.nSamplesPerSec;
02460 const unsigned epsilon = 100;
02461
02462 for(unsigned index=1; index<ARRAY_ENTRIES(FreqLookup); index++)
02463 {
02464 if((sample_freq+epsilon) >= FreqLookup[index] &&
02465 (sample_freq-epsilon) <= FreqLookup[index]) {
02466 freq = (speaker_freq)index;
02467 TRACE(_T(".. using speaker freq %u"), FreqLookup[index]);
02468 break;
02469 }
02470 }
02471 if(freq == FREQ_NONE) {
02472 WARN(_T("Couldn't (loosely) match .wav samplerate %u Hz to speaker"),
02473 sample_freq);
02474 goto unsupported;
02475 }
02476 }
02477 else if(!strncmp(chunk_header.ckID, "data", 4))
02478 {
02479
02480 if(!wf.x.nBlockAlign)
02481 goto corrupt_file;
02482
02483
02484 unsigned total_samples = chunk_header.ckSize / wf.x.nBlockAlign;
02485 if(total_samples == 0)
02486 goto corrupt_file;
02487
02488 short *samples = new short[total_samples];
02489 size_t read = fread(samples, 2, total_samples, file);
02490 fclose(file);
02491 if(read != total_samples)
02492 {
02493 if(read == 0) {
02494 delete[] samples;
02495 goto corrupt_file;
02496 }
02497
02498 WARN(_T("found %s .wav audio data than expected (%u/%u samples)"),
02499 ((read < total_samples)? _T("less") : _T("more")),
02500 read, total_samples);
02501
02502 total_samples = read;
02503 }
02504
02505
02506 bool res = Convert16bitMonoSamples(samples, true, total_samples, freq,
02507 out);
02508 delete[] samples;
02509 return res;
02510 }
02511 else{
02512
02513 DWORD chunk_bytes = (chunk_header.ckSize + 1) & ~1L;
02514 if(fseek(file, chunk_bytes, SEEK_CUR))
02515 goto corrupt_file;
02516 }
02517 }
02518
02519 corrupt_file:
02520 WARN(_T(".wav file is corrupt"));
02521 fclose(file);
02522 return false;
02523
02524 unsupported:
02525 WARN(_T(".wav file format not supported (must be mono 16bit PCM)"));
02526 fclose(file);
02527 return false;
02528 }
02529
02530 bool wiimote::Load16BitMonoSampleRAW (const TCHAR* filepath,
02531 bool _signed,
02532 speaker_freq freq,
02533 wiimote_sample &out)
02534 {
02535
02536
02537
02538 memset(&out, 0, sizeof(out));
02539
02540
02541 struct _stat file_info;
02542 if(_tstat(filepath, &file_info)) {
02543 WARN(_T("couldn't get filesize for '%s'"), filepath);
02544 return false;
02545 }
02546
02547 DWORD len = file_info.st_size;
02548 _ASSERT(len);
02549 if(!len) {
02550 WARN(_T("zero-size sample file '%s'"), filepath);
02551 return false;
02552 }
02553
02554 unsigned total_samples = (len+1) / 2;
02555
02556 short *samples = new short[total_samples];
02557 _ASSERT(samples);
02558 if(!samples) {
02559 TRACE(_T("Couldn't open '%s"), filepath);
02560 return false;
02561 }
02562
02563
02564 FILE *file;
02565 bool res;
02566 #if (_MSC_VER >= 1400) // VC 2005+
02567 _tfopen_s(&file, filepath, _T("rb"));
02568 #else
02569 file = _tfopen(filepath, _T("rb"));
02570 #endif
02571 _ASSERT(file);
02572 if(!file) {
02573 TRACE(_T("Couldn't open '%s"), filepath);
02574 goto error;
02575 }
02576
02577 res = (fread(samples, 1, len, file) == len);
02578 fclose(file);
02579 if(!res) {
02580 WARN(_T("Couldn't load file '%s'"), filepath);
02581 goto error;
02582 }
02583
02584
02585 res = Convert16bitMonoSamples(samples, _signed, total_samples, freq, out);
02586 delete[] samples;
02587 return res;
02588
02589 error:
02590 delete[] samples;
02591 return false;
02592 }
02593
02594 bool wiimote::Convert16bitMonoSamples (const short* samples,
02595 bool _signed,
02596 DWORD length,
02597 speaker_freq freq,
02598 wiimote_sample &out)
02599 {
02600
02601
02602
02603 memset(&out, 0, sizeof(0));
02604
02605 _ASSERT(samples && length);
02606 if(!samples || !length)
02607 return false;
02608
02609
02610 out.samples = new BYTE[length];
02611 _ASSERT(out.samples);
02612 if(!out.samples)
02613 return false;
02614
02615
02616 memset(out.samples, 0, length);
02617 out.length = length;
02618 out.freq = freq;
02619
02620
02621
02622 static const int index_table[16] = { -1, -1, -1, -1, 2, 4, 6, 8,
02623 -1, -1, -1, -1, 2, 4, 6, 8 };
02624 static const int diff_table [16] = { 1, 3, 5, 7, 9, 11, 13, 15,
02625 -1, -3, -5, -7, -9, -11, -13, 15 };
02626 static const int step_scale [16] = { 230, 230, 230, 230, 307, 409, 512, 614,
02627 230, 230, 230, 230, 307, 409, 512, 614 };
02628
02629
02630 int adpcm_prev_value = 0;
02631 int adpcm_step = 127;
02632
02633 for(size_t i=0; i<length; i++)
02634 {
02635
02636 int value = samples[i];
02637 if(!_signed)
02638 value -= 32768;
02639
02640 int diff = value - adpcm_prev_value;
02641 BYTE encoded_val = 0;
02642 if(diff < 0) {
02643 encoded_val |= 8;
02644 diff = -diff;
02645 }
02646 diff = (diff << 2) / adpcm_step;
02647 if (diff > 7)
02648 diff = 7;
02649 encoded_val |= diff;
02650 adpcm_prev_value += ((adpcm_step * diff_table[encoded_val]) / 8);
02651 if(adpcm_prev_value > 0x7fff)
02652 adpcm_prev_value = 0x7fff;
02653 if(adpcm_prev_value < -0x8000)
02654 adpcm_prev_value = -0x8000;
02655 adpcm_step = (adpcm_step * step_scale[encoded_val]) >> 8;
02656 if(adpcm_step < 127)
02657 adpcm_step = 127;
02658 if(adpcm_step > 24567)
02659 adpcm_step = 24567;
02660 if(i & 1)
02661 out.samples[i>>1] |= encoded_val;
02662 else
02663 out.samples[i>>1] |= encoded_val << 4;
02664 }
02665
02666 return true;
02667 }
02668
02669 bool wiimote::PlaySample (const wiimote_sample &sample, BYTE volume,
02670 speaker_freq freq_override)
02671 {
02672 _ASSERT(IsConnected());
02673 if(!IsConnected())
02674 return false;
02675
02676 speaker_freq freq = freq_override? freq_override : sample.freq;
02677
02678 TRACE(_T("playing sample."));
02679 EnableSpeaker(true);
02680 MuteSpeaker (true);
02681
02682 #if 0
02683
02684 BYTE bytes[9] = { 0x00, 0x00, 0x00, 10+freq, vol, 0x00, 0x00, 0x01, 0x01 };
02685 WriteData(0x04a20001, sizeof(bytes), bytes);
02686 #else
02687
02688 WriteData(0x04a20009, 0x01);
02689
02690 WriteData(0x04a20001, 0x08);
02691
02692 BYTE bytes[7] = { 0x00, 0x00, 0x00, 10+(BYTE)freq, volume, 0x00, 0x00 };
02693 WriteData(0x04a20001, sizeof(bytes), bytes);
02694
02695 WriteData(0x04a20008, 0x01);
02696 #endif
02697
02698 Internal.Speaker.Freq = freq;
02699 Internal.Speaker.Volume = volume;
02700 CurrentSample = &sample;
02701
02702 MuteSpeaker(false);
02703
02704 return StartSampleThread();
02705 }
02706
02707 bool wiimote::StartSampleThread ()
02708 {
02709 if(SampleThread)
02710 return true;
02711
02712 SampleThread = (HANDLE)_beginthreadex(NULL, 0, SampleStreamThreadfunc,
02713 this, 0, NULL);
02714 _ASSERT(SampleThread);
02715 if(!SampleThread) {
02716 WARN(_T("couldn't create sample thread!"));
02717 MuteSpeaker (true);
02718 EnableSpeaker(false);
02719 return false;
02720 }
02721 SetThreadPriority(SampleThread, WORKER_THREAD_PRIORITY);
02722 return true;
02723 }
02724
02725 bool wiimote::PlaySquareWave (speaker_freq freq, BYTE volume)
02726 {
02727 _ASSERT(IsConnected());
02728 if(!IsConnected())
02729 return false;
02730
02731
02732 if(IsPlayingSample())
02733 CurrentSample = NULL;
02734
02735 else if(IsPlayingAudio() && (Internal.Speaker.Freq == freq) &&
02736 (Internal.Speaker.Volume == volume))
02737 return true;
02738
02739 TRACE(_T("playing square wave."));
02740
02741 CurrentSample = 0;
02742
02743 EnableSpeaker(true);
02744 MuteSpeaker (true);
02745
02746 #if 0
02747
02748 BYTE bytes[9] = { 0x00, 0x00, 0x00, freq, volume, 0x00, 0x00, 0x01, 0x1 };
02749 WriteData(0x04a20001, sizeof(bytes), bytes);
02750 #else
02751
02752 WriteData(0x04a20009, 0x01);
02753
02754 WriteData(0x04a20001, 0x08);
02755
02756
02757 BYTE bytes[7] = { 0x00, 0x00, 0x00, 10+(BYTE)freq, volume, 0x00, 0x00 };
02758 WriteData(0x04a20001, sizeof(bytes), bytes);
02759
02760 WriteData(0x04a20008, 0x01);
02761 #endif
02762
02763 Internal.Speaker.Freq = freq;
02764 Internal.Speaker.Volume = volume;
02765
02766 MuteSpeaker(false);
02767 return StartSampleThread();
02768 }
02769
02770 void wiimote::RecordState (state_history &events_out,
02771 unsigned max_time_ms,
02772 state_change_flags change_trigger)
02773 {
02774
02775 if(Recording.bEnabled)
02776 StopRecording();
02777
02778
02779 if(!events_out.empty())
02780 events_out.clear();
02781
02782
02783 Recording.StateHistory = &events_out;
02784 Recording.StartTimeMS = timeGetTime();
02785 Recording.EndTimeMS = Recording.StartTimeMS + max_time_ms;
02786 Recording.TriggerFlags = change_trigger;
02787
02788
02789
02790
02791
02792 Recording.bEnabled = true;
02793 }
02794
02795 void wiimote::StopRecording ()
02796 {
02797 if(!Recording.bEnabled)
02798 return;
02799
02800 Recording.bEnabled = false;
02801
02802
02803 Sleep(10);
02804 }
02805
02806