forked from dolphin-emu/dolphin
		
	
		
			
	
	
		
			491 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			491 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
								 | 
							
								// Copyright (C) 2003-2008 Dolphin Project.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// This program is free software: you can redistribute it and/or modify
							 | 
						|||
| 
								 | 
							
								// it under the terms of the GNU General Public License as published by
							 | 
						|||
| 
								 | 
							
								// the Free Software Foundation, version 2.0.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// This program is distributed in the hope that it will be useful,
							 | 
						|||
| 
								 | 
							
								// but WITHOUT ANY WARRANTY; without even the implied warranty of
							 | 
						|||
| 
								 | 
							
								// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
							 | 
						|||
| 
								 | 
							
								// GNU General Public License 2.0 for more details.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// A copy of the GPL 2.0 should have been included with the program.
							 | 
						|||
| 
								 | 
							
								// If not, see http://www.gnu.org/licenses/
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// Official SVN repository and contact information can be found at
							 | 
						|||
| 
								 | 
							
								// http://code.google.com/p/dolphin-emu/
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								//////////////////////////////////////////////////////////////////////////////////////////
							 | 
						|||
| 
								 | 
							
								// Includes
							 | 
						|||
| 
								 | 
							
								// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
							 | 
						|||
| 
								 | 
							
								#include <iostream> // System
							 | 
						|||
| 
								 | 
							
								#include <queue>
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#include "wiiuse.h"
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#include "Common.h"
							 | 
						|||
| 
								 | 
							
								#include "Thread.h"
							 | 
						|||
| 
								 | 
							
								#include "StringUtil.h"
							 | 
						|||
| 
								 | 
							
								#include "Timer.h"
							 | 
						|||
| 
								 | 
							
								#include "pluginspecs_wiimote.h"
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#include "wiimote_hid.h"
							 | 
						|||
| 
								 | 
							
								#include "main.h"
							 | 
						|||
| 
								 | 
							
								#include "Config.h"
							 | 
						|||
| 
								 | 
							
								#include "EmuMain.h"
							 | 
						|||
| 
								 | 
							
								#include "EmuDefinitions.h"
							 | 
						|||
| 
								 | 
							
								#define EXCLUDE_H // Avoid certain declarations in wiimote_real.h
							 | 
						|||
| 
								 | 
							
								#include "wiimote_real.h"
							 | 
						|||
| 
								 | 
							
								#if defined(HAVE_WX) && HAVE_WX
							 | 
						|||
| 
								 | 
							
									#include "ConfigDlg.h"
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								extern SWiimoteInitialize g_WiimoteInitialize;
							 | 
						|||
| 
								 | 
							
								////////////////////////////////////////
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								namespace WiiMoteReal
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								//******************************************************************************
							 | 
						|||
| 
								 | 
							
								// Forwarding
							 | 
						|||
| 
								 | 
							
								//******************************************************************************
							 | 
						|||
| 
								 | 
							
									
							 | 
						|||
| 
								 | 
							
								class CWiiMote;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#ifdef _WIN32
							 | 
						|||
| 
								 | 
							
									DWORD WINAPI ReadWiimote_ThreadFunc(void* arg);
							 | 
						|||
| 
								 | 
							
								#else
							 | 
						|||
| 
								 | 
							
									void* ReadWiimote_ThreadFunc(void* arg);
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								//******************************************************************************
							 | 
						|||
| 
								 | 
							
								// Variable declarations
							 | 
						|||
| 
								 | 
							
								//******************************************************************************
							 | 
						|||
| 
								 | 
							
										
							 | 
						|||
| 
								 | 
							
								wiimote_t**			g_WiiMotesFromWiiUse = NULL;
							 | 
						|||
| 
								 | 
							
								Common::Thread*		g_pReadThread = NULL;
							 | 
						|||
| 
								 | 
							
								int					g_NumberOfWiiMotes;
							 | 
						|||
| 
								 | 
							
								CWiiMote*			g_WiiMotes[MAX_WIIMOTES];	
							 | 
						|||
| 
								 | 
							
								bool				g_Shutdown = false;
							 | 
						|||
| 
								 | 
							
								bool				g_ThreadGoing = false;
							 | 
						|||
| 
								 | 
							
								bool				g_LocalThread = true;
							 | 
						|||
| 
								 | 
							
								bool				g_IRSensing = false;
							 | 
						|||
| 
								 | 
							
								bool				g_MotionSensing = false;
							 | 
						|||
| 
								 | 
							
								u64					g_UpdateTime = 0;
							 | 
						|||
