00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifdef _MSC_VER // VC
00012 # pragma once
00013 #endif
00014
00015 #ifndef _WIIMOTE_H
00016 # define _WIIMOTE_H
00017
00018 #define WIN32_LEAN_AND_MEAN
00019 #include <windows.h>
00020 #include <tchar.h>
00021 #include <queue>
00022 #include <list>
00023
00024 #ifndef QWORD
00025 typedef unsigned __int64 QWORD;
00026 #endif
00027
00028 #ifdef _MSC_VER // VC-specific: _DEBUG build only _ASSERT() sanity checks
00029 # include <crtdbg.h>
00030 #elif defined(__MINGW32__) // define NDEBUG to disable assert
00031 # include <assert.h>
00032 # define _ASSERT assert
00033 #else
00034 # define _ASSERT(x) ((void)0) // (add your compiler's implementation if you like)
00035 #endif
00036
00037
00038
00039
00040 #include "wiimote_state.h"
00041
00042
00043
00044
00045
00046
00047
00048 #define REQUEST_STATUS_EVERY_MS 1000
00049 #define DETECT_MPLUS_EVERY_MS 1000
00050 #define DETECT_MPLUS_COUNT 1 // # of tries in quick succession
00051
00052
00053 #define WORKER_THREAD_PRIORITY THREAD_PRIORITY_HIGHEST
00054
00055
00056 #define WIIYOURSELF_VERSION_MAJOR 1
00057 #define WIIYOURSELF_VERSION_MINOR1 1
00058 #define WIIYOURSELF_VERSION_MINOR2 5
00059
00060 #define WIIYOURSELF_VERSION_STR _T("1.15")
00061
00062
00063 #define TOTAL_BUTTON_BITS 16 // Number of bits for (Classic)ButtonNameFromBit[]
00064 #define TOTAL_FREQUENCIES 10 // Number of frequencies (see speaker_freq[])
00065
00066
00067 typedef HANDLE EVENT;
00068
00069
00070
00071
00072
00073
00074
00075 typedef void (*state_changed_callback) (class wiimote &owner,
00076 state_change_flags changed,
00077 const wiimote_state &new_state);
00078
00079
00080 typedef BOOLEAN (__stdcall *hidwrite_ptr)(HANDLE HidDeviceObject,
00081 PVOID ReportBuffer,
00082 ULONG ReportBufferLength);
00083
00084
00085 struct wiimote_state_event {
00086 DWORD time_ms;
00087 wiimote_state state;
00088 };
00089
00090
00091
00092 class wiimote : public wiimote_state
00093 {
00094 public:
00095 wiimote ();
00096 virtual ~wiimote ();
00097
00098 public:
00099
00100
00101 inline bool operator == (const wiimote& remote)
00102 { return Handle == remote.Handle; }
00103 inline bool operator != (const wiimote& remote)
00104 { return Handle != remote.Handle; }
00105
00106
00107
00108 enum input_report
00109 {
00110
00111 IN_BUTTONS = 0x30,
00112 IN_BUTTONS_ACCEL = 0x31,
00113 IN_BUTTONS_ACCEL_IR = 0x33,
00114 IN_BUTTONS_ACCEL_EXT = 0x35,
00115 IN_BUTTONS_ACCEL_IR_EXT = 0x37,
00116 IN_BUTTONS_BALANCE_BOARD = 0x32,
00117 };
00118
00119 static const TCHAR* ReportTypeName [];
00120
00121
00122 public:
00123 inline bool IsConnected () const { return bStatusReceived; }
00124
00125 inline bool ConnectionLost () const { return bConnectionLost; }
00126 inline bool IsBalanceBoard () const { return (Internal.bExtension &&
00127 (Internal.ExtensionType==wiimote_state::BALANCE_BOARD)); }
00128 inline bool NunchukConnected () const { return (Internal.bExtension &&
00129 (Internal.ExtensionType==wiimote_state::NUNCHUK)); }
00130 inline bool ClassicConnected () const { return (Internal.bExtension &&
00131 (Internal.ExtensionType==wiimote_state::CLASSIC)); }
00132 inline bool MotionPlusConnected () const { return bMotionPlusDetected; }
00133 inline bool MotionPlusEnabled () const { return bMotionPlusEnabled; }
00134 inline bool MotionPlusHasExtension() const { return bMotionPlusExtension; }
00135 inline bool IsPlayingAudio () const { return (Internal.Speaker.Freq &&
00136 Internal.Speaker.Volume); }
00137 inline bool IsPlayingSample () const { return IsPlayingAudio() &&
00138 (CurrentSample != NULL); }
00139 inline bool IsUsingHIDwrites () const { return bUseHIDwrite; }
00140 inline bool IsRecordingState () const { return Recording.bEnabled; }
00141
00142 static inline unsigned TotalConnected() { return _TotalConnected; }
00143
00144
00145 public:
00146 QWORD UniqueID;
00147
00148
00149
00150
00151 #ifdef ID2_FROM_DEVICEPATH
00152 QWORD UniqueID2;
00153
00154
00155
00156
00157 #endif
00158
00159 state_changed_callback ChangedCallback;
00160
00161
00162 state_change_flags CallbackTriggerFlags;
00163
00164 virtual void ChangedNotifier (state_change_flags changed,
00165 const wiimote_state &new_state) {};
00166
00167
00168 static const TCHAR* ButtonNameFromBit [TOTAL_BUTTON_BITS];
00169 static const TCHAR* GetButtonNameFromBit (unsigned index)
00170 {
00171 _ASSERT(index < TOTAL_BUTTON_BITS);
00172 if(index >= TOTAL_BUTTON_BITS)
00173 return _T("[invalid index]");
00174 return ButtonNameFromBit[index];
00175 }
00176
00177
00178 static const TCHAR* ClassicButtonNameFromBit [TOTAL_BUTTON_BITS];
00179 static const TCHAR* GetClassicButtonNameFromBit (unsigned index)
00180 {
00181 _ASSERT(index < TOTAL_BUTTON_BITS);
00182 if(index >= TOTAL_BUTTON_BITS)
00183 return _T("[invalid index]");
00184 return ClassicButtonNameFromBit[index];
00185 }
00186
00187
00188 static const unsigned FreqLookup [TOTAL_FREQUENCIES];
00189 static const unsigned GetFreqLookup (unsigned index)
00190 {
00191 _ASSERT(index < TOTAL_FREQUENCIES);
00192 if(index >= TOTAL_FREQUENCIES)
00193 return 0;
00194 return FreqLookup[index];
00195 }
00196
00197 public:
00198
00199
00200
00201
00202
00203
00204
00205 static const unsigned FIRST_AVAILABLE = 0xffffffff;
00206 bool Connect (unsigned wiimote_index = FIRST_AVAILABLE,
00207 bool force_hidwrites = false);
00208
00209 void Disconnect ();
00210
00211
00212
00213
00214
00215
00216 void SetReportType (input_report type, bool continuous = false);
00217
00218
00219
00220
00221
00222
00223
00224 bool EnableMotionPlus ();
00225 bool DisableMotionPlus ();
00226
00227
00228
00229
00230
00231
00232 void CalibrateAtRest ();
00233
00234
00235
00236
00237
00238
00239
00240
00241 state_change_flags RefreshState ();
00242
00243
00244
00245 void Reset ();
00246
00247 void SetLEDs (BYTE led_bits);
00248
00249 void SetRumble (bool on);
00250
00251 void RumbleForAsync (unsigned milliseconds);
00252
00253
00254 bool MuteSpeaker (bool on);
00255 bool EnableSpeaker (bool on);
00256 bool PlaySquareWave (speaker_freq freq, BYTE volume = 0x40);
00257
00258
00259 bool PlaySample (const wiimote_sample &sample,
00260 BYTE volume = 0x40,
00261 speaker_freq freq_override = FREQ_NONE);
00262
00263
00264
00265 static bool Load16bitMonoSampleWAV (const TCHAR* filepath,
00266 wiimote_sample &out);
00267
00268 static bool Load16BitMonoSampleRAW (const TCHAR* filepath,
00269 bool _signed,
00270 speaker_freq freq,
00271 wiimote_sample &out);
00272
00273 static bool Convert16bitMonoSamples (const short* samples,
00274 bool _signed,
00275 DWORD length,
00276 speaker_freq freq,
00277 wiimote_sample &out);
00278
00279
00280
00281
00282 #ifndef SWIG // !Python Wrapper
00283 typedef wiimote_state_event state_event;
00284 #endif
00285 typedef std::list<state_event> state_history;
00286 static const unsigned UNTIL_STOP = 0xffffffff;
00287
00288
00289
00290
00291
00292
00293 void RecordState (state_history &events_out,
00294 unsigned max_time_ms = UNTIL_STOP,
00295 state_change_flags change_trigger = CHANGED_ALL);
00296 void StopRecording ();
00297
00298
00299 private:
00300
00301 bool BeginAsyncRead ();
00302
00303 void RequestStatusReport ();
00304
00305
00306 bool ReadAddress (int address, short size);
00307
00308 inline void WriteData (int address, BYTE data) { WriteData(address, 1, &data); }
00309
00310 void WriteData (int address, BYTE size, const BYTE* buff);
00311
00312 void OnReadData (DWORD bytes_read);
00313
00314 int ParseInput (BYTE* buff);
00315
00316
00317 void DetectMotionPlusExtensionAsync ();
00318
00319 void InitializeExtension ();
00320
00321 int ParseStatus (BYTE* buff);
00322
00323 int ParseButtons (BYTE* buff);
00324
00325 int ParseAccel (BYTE* buff);
00326 bool EstimateOrientationFrom(wiimote_state::acceleration &accel);
00327 void ApplyJoystickDeadZones (wiimote_state::joystick &joy);
00328
00329 int ParseIR (BYTE* buff);
00330
00331 int ParseExtension (BYTE* buff, unsigned offset);
00332
00333 int ParseReadAddress (BYTE* buff);
00334
00335 void ReadCalibration ();
00336 float GetBalanceValue(short sensor, short min, short mid, short max);
00337
00338 void EnableIR (wiimote_state::ir::mode mode);
00339
00340 void DisableIR ();
00341
00342 bool WriteReport (BYTE* buff);
00343 bool StartSampleThread ();
00344
00345 inline BYTE GetRumbleBit () const { return Internal.bRumble? 0x01 : 0x00; }
00346
00347
00348 static unsigned __stdcall ReadParseThreadfunc (void* param);
00349 static unsigned __stdcall AsyncRumbleThreadfunc (void* param);
00350 static unsigned __stdcall SampleStreamThreadfunc(void* param);
00351 static unsigned __stdcall HIDwriteThreadfunc (void* param);
00352
00353 private:
00354
00355 enum output_report
00356 {
00357 OUT_NONE = 0x00,
00358 OUT_LEDs = 0x11,
00359 OUT_TYPE = 0x12,
00360 OUT_IR = 0x13,
00361 OUT_SPEAKER_ENABLE = 0x14,
00362 OUT_STATUS = 0x15,
00363 OUT_WRITEMEMORY = 0x16,
00364 OUT_READMEMORY = 0x17,
00365 OUT_SPEAKER_DATA = 0x18,
00366 OUT_SPEAKER_MUTE = 0x19,
00367 OUT_IR2 = 0x1a,
00368 };
00369
00370 static const int IN_STATUS = 0x20;
00371 static const int IN_READADDRESS = 0x21;
00372
00373 static const int VID = 0x057e;
00374 static const int PID = 0x0306;
00375
00376 static const int REPORT_LENGTH = 22;
00377
00378 static const int REGISTER_CALIBRATION = 0x0016;
00379 static const int REGISTER_IR = 0x4b00030;
00380 static const int REGISTER_IR_SENSITIVITY_1 = 0x4b00000;
00381 static const int REGISTER_IR_SENSITIVITY_2 = 0x4b0001a;
00382 static const int REGISTER_IR_MODE = 0x4b00033;
00383 static const int REGISTER_EXTENSION_INIT1 = 0x4a400f0;
00384 static const int REGISTER_EXTENSION_INIT2 = 0x4a400fb;
00385 static const int REGISTER_EXTENSION_TYPE = 0x4a400fa;
00386 static const int REGISTER_EXTENSION_CALIBRATION = 0x4a40020;
00387 static const int REGISTER_BALANCE_CALIBRATION = 0x4a40024;
00388 static const int REGISTER_MOTIONPLUS_DETECT = 0x4a600fa;
00389 static const int REGISTER_MOTIONPLUS_INIT = 0x4a600f0;
00390 static const int REGISTER_MOTIONPLUS_ENABLE = 0x4a600fe;
00391
00392 HANDLE Handle;
00393 OVERLAPPED Overlapped;
00394 HANDLE ReadParseThread;
00395 EVENT DataRead;
00396 bool bUseHIDwrite;
00397
00398
00399
00400 static HMODULE HidDLL;
00401 static hidwrite_ptr _HidD_SetOutputReport;
00402
00403 volatile bool bStatusReceived;
00404 volatile bool bConnectInProgress;
00405 volatile bool bInitInProgress;
00406 volatile bool bEnablingMotionPlus;
00407 volatile bool bConnectionLost;
00408 volatile int MotionPlusDetectCount;
00409 volatile bool bMotionPlusDetected;
00410 volatile bool bMotionPlusEnabled;
00411 volatile bool bMotionPlusExtension;
00412 volatile bool bCalibrateAtRest;
00413 static unsigned _TotalCreated;
00414 static unsigned _TotalConnected;
00415 input_report ReportType;
00416
00417 BYTE ReadBuff [REPORT_LENGTH];
00418
00419
00420 CRITICAL_SECTION StateLock;
00421 wiimote_state Internal;
00422 state_change_flags InternalChanged;
00423
00424
00425 DWORD NextStatusTime;
00426 DWORD NextMPlusDetectTime;
00427 DWORD MPlusDetectCount;
00428
00429 HANDLE HIDwriteThread;
00430 #ifdef USE_DYNAMIC_HIDQUEUE
00431 std::queue<BYTE*> HIDwriteQueue;
00432 #else
00433
00434
00435 struct hid
00436 {
00437 hid () : Queue(NULL), ReadIndex(0), WriteIndex(0) {}
00438
00439
00440
00441
00442
00443
00444
00445
00446 static const unsigned MAX_QUEUE_ENTRIES = 1<<7;
00447
00448 inline bool IsEmpty() const { return (ReadIndex == WriteIndex); }
00449
00450 bool Allocate () {
00451 _ASSERT(!Queue); if(Queue) return true;
00452 ReadIndex = WriteIndex = 0;
00453 Queue = new queue_entry[MAX_QUEUE_ENTRIES];
00454 _ASSERT(Queue); return (Queue != NULL);
00455 }
00456 void Deallocate () {
00457 if(!Queue) return;
00458 delete[] Queue; Queue = NULL;
00459 ReadIndex = WriteIndex = 0;
00460 }
00461
00462 struct queue_entry
00463 {
00464 queue_entry() { memset(Report, 0, sizeof(Report)); }
00465
00466 BYTE Report [REPORT_LENGTH];
00467 } *Queue;
00468
00469 unsigned ReadIndex, WriteIndex;
00470 } HID;
00471 #endif
00472 CRITICAL_SECTION HIDwriteQueueLock;
00473
00474
00475 HANDLE AsyncRumbleThread;
00476 volatile DWORD AsyncRumbleTimeout;
00477
00478 unsigned WiimoteNearGUpdates;
00479 unsigned NunchukNearGUpdates;
00480
00481 HANDLE SampleThread;
00482 const wiimote_sample* volatile CurrentSample;
00483
00484 struct recording
00485 {
00486 volatile bool bEnabled;
00487 state_history *StateHistory;
00488 volatile DWORD StartTimeMS;
00489 volatile DWORD EndTimeMS;
00490 unsigned TriggerFlags;
00491 unsigned ExtTriggerFlags;
00492 } Recording;
00493 };
00494
00495 #endif // _WIIMOTE_H