New Wiimote Plugin: Added a "Hybrid Wiimote" input source type. This allows a real wiimote to be used with an emulated extension.(and in the future, real wiimote with emulated motion plus) If the emulated extension is set to "None", a real extension can be used. Real/Emulated buttons are combined. Real acceleration data is used. Currently, emulated IR data is used.(might change this to allow both) Switching between an emulated and a real extension in-game is a bit testy right now, but if you switch the emu-extension to "None" before connecting a real extension, it usually works.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6082 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Jordan Woyak
2010-08-10 04:12:32 +00:00
parent a1daa636c2
commit 2b45e87b3e
9 changed files with 603 additions and 417 deletions
+38 -25
View File
@@ -5,6 +5,8 @@
// a simple lockless thread-safe,
// single reader, single writer queue
#include "Atomic.h"
namespace Common
{
@@ -12,7 +14,7 @@ template <typename T>
class FifoQueue
{
public:
FifoQueue()
FifoQueue() : m_size(0)
{
m_write_ptr = m_read_ptr = new ElementPtr();
}
@@ -23,9 +25,20 @@ public:
delete m_read_ptr;
}
bool Empty() const // true if the queue is empty
u32 Size() const
{
return (m_read_ptr == m_write_ptr);
return m_size;
}
bool Empty() const
{
//return (m_read_ptr == m_write_ptr);
return (0 == m_size);
}
const T& Front() const
{
return *m_read_ptr->current;
}
void Push(const T& t)
@@ -35,42 +48,41 @@ public:
// set the next pointer to a new element ptr
// then advance the write pointer
m_write_ptr = m_write_ptr->next = new ElementPtr();
Common::AtomicIncrement(m_size);
}
void Pop()
{
Common::AtomicDecrement(m_size);
ElementPtr *const tmpptr = m_read_ptr;
// advance the read pointer
m_read_ptr = m_read_ptr->next;
// set the next element to NULL to stop the recursive deletion
tmpptr->next = NULL;
delete tmpptr; // this also deletes the element
}
bool Pop(T& t)
{
// if write pointer points to the same element, queue is empty
if (m_read_ptr == m_write_ptr)
if (Empty())
return false;
// get the element from out of the queue
t = *m_read_ptr->current;
ElementPtr *const tmpptr = m_read_ptr;
// advance the read pointer
m_read_ptr = m_read_ptr->next;
// set the next element to NULL to stop the recursive deletion
tmpptr->next = NULL;
delete tmpptr; // this also deletes the element
t = Front();
Pop();
return true;
}
bool Peek(T& t)
// not thread-safe
void Clear()
{
// if write pointer points to the same element, queue is empty
if (m_read_ptr == m_write_ptr)
return false;
// get the element from out of the queue
t = *m_read_ptr->current;
return true;
m_size = 0;
delete m_read_ptr;
m_write_ptr = m_read_ptr = new ElementPtr();
}
private:
// stores a pointer to element at front of queue
// stores a pointer to element
// and a pointer to the next ElementPtr
class ElementPtr
{
@@ -94,6 +106,7 @@ private:
ElementPtr *volatile m_write_ptr;
ElementPtr *volatile m_read_ptr;
volatile u32 m_size;
};
}
@@ -13,6 +13,7 @@ WiimoteConfigPage::WiimoteConfigPage(wxWindow* const parent, const int index)
m_input_src_choice->Append(wxT("None"));
m_input_src_choice->Append(wxT("Emulated Wiimote"));
m_input_src_choice->Append(wxT("Real Wiimote"));
m_input_src_choice->Append(wxT("Hybrid Wiimote"));
m_input_src_choice->Select(g_wiimote_sources[m_index]);
_connect_macro_(m_input_src_choice, WiimoteConfigPage::SelectSource, wxEVT_COMMAND_CHOICE_SELECTED, this);
@@ -38,23 +38,21 @@
#include "pluginspecs_wiimote.h"
#include "WiimoteEmu.h"
#include "WiimoteHid.h"
#include "../WiimoteReal/WiimoteReal.h"
#include "Attachment/Attachment.h"
/* Bit shift conversions */
u32 convert24bit(const u8* src)
u32 swap24(const u8* src)
{
return (src[0] << 16) | (src[1] << 8) | src[2];
}
u16 convert16bit(const u8* src)
{
return (src[0] << 8) | src[1];
}
namespace WiimoteEmu
{
void Wiimote::ReportMode(const u16 _channelID, wm_report_mode* dr)
void Wiimote::ReportMode(const wm_report_mode* const dr)
{
//INFO_LOG(WIIMOTE, "Set data report mode");
//DEBUG_LOG(WIIMOTE, " Rumble: %x", dr->rumble);
@@ -92,9 +90,9 @@ void Wiimote::ReportMode(const u16 _channelID, wm_report_mode* dr)
The IR enable/disable and speaker enable/disable and mute/unmute values are
bit2: 0 = Disable (0x02), 1 = Enable (0x06)
*/
void Wiimote::HidOutputReport(const u16 _channelID, wm_report* sr)
void Wiimote::HidOutputReport(const wm_report* const sr, const bool send_ack)
{
INFO_LOG(WIIMOTE, "HidOutputReport (page: %i, cid: 0x%02x, wm: 0x%02x)", m_index, _channelID, sr->wm);
INFO_LOG(WIIMOTE, "HidOutputReport (page: %i, cid: 0x%02x, wm: 0x%02x)", m_index, m_reporting_channel, sr->wm);
// wiibrew:
// In every single Output Report, bit 0 (0x01) of the first byte controls the Rumble feature.
@@ -113,7 +111,7 @@ void Wiimote::HidOutputReport(const u16 _channelID, wm_report* sr)
break;
case WM_REPORT_MODE : // 0x12
ReportMode(_channelID, (wm_report_mode*)sr->data);
ReportMode((wm_report_mode*)sr->data);
break;
case WM_IR_PIXEL_CLOCK : // 0x13
@@ -128,16 +126,16 @@ void Wiimote::HidOutputReport(const u16 _channelID, wm_report* sr)
break;
case WM_REQUEST_STATUS : // 0x15
RequestStatus(_channelID, (wm_request_status*)sr->data);
RequestStatus((wm_request_status*)sr->data);
return; // sends its own ack
break;
case WM_WRITE_DATA : // 0x16
WriteData(_channelID, (wm_write_data*)sr->data);
WriteData((wm_write_data*)sr->data);
break;
case WM_READ_DATA : // 0x17
ReadData(_channelID, (wm_read_data*)sr->data);
ReadData((wm_read_data*)sr->data);
return; // sends its own ack
break;
@@ -175,7 +173,8 @@ void Wiimote::HidOutputReport(const u16 _channelID, wm_report* sr)
}
// send ack
SendAck(_channelID, sr->wm);
if (send_ack)
SendAck(sr->wm);
}
/* This will generate the 0x22 acknowledgement for most Input reports.
@@ -183,7 +182,7 @@ void Wiimote::HidOutputReport(const u16 _channelID, wm_report* sr)
The first two bytes are the core buttons data,
00 00 means nothing is pressed.
The last byte is the success code 00. */
void Wiimote::SendAck(const u16 _channelID, u8 _reportID)
void Wiimote::SendAck(u8 _reportID)
{
u8 data[6];
@@ -196,23 +195,16 @@ void Wiimote::SendAck(const u16 _channelID, u8 _reportID)
ack->reportID = _reportID;
ack->errorID = 0;
g_WiimoteInitialize.pWiimoteInterruptChannel( m_index, _channelID, data, sizeof(data));
g_WiimoteInitialize.pWiimoteInterruptChannel( m_index, m_reporting_channel, data, sizeof(data));
}
// old comment
/* Here we produce a 0x20 status report to send to the Wii. We currently ignore
the status request rs and all its eventual instructions it may include (for
example turn off rumble or something else) and just send the status
report. */
void Wiimote::RequestStatus(const u16 _channelID, wm_request_status* rs)
void Wiimote::HandleExtensionSwap()
{
//if (rs)
// handle switch extension
if ( m_extension->active_extension != m_extension->switch_extension )
if (m_extension->active_extension != m_extension->switch_extension)
{
// if an extension is currently connected and we want to switch to a different extension
if ( (m_extension->active_extension > 0) && m_extension->switch_extension )
if ((m_extension->active_extension > 0) && m_extension->switch_extension)
// detach extension first, wait til next Update() or RequestStatus() call to change to the new extension
m_extension->active_extension = 0;
else
@@ -223,8 +215,18 @@ void Wiimote::RequestStatus(const u16 _channelID, wm_request_status* rs)
m_status.extension = m_extension->active_extension ? 1 : 0;
// set register, I hate this line
m_register[ 0xa40000 ] = ((WiimoteEmu::Attachment*)m_extension->attachments[ m_extension->active_extension ])->reg;
m_register[0xa40000] = ((WiimoteEmu::Attachment*)m_extension->attachments[m_extension->active_extension])->reg;
}
}
// old comment
/* Here we produce a 0x20 status report to send to the Wii. We currently ignore
the status request rs and all its eventual instructions it may include (for
example turn off rumble or something else) and just send the status
report. */
void Wiimote::RequestStatus(const wm_request_status* const rs)
{
HandleExtensionSwap();
// set up report
u8 data[8];
@@ -234,14 +236,31 @@ void Wiimote::RequestStatus(const u16 _channelID, wm_request_status* rs)
// status values
*(wm_status_report*)(data + 2) = m_status;
// hybrid wiimote stuff
if (WIIMOTE_SRC_HYBRID == g_wiimote_sources[m_index] && (m_extension->switch_extension <= 0))
{
using namespace WiimoteReal;
g_refresh_critsec.Enter();
if (g_wiimotes[m_index])
{
wm_request_status rpt;
rpt.rumble = 0;
g_wiimotes[m_index]->SendPacket(WM_REQUEST_STATUS, &rpt, sizeof(rpt));
}
g_refresh_critsec.Leave();
return;
}
// send report
g_WiimoteInitialize.pWiimoteInterruptChannel(m_index, _channelID, data, sizeof(data));
g_WiimoteInitialize.pWiimoteInterruptChannel(m_index, m_reporting_channel, data, sizeof(data));
}
/* Write data to Wiimote and Extensions registers. */
void Wiimote::WriteData(const u16 _channelID, wm_write_data* wd)
void Wiimote::WriteData(const wm_write_data* const wd)
{
u32 address = convert24bit(wd->address);
u32 address = swap24(wd->address);
// ignore the 0x010000 bit
address &= 0xFEFFFF;
@@ -324,14 +343,24 @@ void Wiimote::WriteData(const u16 _channelID, wm_write_data* wd)
}
/* Read data from Wiimote and Extensions registers. */
void Wiimote::ReadData(const u16 _channelID, wm_read_data* rd)
void Wiimote::ReadData(const wm_read_data* const rd)
{
u32 address = convert24bit(rd->address);
u16 size = convert16bit(rd->size);
u32 address = swap24(rd->address);
u16 size = Common::swap16(rd->size);
// ignore the 0x010000 bit
address &= 0xFEFFFF;
// hybrid wiimote stuff
// relay the read data request to real-wiimote
if (WIIMOTE_SRC_HYBRID == g_wiimote_sources[m_index] && ((0xA4 != (address >> 16)) || (m_extension->switch_extension <= 0)))
{
WiimoteReal::InterruptChannel(m_index, m_reporting_channel, ((u8*)rd) - 2, sizeof(wm_read_data) + 2); // hacky
// don't want emu-wiimote to send reply
return;
}
ReadRequest rr;
u8* block = new u8[size];
@@ -416,14 +445,14 @@ void Wiimote::ReadData(const u16 _channelID, wm_read_data* rd)
}
// want the requested address, not the above modified one
rr.address = convert24bit(rd->address);
rr.address = swap24(rd->address);
rr.size = size;
//rr.channel = _channelID;
rr.position = 0;
rr.data = block;
// send up to 16 bytes
SendReadDataReply( _channelID, rr );
SendReadDataReply(rr);
// if there is more data to be sent, add it to the queue
if (rr.size)
@@ -440,7 +469,7 @@ void Wiimote::ReadData(const u16 _channelID, wm_read_data* rd)
bytes in the message, the 0 means no error, the 00 20 means that the message
is at the 00 20 offest in the registry that was read.
*/
void Wiimote::SendReadDataReply(const u16 _channelID, ReadRequest& _request)
void Wiimote::SendReadDataReply(ReadRequest& _request)
{
u8 data[23];
data[0] = 0xA1;
@@ -488,7 +517,7 @@ void Wiimote::SendReadDataReply(const u16 _channelID, ReadRequest& _request)
}
// Send a piece
g_WiimoteInitialize.pWiimoteInterruptChannel(m_index, _channelID, data, sizeof(data));
g_WiimoteInitialize.pWiimoteInterruptChannel(m_index, m_reporting_channel, data, sizeof(data));
}
void Wiimote::DoState(PointerWrap& p)
File diff suppressed because it is too large Load Diff
@@ -8,7 +8,7 @@
// just used to get the OpenAL includes :p
//#include <OpenALStream.h>
#include <ControllerEmu.h>
#include "ControllerEmu.h"
#include "ChunkFile.h"
#include "WiimoteHid.h"
@@ -32,6 +32,13 @@ extern SWiimoteInitialize g_WiimoteInitialize;
namespace WiimoteEmu
{
struct ReportFeatures
{
u8 core, accel, ir, ext, size;
};
extern const ReportFeatures reporting_mode_features[];
void EmulateShake(u8* const accel_data
, ControllerEmu::Buttons* const buttons_group
, unsigned int* const shake_step);
@@ -77,6 +84,19 @@ public:
void LoadDefaults(const ControllerInterface& ciface);
protected:
bool Step();
void HidOutputReport(const wm_report* const sr, const bool send_ack = true);
void HandleExtensionSwap();
void GetCoreData(u8* const data);
void GetAccelData(u8* const data);
void GetIRData(u8* const data);
void GetExtData(u8* const data);
bool HaveExtension() const { return m_extension->active_extension > 0; }
bool WantExtension() const { return m_extension->switch_extension != 0; }
private:
struct ReadRequest
{
@@ -87,14 +107,12 @@ private:
void Reset();
void ReportMode(const u16 _channelID, wm_report_mode* dr);
void HidOutputReport(const u16 _channelID, wm_report* sr);
void SendAck(const u16 _channelID, u8 _reportID);
void RequestStatus(const u16 _channelID, wm_request_status* rs = NULL);
void WriteData(const u16 _channelID, wm_write_data* wd);
void ReadData(const u16 _channelID, wm_read_data* rd);
void SendReadDataReply(const u16 _channelID, ReadRequest& _request);
void ReportMode(const wm_report_mode* const dr);
void SendAck(const u8 _reportID);
void RequestStatus(const wm_request_status* const rs = NULL);
void ReadData(const wm_read_data* const rd);
void WriteData(const wm_write_data* const wd);
void SendReadDataReply(ReadRequest& _request);
#ifdef USE_WIIMOTE_EMU_SPEAKER
void SpeakerData(wm_speaker_data* sd);
@@ -131,7 +149,7 @@ private:
class Register : public std::map< size_t, std::vector<u8> >
{
public:
void Write( size_t address, void* src, size_t length );
void Write( size_t address, const void* src, size_t length );
void Read( size_t address, void* dst, size_t length );
} m_register;
@@ -205,7 +205,7 @@ struct wm_read_data {
u8 space : 2; //see WM_SPACE_*
u8 : 5;
u8 address[3];
u8 size[2];
u16 size;
};
#define WM_SPACE_EEPROM 0
@@ -3,9 +3,9 @@
#include "pluginspecs_wiimote.h"
#include "WiimoteReal/WiimoteReal.h"
#include "WiimoteEmu/WiimoteEmu.h"
#include "ControllerInterface/ControllerInterface.h"
#include "WiimoteEmu/WiimoteEmu.h"
#if defined(HAVE_WX) && HAVE_WX
#include "WiimoteConfigDiag.h"
@@ -127,15 +127,11 @@ void InitPlugin( void* const hwnd )
//
void Wiimote_ControlChannel(int _number, u16 _channelID, const void* _pData, u32 _Size)
{
switch (g_wiimote_sources[_number])
{
case WIIMOTE_SRC_REAL :
if (WIIMOTE_SRC_EMU & g_wiimote_sources[_number])
((WiimoteEmu::Wiimote*)g_plugin.controllers[_number])->ControlChannel(_channelID, _pData, _Size);
if (WIIMOTE_SRC_REAL & g_wiimote_sources[_number])
WiimoteReal::ControlChannel(_number, _channelID, _pData, _Size);
break;
case WIIMOTE_SRC_EMU :
((WiimoteEmu::Wiimote*)g_plugin.controllers[ _number ])->ControlChannel( _channelID, _pData, _Size );
break;
}
}
// __________________________________________________________________________________________________
@@ -169,15 +165,10 @@ unsigned int Wiimote_UnPairWiimotes(void)
//
void Wiimote_InterruptChannel(int _number, u16 _channelID, const void* _pData, u32 _Size)
{
switch (g_wiimote_sources[_number])
{
case WIIMOTE_SRC_REAL :
if (WIIMOTE_SRC_EMU & g_wiimote_sources[_number])
((WiimoteEmu::Wiimote*)g_plugin.controllers[_number])->InterruptChannel(_channelID, _pData, _Size);
else
WiimoteReal::InterruptChannel(_number, _channelID, _pData, _Size);
break;
case WIIMOTE_SRC_EMU :
((WiimoteEmu::Wiimote*)g_plugin.controllers[ _number ])->InterruptChannel( _channelID, _pData, _Size );
break;
}
}
// __________________________________________________________________________________________________
@@ -201,15 +192,10 @@ void Wiimote_Update(int _number)
}
_last_number = _number;
switch (g_wiimote_sources[_number])
{
case WIIMOTE_SRC_REAL :
WiimoteReal::Update(_number);
break;
case WIIMOTE_SRC_EMU :
if (WIIMOTE_SRC_EMU & g_wiimote_sources[_number])
((WiimoteEmu::Wiimote*)g_plugin.controllers[_number])->Update();
break;
}
else
WiimoteReal::Update(_number);
g_plugin.controls_crit.Leave();
}
@@ -19,10 +19,8 @@
#include "Common.h"
#include "IniFile.h"
#include "Thread.h"
#include "StringUtil.h"
#include "Timer.h"
#include "FifoQueue.h"
#include "pluginspecs_wiimote.h"
#include "wiiuse.h"
@@ -46,45 +44,13 @@ Common::CriticalSection g_refresh_critsec, g_wiimote_critsec;
THREAD_RETURN WiimoteThreadFunc(void* arg);
class Wiimote
{
public:
Wiimote(wiimote_t* const wm, const unsigned int index);
~Wiimote();
void ControlChannel(const u16 channel, const void* const data, const u32 size);
void InterruptChannel(const u16 channel, const void* const data, const u32 size);
void Update();
void Read();
void Write();
void Disconnect();
void DisableDataReporting();
void SendPacket(const u8 rpt_id, const void* const data, const unsigned int size);
// pointer to data, and size of data
typedef std::pair<u8*,u8> Report;
private:
void ClearReports();
wiimote_t* const m_wiimote;
const unsigned int m_index;
u16 m_channel;
u8 m_last_data_report[MAX_PAYLOAD];
bool m_last_data_report_valid;
Common::FifoQueue<u8*> m_read_reports;
Common::FifoQueue<Report> m_write_reports;
};
Wiimote *g_wiimotes[4];
Wiimote::Wiimote(wiimote_t* const wm, const unsigned int index)
: m_wiimote(wm)
, m_index(index)
, m_channel(0)
, m_last_data_report_valid(false)
, m_last_data_report(NULL)
{
// disable reporting
DisableDataReporting();
@@ -100,7 +66,7 @@ Wiimote::Wiimote(wiimote_t* const wm, const unsigned int index)
//SendPacket(g_wiimotes_from_wiiuse[i], WM_LEDS, &rpt, sizeof(rpt));
//}
// Rumble briefly
// Rumble briefly, this is a bad spot for the rumble
wiiuse_rumble(m_wiimote, 1);
SLEEP(200);
wiiuse_rumble(m_wiimote, 0);
@@ -145,19 +111,26 @@ void Wiimote::SendPacket(const u8 rpt_id, const void* const data, const unsigned
void Wiimote::DisableDataReporting()
{
wm_report_mode rpt = wm_report_mode();
wm_report_mode rpt;
rpt.mode = WM_REPORT_CORE;
rpt.all_the_time = 0;
rpt.continuous = 0;
rpt.rumble = 0;
SendPacket(WM_REPORT_MODE, &rpt, sizeof(rpt));
}
void Wiimote::ClearReports()
{
m_last_data_report_valid = false;
if (m_last_data_report)
{
delete[] m_last_data_report;
m_last_data_report = NULL;
}
Report rpt;
while (m_read_reports.Pop(rpt.first))
delete[] rpt.first;
while (m_write_reports.Pop(rpt))
delete[] rpt.first;
delete rpt.first;
while (m_read_reports.Pop(rpt.first))
delete rpt.first;
}
void Wiimote::ControlChannel(const u16 channel, const void* const data, const u32 size)
@@ -177,7 +150,8 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const
while (wiiuse_io_read(m_wiimote)) {};
// request status
wm_request_status rpt = wm_request_status();
wm_request_status rpt;
rpt.rumble = 0;
SendPacket(WM_REQUEST_STATUS, &rpt, sizeof(rpt));
}
@@ -187,6 +161,24 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const
rpt.first = new u8[size];
rpt.second = (u8)size;
memcpy(rpt.first, (u8*)data, size);
// some hax, since we just send the last data report to Dolphin on each Update() call
// , make the wiimote only send updated data reports when data changes
// == less bt traffic, eliminates some unneeded packets
if (WM_REPORT_MODE == ((u8*)data)[1])
{
// also delete the last data report
if (m_last_data_report)
{
delete[] m_last_data_report;
m_last_data_report = NULL;
}
// nice var names :p, this seems to be this one
((wm_report_mode*)(rpt.first + 2))->all_the_time = false;
//((wm_report_mode*)(data + 2))->continuous = false;
}
m_write_reports.Push(rpt);
}
@@ -198,19 +190,10 @@ void Wiimote::Read()
if (wiiuse_io_read(m_wiimote))
{
// a data report, save it
if (m_wiimote->event_buf[1] >= 0x30)
{
memcpy(m_last_data_report, m_wiimote->event_buf, MAX_PAYLOAD);
m_last_data_report_valid = true;
}
else
{
// some other report, add it to queue
u8* const rpt = new u8[MAX_PAYLOAD];
memcpy(rpt, m_wiimote->event_buf, MAX_PAYLOAD);
m_read_reports.Push(rpt);
}
// add it to queue
u8* const rpt = new u8[MAX_PAYLOAD];
memcpy(rpt, m_wiimote->event_buf, MAX_PAYLOAD);
m_read_reports.Push(rpt);
}
}
@@ -224,20 +207,37 @@ void Wiimote::Write()
}
}
// returns the next report that should be sent
u8* Wiimote::ProcessReadQueue()
{
// pop through the queued reports
u8* rpt = m_last_data_report;
while (m_read_reports.Pop(rpt))
{
// a data report
if (rpt[1] >= WM_REPORT_CORE)
m_last_data_report = rpt;
// some other kind of report
else
return rpt;
}
// the queue was empty, or there were only data reports
return rpt;
}
void Wiimote::Update()
{
// do we have some queued reports
u8* rpt;
if (m_read_reports.Pop(rpt))
{
// pop through the queued reports
u8* const rpt = ProcessReadQueue();
// send the report
if (rpt)
g_WiimoteInitialize.pWiimoteInterruptChannel(m_index, m_channel, rpt, MAX_PAYLOAD);
// delete the data if it isn't also the last data rpt
if (rpt != m_last_data_report)
delete[] rpt;
}
else if (m_last_data_report_valid)
{
// otherwise send the last data report, if there is one
g_WiimoteInitialize.pWiimoteInterruptChannel(m_index, m_channel, m_last_data_report, MAX_PAYLOAD);
}
}
void Wiimote::Disconnect()
@@ -248,14 +248,14 @@ void Wiimote::Disconnect()
DisableDataReporting();
// clear queue
ClearReports();
u8 *rpt;
while (m_read_reports.Pop(rpt))
delete rpt;
// clear out wiiuse queue, or maybe not, silly? idk
while (wiiuse_io_read(m_wiimote)) {};
}
Wiimote* g_wiimotes[4];
void LoadSettings()
{
std::string ini_filename = (std::string(File::GetUserPath(D_CONFIG_IDX)) + g_plugin.ini_name + ".ini" );
@@ -284,7 +284,7 @@ unsigned int Initialize()
// only call wiiuse_find with the number of slots configured for real wiimotes
unsigned int wanted_wiimotes = 0;
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
if (WIIMOTE_SRC_REAL == g_wiimote_sources[i])
if (WIIMOTE_SRC_REAL & g_wiimote_sources[i])
++wanted_wiimotes;
// don't bother initializing wiiuse if we don't want any real wiimotes
@@ -320,14 +320,11 @@ unsigned int Initialize()
g_wiimote_critsec.Enter(); // enter
// create real wiimote class instances, assign wiimotes
for (unsigned int i = 0, w = 0; i<MAX_WIIMOTES && w<g_wiimotes_found; ++i)
{
if (WIIMOTE_SRC_REAL != g_wiimote_sources[i])
continue;
// create/assign wiimote
g_wiimotes[i] = new Wiimote(g_wiimotes_from_wiiuse[w++], i);
if (WIIMOTE_SRC_REAL & g_wiimote_sources[i])
g_wiimotes[i] = new Wiimote(g_wiimotes_from_wiiuse[w++], i);
}
g_wiimote_critsec.Leave(); // leave
@@ -383,29 +380,21 @@ void Shutdown(void)
void Refresh() // this gets called from the GUI thread
{
g_refresh_critsec.Enter();
#ifdef __linux__
// make sure real wiimotes have been initialized
if (!g_real_wiimotes_initialized)
{
g_refresh_critsec.Leave();
Initialize();
return;
}
// find the number of slots configured for real wiimotes
unsigned int wanted_wiimotes = 0;
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
if (g_wiimote_sources[i] == WIIMOTE_SRC_REAL)
if (WIIMOTE_SRC_REAL & g_wiimote_sources[i])
++wanted_wiimotes;
// don't scan for wiimotes if we don't want any more
if (wanted_wiimotes <= g_wiimotes_found)
{
g_refresh_critsec.Leave();
return;
}
// scan for wiimotes
unsigned int num_wiimotes = wiiuse_find(g_wiimotes_from_wiiuse, wanted_wiimotes, 5);
@@ -416,58 +405,41 @@ void Refresh() // this gets called from the GUI thread
DEBUG_LOG(WIIMOTE, "Connected to %i additional Real Wiimotes", num_new_wiimotes);
g_refresh_critsec.Enter();
g_wiimote_critsec.Enter(); // enter
// create real wiimote class instances, and assign wiimotes for the new wiimotes
for (unsigned int i = g_wiimotes_found, w = g_wiimotes_found;
i < MAX_WIIMOTES && w < num_wiimotes; ++i)
{
if (g_wiimote_sources[i] != WIIMOTE_SRC_REAL || g_wiimotes[i] != NULL)
continue;
// create/assign wiimote
g_wiimotes[i] = new Wiimote(g_wiimotes_from_wiiuse[w++], i);
if (WIIMOTE_SRC_REAL & g_wiimote_sources[i] && NULL == g_wiimotes[i])
g_wiimotes[i] = new Wiimote(g_wiimotes_from_wiiuse[w++], i);
}
g_wiimotes_found = num_wiimotes;
g_wiimote_critsec.Leave(); // leave
g_refresh_critsec.Leave();
#else // windows/ OSX
g_refresh_critsec.Enter();
// should be fine i think
Shutdown();
Initialize();
#endif
g_refresh_critsec.Leave();
#endif
}
void InterruptChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size)
{
u8* data = (u8*)_pData;
// some hax, since we just send the last data report to Dolphin on each Update() call
// , make the wiimote only send updated data reports when data changes
// == less bt traffic, eliminates some unneeded packets
if (WM_REPORT_MODE == ((u8*)_pData)[1])
{
// I dont wanna write on the const *_pData
data = new u8[_Size];
memcpy(data, _pData, _Size);
// nice var names :p, this seems to be this one
((wm_report_mode*)(data + 2))->all_the_time = false;
//((wm_report_mode*)(data + 2))->continuous = false;
}
g_refresh_critsec.Enter();
if (g_wiimotes[_WiimoteNumber])
g_wiimotes[_WiimoteNumber]->InterruptChannel(_channelID, data, _Size);
g_wiimotes[_WiimoteNumber]->InterruptChannel(_channelID, _pData, _Size);
g_refresh_critsec.Leave();
if (data != _pData)
delete[] data;
}
void ControlChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size)
@@ -21,6 +21,9 @@
#include "wiiuse.h"
#include "ChunkFile.h"
#include "Thread.h"
#include "FifoQueue.h"
#include "../WiimoteEmu/WiimoteEmu.h"
#include "../../InputCommon/Src/InputConfig.h"
@@ -33,13 +36,53 @@ extern SWiimoteInitialize g_WiimoteInitialize;
enum
{
WIIMOTE_SRC_NONE = 0,
WIIMOTE_SRC_EMU,
WIIMOTE_SRC_REAL,
WIIMOTE_SRC_EMU = 1,
WIIMOTE_SRC_REAL = 2,
WIIMOTE_SRC_HYBRID = 3, // emu + real
};
namespace WiimoteReal
{
class Wiimote
{
friend class WiimoteEmu::Wiimote;
public:
Wiimote(wiimote_t* const wm, const unsigned int index);
~Wiimote();
void ControlChannel(const u16 channel, const void* const data, const u32 size);
void InterruptChannel(const u16 channel, const void* const data, const u32 size);
void Update();
u8* ProcessReadQueue();
void Read();
void Write();
void Disconnect();
void DisableDataReporting();
void SendPacket(const u8 rpt_id, const void* const data, const unsigned int size);
// pointer to data, and size of data
typedef std::pair<u8*,u8> Report;
protected:
u8 *m_last_data_report;
u16 m_channel;
private:
void ClearReports();
wiimote_t* const m_wiimote;
const unsigned int m_index;
Common::FifoQueue<u8*> m_read_reports;
Common::FifoQueue<Report> m_write_reports;
};
extern Common::CriticalSection g_refresh_critsec;
extern Wiimote *g_wiimotes[4];
unsigned int Initialize();
void Shutdown();
void Refresh();