| 
								 | 
							
								int					g_UpdateCounter = 0;
							 | 
						|||
| 
								 | 
							
								bool				g_RunTemporary = false;
							 | 
						|||
| 
								 | 
							
								int					g_RunTemporaryCountdown = 0;
							 | 
						|||
| 
								 | 
							
								u8					g_EventBuffer[32];
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								//******************************************************************************
							 | 
						|||
| 
								 | 
							
								// Probably this class should be in its own file
							 | 
						|||
| 
								 | 
							
								//******************************************************************************
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								class CWiiMote
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								public:
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								//////////////////////////////////////////
							 | 
						|||
| 
								 | 
							
								// On create and on uncreate
							 | 
						|||
| 
								 | 
							
								// ---------------
							 | 
						|||
| 
								 | 
							
								CWiiMote(u8 _WiimoteNumber, wiimote_t* _pWiimote) 
							 | 
						|||
| 
								 | 
							
								    : m_WiimoteNumber(_WiimoteNumber)
							 | 
						|||
| 
								 | 
							
								    , m_channelID(0)
							 | 
						|||
| 
								 | 
							
								    , m_pWiiMote(_pWiimote)
							 | 
						|||
| 
								 | 
							
								    , m_pCriticalSection(NULL)
							 | 
						|||
| 
								 | 
							
								    , m_LastReportValid(false)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    m_pCriticalSection = new Common::CriticalSection();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    //wiiuse_set_leds(m_pWiiMote, WIIMOTE_LED_4);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									#ifdef _WIN32
							 | 
						|||
| 
								 | 
							
										// F|RES: i dunno if we really need this
							 | 
						|||
| 
								 | 
							
										CancelIo(m_pWiiMote->dev_handle);
							 | 
						|||
| 
								 | 
							
									#endif
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								virtual ~CWiiMote() 
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    delete m_pCriticalSection;
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								//////////////////////
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								//////////////////////////////////////////
							 | 
						|||
| 
								 | 
							
								// Queue raw HID data from the core to the wiimote
							 | 
						|||
| 
								 | 
							
								// ---------------
							 | 
						|||
| 
								 | 
							
								void SendData(u16 _channelID, const u8* _pData, u32 _Size)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    m_channelID = _channelID;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    m_pCriticalSection->Enter();
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        SEvent WriteEvent;
							 | 
						|||
| 
								 | 
							
								        memcpy(WriteEvent.m_PayLoad, _pData + 1, _Size - 1);
							 | 
						|||
| 
								 | 
							
								        m_EventWriteQueue.push(WriteEvent);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										// Debugging
							 | 
						|||
| 
								 | 
							
										//std::string Temp = ArrayToString(WriteEvent.m_PayLoad, 28, 0, 30);
							 | 
						|||
| 
								 | 
							
										//INFO_LOG(CONSOLE, "Wiimote Write:\n%s\n", Temp.c_str());
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    m_pCriticalSection->Leave();
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								/////////////////////
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								//////////////////////////////////////////////////
							 | 
						|||
| 
								 | 
							
								/* Read and write data to the Wiimote */
							 | 
						|||
| 
								 | 
							
								// ---------------
							 | 
						|||
| 
								 | 
							
								void ReadData() 
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    m_pCriticalSection->Enter();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Send data to the Wiimote
							 | 
						|||
| 
								 | 
							
								    if (!m_EventWriteQueue.empty())
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
										//INFO_LOG(CONSOLE, "Writing data to the Wiimote\n");
							 | 
						|||
| 
								 | 
							
								        SEvent& rEvent = m_EventWriteQueue.front();
							 | 
						|||
| 
								 | 
							
										wiiuse_io_write(m_pWiiMote, (byte*)rEvent.m_PayLoad, MAX_PAYLOAD);
							 | 
						|||
| 
								 | 
							
										m_EventWriteQueue.pop();
							 | 
						|||
| 
								 | 
							
										
							 | 
						|||
| 
								 | 
							
								#ifdef _WIN32
							 | 
						|||
| 
								 | 
							
										// Debugging. Move the data one step to the right first.
							 | 
						|||
| 
								 | 
							
										memcpy(rEvent.m_PayLoad + 1, rEvent.m_PayLoad, sizeof(rEvent.m_PayLoad) - 1);
							 | 
						|||
| 
								 | 
							
										rEvent.m_PayLoad[0] = 0xa2;
							 | 
						|||
