mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-04-18 02:42:42 +00:00
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:
parent
a1daa636c2
commit
2b45e87b3e
@ -5,6 +5,8 @@
|
|||||||
// a simple lockless thread-safe,
|
// a simple lockless thread-safe,
|
||||||
// single reader, single writer queue
|
// single reader, single writer queue
|
||||||
|
|
||||||
|
#include "Atomic.h"
|
||||||
|
|
||||||
namespace Common
|
namespace Common
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -12,7 +14,7 @@ template <typename T>
|
|||||||
class FifoQueue
|
class FifoQueue
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FifoQueue()
|
FifoQueue() : m_size(0)
|
||||||
{
|
{
|
||||||
m_write_ptr = m_read_ptr = new ElementPtr();
|
m_write_ptr = m_read_ptr = new ElementPtr();
|
||||||
}
|
}
|
||||||
@ -23,9 +25,20 @@ public:
|
|||||||
delete m_read_ptr;
|
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)
|
void Push(const T& t)
|
||||||
@ -35,42 +48,41 @@ public:
|
|||||||
// set the next pointer to a new element ptr
|
// set the next pointer to a new element ptr
|
||||||
// then advance the write pointer
|
// then advance the write pointer
|
||||||
m_write_ptr = m_write_ptr->next = new ElementPtr();
|
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)
|
bool Pop(T& t)
|
||||||
{
|
{
|
||||||
// if write pointer points to the same element, queue is empty
|
if (Empty())
|
||||||
if (m_read_ptr == m_write_ptr)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// get the element from out of the queue
|
t = Front();
|
||||||
t = *m_read_ptr->current;
|
Pop();
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Peek(T& t)
|
// not thread-safe
|
||||||
|
void Clear()
|
||||||
{
|
{
|
||||||
// if write pointer points to the same element, queue is empty
|
m_size = 0;
|
||||||
if (m_read_ptr == m_write_ptr)
|
delete m_read_ptr;
|
||||||
return false;
|
m_write_ptr = m_read_ptr = new ElementPtr();
|
||||||
|
|
||||||
// get the element from out of the queue
|
|
||||||
t = *m_read_ptr->current;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// stores a pointer to element at front of queue
|
// stores a pointer to element
|
||||||
// and a pointer to the next ElementPtr
|
// and a pointer to the next ElementPtr
|
||||||
class ElementPtr
|
class ElementPtr
|
||||||
{
|
{
|
||||||
@ -94,6 +106,7 @@ private:
|
|||||||
|
|
||||||
ElementPtr *volatile m_write_ptr;
|
ElementPtr *volatile m_write_ptr;
|
||||||
ElementPtr *volatile m_read_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("None"));
|
||||||
m_input_src_choice->Append(wxT("Emulated Wiimote"));
|
m_input_src_choice->Append(wxT("Emulated Wiimote"));
|
||||||
m_input_src_choice->Append(wxT("Real 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]);
|
m_input_src_choice->Select(g_wiimote_sources[m_index]);
|
||||||
_connect_macro_(m_input_src_choice, WiimoteConfigPage::SelectSource, wxEVT_COMMAND_CHOICE_SELECTED, this);
|
_connect_macro_(m_input_src_choice, WiimoteConfigPage::SelectSource, wxEVT_COMMAND_CHOICE_SELECTED, this);
|
||||||
|
|
||||||
|
@ -38,23 +38,21 @@
|
|||||||
#include "pluginspecs_wiimote.h"
|
#include "pluginspecs_wiimote.h"
|
||||||
|
|
||||||
#include "WiimoteEmu.h"
|
#include "WiimoteEmu.h"
|
||||||
|
#include "WiimoteHid.h"
|
||||||
|
#include "../WiimoteReal/WiimoteReal.h"
|
||||||
|
|
||||||
#include "Attachment/Attachment.h"
|
#include "Attachment/Attachment.h"
|
||||||
|
|
||||||
/* Bit shift conversions */
|
/* Bit shift conversions */
|
||||||
u32 convert24bit(const u8* src)
|
u32 swap24(const u8* src)
|
||||||
{
|
{
|
||||||
return (src[0] << 16) | (src[1] << 8) | src[2];
|
return (src[0] << 16) | (src[1] << 8) | src[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 convert16bit(const u8* src)
|
|
||||||
{
|
|
||||||
return (src[0] << 8) | src[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace WiimoteEmu
|
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");
|
//INFO_LOG(WIIMOTE, "Set data report mode");
|
||||||
//DEBUG_LOG(WIIMOTE, " Rumble: %x", dr->rumble);
|
//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
|
The IR enable/disable and speaker enable/disable and mute/unmute values are
|
||||||
bit2: 0 = Disable (0x02), 1 = Enable (0x06)
|
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:
|
// wiibrew:
|
||||||
// In every single Output Report, bit 0 (0x01) of the first byte controls the Rumble feature.
|
// 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;
|
break;
|
||||||
|
|
||||||
case WM_REPORT_MODE : // 0x12
|
case WM_REPORT_MODE : // 0x12
|
||||||
ReportMode(_channelID, (wm_report_mode*)sr->data);
|
ReportMode((wm_report_mode*)sr->data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_IR_PIXEL_CLOCK : // 0x13
|
case WM_IR_PIXEL_CLOCK : // 0x13
|
||||||
@ -128,16 +126,16 @@ void Wiimote::HidOutputReport(const u16 _channelID, wm_report* sr)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_REQUEST_STATUS : // 0x15
|
case WM_REQUEST_STATUS : // 0x15
|
||||||
RequestStatus(_channelID, (wm_request_status*)sr->data);
|
RequestStatus((wm_request_status*)sr->data);
|
||||||
return; // sends its own ack
|
return; // sends its own ack
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_WRITE_DATA : // 0x16
|
case WM_WRITE_DATA : // 0x16
|
||||||
WriteData(_channelID, (wm_write_data*)sr->data);
|
WriteData((wm_write_data*)sr->data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_READ_DATA : // 0x17
|
case WM_READ_DATA : // 0x17
|
||||||
ReadData(_channelID, (wm_read_data*)sr->data);
|
ReadData((wm_read_data*)sr->data);
|
||||||
return; // sends its own ack
|
return; // sends its own ack
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -175,7 +173,8 @@ void Wiimote::HidOutputReport(const u16 _channelID, wm_report* sr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// send ack
|
// send ack
|
||||||
SendAck(_channelID, sr->wm);
|
if (send_ack)
|
||||||
|
SendAck(sr->wm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This will generate the 0x22 acknowledgement for most Input reports.
|
/* 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,
|
The first two bytes are the core buttons data,
|
||||||
00 00 means nothing is pressed.
|
00 00 means nothing is pressed.
|
||||||
The last byte is the success code 00. */
|
The last byte is the success code 00. */
|
||||||
void Wiimote::SendAck(const u16 _channelID, u8 _reportID)
|
void Wiimote::SendAck(u8 _reportID)
|
||||||
{
|
{
|
||||||
u8 data[6];
|
u8 data[6];
|
||||||
|
|
||||||
@ -196,23 +195,16 @@ void Wiimote::SendAck(const u16 _channelID, u8 _reportID)
|
|||||||
ack->reportID = _reportID;
|
ack->reportID = _reportID;
|
||||||
ack->errorID = 0;
|
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
|
void Wiimote::HandleExtensionSwap()
|
||||||
/* 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)
|
|
||||||
{
|
{
|
||||||
//if (rs)
|
|
||||||
|
|
||||||
// handle switch extension
|
// 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 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
|
// detach extension first, wait til next Update() or RequestStatus() call to change to the new extension
|
||||||
m_extension->active_extension = 0;
|
m_extension->active_extension = 0;
|
||||||
else
|
else
|
||||||
@ -223,8 +215,18 @@ void Wiimote::RequestStatus(const u16 _channelID, wm_request_status* rs)
|
|||||||
m_status.extension = m_extension->active_extension ? 1 : 0;
|
m_status.extension = m_extension->active_extension ? 1 : 0;
|
||||||
|
|
||||||
// set register, I hate this line
|
// 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
|
// set up report
|
||||||
u8 data[8];
|
u8 data[8];
|
||||||
@ -234,14 +236,31 @@ void Wiimote::RequestStatus(const u16 _channelID, wm_request_status* rs)
|
|||||||
// status values
|
// status values
|
||||||
*(wm_status_report*)(data + 2) = m_status;
|
*(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
|
// 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. */
|
/* 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
|
// ignore the 0x010000 bit
|
||||||
address &= 0xFEFFFF;
|
address &= 0xFEFFFF;
|
||||||
@ -324,14 +343,24 @@ void Wiimote::WriteData(const u16 _channelID, wm_write_data* wd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Read data from Wiimote and Extensions registers. */
|
/* 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);
|
u32 address = swap24(rd->address);
|
||||||
u16 size = convert16bit(rd->size);
|
u16 size = Common::swap16(rd->size);
|
||||||
|
|
||||||
// ignore the 0x010000 bit
|
// ignore the 0x010000 bit
|
||||||
address &= 0xFEFFFF;
|
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;
|
ReadRequest rr;
|
||||||
u8* block = new u8[size];
|
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
|
// want the requested address, not the above modified one
|
||||||
rr.address = convert24bit(rd->address);
|
rr.address = swap24(rd->address);
|
||||||
rr.size = size;
|
rr.size = size;
|
||||||
//rr.channel = _channelID;
|
//rr.channel = _channelID;
|
||||||
rr.position = 0;
|
rr.position = 0;
|
||||||
rr.data = block;
|
rr.data = block;
|
||||||
|
|
||||||
// send up to 16 bytes
|
// send up to 16 bytes
|
||||||
SendReadDataReply( _channelID, rr );
|
SendReadDataReply(rr);
|
||||||
|
|
||||||
// if there is more data to be sent, add it to the queue
|
// if there is more data to be sent, add it to the queue
|
||||||
if (rr.size)
|
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
|
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.
|
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];
|
u8 data[23];
|
||||||
data[0] = 0xA1;
|
data[0] = 0xA1;
|
||||||
@ -488,7 +517,7 @@ void Wiimote::SendReadDataReply(const u16 _channelID, ReadRequest& _request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send a piece
|
// 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)
|
void Wiimote::DoState(PointerWrap& p)
|
||||||
|
@ -7,8 +7,10 @@
|
|||||||
#include "WiimoteEmu.h"
|
#include "WiimoteEmu.h"
|
||||||
#include "WiimoteHid.h"
|
#include "WiimoteHid.h"
|
||||||
|
|
||||||
#include <Timer.h>
|
#include "../WiimoteReal/WiimoteReal.h"
|
||||||
#include <Common.h>
|
|
||||||
|
#include "Timer.h"
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
#include "UDPTLayer.h"
|
#include "UDPTLayer.h"
|
||||||
|
|
||||||
@ -38,10 +40,7 @@ static const u8 eeprom_data_16D0[] = {
|
|||||||
|
|
||||||
#define SWING_INTENSITY 0x40
|
#define SWING_INTENSITY 0x40
|
||||||
|
|
||||||
static struct ReportFeatures
|
const ReportFeatures reporting_mode_features[] =
|
||||||
{
|
|
||||||
u8 core, accel, ir, ext, size;
|
|
||||||
} const reporting_mode_features[] =
|
|
||||||
{
|
{
|
||||||
//0x30: Core Buttons
|
//0x30: Core Buttons
|
||||||
{ 2, 0, 0, 0, 4 },
|
{ 2, 0, 0, 0, 4 },
|
||||||
@ -324,19 +323,215 @@ std::string Wiimote::GetName() const
|
|||||||
return std::string("Wiimote") + char('1'+m_index);
|
return std::string("Wiimote") + char('1'+m_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::Update()
|
// if windows is focused or background input is enabled
|
||||||
{
|
#define HAS_FOCUS (g_WiimoteInitialize.pRendererHasFocus() || (m_options->settings[0]->value != 0))
|
||||||
const bool is_sideways = m_options->settings[1]->value > 0;
|
|
||||||
const bool is_upright = m_options->settings[2]->value > 0;
|
|
||||||
|
|
||||||
// if windows is focused or background input is enabled
|
bool Wiimote::Step()
|
||||||
const bool is_focus = g_WiimoteInitialize.pRendererHasFocus() || (m_options->settings[0]->value != 0);
|
{
|
||||||
|
const bool has_focus = HAS_FOCUS;
|
||||||
|
const bool is_sideways = m_options->settings[1]->value != 0;
|
||||||
|
|
||||||
// no rumble if no focus
|
// no rumble if no focus
|
||||||
if (false == is_focus)
|
if (false == has_focus)
|
||||||
m_rumble_on = false;
|
m_rumble_on = false;
|
||||||
|
|
||||||
m_rumble->controls[0]->control_ref->State(m_rumble_on);
|
m_rumble->controls[0]->control_ref->State(m_rumble_on);
|
||||||
|
|
||||||
|
// update buttons in status struct
|
||||||
|
m_status.buttons = 0;
|
||||||
|
if (has_focus)
|
||||||
|
{
|
||||||
|
m_buttons->GetState(&m_status.buttons, button_bitmasks);
|
||||||
|
m_dpad->GetState(&m_status.buttons, is_sideways ? dpad_sideways_bitmasks : dpad_bitmasks);
|
||||||
|
UDPTLayer::GetButtons(m_udp, &m_status.buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if there is a read data request
|
||||||
|
if (m_read_requests.size())
|
||||||
|
{
|
||||||
|
ReadRequest& rr = m_read_requests.front();
|
||||||
|
// send up to 16 bytes to the wii
|
||||||
|
SendReadDataReply(rr);
|
||||||
|
//SendReadDataReply(rr.channel, rr);
|
||||||
|
|
||||||
|
// if there is no more data, remove from queue
|
||||||
|
if (0 == rr.size)
|
||||||
|
{
|
||||||
|
delete[] rr.data;
|
||||||
|
m_read_requests.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// dont send any other reports
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if a status report needs to be sent
|
||||||
|
// this happens on wiimote sync and when extensions are switched
|
||||||
|
if (m_extension->active_extension != m_extension->switch_extension)
|
||||||
|
{
|
||||||
|
RequestStatus();
|
||||||
|
|
||||||
|
// Wiibrew: Following a connection or disconnection event on the Extension Port,
|
||||||
|
// data reporting is disabled and the Data Reporting Mode must be reset before new data can arrive.
|
||||||
|
// after a game receives an unrequested status report,
|
||||||
|
// it expects data reports to stop until it sets the reporting mode again
|
||||||
|
m_reporting_auto = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wiimote::GetCoreData(u8* const data)
|
||||||
|
{
|
||||||
|
*(wm_core*)data |= m_status.buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wiimote::GetAccelData(u8* const data)
|
||||||
|
{
|
||||||
|
const bool has_focus = HAS_FOCUS;
|
||||||
|
const bool is_sideways = m_options->settings[1]->value != 0;
|
||||||
|
const bool is_upright = m_options->settings[2]->value != 0;
|
||||||
|
|
||||||
|
// ----TILT----
|
||||||
|
EmulateTilt((wm_accel*)data, m_tilt, (accel_cal*)&m_eeprom[0x16], has_focus, is_sideways, is_upright);
|
||||||
|
|
||||||
|
// ----SWING----
|
||||||
|
// ----SHAKE----
|
||||||
|
if (has_focus)
|
||||||
|
{
|
||||||
|
EmulateSwing((wm_accel*)data, m_swing, (accel_cal*)&m_eeprom[0x16], is_sideways, is_upright);
|
||||||
|
EmulateShake(data, m_shake, m_shake_step);
|
||||||
|
// UDP Wiimote
|
||||||
|
UDPTLayer::GetAcceleration(m_udp, (wm_accel*)data, (accel_cal*)&m_eeprom[0x16]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wiimote::GetIRData(u8* const data)
|
||||||
|
{
|
||||||
|
const bool has_focus = HAS_FOCUS;
|
||||||
|
|
||||||
|
u16 x[4], y[4];
|
||||||
|
memset(x, 0xFF, sizeof(x));
|
||||||
|
|
||||||
|
if (has_focus)
|
||||||
|
{
|
||||||
|
float xx = 10000, yy = 0, zz = 0;
|
||||||
|
float tx, ty;
|
||||||
|
|
||||||
|
m_ir->GetState(&xx, &yy, &zz, true);
|
||||||
|
UDPTLayer::GetIR(m_udp, &xx, &yy, &zz);
|
||||||
|
|
||||||
|
m_tilt->GetState(&tx, &ty, 0, PI/2, false);
|
||||||
|
|
||||||
|
// disabled cause my math still fails
|
||||||
|
const float rsin = 0;//sin(tx);
|
||||||
|
const float rcos = 1;//cos(tx);
|
||||||
|
|
||||||
|
{
|
||||||
|
const float xxx = (xx * -256 * 0.95f);
|
||||||
|
const float yyy = (yy * -256 * 0.90f);
|
||||||
|
|
||||||
|
xx = 512 + xxx * rcos + (144 + yyy) * rsin;
|
||||||
|
yy = 384 + (108 + yyy) * rcos - xxx * rsin;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dot distance of 25 is too little
|
||||||
|
const unsigned int distance = (unsigned int)(150 + 100 * zz);
|
||||||
|
|
||||||
|
x[0] = (unsigned int)(xx - distance * rcos);
|
||||||
|
x[1] = (unsigned int)(xx + distance * rcos);
|
||||||
|
x[2] = (unsigned int)(xx - 1.2f * distance * rcos);
|
||||||
|
x[3] = (unsigned int)(xx + 1.2f * distance * rcos);
|
||||||
|
|
||||||
|
y[0] = (unsigned int)(yy - 0.75 * distance * rsin);
|
||||||
|
y[1] = (unsigned int)(yy + 0.75 * distance * rsin);
|
||||||
|
y[2] = (unsigned int)(yy - 0.75 * 1.2f * distance * rsin);
|
||||||
|
y[3] = (unsigned int)(yy + 0.75 * 1.2f * distance * rsin);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill report with valid data when full handshake was done
|
||||||
|
if (m_reg_ir->data[0x30])
|
||||||
|
// ir mode
|
||||||
|
switch (m_reg_ir->mode)
|
||||||
|
{
|
||||||
|
// basic
|
||||||
|
case 1 :
|
||||||
|
{
|
||||||
|
memset(data, 0xFF, 10);
|
||||||
|
wm_ir_basic* const irdata = (wm_ir_basic*)data;
|
||||||
|
for (unsigned int i=0; i<2; ++i)
|
||||||
|
{
|
||||||
|
if (x[i*2] < 1024 && y[i*2] < 768)
|
||||||
|
{
|
||||||
|
irdata[i].x1 = u8(x[i*2]);
|
||||||
|
irdata[i].x1hi = x[i*2] >> 8;
|
||||||
|
|
||||||
|
irdata[i].y1 = u8(y[i*2]);
|
||||||
|
irdata[i].y1hi = y[i*2] >> 8;
|
||||||
|
}
|
||||||
|
if (x[i*2+1] < 1024 && y[i*2+1] < 768)
|
||||||
|
{
|
||||||
|
irdata[i].x2 = u8(x[i*2+1]);
|
||||||
|
irdata[i].x2hi = x[i*2+1] >> 8;
|
||||||
|
|
||||||
|
irdata[i].y2 = u8(y[i*2+1]);
|
||||||
|
irdata[i].y2hi = y[i*2+1] >> 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// extended
|
||||||
|
case 3 :
|
||||||
|
{
|
||||||
|
memset(data, 0xFF, 12);
|
||||||
|
wm_ir_extended* const irdata = (wm_ir_extended*)data;
|
||||||
|
for (unsigned int i=0; i<4; ++i)
|
||||||
|
if (x[i] < 1024 && y[i] < 768)
|
||||||
|
{
|
||||||
|
irdata[i].x = u8(x[i]);
|
||||||
|
irdata[i].xhi = x[i] >> 8;
|
||||||
|
|
||||||
|
irdata[i].y = u8(y[i]);
|
||||||
|
irdata[i].yhi = y[i] >> 8;
|
||||||
|
|
||||||
|
irdata[i].size = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// full
|
||||||
|
case 5 :
|
||||||
|
// UNSUPPORTED
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wiimote::GetExtData(u8* const data)
|
||||||
|
{
|
||||||
|
const bool has_focus = HAS_FOCUS;
|
||||||
|
|
||||||
|
m_extension->GetState(data, HAS_FOCUS);
|
||||||
|
|
||||||
|
// i dont think anything accesses the extension data like this, but ill support it. Indeed, commercial games don't do this.
|
||||||
|
// i think it should be unencrpyted in the register, encrypted when read.
|
||||||
|
memcpy(m_reg_ext->controller_data, data, sizeof(wm_extension));
|
||||||
|
|
||||||
|
if (0xAA == m_reg_ext->encryption)
|
||||||
|
wiimote_encrypt(&m_ext_key, data, 0x00, sizeof(wm_extension));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wiimote::Update()
|
||||||
|
{
|
||||||
|
// no channel == not connected i guess
|
||||||
|
if (0 == m_reporting_channel)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// returns true if a report was sent
|
||||||
|
if (Step())
|
||||||
|
return;
|
||||||
|
|
||||||
// ----speaker----
|
// ----speaker----
|
||||||
#ifdef USE_WIIMOTE_EMU_SPEAKER
|
#ifdef USE_WIIMOTE_EMU_SPEAKER
|
||||||
|
|
||||||
@ -367,208 +562,119 @@ void Wiimote::Update()
|
|||||||
//}
|
//}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// update buttons in status struct
|
u8 data[MAX_PAYLOAD];
|
||||||
m_status.buttons = 0;
|
memset(data, 0, sizeof(data));
|
||||||
if (is_focus)
|
|
||||||
{
|
|
||||||
m_buttons->GetState(&m_status.buttons, button_bitmasks);
|
|
||||||
m_dpad->GetState(&m_status.buttons, is_sideways ? dpad_sideways_bitmasks : dpad_bitmasks);
|
|
||||||
UDPTLayer::GetButtons(m_udp, &m_status.buttons);
|
|
||||||
}
|
|
||||||
|
|
||||||
// no channel == not connected i guess
|
|
||||||
if (0 == m_reporting_channel)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// check if there is a read data request
|
|
||||||
if (m_read_requests.size())
|
|
||||||
{
|
|
||||||
ReadRequest& rr = m_read_requests.front();
|
|
||||||
// send up to 16 bytes to the wii
|
|
||||||
SendReadDataReply(m_reporting_channel, rr);
|
|
||||||
//SendReadDataReply(rr.channel, rr);
|
|
||||||
|
|
||||||
// if there is no more data, remove from queue
|
|
||||||
if (0 == rr.size)
|
|
||||||
{
|
|
||||||
delete[] rr.data;
|
|
||||||
m_read_requests.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// dont send any other reports
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- maybe this should happen before the read request stuff?
|
|
||||||
// check if a status report needs to be sent
|
|
||||||
// this happens on wiimote sync and when extensions are switched
|
|
||||||
if (m_extension->active_extension != m_extension->switch_extension)
|
|
||||||
{
|
|
||||||
RequestStatus(m_reporting_channel);
|
|
||||||
|
|
||||||
// Wiibrew: Following a connection or disconnection event on the Extension Port,
|
|
||||||
// data reporting is disabled and the Data Reporting Mode must be reset before new data can arrive.
|
|
||||||
// after a game receives an unrequested status report,
|
|
||||||
// it expects data reports to stop until it sets the reporting mode again
|
|
||||||
m_reporting_auto = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false == m_reporting_auto)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// figure out what data we need
|
|
||||||
const ReportFeatures& rpt = reporting_mode_features[m_reporting_mode - WM_REPORT_CORE];
|
|
||||||
|
|
||||||
// what does the real wiimote do when put in a reporting mode with extension data,
|
|
||||||
// but with no extension attached? should i just send zeros? sure
|
|
||||||
//if (rpt.ext && (m_extension->active_extension <= 0))
|
|
||||||
//{
|
|
||||||
// m_reporting_auto = false;
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
|
|
||||||
// set up output report
|
|
||||||
// made data bigger than needed in case the wii specifies the wrong ir mode for a reporting mode
|
|
||||||
u8 data[46];
|
|
||||||
memset( data, 0, sizeof(data) );
|
|
||||||
|
|
||||||
data[0] = 0xA1;
|
data[0] = 0xA1;
|
||||||
data[1] = m_reporting_mode;
|
data[1] = m_reporting_mode;
|
||||||
|
|
||||||
|
// figure out what data we need
|
||||||
|
const ReportFeatures& rptf = reporting_mode_features[m_reporting_mode - WM_REPORT_CORE];
|
||||||
|
s8 rptf_size = rptf.size;
|
||||||
|
|
||||||
// core buttons
|
// core buttons
|
||||||
if (rpt.core)
|
if (rptf.core)
|
||||||
*(wm_core*)(data + rpt.core) = m_status.buttons;
|
GetCoreData(data + rptf.core);
|
||||||
|
|
||||||
// ----accelerometer----
|
// acceleration
|
||||||
if (rpt.accel)
|
if (rptf.accel)
|
||||||
|
GetAccelData(data + rptf.accel);
|
||||||
|
|
||||||
|
// IR
|
||||||
|
if (rptf.ir)
|
||||||
|
GetIRData(data + rptf.ir);
|
||||||
|
|
||||||
|
// extension
|
||||||
|
if (rptf.ext)
|
||||||
|
GetExtData(data + rptf.ext);
|
||||||
|
|
||||||
|
// hybrid wiimote stuff
|
||||||
|
if (WIIMOTE_SRC_HYBRID == g_wiimote_sources[m_index])
|
||||||
{
|
{
|
||||||
// ----TILT----
|
using namespace WiimoteReal;
|
||||||
EmulateTilt((wm_accel*)&data[rpt.accel], m_tilt, (accel_cal*)&m_eeprom[0x16], is_focus, is_sideways, is_upright);
|
|
||||||
|
|
||||||
// ----SWING----
|
g_refresh_critsec.Enter();
|
||||||
// ----SHAKE----
|
if (g_wiimotes[m_index])
|
||||||
if (is_focus)
|
|
||||||
{
|
{
|
||||||
EmulateSwing((wm_accel*)&data[rpt.accel], m_swing, (accel_cal*)&m_eeprom[0x16], is_sideways, is_upright);
|
u8* const real_data = g_wiimotes[m_index]->ProcessReadQueue();
|
||||||
EmulateShake(data + rpt.accel, m_shake, m_shake_step);
|
if (real_data)
|
||||||
// UDP Wiimote
|
{
|
||||||
UDPTLayer::GetAcceleration(m_udp, (wm_accel*)&data[rpt.accel], (accel_cal*)&m_eeprom[0x16]);
|
switch (real_data[1])
|
||||||
|
{
|
||||||
|
// use data reports
|
||||||
|
default:
|
||||||
|
if (real_data[1] >= WM_REPORT_CORE)
|
||||||
|
{
|
||||||
|
const ReportFeatures& real_rptf = reporting_mode_features[real_data[1] - WM_REPORT_CORE];
|
||||||
|
|
||||||
|
// force same report type from real-wiimote
|
||||||
|
if (&real_rptf != &rptf)
|
||||||
|
rptf_size = 0;
|
||||||
|
|
||||||
|
// core
|
||||||
|
// mix real-buttons with emu-buttons in the status struct, and in the report
|
||||||
|
if (real_rptf.core && rptf.core)
|
||||||
|
{
|
||||||
|
m_status.buttons |= *(wm_core*)(real_data + real_rptf.core);
|
||||||
|
*(wm_core*)(data + rptf.core) = m_status.buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
// accel
|
||||||
|
// use real-accel data always i guess
|
||||||
|
if (real_rptf.accel && rptf.accel)
|
||||||
|
memcpy(data + rptf.accel, real_data + real_rptf.accel, sizeof(wm_accel));
|
||||||
|
|
||||||
|
// ir
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
// ext
|
||||||
|
// use real-ext data if an emu-extention isn't chosen
|
||||||
|
if (real_rptf.ext && rptf.ext && (0 == m_extension->switch_extension))
|
||||||
|
memcpy(data + rptf.ext, real_data + real_rptf.ext, sizeof(wm_extension));
|
||||||
|
}
|
||||||
|
else if (WM_ACK_DATA != real_data[1] || m_extension->active_extension > 0)
|
||||||
|
rptf_size = 0;
|
||||||
|
else
|
||||||
|
// use real-acks if an emu-extension isn't chosen
|
||||||
|
rptf_size = -1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// use all status reports, after modification of the extension bit
|
||||||
|
case WM_STATUS_REPORT :
|
||||||
|
//if (m_extension->switch_extension)
|
||||||
|
//((wm_status_report*)(real_data + 2))->extension = (m_extension->active_extension > 0);
|
||||||
|
if (m_extension->active_extension)
|
||||||
|
((wm_status_report*)(real_data + 2))->extension = 1;
|
||||||
|
rptf_size = -1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// use all read-data replies
|
||||||
|
case WM_READ_DATA_REPLY:
|
||||||
|
rptf_size = -1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy over report from real-wiimote
|
||||||
|
if (-1 == rptf_size)
|
||||||
|
{
|
||||||
|
memcpy(data, real_data, MAX_PAYLOAD);
|
||||||
|
rptf_size = MAX_PAYLOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (real_data != g_wiimotes[m_index]->m_last_data_report)
|
||||||
|
delete[] real_data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
g_refresh_critsec.Leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----ir----
|
// don't send a data report if auto reporting is off
|
||||||
if (rpt.ir)
|
if (false == m_reporting_auto && data[2] >= WM_REPORT_CORE)
|
||||||
{
|
return;
|
||||||
float xx = 10000, yy = 0, zz = 0;
|
|
||||||
unsigned int x[4], y[4];
|
|
||||||
|
|
||||||
if (is_focus)
|
|
||||||
{
|
|
||||||
m_ir->GetState(&xx, &yy, &zz, true);
|
|
||||||
UDPTLayer::GetIR(m_udp, &xx, &yy, &zz);
|
|
||||||
|
|
||||||
float tx, ty;
|
|
||||||
m_tilt->GetState(&tx, &ty, 0, 1, false);
|
|
||||||
|
|
||||||
// TODO: fix tilt math stuff
|
|
||||||
|
|
||||||
const float rtan = tan(0.0f/*tx*/); // disabled cause my math fails
|
|
||||||
const float rsin = sin(rtan);
|
|
||||||
const float rcos = cos(rtan);
|
|
||||||
|
|
||||||
{
|
|
||||||
const float xxx = (xx * -256 * 0.95f);
|
|
||||||
const float yyy = (yy * -256 * 0.90f);
|
|
||||||
|
|
||||||
xx = 512 + xxx * rcos + yyy * rsin;
|
|
||||||
yy = 490 + yyy * rcos + xxx * rsin;
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned int distance = (unsigned int)(200 + 100 * zz);
|
|
||||||
|
|
||||||
x[0] = (unsigned int)(xx - distance * rcos);
|
|
||||||
x[1] = (unsigned int)(xx + distance * rcos);
|
|
||||||
x[2] = (unsigned int)(xx - 1.2f * distance * rcos);
|
|
||||||
x[3] = (unsigned int)(xx + 1.2f * distance * rcos);
|
|
||||||
|
|
||||||
y[0] = (unsigned int)(yy - 0.75 * distance * rsin);
|
|
||||||
y[1] = (unsigned int)(yy + 0.75 * distance * rsin);
|
|
||||||
y[2] = (unsigned int)(yy - 0.75 * 1.2f * distance * rsin);
|
|
||||||
y[3] = (unsigned int)(yy + 0.75 * 1.2f * distance * rsin);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill report with valid data when full handshake was done
|
|
||||||
if (m_reg_ir->data[0x30])
|
|
||||||
// ir mode
|
|
||||||
switch (m_reg_ir->mode)
|
|
||||||
{
|
|
||||||
// basic
|
|
||||||
case 1 :
|
|
||||||
{
|
|
||||||
memset(data + rpt.ir, 0xFF, 10);
|
|
||||||
wm_ir_basic* const irdata = (wm_ir_basic*)(data + rpt.ir);
|
|
||||||
for (unsigned int i=0; i<2; ++i)
|
|
||||||
{
|
|
||||||
if (x[i*2] < 1024 && y[i*2] < 768)
|
|
||||||
{
|
|
||||||
irdata[i].x1 = u8(x[i*2]);
|
|
||||||
irdata[i].x1hi = x[i*2] >> 8;
|
|
||||||
|
|
||||||
irdata[i].y1 = u8(y[i*2]);
|
|
||||||
irdata[i].y1hi = y[i*2] >> 8;
|
|
||||||
}
|
|
||||||
if (x[i*2+1] < 1024 && y[i*2+1] < 768)
|
|
||||||
{
|
|
||||||
irdata[i].x2 = u8(x[i*2+1]);
|
|
||||||
irdata[i].x2hi = x[i*2+1] >> 8;
|
|
||||||
|
|
||||||
irdata[i].y2 = u8(y[i*2+1]);
|
|
||||||
irdata[i].y2hi = y[i*2+1] >> 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// extended
|
|
||||||
case 3 :
|
|
||||||
{
|
|
||||||
memset(data + rpt.ir, 0xFF, 12);
|
|
||||||
wm_ir_extended* const irdata = (wm_ir_extended*)(data + rpt.ir);
|
|
||||||
for (unsigned int i=0; i<4; ++i)
|
|
||||||
if (x[i] < 1024 && y[i] < 768)
|
|
||||||
{
|
|
||||||
irdata[i].x = u8(x[i]);
|
|
||||||
irdata[i].xhi = x[i] >> 8;
|
|
||||||
|
|
||||||
irdata[i].y = u8(y[i]);
|
|
||||||
irdata[i].yhi = y[i] >> 8;
|
|
||||||
|
|
||||||
irdata[i].size = 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// full
|
|
||||||
case 5 :
|
|
||||||
// UNSUPPORTED
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----extension----
|
|
||||||
if (rpt.ext)
|
|
||||||
{
|
|
||||||
m_extension->GetState(data + rpt.ext, is_focus);
|
|
||||||
|
|
||||||
// i dont think anything accesses the extension data like this, but ill support it. Indeed, commercial games don't do this.
|
|
||||||
// i think it should be unencrpyted in the register, encrypted when read.
|
|
||||||
memcpy(m_reg_ext->controller_data, data + rpt.ext, sizeof(wm_extension));
|
|
||||||
|
|
||||||
if (0xAA == m_reg_ext->encryption) {
|
|
||||||
wiimote_encrypt(&m_ext_key, data + rpt.ext, 0x00, sizeof(wm_extension));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// send data report
|
// send data report
|
||||||
g_WiimoteInitialize.pWiimoteInterruptChannel( m_index, m_reporting_channel, data, rpt.size );
|
if (rptf_size)
|
||||||
|
g_WiimoteInitialize.pWiimoteInterruptChannel(m_index, m_reporting_channel, data, rptf_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::ControlChannel(const u16 _channelID, const void* _pData, u32 _Size)
|
void Wiimote::ControlChannel(const u16 _channelID, const void* _pData, u32 _Size)
|
||||||
@ -587,7 +693,7 @@ void Wiimote::ControlChannel(const u16 _channelID, const void* _pData, u32 _Size
|
|||||||
// this all good?
|
// this all good?
|
||||||
m_reporting_channel = _channelID;
|
m_reporting_channel = _channelID;
|
||||||
|
|
||||||
hid_packet* hidp = (hid_packet*)_pData;
|
const hid_packet* const hidp = (hid_packet*)_pData;
|
||||||
|
|
||||||
INFO_LOG(WIIMOTE, "Emu ControlChannel (page: %i, type: 0x%02x, param: 0x%02x)", m_index, hidp->type, hidp->param);
|
INFO_LOG(WIIMOTE, "Emu ControlChannel (page: %i, type: 0x%02x, param: 0x%02x)", m_index, hidp->type, hidp->param);
|
||||||
|
|
||||||
@ -606,7 +712,7 @@ void Wiimote::ControlChannel(const u16 _channelID, const void* _pData, u32 _Size
|
|||||||
{
|
{
|
||||||
// AyuanX: My experiment shows Control Channel is never used
|
// AyuanX: My experiment shows Control Channel is never used
|
||||||
// shuffle2: but homebrew uses this, so we'll do what we must :)
|
// shuffle2: but homebrew uses this, so we'll do what we must :)
|
||||||
HidOutputReport(_channelID, (wm_report*)hidp->data);
|
HidOutputReport((wm_report*)hidp->data);
|
||||||
|
|
||||||
u8 handshake = HID_HANDSHAKE_SUCCESS;
|
u8 handshake = HID_HANDSHAKE_SUCCESS;
|
||||||
g_WiimoteInitialize.pWiimoteInterruptChannel(m_index, _channelID, &handshake, 1);
|
g_WiimoteInitialize.pWiimoteInterruptChannel(m_index, _channelID, &handshake, 1);
|
||||||
@ -631,7 +737,7 @@ void Wiimote::InterruptChannel(const u16 _channelID, const void* _pData, u32 _Si
|
|||||||
// this all good?
|
// this all good?
|
||||||
m_reporting_channel = _channelID;
|
m_reporting_channel = _channelID;
|
||||||
|
|
||||||
hid_packet* hidp = (hid_packet*)_pData;
|
const hid_packet* const hidp = (hid_packet*)_pData;
|
||||||
|
|
||||||
switch (hidp->type)
|
switch (hidp->type)
|
||||||
{
|
{
|
||||||
@ -640,8 +746,26 @@ void Wiimote::InterruptChannel(const u16 _channelID, const void* _pData, u32 _Si
|
|||||||
{
|
{
|
||||||
case HID_PARAM_OUTPUT :
|
case HID_PARAM_OUTPUT :
|
||||||
{
|
{
|
||||||
wm_report* sr = (wm_report*)hidp->data;
|
const wm_report* const sr = (wm_report*)hidp->data;
|
||||||
HidOutputReport(_channelID, sr);
|
|
||||||
|
if (WIIMOTE_SRC_HYBRID == g_wiimote_sources[m_index])
|
||||||
|
{
|
||||||
|
switch (sr->wm)
|
||||||
|
{
|
||||||
|
// these two types are handled in RequestStatus() & ReadData()
|
||||||
|
case WM_REQUEST_STATUS :
|
||||||
|
case WM_READ_DATA :
|
||||||
|
break;
|
||||||
|
|
||||||
|
default :
|
||||||
|
WiimoteReal::InterruptChannel(m_index, _channelID, _pData, _Size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
HidOutputReport(sr, m_extension->switch_extension > 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
HidOutputReport(sr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -762,7 +886,7 @@ void Wiimote::Register::Read( size_t address, void* dst, size_t length )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: i need to test this
|
// TODO: i need to test this
|
||||||
void Wiimote::Register::Write( size_t address, void* src, size_t length )
|
void Wiimote::Register::Write( size_t address, const void* src, size_t length )
|
||||||
{
|
{
|
||||||
iterator i = begin();
|
iterator i = begin();
|
||||||
const const_iterator e = end();
|
const const_iterator e = end();
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
// just used to get the OpenAL includes :p
|
// just used to get the OpenAL includes :p
|
||||||
//#include <OpenALStream.h>
|
//#include <OpenALStream.h>
|
||||||
|
|
||||||
#include <ControllerEmu.h>
|
#include "ControllerEmu.h"
|
||||||
#include "ChunkFile.h"
|
#include "ChunkFile.h"
|
||||||
|
|
||||||
#include "WiimoteHid.h"
|
#include "WiimoteHid.h"
|
||||||
@ -32,6 +32,13 @@ extern SWiimoteInitialize g_WiimoteInitialize;
|
|||||||
namespace WiimoteEmu
|
namespace WiimoteEmu
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct ReportFeatures
|
||||||
|
{
|
||||||
|
u8 core, accel, ir, ext, size;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const ReportFeatures reporting_mode_features[];
|
||||||
|
|
||||||
void EmulateShake(u8* const accel_data
|
void EmulateShake(u8* const accel_data
|
||||||
, ControllerEmu::Buttons* const buttons_group
|
, ControllerEmu::Buttons* const buttons_group
|
||||||
, unsigned int* const shake_step);
|
, unsigned int* const shake_step);
|
||||||
@ -77,6 +84,19 @@ public:
|
|||||||
|
|
||||||
void LoadDefaults(const ControllerInterface& ciface);
|
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:
|
private:
|
||||||
struct ReadRequest
|
struct ReadRequest
|
||||||
{
|
{
|
||||||
@ -87,14 +107,12 @@ private:
|
|||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
void ReportMode(const u16 _channelID, wm_report_mode* dr);
|
void ReportMode(const wm_report_mode* const dr);
|
||||||
void HidOutputReport(const u16 _channelID, wm_report* sr);
|
void SendAck(const u8 _reportID);
|
||||||
void SendAck(const u16 _channelID, u8 _reportID);
|
void RequestStatus(const wm_request_status* const rs = NULL);
|
||||||
void RequestStatus(const u16 _channelID, wm_request_status* rs = NULL);
|
void ReadData(const wm_read_data* const rd);
|
||||||
|
void WriteData(const wm_write_data* const wd);
|
||||||
void WriteData(const u16 _channelID, wm_write_data* wd);
|
void SendReadDataReply(ReadRequest& _request);
|
||||||
void ReadData(const u16 _channelID, wm_read_data* rd);
|
|
||||||
void SendReadDataReply(const u16 _channelID, ReadRequest& _request);
|
|
||||||
|
|
||||||
#ifdef USE_WIIMOTE_EMU_SPEAKER
|
#ifdef USE_WIIMOTE_EMU_SPEAKER
|
||||||
void SpeakerData(wm_speaker_data* sd);
|
void SpeakerData(wm_speaker_data* sd);
|
||||||
@ -131,7 +149,7 @@ private:
|
|||||||
class Register : public std::map< size_t, std::vector<u8> >
|
class Register : public std::map< size_t, std::vector<u8> >
|
||||||
{
|
{
|
||||||
public:
|
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 );
|
void Read( size_t address, void* dst, size_t length );
|
||||||
|
|
||||||
} m_register;
|
} m_register;
|
||||||
|
@ -205,7 +205,7 @@ struct wm_read_data {
|
|||||||
u8 space : 2; //see WM_SPACE_*
|
u8 space : 2; //see WM_SPACE_*
|
||||||
u8 : 5;
|
u8 : 5;
|
||||||
u8 address[3];
|
u8 address[3];
|
||||||
u8 size[2];
|
u16 size;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define WM_SPACE_EEPROM 0
|
#define WM_SPACE_EEPROM 0
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
#include "pluginspecs_wiimote.h"
|
#include "pluginspecs_wiimote.h"
|
||||||
|
|
||||||
#include "WiimoteReal/WiimoteReal.h"
|
#include "WiimoteReal/WiimoteReal.h"
|
||||||
|
#include "WiimoteEmu/WiimoteEmu.h"
|
||||||
|
|
||||||
#include "ControllerInterface/ControllerInterface.h"
|
#include "ControllerInterface/ControllerInterface.h"
|
||||||
#include "WiimoteEmu/WiimoteEmu.h"
|
|
||||||
|
|
||||||
#if defined(HAVE_WX) && HAVE_WX
|
#if defined(HAVE_WX) && HAVE_WX
|
||||||
#include "WiimoteConfigDiag.h"
|
#include "WiimoteConfigDiag.h"
|
||||||
@ -127,15 +127,11 @@ void InitPlugin( void* const hwnd )
|
|||||||
//
|
//
|
||||||
void Wiimote_ControlChannel(int _number, u16 _channelID, const void* _pData, u32 _Size)
|
void Wiimote_ControlChannel(int _number, u16 _channelID, const void* _pData, u32 _Size)
|
||||||
{
|
{
|
||||||
switch (g_wiimote_sources[_number])
|
if (WIIMOTE_SRC_EMU & g_wiimote_sources[_number])
|
||||||
{
|
((WiimoteEmu::Wiimote*)g_plugin.controllers[_number])->ControlChannel(_channelID, _pData, _Size);
|
||||||
case WIIMOTE_SRC_REAL :
|
|
||||||
|
if (WIIMOTE_SRC_REAL & g_wiimote_sources[_number])
|
||||||
WiimoteReal::ControlChannel(_number, _channelID, _pData, _Size);
|
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)
|
void Wiimote_InterruptChannel(int _number, u16 _channelID, const void* _pData, u32 _Size)
|
||||||
{
|
{
|
||||||
switch (g_wiimote_sources[_number])
|
if (WIIMOTE_SRC_EMU & g_wiimote_sources[_number])
|
||||||
{
|
((WiimoteEmu::Wiimote*)g_plugin.controllers[_number])->InterruptChannel(_channelID, _pData, _Size);
|
||||||
case WIIMOTE_SRC_REAL :
|
else
|
||||||
WiimoteReal::InterruptChannel(_number, _channelID, _pData, _Size);
|
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;
|
_last_number = _number;
|
||||||
|
|
||||||
switch (g_wiimote_sources[_number])
|
if (WIIMOTE_SRC_EMU & g_wiimote_sources[_number])
|
||||||
{
|
|
||||||
case WIIMOTE_SRC_REAL :
|
|
||||||
WiimoteReal::Update(_number);
|
|
||||||
break;
|
|
||||||
case WIIMOTE_SRC_EMU :
|
|
||||||
((WiimoteEmu::Wiimote*)g_plugin.controllers[_number])->Update();
|
((WiimoteEmu::Wiimote*)g_plugin.controllers[_number])->Update();
|
||||||
break;
|
else
|
||||||
}
|
WiimoteReal::Update(_number);
|
||||||
|
|
||||||
g_plugin.controls_crit.Leave();
|
g_plugin.controls_crit.Leave();
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,8 @@
|
|||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "IniFile.h"
|
#include "IniFile.h"
|
||||||
#include "Thread.h"
|
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
#include "FifoQueue.h"
|
|
||||||
#include "pluginspecs_wiimote.h"
|
#include "pluginspecs_wiimote.h"
|
||||||
|
|
||||||
#include "wiiuse.h"
|
#include "wiiuse.h"
|
||||||
@ -46,45 +44,13 @@ Common::CriticalSection g_refresh_critsec, g_wiimote_critsec;
|
|||||||
|
|
||||||
THREAD_RETURN WiimoteThreadFunc(void* arg);
|
THREAD_RETURN WiimoteThreadFunc(void* arg);
|
||||||
|
|
||||||
class Wiimote
|
Wiimote *g_wiimotes[4];
|
||||||
{
|
|
||||||
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::Wiimote(wiimote_t* const wm, const unsigned int index)
|
Wiimote::Wiimote(wiimote_t* const wm, const unsigned int index)
|
||||||
: m_wiimote(wm)
|
: m_wiimote(wm)
|
||||||
, m_index(index)
|
, m_index(index)
|
||||||
, m_channel(0)
|
, m_channel(0)
|
||||||
, m_last_data_report_valid(false)
|
, m_last_data_report(NULL)
|
||||||
{
|
{
|
||||||
// disable reporting
|
// disable reporting
|
||||||
DisableDataReporting();
|
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));
|
//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);
|
wiiuse_rumble(m_wiimote, 1);
|
||||||
SLEEP(200);
|
SLEEP(200);
|
||||||
wiiuse_rumble(m_wiimote, 0);
|
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()
|
void Wiimote::DisableDataReporting()
|
||||||
{
|
{
|
||||||
wm_report_mode rpt = wm_report_mode();
|
wm_report_mode rpt;
|
||||||
rpt.mode = WM_REPORT_CORE;
|
rpt.mode = WM_REPORT_CORE;
|
||||||
|
rpt.all_the_time = 0;
|
||||||
|
rpt.continuous = 0;
|
||||||
|
rpt.rumble = 0;
|
||||||
SendPacket(WM_REPORT_MODE, &rpt, sizeof(rpt));
|
SendPacket(WM_REPORT_MODE, &rpt, sizeof(rpt));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::ClearReports()
|
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;
|
Report rpt;
|
||||||
while (m_read_reports.Pop(rpt.first))
|
|
||||||
delete[] rpt.first;
|
|
||||||
while (m_write_reports.Pop(rpt))
|
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)
|
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)) {};
|
while (wiiuse_io_read(m_wiimote)) {};
|
||||||
|
|
||||||
// request status
|
// request status
|
||||||
wm_request_status rpt = wm_request_status();
|
wm_request_status rpt;
|
||||||
|
rpt.rumble = 0;
|
||||||
SendPacket(WM_REQUEST_STATUS, &rpt, sizeof(rpt));
|
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.first = new u8[size];
|
||||||
rpt.second = (u8)size;
|
rpt.second = (u8)size;
|
||||||
memcpy(rpt.first, (u8*)data, 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);
|
m_write_reports.Push(rpt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,19 +190,10 @@ void Wiimote::Read()
|
|||||||
|
|
||||||
if (wiiuse_io_read(m_wiimote))
|
if (wiiuse_io_read(m_wiimote))
|
||||||
{
|
{
|
||||||
// a data report, save it
|
// add it to queue
|
||||||
if (m_wiimote->event_buf[1] >= 0x30)
|
u8* const rpt = new u8[MAX_PAYLOAD];
|
||||||
{
|
memcpy(rpt, m_wiimote->event_buf, MAX_PAYLOAD);
|
||||||
memcpy(m_last_data_report, m_wiimote->event_buf, MAX_PAYLOAD);
|
m_read_reports.Push(rpt);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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()
|
void Wiimote::Update()
|
||||||
{
|
{
|
||||||
// do we have some queued reports
|
// pop through the queued reports
|
||||||
u8* rpt;
|
u8* const rpt = ProcessReadQueue();
|
||||||
if (m_read_reports.Pop(rpt))
|
|
||||||
{
|
// send the report
|
||||||
|
if (rpt)
|
||||||
g_WiimoteInitialize.pWiimoteInterruptChannel(m_index, m_channel, rpt, MAX_PAYLOAD);
|
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;
|
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()
|
void Wiimote::Disconnect()
|
||||||
@ -248,14 +248,14 @@ void Wiimote::Disconnect()
|
|||||||
DisableDataReporting();
|
DisableDataReporting();
|
||||||
|
|
||||||
// clear queue
|
// clear queue
|
||||||
ClearReports();
|
u8 *rpt;
|
||||||
|
while (m_read_reports.Pop(rpt))
|
||||||
|
delete rpt;
|
||||||
|
|
||||||
// clear out wiiuse queue, or maybe not, silly? idk
|
// clear out wiiuse queue, or maybe not, silly? idk
|
||||||
while (wiiuse_io_read(m_wiimote)) {};
|
while (wiiuse_io_read(m_wiimote)) {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Wiimote* g_wiimotes[4];
|
|
||||||
|
|
||||||
void LoadSettings()
|
void LoadSettings()
|
||||||
{
|
{
|
||||||
std::string ini_filename = (std::string(File::GetUserPath(D_CONFIG_IDX)) + g_plugin.ini_name + ".ini" );
|
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
|
// only call wiiuse_find with the number of slots configured for real wiimotes
|
||||||
unsigned int wanted_wiimotes = 0;
|
unsigned int wanted_wiimotes = 0;
|
||||||
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
|
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;
|
++wanted_wiimotes;
|
||||||
|
|
||||||
// don't bother initializing wiiuse if we don't want any real 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
|
g_wiimote_critsec.Enter(); // enter
|
||||||
|
|
||||||
// create real wiimote class instances, assign wiimotes
|
// create real wiimote class instances, assign wiimotes
|
||||||
|
|
||||||
for (unsigned int i = 0, w = 0; i<MAX_WIIMOTES && w<g_wiimotes_found; ++i)
|
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
|
// 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
|
g_wiimote_critsec.Leave(); // leave
|
||||||
@ -383,29 +380,21 @@ void Shutdown(void)
|
|||||||
|
|
||||||
void Refresh() // this gets called from the GUI thread
|
void Refresh() // this gets called from the GUI thread
|
||||||
{
|
{
|
||||||
g_refresh_critsec.Enter();
|
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
// make sure real wiimotes have been initialized
|
// make sure real wiimotes have been initialized
|
||||||
if (!g_real_wiimotes_initialized)
|
if (!g_real_wiimotes_initialized)
|
||||||
{
|
|
||||||
g_refresh_critsec.Leave();
|
|
||||||
Initialize();
|
Initialize();
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// find the number of slots configured for real wiimotes
|
// find the number of slots configured for real wiimotes
|
||||||
unsigned int wanted_wiimotes = 0;
|
unsigned int wanted_wiimotes = 0;
|
||||||
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
|
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;
|
++wanted_wiimotes;
|
||||||
|
|
||||||
// don't scan for wiimotes if we don't want any more
|
// don't scan for wiimotes if we don't want any more
|
||||||
if (wanted_wiimotes <= g_wiimotes_found)
|
if (wanted_wiimotes <= g_wiimotes_found)
|
||||||
{
|
|
||||||
g_refresh_critsec.Leave();
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// scan for wiimotes
|
// scan for wiimotes
|
||||||
unsigned int num_wiimotes = wiiuse_find(g_wiimotes_from_wiiuse, wanted_wiimotes, 5);
|
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);
|
DEBUG_LOG(WIIMOTE, "Connected to %i additional Real Wiimotes", num_new_wiimotes);
|
||||||
|
|
||||||
|
g_refresh_critsec.Enter();
|
||||||
g_wiimote_critsec.Enter(); // enter
|
g_wiimote_critsec.Enter(); // enter
|
||||||
|
|
||||||
// create real wiimote class instances, and assign wiimotes for the new wiimotes
|
// create real wiimote class instances, and assign wiimotes for the new wiimotes
|
||||||
for (unsigned int i = g_wiimotes_found, w = g_wiimotes_found;
|
for (unsigned int i = g_wiimotes_found, w = g_wiimotes_found;
|
||||||
i < MAX_WIIMOTES && w < num_wiimotes; ++i)
|
i < MAX_WIIMOTES && w < num_wiimotes; ++i)
|
||||||
{
|
{
|
||||||
if (g_wiimote_sources[i] != WIIMOTE_SRC_REAL || g_wiimotes[i] != NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// create/assign wiimote
|
// 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_wiimotes_found = num_wiimotes;
|
||||||
|
|
||||||
g_wiimote_critsec.Leave(); // leave
|
g_wiimote_critsec.Leave(); // leave
|
||||||
|
g_refresh_critsec.Leave();
|
||||||
|
|
||||||
#else // windows/ OSX
|
#else // windows/ OSX
|
||||||
|
g_refresh_critsec.Enter();
|
||||||
|
|
||||||
// should be fine i think
|
// should be fine i think
|
||||||
Shutdown();
|
Shutdown();
|
||||||
Initialize();
|
Initialize();
|
||||||
#endif
|
|
||||||
|
|
||||||
g_refresh_critsec.Leave();
|
g_refresh_critsec.Leave();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterruptChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size)
|
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();
|
g_refresh_critsec.Enter();
|
||||||
|
|
||||||
if (g_wiimotes[_WiimoteNumber])
|
if (g_wiimotes[_WiimoteNumber])
|
||||||
g_wiimotes[_WiimoteNumber]->InterruptChannel(_channelID, data, _Size);
|
g_wiimotes[_WiimoteNumber]->InterruptChannel(_channelID, _pData, _Size);
|
||||||
|
|
||||||
g_refresh_critsec.Leave();
|
g_refresh_critsec.Leave();
|
||||||
|
|
||||||
if (data != _pData)
|
|
||||||
delete[] data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControlChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size)
|
void ControlChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size)
|
||||||
|
@ -21,6 +21,9 @@
|
|||||||
|
|
||||||
#include "wiiuse.h"
|
#include "wiiuse.h"
|
||||||
#include "ChunkFile.h"
|
#include "ChunkFile.h"
|
||||||
|
#include "Thread.h"
|
||||||
|
#include "FifoQueue.h"
|
||||||
|
#include "../WiimoteEmu/WiimoteEmu.h"
|
||||||
|
|
||||||
#include "../../InputCommon/Src/InputConfig.h"
|
#include "../../InputCommon/Src/InputConfig.h"
|
||||||
|
|
||||||
@ -33,13 +36,53 @@ extern SWiimoteInitialize g_WiimoteInitialize;
|
|||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
WIIMOTE_SRC_NONE = 0,
|
WIIMOTE_SRC_NONE = 0,
|
||||||
WIIMOTE_SRC_EMU,
|
WIIMOTE_SRC_EMU = 1,
|
||||||
WIIMOTE_SRC_REAL,
|
WIIMOTE_SRC_REAL = 2,
|
||||||
|
WIIMOTE_SRC_HYBRID = 3, // emu + real
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace WiimoteReal
|
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();
|
unsigned int Initialize();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
void Refresh();
|
void Refresh();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user