mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-21 13:20:27 -06:00
just trying some stuff, please don't try to auto build it
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3375 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
490
Source/Plugins/Plugin_Wiimote-testing/Src/wiimote_real.cpp
Normal file
490
Source/Plugins/Plugin_Wiimote-testing/Src/wiimote_real.cpp
Normal file
@ -0,0 +1,490 @@
|
||||
// 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
|
||||
|
Reference in New Issue
Block a user