| 
								 | 
							
										InterruptDebugging(false, rEvent.m_PayLoad);
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    m_pCriticalSection->Leave();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Read data from wiimote (but don't send it to the core, just filter and queue)
							 | 
						|||
| 
								 | 
							
									if (wiiuse_io_read(m_pWiiMote))
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										const byte* pBuffer = m_pWiiMote->event_buf;
							 | 
						|||
| 
								 | 
							
										#ifndef _WIN32
							 | 
						|||
| 
								 | 
							
											// The Linux packets are starting out one spot before the Windows one. This should really be handled in the wiiuse library
							 | 
						|||
| 
								 | 
							
											pBuffer++;
							 | 
						|||
| 
								 | 
							
										#endif
							 | 
						|||
| 
								 | 
							
										// Check if we have a channel (connection) if so save the data...
							 | 
						|||
| 
								 | 
							
										if (m_channelID > 0)
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											m_pCriticalSection->Enter();
							 | 
						|||
| 
								 | 
							
											
							 | 
						|||
| 
								 | 
							
											// Filter out data reports
							 | 
						|||
| 
								 | 
							
											if (pBuffer[0] >= 0x30) 
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												// Copy Buffer to LastReport
							 | 
						|||
| 
								 | 
							
												memcpy(m_LastReport.m_PayLoad, pBuffer, MAX_PAYLOAD);
							 | 
						|||
| 
								 | 
							
												m_LastReportValid = true;
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
											else
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												// Copy Buffer to ImportantEvent
							 | 
						|||
| 
								 | 
							
												SEvent ImportantEvent;
							 | 
						|||
| 
								 | 
							
												memcpy(ImportantEvent.m_PayLoad, pBuffer, MAX_PAYLOAD);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
												// Put it in the read queue right away
							 | 
						|||
| 
								 | 
							
												m_EventReadQueue.push(ImportantEvent);
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
											m_pCriticalSection->Leave();
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								/////////////////////
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								//////////////////////////////////////////
							 | 
						|||
| 
								 | 
							
								// Send queued data to the core
							 | 
						|||
| 
								 | 
							
								// ---------------
							 | 
						|||
| 
								 | 
							
								void Update() 
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									// Thread function
							 | 
						|||
| 
								 | 
							
								    m_pCriticalSection->Enter();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    if (m_EventReadQueue.empty())
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
										// Send the data report
							 | 
						|||
| 
								 | 
							
								        if (m_LastReportValid) SendEvent(m_LastReport);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    else
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
										// Send a 0x20, 0x21 or 0x22 report
							 | 
						|||
| 
								 | 
							
								        SendEvent(m_EventReadQueue.front());
							 | 
						|||
| 
								 | 
							
								        m_EventReadQueue.pop();
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    m_pCriticalSection->Leave();
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								/////////////////////
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								//////////////////////////////////////////
							 | 
						|||
| 
								 | 
							
								// Clear events
							 | 
						|||
| 
								 | 
							
								// ---------------
							 | 
						|||
| 
								 | 
							
								void ClearEvents()
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									while (!m_EventReadQueue.empty())
							 | 
						|||
| 
								 | 
							
										m_EventReadQueue.pop();
							 | 
						|||
| 
								 | 
							
									while (!m_EventWriteQueue.empty())
							 | 
						|||
| 
								 | 
							
										m_EventWriteQueue.pop();	
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								/////////////////////
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								private:
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    struct SEvent 
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        SEvent()
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            memset(m_PayLoad, 0, MAX_PAYLOAD);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        byte m_PayLoad[MAX_PAYLOAD];
							 | 
						|||
| 
								 | 
							
								    };
							 | 
						|||
| 
								 | 
							
								    typedef std::queue<SEvent> CEventQueue;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    u8 m_WiimoteNumber; // Just for debugging
							 | 
						|||
| 
								 | 
							
								    u16 m_channelID;  
							 | 
						|||
| 
								 | 
							
								    CEventQueue m_EventReadQueue; // Read from Wiimote
							 | 
						|||
| 
								 | 
							
								    CEventQueue m_EventWriteQueue; // Write to Wiimote
							 | 
						|||
| 
								 | 
							
								    Common::CriticalSection* m_pCriticalSection;
							 | 
						|||
| 
								 | 
							
								    bool m_LastReportValid;
							 | 
						|||
| 
								 | 
							
								    SEvent m_LastReport;
							 | 
						|||
| 
								 | 
							
									wiimote_t* m_pWiiMote; // This is g_WiiMotesFromWiiUse[]
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								//////////////////////////////////////////
							 | 
						|||
| 
								 | 
							
								// Send queued data to the core
							 | 
						|||
| 
								 | 
							
								// ---------------
							 | 
						|||
| 
								 | 
							
								void SendEvent(SEvent& _rEvent)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    // We don't have an answer channel
							 | 
						|||
| 
								 | 
							
								    if (m_channelID == 0) return;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // Check event buffer
							 | 
						|||
| 
								 | 
							
								    u8 Buffer[1024];
							 | 
						|||
| 
								 | 
							
								    u32 Offset = 0;
							 | 
						|||
| 
								 | 
							
								    hid_packet* pHidHeader = (hid_packet*)(Buffer + Offset);
							 | 
						|||
| 
								 | 
							
								    Offset += sizeof(hid_packet);
							 | 
						|||
| 
								 | 
							
								    pHidHeader->type = HID_TYPE_DATA;
							 | 
						|||
| 
								 | 
							
								    pHidHeader->param = HID_PARAM_INPUT;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Create the buffer
							 | 
						|||
| 
								 | 
							
								    memcpy(&Buffer[Offset], _rEvent.m_PayLoad, MAX_PAYLOAD);
							 | 
						|||
| 
								 | 
							
									/* This Offset value is not exactly correct like it is for the emulated Wiimote reports. It's
							 | 
						|||
| 
								 | 
							
									   often to big, but I guess that's okay. The game will know how big the actual data is. */
							 | 
						|||
| 
								 | 
							
								    Offset += MAX_PAYLOAD;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Send it
							 | 
						|||
| 
								 | 
							
									g_WiimoteInitialize.pWiimoteInput(m_channelID, Buffer, Offset);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Debugging
							 | 
						|||
| 
								 | 
							
									// ReadDebugging(false, Buffer, Offset);  
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								/////////////////////
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								//******************************************************************************
							 | 
						|||
| 
								 | 
							
								// Function Definitions 
							 | 
						|||
| 
								 | 
							
								//******************************************************************************
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void SendAcc(u8 _ReportID)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									byte DataAcc[MAX_PAYLOAD];
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									DataAcc[0] = 0x22; // Report 0x12
							 | 
						|||
| 
								 | 
							
									DataAcc[1] = 0x00; // Core buttons
							 | 
						|||
| 
								 | 
							
									DataAcc[2] = 0x00;
							 | 
						|||
| 
								 | 
							
									DataAcc[3] = _ReportID; // Reporting mode
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// TODO: Update for multiple wiimotes?
							 | 
						|||
| 
								 | 
							
									wiiuse_io_write(WiiMoteReal::g_WiiMotesFromWiiUse[0], (byte*)DataAcc, MAX_PAYLOAD);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									std::string Temp = ArrayToString(DataAcc, 28, 0, 30);
							 | 
						|||
| 
								 | 
							
									INFO_LOG(CONSOLE, "SendAcc: %s\n", Temp.c_str());
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									//22 00 00 _reportID 00
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// Clear any potential queued events
							 | 
						|||
| 
								 | 
							
								void ClearEvents()
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									for (int i = 0; i < g_NumberOfWiiMotes; i++)
							 | 
						|||
| 
								 | 
							
										g_WiiMotes[i]->ClearEvents();
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// Flash lights, and if connecting, also rumble
							 | 
						|||
| 
								 | 
							
								void FlashLights(bool Connect)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									for (int i = 0; i < g_NumberOfWiiMotes; i++)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										if(Connect)	wiiuse_rumble(WiiMoteReal::g_WiiMotesFromWiiUse[i], 1);
							 | 
						|||
| 
								 | 
							
										wiiuse_set_leds(WiiMoteReal::g_WiiMotesFromWiiUse[i], WIIMOTE_LED_1 | WIIMOTE_LED_2 | WIIMOTE_LED_3 | WIIMOTE_LED_4);
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									sleep(100);
							 | 
						|||
| 
								 | 
							
									
							 | 
						|||
| 
								 | 
							
									for (int i = 0; i < g_NumberOfWiiMotes; i++)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										if(Connect)
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											wiiuse_rumble(WiiMoteReal::g_WiiMotesFromWiiUse[i], 0);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											// End with light 1 or 4
							 | 
						|||
| 
								 | 
							
											wiiuse_set_leds(WiiMoteReal::g_WiiMotesFromWiiUse[i], WIIMOTE_LED_1);
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
										else wiiuse_set_leds(WiiMoteReal::g_WiiMotesFromWiiUse[i], WIIMOTE_LED_4);
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								int Initialize()
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									// Return if already initialized
							 | 
						|||
| 
								 | 
							
									if (g_RealWiiMoteInitialized) return g_NumberOfWiiMotes;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Clear the wiimote classes
							 | 
						|||
| 
								 | 
							
								    memset(g_WiiMotes, 0, sizeof(CWiiMote*) * MAX_WIIMOTES);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Call Wiiuse.dll
							 | 
						|||
| 
								 | 
							
								    g_WiiMotesFromWiiUse = wiiuse_init(MAX_WIIMOTES);
							 | 
						|||
| 
								 | 
							
									g_NumberOfWiiMotes = wiiuse_find(g_WiiMotesFromWiiUse, MAX_WIIMOTES, 5);
							 | 
						|||
| 
								 | 
							
									if (g_NumberOfWiiMotes > 0) g_RealWiiMotePresent = true;
							 | 
						|||
| 
								 | 
							
									INFO_LOG(CONSOLE, "Found No of Wiimotes: %i\n", g_NumberOfWiiMotes);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									for (int i = 0; i < g_NumberOfWiiMotes; i++)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										// Remove the wiiuse_poll() threshold
							 | 
						|||
| 
								 | 
							
										wiiuse_set_accel_threshold(g_WiiMotesFromWiiUse[i], 0);
							 | 
						|||
| 
								 | 
							
										
							 | 
						|||
| 
								 | 
							
										// Set the sensor bar position, this should only affect the internal wiiuse api functions
							 | 
						|||
| 
								 | 
							
										wiiuse_set_ir_position(g_WiiMotesFromWiiUse[i], WIIUSE_IR_ABOVE);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										// Set flags
							 | 
						|||
| 
								 | 
							
										//wiiuse_set_flags(g_WiiMotesFromWiiUse[i], NULL, WIIUSE_SMOOTHING);
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									// I don't seem to need wiiuse_connect() in Windows. But Linux needs it.
							 | 
						|||
| 
								 | 
							
									#ifndef _WIN32
							 | 
						|||
| 
								 | 
							
										int Connect = wiiuse_connect(g_WiiMotesFromWiiUse, MAX_WIIMOTES);
							 | 
						|||
| 
								 | 
							
										INFO_LOG(CONSOLE, "Connected: %i\n", Connect);
							 | 
						|||
| 
								 | 
							
									#endif
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// If we are connecting from the config window without a game running we flash the lights
							 | 
						|||
| 
								 | 
							
									if (!g_EmulatorRunning && g_RealWiiMotePresent) FlashLights(true);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Create Wiimote classes
							 | 
						|||
| 
								 | 
							
									for (int i = 0; i < g_NumberOfWiiMotes; i++)
							 | 
						|||
| 
								 | 
							
										g_WiiMotes[i] = new CWiiMote(i + 1, g_WiiMotesFromWiiUse[i]);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Create a new thread and start listening for Wiimote data
							 | 
						|||
| 
								 | 
							
									if (g_NumberOfWiiMotes > 0)
							 | 
						|||
| 
								 | 
							
										g_pReadThread = new Common::Thread(ReadWiimote_ThreadFunc, NULL);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// If we are not using the emulated wiimote we can run the thread temporary until the data has beeen copied
							 | 
						|||
| 
								 | 
							
									if(g_Config.bUseRealWiimote) g_RunTemporary = true;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									/* Allocate memory and copy the Wiimote eeprom accelerometer neutral values to g_Eeprom. Unlike with
							 | 
						|||
| 
								 | 
							
									   and extension we have to do this here, because this data is only read once when the Wiimote
							 | 
						|||
| 
								 | 
							
									   is connected. Also, we can't change the neutral values the wiimote will report, I think, unless
							 | 
						|||
| 
								 | 
							
									   we update its eeprom? In any case it's probably better to let the current calibration be where it
							 | 
						|||
| 
								 | 
							
									   is and adjust the global values after that to avoid overwriting critical data on any Wiimote. */
							 | 
						|||
| 
								 | 
							
									// TODO: Update for multiple wiimotes?
							 | 
						|||
| 
								 | 
							
									byte *data = (byte*)malloc(sizeof(byte) * sizeof(WiiMoteEmu::EepromData_0));
							 | 
						|||
| 
								 | 
							
									wiiuse_read_data(g_WiiMotesFromWiiUse[0], data, 0, sizeof(WiiMoteEmu::EepromData_0));
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Don't run the Wiimote thread if no wiimotes were found
							 | 
						|||
| 
								 | 
							
									if (g_NumberOfWiiMotes > 0) g_Shutdown = false;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Initialized, even if we didn't find a Wiimote
							 | 
						|||
| 
								 | 
							
									g_RealWiiMoteInitialized = true;
							 | 
						|||
| 
								 | 
							
									
							 | 
						|||
| 
								 | 
							
									return g_NumberOfWiiMotes;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void DoState(void* ptr, int mode) {}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void Shutdown(void)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									// Stop the loop in the thread
							 | 
						|||
| 
								 | 
							
									g_Shutdown = true;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Stop the thread
							 | 
						|||
| 
								 | 
							
									if (g_pReadThread != NULL)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										delete g_pReadThread;
							 | 
						|||
| 
								 | 
							
										g_pReadThread = NULL;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Delete the wiimotes
							 | 
						|||
| 
								 | 
							
									for (int i = 0; i < g_NumberOfWiiMotes; i++)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										delete g_WiiMotes[i];
							 | 
						|||
| 
								 | 
							
										g_WiiMotes[i] = NULL;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Flash flights
							 | 
						|||
| 
								 | 
							
									if (!g_EmulatorRunning && g_RealWiiMotePresent)
							 | 
						|||
| 
								 | 
							
										FlashLights(false);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Clean up wiiuse
							 | 
						|||
| 
								 | 
							
									wiiuse_cleanup(g_WiiMotesFromWiiUse, g_NumberOfWiiMotes);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Uninitialized
							 | 
						|||
| 
								 | 
							
									g_RealWiiMoteInitialized = false;
							 | 
						|||
| 
								 | 
							
									g_RealWiiMotePresent = false;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void InterruptChannel(u16 _channelID, const void* _pData, u32 _Size)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									//INFO_LOG(CONSOLE, "Real InterruptChannel\n");
							 | 
						|||
| 
								 | 
							
									// TODO: Update for multiple Wiimotes
							 | 
						|||
| 
								 | 
							
									g_WiiMotes[0]->SendData(_channelID, (const u8*)_pData, _Size);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void ControlChannel(u16 _channelID, const void* _pData, u32 _Size)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									//INFO_LOG(CONSOLE, "Real ControlChannel\n");
							 | 
						|||
| 
								 | 
							
								    g_WiiMotes[0]->SendData(_channelID, (const u8*)_pData, _Size);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								//////////////////////////////////
							 | 
						|||
| 
								 | 
							
								// Read the Wiimote once
							 | 
						|||
| 
								 | 
							
								// ---------------
							 | 
						|||
| 
								 | 
							
								void Update()
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									//INFO_LOG(CONSOLE, "Real Update\n");
							 | 
						|||
| 
								 | 
							
									for (int i = 0; i < g_NumberOfWiiMotes; i++)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										g_WiiMotes[i]->Update();
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								//////////////////////////////////
							 | 
						|||
| 
								 | 
							
								/* Continuously read the Wiimote status. However, the actual sending of data occurs in Update(). If we are
							 | 
						|||
| 
								 | 
							
								   not currently using the real Wiimote we allow the separate ReadWiimote() function to run. Wo don't use
							 | 
						|||
| 
								 | 
							
								   them at the same time to avoid a potential collision. */
							 | 
						|||
| 
								 | 
							
								// ---------------
							 | 
						|||
| 
								 | 
							
								#ifdef _WIN32
							 | 
						|||
| 
								 | 
							
									DWORD WINAPI ReadWiimote_ThreadFunc(void* arg)
							 | 
						|||
| 
								 | 
							
								#else
							 | 
						|||
| 
								 | 
							
									void *ReadWiimote_ThreadFunc(void* arg)
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									while (!g_Shutdown)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										// We need g_ThreadGoing to do a manual WaitForSingleObject() from the configuration window
							 | 
						|||
| 
								 | 
							
										g_ThreadGoing = true;
							 | 
						|||
| 
								 | 
							
										if(g_Config.bUseRealWiimote && !g_RunTemporary)
							 | 
						|||
| 
								 | 
							
											for (int i = 0; i < g_NumberOfWiiMotes; i++) g_WiiMotes[i]->ReadData();
							 | 
						|||
| 
								 | 
							
										else
							 | 
						|||
| 
								 | 
							
											ReadWiimote();
							 | 
						|||
| 
								 | 
							
										g_ThreadGoing = false;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									return 0;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								}; // end of namespace
							 | 
						|||
| 
								 | 
							
								
							 |