Fix the wiimote speaker problem in the core and remove the HLE patch for it.

Real wiimote tested on windows, untested but should work on linux, dunno about osx.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@7272 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Shawn Hoffman 2011-03-02 12:06:06 +00:00
parent 3af93e8cf3
commit a80429b020
18 changed files with 196 additions and 200 deletions

Binary file not shown.

View File

@ -47,7 +47,6 @@
#include "../ConfigManager.h" #include "../ConfigManager.h"
#include "VolumeCreator.h" // DiscIO #include "VolumeCreator.h" // DiscIO
#include "NANDContentLoader.h" #include "NANDContentLoader.h"
#include "CommonPaths.h"
void CBoot::Load_FST(bool _bIsWii) void CBoot::Load_FST(bool _bIsWii)
{ {
@ -218,19 +217,6 @@ bool CBoot::BootUp()
EmulatedBS2(_StartupPara.bWii); EmulatedBS2(_StartupPara.bWii);
} }
// Scan for common HLE functions
if (!_StartupPara.bEnableDebugging)
{
PPCAnalyst::FindFunctions(0x80000000, 0x81800000, &g_symbolDB);
SignatureDB db;
if (db.Load((File::GetSysDirectory() + TOTALDB).c_str()))
{
db.Apply(&g_symbolDB);
}
HLE::PatchFunctions();
g_symbolDB.Clear();
}
/* Try to load the symbol map if there is one, and then scan it for /* Try to load the symbol map if there is one, and then scan it for
and eventually replace code */ and eventually replace code */
if (LoadMapFromFilename(_StartupPara.m_strFilename, gameID)) if (LoadMapFromFilename(_StartupPara.m_strFilename, gameID))

View File

@ -222,7 +222,6 @@ void SConfig::SaveSettings()
ini.Set("Core", "WiiSDCard", m_WiiSDCard); ini.Set("Core", "WiiSDCard", m_WiiSDCard);
ini.Set("Core", "WiiKeyboard", m_WiiKeyboard); ini.Set("Core", "WiiKeyboard", m_WiiKeyboard);
ini.Set("Core", "WiimoteSpeaker", m_WiimoteSpeaker);
ini.Set("Core", "WiimoteReconnectOnLoad", m_WiimoteReconnectOnLoad); ini.Set("Core", "WiimoteReconnectOnLoad", m_WiimoteReconnectOnLoad);
ini.Set("Core", "RunCompareServer", m_LocalCoreStartupParameter.bRunCompareServer); ini.Set("Core", "RunCompareServer", m_LocalCoreStartupParameter.bRunCompareServer);
ini.Set("Core", "RunCompareClient", m_LocalCoreStartupParameter.bRunCompareClient); ini.Set("Core", "RunCompareClient", m_LocalCoreStartupParameter.bRunCompareClient);
@ -350,7 +349,6 @@ void SConfig::LoadSettings()
ini.Get("Core", "WiiSDCard", &m_WiiSDCard, false); ini.Get("Core", "WiiSDCard", &m_WiiSDCard, false);
ini.Get("Core", "WiiKeyboard", &m_WiiKeyboard, false); ini.Get("Core", "WiiKeyboard", &m_WiiKeyboard, false);
ini.Get("Core", "WiimoteSpeaker", &m_WiimoteSpeaker, false);
ini.Get("Core", "WiimoteReconnectOnLoad", &m_WiimoteReconnectOnLoad, true); ini.Get("Core", "WiimoteReconnectOnLoad", &m_WiimoteReconnectOnLoad, true);
ini.Get("Core", "RunCompareServer", &m_LocalCoreStartupParameter.bRunCompareServer, false); ini.Get("Core", "RunCompareServer", &m_LocalCoreStartupParameter.bRunCompareServer, false);
ini.Get("Core", "RunCompareClient", &m_LocalCoreStartupParameter.bRunCompareClient, false); ini.Get("Core", "RunCompareClient", &m_LocalCoreStartupParameter.bRunCompareClient, false);

View File

@ -33,7 +33,6 @@ struct SConfig : NonCopyable
bool m_WiiKeyboard; bool m_WiiKeyboard;
bool m_WiiAutoReconnect[4]; bool m_WiiAutoReconnect[4];
bool m_WiiAutoUnpair; bool m_WiiAutoUnpair;
int m_WiimoteSpeaker;
bool m_WiimoteReconnectOnLoad; bool m_WiimoteReconnectOnLoad;
// name of the last used filename // name of the last used filename

View File

@ -59,6 +59,7 @@ static const SPatch OSPatches[] =
// debug out is very nice ;) // debug out is very nice ;)
{ "OSReport", HLE_OS::HLE_GeneralDebugPrint }, { "OSReport", HLE_OS::HLE_GeneralDebugPrint },
{ "DEBUGPrint", HLE_OS::HLE_GeneralDebugPrint }, { "DEBUGPrint", HLE_OS::HLE_GeneralDebugPrint },
{ "WUD_DEBUGPrint", HLE_OS::HLE_GeneralDebugPrint },
{ "OSPanic", HLE_OS::HLE_OSPanic }, { "OSPanic", HLE_OS::HLE_OSPanic },
{ "vprintf", HLE_OS::HLE_GeneralDebugPrint }, { "vprintf", HLE_OS::HLE_GeneralDebugPrint },
{ "printf", HLE_OS::HLE_GeneralDebugPrint }, { "printf", HLE_OS::HLE_GeneralDebugPrint },
@ -93,8 +94,6 @@ static const SPatch OSPatches[] =
// Name doesn't matter, installed in CBoot::BootUp() // Name doesn't matter, installed in CBoot::BootUp()
{ "HBReload", HLE_Misc::HBReload }, { "HBReload", HLE_Misc::HBReload },
// hax :|
{ "IsBusyStrm_", HLE_Misc::IsBusyStream },
}; };
static const SPatch OSBreakPoints[] = static const SPatch OSBreakPoints[] =

View File

@ -22,8 +22,6 @@
#include "../PowerPC/PowerPC.h" #include "../PowerPC/PowerPC.h"
#include "../HW/Memmap.h" #include "../HW/Memmap.h"
#include "../Host.h" #include "../Host.h"
#include "CoreTiming.h"
#include "ConfigManager.h"
namespace HLE_Misc namespace HLE_Misc
{ {
@ -284,39 +282,4 @@ void HBReload()
Host_Message(WM_USER_STOP); Host_Message(WM_USER_STOP);
} }
u8 isBusyPoll = 0;
// Hack: Wiimotes are never too busy to process speaker data
void IsBusyStream()
{
if (SConfig::GetInstance().m_WiimoteSpeaker == 1)
{
GPR(3) = 0;
}
else if (SConfig::GetInstance().m_WiimoteSpeaker == 2)
{
isBusyPoll++;
// Signal that the wiimote is idle for a few cycles, allowing sound
// to be processed.
if (isBusyPoll < 5)
{
// Wiimote is idle
GPR(3) = 0;
}
else
{
// Wiimote is busy
GPR(3) = 1;
if (isBusyPoll >= 8)
isBusyPoll = 0;
}
}
else
{
GPR(3) = 1;
}
NPC = LR;
}
} }

View File

@ -39,7 +39,6 @@ namespace HLE_Misc
void FZ_sqrt_internal(); void FZ_sqrt_internal();
void FZ_rsqrt_internal(); void FZ_rsqrt_internal();
void HBReload(); void HBReload();
void IsBusyStream();
} }
#endif #endif

View File

@ -118,7 +118,7 @@ void Wiimote::HidOutputReport(const wm_report* const sr, const bool send_ack)
break; break;
case WM_SPEAKER_ENABLE : // 0x14 case WM_SPEAKER_ENABLE : // 0x14
//INFO_LOG(WIIMOTE, "WM Speaker Enable: 0x%02x", sr->data[0]); //ERROR_LOG(WIIMOTE, "WM Speaker Enable: %02x", sr->enable);
//PanicAlert( "WM Speaker Enable: %d", sr->data[0] ); //PanicAlert( "WM Speaker Enable: %d", sr->data[0] );
m_status.speaker = sr->enable; m_status.speaker = sr->enable;
if (false == sr->ack) if (false == sr->ack)
@ -140,13 +140,17 @@ void Wiimote::HidOutputReport(const wm_report* const sr, const bool send_ack)
break; break;
case WM_WRITE_SPEAKER_DATA : // 0x18 case WM_WRITE_SPEAKER_DATA : // 0x18
{
//wm_speaker_data *spkz = (wm_speaker_data*)sr->data;
//ERROR_LOG(WIIMOTE, "WM_WRITE_SPEAKER_DATA len:%x %s", spkz->length,
// ArrayToString(spkz->data, spkz->length, 100, false).c_str());
Wiimote::SpeakerData((wm_speaker_data*)sr->data); Wiimote::SpeakerData((wm_speaker_data*)sr->data);
// TODO: Does this need an ack? }
return; // no ack return; // no ack
break; break;
case WM_SPEAKER_MUTE : // 0x19 case WM_SPEAKER_MUTE : // 0x19
//INFO_LOG(WIIMOTE, "WM Speaker Mute: 0x%02x", sr->data[0]); //ERROR_LOG(WIIMOTE, "WM Speaker Mute: %02x", sr->enable);
//PanicAlert( "WM Speaker Mute: %d", sr->data[0] & 0x04 ); //PanicAlert( "WM Speaker Mute: %d", sr->data[0] & 0x04 );
// testing // testing
//if (sr->data[0] & 0x04) //if (sr->data[0] & 0x04)
@ -354,6 +358,14 @@ void Wiimote::WriteData(const wm_write_data* const wd)
else else
return; // TODO: generate a writedata error reply return; // TODO: generate a writedata error reply
/* TODO?
if (region_ptr == &m_reg_speaker)
{
ERROR_LOG(WIIMOTE, "Write to speaker reg %x %s", address,
ArrayToString(wd->data, wd->size, 100, false).c_str());
}
*/
if (&m_reg_ext == region_ptr) if (&m_reg_ext == region_ptr)
{ {
// Run the key generation on all writes in the key area, it doesn't matter // Run the key generation on all writes in the key area, it doesn't matter

View File

@ -16,79 +16,111 @@
// http://code.google.com/p/dolphin-emu/ // http://code.google.com/p/dolphin-emu/
#include "WiimoteEmu.h" #include "WiimoteEmu.h"
//#define WIIMOTE_SPEAKER_DUMP
#ifdef WIIMOTE_SPEAKER_DUMP
#include <fstream> #include <fstream>
#include "WaveFile.h"
#include <stdlib.h>
#include "FileUtil.h"
#endif
// Yamaha ADPCM decoder code based on The ffmpeg Project (Copyright (c) 2001-2003) namespace WiimoteEmu
typedef struct ADPCMChannelStatus
{ {
int predictor;
int step;
} ADPCMChannelStatus;
static const int yamaha_difflookup[] = { // Yamaha ADPCM decoder code based on The ffmpeg Project (Copyright (s) 2001-2003)
static const s32 yamaha_difflookup[] = {
1, 3, 5, 7, 9, 11, 13, 15, 1, 3, 5, 7, 9, 11, 13, 15,
-1, -3, -5, -7, -9, -11, -13, -15 -1, -3, -5, -7, -9, -11, -13, -15
}; };
static const int yamaha_indexscale[] = { static const s32 yamaha_indexscale[] = {
230, 230, 230, 230, 307, 409, 512, 614, 230, 230, 230, 230, 307, 409, 512, 614,
230, 230, 230, 230, 307, 409, 512, 614 230, 230, 230, 230, 307, 409, 512, 614
}; };
static u16 av_clip_int16(int a) static u16 av_clip16(s32 a)
{ {
if ((a+32768) & ~65535) return (a>>31) ^ 32767; if ((a+32768) & ~65535) return (a>>31) ^ 32767;
else return a; else return a;
} }
static int av_clip(int a, int amin, int amax) static s32 av_clip(s32 a, s32 amin, s32 amax)
{ {
if (a < amin) return amin; if (a < amin) return amin;
else if (a > amax) return amax; else if (a > amax) return amax;
else return a; else return a;
} }
static s16 adpcm_yamaha_expand_nibble(ADPCMChannelStatus *c, unsigned char nibble) static s16 adpcm_yamaha_expand_nibble(ADPCMState& s, u8 nibble)
{ {
if(!c->step) { if(!s.step) {
c->predictor = 0; s.predictor = 0;
c->step = 127; s.step = 0;
} }
c->predictor += (c->step * yamaha_difflookup[nibble]) / 8; s.predictor += (s.step * yamaha_difflookup[nibble]) / 8;
c->predictor = av_clip_int16(c->predictor); s.predictor = av_clip16(s.predictor);
c->step = (c->step * yamaha_indexscale[nibble]) >> 8; s.step = (s.step * yamaha_indexscale[nibble]) >> 8;
c->step = av_clip(c->step, 127, 24567); s.step = av_clip(s.step, 127, 24576);
return c->predictor; return s.predictor;
} }
namespace WiimoteEmu #ifdef WIIMOTE_SPEAKER_DUMP
{ std::ofstream ofile;
ADPCMChannelStatus cs; WaveFileWriter wav;
void stopdamnwav(){wav.Stop();ofile.close();}
#endif
void Wiimote::SpeakerData(wm_speaker_data* sd) void Wiimote::SpeakerData(wm_speaker_data* sd)
{ {
s16 samples[40]; // TODO consider using static max size instead of new
s16 *samples = new s16[sd->length * 2];
if (m_reg_speaker.format == 0x40) if (m_reg_speaker.format == 0x40)
{ {
// 8 bit PCM // 8 bit PCM
for (int i = 0; i < 20; ++i) for (int i = 0; i < sd->length; ++i)
{ {
samples[i] = (s16)(s8)sd->data[i]; samples[i] = (s16)(s8)sd->data[i];
} }
} }
else if (m_reg_speaker.format == 0x00) else if (m_reg_speaker.format == 0x00)
{ {
// 4 bit Yamaha ADPCM // 4 bit Yamaha ADPCM (same as dreamcast)
// TODO: The first byte of the source data = length? for (int i = 0; i < sd->length; ++i)
for (int i = 0; i < 20; ++i)
{ {
samples[i * 2] = adpcm_yamaha_expand_nibble(&cs, sd->data[i] & 0x0F); samples[i * 2] = adpcm_yamaha_expand_nibble(m_adpcm_state, (sd->data[i] >> 4) & 0xf);
samples[i * 2 + 1] = adpcm_yamaha_expand_nibble(&cs, (sd->data[i] >> 4) & 0x0F); samples[i * 2 + 1] = adpcm_yamaha_expand_nibble(m_adpcm_state, sd->data[i] & 0xf);
}
} }
} }
#ifdef WIIMOTE_SPEAKER_DUMP
std::stringstream name;
static int num = 0;
if (num == 0)
{
File::Delete("rmtdump.wav");
File::Delete("rmtdump.bin");
atexit(stopdamnwav);
ofile.open("rmtdump.bin", ofile.binary | ofile.out);
wav.Start("rmtdump.wav", 6000/*Common::swap16(m_reg_speaker.sample_rate)*/);
}
wav.AddMonoSamples(samples, sd->length*2);
if (ofile.good())
{
for (int i = 0; i < sd->length; i++)
{
ofile << sd->data[i];
}
}
num++;
#endif
delete[] samples;
}
} }

View File

@ -52,6 +52,11 @@ struct AccelData
double x,y,z; double x,y,z;
}; };
struct ADPCMState
{
s32 predictor, step;
};
extern const ReportFeatures reporting_mode_features[]; extern const ReportFeatures reporting_mode_features[];
void EmulateShake(AccelData* const accel_data void EmulateShake(AccelData* const accel_data
@ -167,6 +172,8 @@ private:
wm_status_report m_status; wm_status_report m_status;
ADPCMState m_adpcm_state;
// read data request queue // read data request queue
// maybe it isn't actualy a queue // maybe it isn't actualy a queue
// maybe read requests cancel any current requests // maybe read requests cancel any current requests
@ -224,11 +231,17 @@ private:
struct SpeakerReg struct SpeakerReg
{ {
u16 unknown; u8 unused_0;
u8 unk_1;
u8 format; u8 format;
// seems to always play at 6khz no matter what this is set to?
// or maybe it only applies to pcm input
u16 sample_rate; u16 sample_rate;
u8 volume; u8 volume;
u8 unk[4]; u8 unk_6;
u8 unk_7;
u8 play;
u8 unk_9;
} m_reg_speaker; } m_reg_speaker;
}; };

View File

@ -239,6 +239,13 @@ bool Wiimote::Connect()
m_wiimote_thread = std::thread(std::mem_fun(&Wiimote::ThreadFunc), this); m_wiimote_thread = std::thread(std::mem_fun(&Wiimote::ThreadFunc), this);
// This isn't as drastic as it sounds, since the process in which the threads
// reside is normal priority. Needed for keeping audio reports at a decent rate
if (!SetThreadPriority(m_wiimote_thread.native_handle(), THREAD_PRIORITY_TIME_CRITICAL))
{
ERROR_LOG(WIIMOTE, "Failed to set wiimote thread priority");
}
NOTICE_LOG(WIIMOTE, "Connected to wiimote %i.", index + 1); NOTICE_LOG(WIIMOTE, "Connected to wiimote %i.", index + 1);
return true; return true;

View File

@ -159,6 +159,12 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const
// //((wm_report_mode*)(data + 2))->continuous = false; // //((wm_report_mode*)(data + 2))->continuous = false;
//} //}
if (rpt.first[0] == 0xa2 && rpt.first[1] == 0x18 && rpt.second == 23)
{
m_audio_reports.Push(rpt);
return;
}
m_write_reports.Push(rpt); m_write_reports.Push(rpt);
} }
@ -182,15 +188,23 @@ bool Wiimote::Read()
bool Wiimote::Write() bool Wiimote::Write()
{ {
Report rpt; Report rpt;
bool audio_written = false;
if (m_audio_reports.Pop(rpt))
{
IOWrite(rpt.first, rpt.second);
delete[] rpt.first;
audio_written = true;
}
if (m_write_reports.Pop(rpt)) if (m_write_reports.Pop(rpt))
{ {
IOWrite(rpt.first, rpt.second); IOWrite(rpt.first, rpt.second);
delete[] rpt.first; delete[] rpt.first;
return true; return true;
} }
return false; return audio_written;
} }
// Returns the next report that should be sent // Returns the next report that should be sent
@ -308,14 +322,19 @@ void Wiimote::ThreadFunc()
// main loop // main loop
while (IsConnected()) while (IsConnected())
{ {
// hopefully this is alright #ifdef __APPLE__
while (Write()) {} while (Write()) {}
#ifndef __APPLE__
// sleep if there was nothing to read
if (false == Read())
#endif
Common::SleepCurrentThread(1); Common::SleepCurrentThread(1);
#else
bool read = false;
while (Write() || (read = true, Read()))
{
if (m_audio_reports.Size() && !read)
Read();
Common::SleepCurrentThread(m_audio_reports.Size() ? 5 : 2);
read = false;
}
#endif
} }
} }

View File

@ -98,6 +98,7 @@ private:
std::thread m_wiimote_thread; std::thread m_wiimote_thread;
Common::FifoQueue<Report> m_read_reports; Common::FifoQueue<Report> m_read_reports;
Common::FifoQueue<Report> m_write_reports; Common::FifoQueue<Report> m_write_reports;
Common::FifoQueue<Report> m_audio_reports;
}; };
extern Common::CriticalSection g_refresh_critsec; extern Common::CriticalSection g_refresh_critsec;

View File

@ -23,16 +23,18 @@
#include "WII_IPC_HLE.h" #include "WII_IPC_HLE.h"
#include "WII_IPC_HLE_Device_usb.h" #include "WII_IPC_HLE_Device_usb.h"
#include "../ConfigManager.h" #include "../ConfigManager.h"
#include "CoreTiming.h"
#define WIIMOTESIZE 0x46 #define WIIMOTESIZE 0x46
#define BTDINFSIZE WIIMOTESIZE * 0x10 #define BTDINFSIZE WIIMOTESIZE * 0x10
// The device class // The device class
CWII_IPC_HLE_Device_usb_oh1_57e_305::CWII_IPC_HLE_Device_usb_oh1_57e_305(u32 _DeviceID, const std::string& _rDeviceName) CWII_IPC_HLE_Device_usb_oh1_57e_305::CWII_IPC_HLE_Device_usb_oh1_57e_305(u32 _DeviceID, const std::string& _rDeviceName)
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
, m_ScanEnable(0) , m_ScanEnable(0)
, m_HCIEndpoint(0) , m_HCIEndpoint(0)
, m_ACLEndpoint(0) , m_ACLEndpoint(0)
, m_WiimoteUpdate_Freq(0) , m_last_ticks(0)
, m_NumCompPackets_Freq(0)
{ {
// Activate only first Wiimote by default // Activate only first Wiimote by default
@ -108,8 +110,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::DoState(PointerWrap &p)
p.Do(m_ACLSetup); p.Do(m_ACLSetup);
p.Do(m_HCIEndpoint); p.Do(m_HCIEndpoint);
p.Do(m_ACLEndpoint); p.Do(m_ACLEndpoint);
p.Do(m_NumCompPackets_Freq); p.Do(m_last_ticks);
p.Do(m_WiimoteUpdate_Freq);
u32 size; u32 size;
if (p.GetMode() == PointerWrap::MODE_READ) if (p.GetMode() == PointerWrap::MODE_READ)
@ -163,8 +164,7 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::Open(u32 _CommandAddress, u32 _Mode)
{ {
m_ScanEnable = 0; m_ScanEnable = 0;
m_NumCompPackets_Freq = 0; m_last_ticks = 0;
m_WiimoteUpdate_Freq = 0;
memset(m_PacketCount, 0, sizeof(m_PacketCount)); memset(m_PacketCount, 0, sizeof(m_PacketCount));
m_HCIEndpoint.m_address = 0; m_HCIEndpoint.m_address = 0;
@ -179,8 +179,7 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::Close(u32 _CommandAddress, bool _bForc
{ {
m_ScanEnable = 0; m_ScanEnable = 0;
m_NumCompPackets_Freq = 0; m_last_ticks = 0;
m_WiimoteUpdate_Freq = 0;
memset(m_PacketCount, 0, sizeof(m_PacketCount)); memset(m_PacketCount, 0, sizeof(m_PacketCount));
m_HCIEndpoint.m_address = 0; m_HCIEndpoint.m_address = 0;
@ -348,6 +347,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendToDevice(u16 _ConnectionHandle, u8
return; return;
INFO_LOG(WII_IPC_WIIMOTE, "Send ACL Packet to ConnectionHandle 0x%04x", _ConnectionHandle); INFO_LOG(WII_IPC_WIIMOTE, "Send ACL Packet to ConnectionHandle 0x%04x", _ConnectionHandle);
IncDataPacket(_ConnectionHandle);
pWiiMote->ExecuteL2capCmd(_pData, _Size); pWiiMote->ExecuteL2capCmd(_pData, _Size);
} }
@ -357,12 +357,21 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendToDevice(u16 _ConnectionHandle, u8
// AyuanX: Basically, our WII_IPC_HLE is efficient enough to send the packet immediately // AyuanX: Basically, our WII_IPC_HLE is efficient enough to send the packet immediately
// rather than enqueue it to some other memory // rather than enqueue it to some other memory
// But...the only exception comes from the Wiimote_Plugin // But...the only exception comes from the Wiimote_Plugin
void CWII_IPC_HLE_Device_usb_oh1_57e_305::IncDataPacket(u16 _ConnectionHandle)
{
m_PacketCount[_ConnectionHandle & 0xff]++;
if (m_PacketCount[_ConnectionHandle & 0xff] > 10)
{
DEBUG_LOG(WII_IPC_WIIMOTE, "ACL buffer overflow");
m_PacketCount[_ConnectionHandle & 0xff] = 10;
}
}
void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLPacket(u16 _ConnectionHandle, u8* _pData, u32 _Size) void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLPacket(u16 _ConnectionHandle, u8* _pData, u32 _Size)
{ {
DEBUG_LOG(WII_IPC_WIIMOTE, "ACL packet from %x ready to send to stack...", _ConnectionHandle); DEBUG_LOG(WII_IPC_WIIMOTE, "ACL packet from %x ready to send to stack...", _ConnectionHandle);
m_PacketCount[_ConnectionHandle & 0xff]++;
if (m_ACLEndpoint.IsValid() && !m_HCIEndpoint.IsValid() && m_EventQueue.empty()) if (m_ACLEndpoint.IsValid() && !m_HCIEndpoint.IsValid() && m_EventQueue.empty())
{ {
DEBUG_LOG(WII_IPC_WIIMOTE, "ACL endpoint valid, sending packet to %08x", m_ACLEndpoint.m_address); DEBUG_LOG(WII_IPC_WIIMOTE, "ACL endpoint valid, sending packet to %08x", m_ACLEndpoint.m_address);
@ -395,9 +404,6 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::AddEventToQueue(const SQueuedEvent& _e
{ {
DEBUG_LOG(WII_IPC_WIIMOTE, "HCI event %x completed...", ((hci_event_hdr_t*)_event.m_buffer)->event); DEBUG_LOG(WII_IPC_WIIMOTE, "HCI event %x completed...", ((hci_event_hdr_t*)_event.m_buffer)->event);
if (_event.m_connectionHandle)
m_PacketCount[_event.m_connectionHandle & 0xff]++;
if (m_HCIEndpoint.IsValid()) if (m_HCIEndpoint.IsValid())
{ {
if (m_EventQueue.empty()) // fast path :) if (m_EventQueue.empty()) // fast path :)
@ -439,6 +445,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::AddEventToQueue(const SQueuedEvent& _e
u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update() u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
{ {
bool packet_transferred = false;
// check hci queue // check hci queue
if (!m_EventQueue.empty() && m_HCIEndpoint.IsValid()) if (!m_EventQueue.empty() && m_HCIEndpoint.IsValid())
{ {
@ -455,7 +462,7 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
WII_IPC_HLE_Interface::EnqReply(m_HCIEndpoint.m_address); WII_IPC_HLE_Interface::EnqReply(m_HCIEndpoint.m_address);
m_HCIEndpoint.Invalidate(); m_HCIEndpoint.Invalidate();
m_EventQueue.pop(); m_EventQueue.pop();
return true; packet_transferred = true;
} }
// check acl queue // check acl queue
@ -478,7 +485,7 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
WII_IPC_HLE_Interface::EnqReply(m_ACLEndpoint.m_address); WII_IPC_HLE_Interface::EnqReply(m_ACLEndpoint.m_address);
m_ACLEndpoint.Invalidate(); m_ACLEndpoint.Invalidate();
m_ACLQ.pop(); m_ACLQ.pop();
return true; packet_transferred = true;
} }
// We wait for ScanEnable to be sent from the bt stack through HCI_CMD_WRITE_SCAN_ENABLE // We wait for ScanEnable to be sent from the bt stack through HCI_CMD_WRITE_SCAN_ENABLE
@ -486,13 +493,8 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
// //
// FiRES: TODO find a better way to do this // FiRES: TODO find a better way to do this
// Supposedly this delay is needed for real wiimotes
// TODO try removing this hack, or handling real wiimotes better
static int counter = Core::GetRealWiimote() ? 1000 : 0;
// Create ACL connection // Create ACL connection
if (m_HCIEndpoint.IsValid() && (m_ScanEnable & HCI_PAGE_SCAN_ENABLE)) if (m_HCIEndpoint.IsValid() && (m_ScanEnable & HCI_PAGE_SCAN_ENABLE))
{
if (--counter < 0)
{ {
for (unsigned int i = 0; i < m_WiiMotes.size(); i++) for (unsigned int i = 0; i < m_WiiMotes.size(); i++)
{ {
@ -504,7 +506,6 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
} }
} }
} }
}
// Link channels when connected // Link channels when connected
if (m_ACLEndpoint.IsValid()) if (m_ACLEndpoint.IsValid())
@ -516,44 +517,29 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
} }
} }
// The Real Wiimote sends report at a fixed frequency of 100Hz // The Real Wiimote sends report every ~6.66ms.
// So let's make it also 100Hz here // However, we don't actually reach here at dependable intervals, so we
// Calculation: 1500Hz (IPC_HLE) / 100Hz (WiiMote) = 15 // instead just timeslice in such a way that makes the stack think we have
if (m_ACLEndpoint.IsValid()) // perfect "radio quality" (WPADGetRadioSensitivity) and yet still have some
// idle time.
static int wiimote_to_update = 0;
const u64 interval = 729000000u / 200; // 5ms behaves well
u64 each_wiimote_interval = interval / m_WiiMotes.size();
u64 now = CoreTiming::GetTicks();
if (now - m_last_ticks > each_wiimote_interval)
{ {
if (++m_WiimoteUpdate_Freq > 15) if (m_WiiMotes[wiimote_to_update].IsConnected())
m_WiimoteUpdate_Freq = 0;
for (unsigned int i = 0; i < m_WiiMotes.size(); i++)
{ {
if (m_WiiMotes[i].IsConnected() && m_WiimoteUpdate_Freq == 15 / (i + 1)) NetPlay_WiimoteUpdate(wiimote_to_update);
{ Wiimote::Update(wiimote_to_update);
NetPlay_WiimoteUpdate(i);
Wiimote::Update(i);
//return true;
}
} }
wiimote_to_update = ++wiimote_to_update % m_WiiMotes.size();
m_last_ticks = now;
} }
//////////////////////////////////////////////////////////////////////////
// This event should be sent periodically after ACL connection is accepted
// or CPU will disconnect WiiMote automatically
// but don't send too many or it will jam the bus and cost extra CPU time
//////////////////////////////////////////////////////////////////////////
// "When the Host has completed one or more HCI Data Packet(s) it shall send a
// Host_Number_Of_Completed_Packets command to the Controller, until it
// finally reports that all pending HCI Data Packets have been completed. The
// frequency at which this command is sent is manufacturer specific."
// -- Figuring out the "correct" rate could be annoying, so our guess will suffice :p
if (m_HCIEndpoint.IsValid())
{
if (++m_NumCompPackets_Freq > 500)
{
m_NumCompPackets_Freq = 0;
SendEventNumberOfCompletedPackets(); SendEventNumberOfCompletedPackets();
}
}
return false; return packet_transferred;
} }
bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventInquiryComplete() bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventInquiryComplete()
@ -913,20 +899,29 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventNumberOfCompletedPackets()
event_hdr->length = sizeof(hci_num_compl_pkts_ep); event_hdr->length = sizeof(hci_num_compl_pkts_ep);
event->num_con_handles = 0; event->num_con_handles = 0;
u32 acc = 0;
for (unsigned int i = 0; i < m_WiiMotes.size(); i++) for (unsigned int i = 0; i < m_WiiMotes.size(); i++)
{ {
event_hdr->length += sizeof(hci_num_compl_pkts_info); event_hdr->length += sizeof(hci_num_compl_pkts_info);
event->num_con_handles++; event->num_con_handles++;
info->compl_pkts = m_PacketCount[i]; info->compl_pkts = m_PacketCount[i];
info->con_handle = m_WiiMotes[i].GetConnectionHandle(); info->con_handle = m_WiiMotes[i].GetConnectionHandle();
info++;
m_PacketCount[i] = 0;
DEBUG_LOG(WII_IPC_WIIMOTE, " Connection_Handle: 0x%04x", info->con_handle); DEBUG_LOG(WII_IPC_WIIMOTE, " Connection_Handle: 0x%04x", info->con_handle);
DEBUG_LOG(WII_IPC_WIIMOTE, " Number_Of_Completed_Packets: %i", info->compl_pkts); DEBUG_LOG(WII_IPC_WIIMOTE, " Number_Of_Completed_Packets: %i", info->compl_pkts);
acc += info->compl_pkts;
m_PacketCount[i] = 0;
info++;
} }
if (acc)
AddEventToQueue(Event); AddEventToQueue(Event);
else
{
INFO_LOG(WII_IPC_WIIMOTE, "SendEventNumberOfCompletedPackets: no packets; no event");
}
return true; return true;
} }
@ -1771,11 +1766,13 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandReadBufferSize(u8* _Input)
{ {
hci_read_buffer_size_rp Reply; hci_read_buffer_size_rp Reply;
Reply.status = 0x00; Reply.status = 0x00;
Reply.max_acl_size = 0x0FFF; //339; Reply.max_acl_size = 339;
Reply.num_acl_pkts = 0xFF; //10; // Due to how the widcomm stack which nintendo uses is coded, we must never
// let the stack think the controller is buffering more than 10 data packets
// - it will cause a u8 underflow and royally screw things up.
Reply.num_acl_pkts = 10;
Reply.max_sco_size = 64; Reply.max_sco_size = 64;
Reply.num_sco_pkts = 0; Reply.num_sco_pkts = 0;
// AyuanX: Are these parameters fixed or adjustable ???
INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_READ_BUFFER_SIZE:"); INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_READ_BUFFER_SIZE:");
DEBUG_LOG(WII_IPC_WIIMOTE, "return:"); DEBUG_LOG(WII_IPC_WIIMOTE, "return:");

View File

@ -171,10 +171,10 @@ private:
std::queue<ACLQ> m_ACLQ; std::queue<ACLQ> m_ACLQ;
u32 m_PacketCount[4]; u32 m_PacketCount[4];
u32 m_WiimoteUpdate_Freq; u64 m_last_ticks;
u32 m_NumCompPackets_Freq;
// Send ACL data to a device (wiimote) // Send ACL data to a device (wiimote)
void IncDataPacket(u16 _ConnectionHandle);
void SendToDevice(u16 _ConnectionHandle, u8* _pData, u32 _Size); void SendToDevice(u16 _ConnectionHandle, u8* _pData, u32 _Size);
// Events // Events

View File

@ -79,17 +79,7 @@
#pragma once #pragma once
// msvc >= msvc10 has stdint.h/cstdint
#ifdef _MSC_VER
typedef u8 uint8_t;
typedef s8 int8_t;
typedef u16 uint16_t;
typedef s16 int16_t;
typedef u32 uint32_t;
typedef s32 int32_t;
#else
#include <stdint.h> #include <stdint.h>
#endif
// All structs in this file are packed // All structs in this file are packed
#pragma pack(push, 1) #pragma pack(push, 1)

View File

@ -164,7 +164,6 @@ EVT_CHOICE(ID_WII_IPL_LNG, CConfigMain::WiiSettingsChanged)
EVT_CHECKBOX(ID_WII_SD_CARD, CConfigMain::WiiSettingsChanged) EVT_CHECKBOX(ID_WII_SD_CARD, CConfigMain::WiiSettingsChanged)
EVT_CHECKBOX(ID_WII_KEYBOARD, CConfigMain::WiiSettingsChanged) EVT_CHECKBOX(ID_WII_KEYBOARD, CConfigMain::WiiSettingsChanged)
EVT_CHECKBOX(ID_WII_WIIMOTE_SPEAKER, CConfigMain::WiiSettingsChanged)
EVT_CHECKBOX(ID_WII_WIIMOTE_RECONNECT, CConfigMain::WiiSettingsChanged) EVT_CHECKBOX(ID_WII_WIIMOTE_RECONNECT, CConfigMain::WiiSettingsChanged)
@ -504,12 +503,6 @@ void CConfigMain::InitializeGUIValues()
WiiSensBarPos->SetSelection(SConfig::GetInstance().m_SYSCONF->GetData<u8>("BT.BAR")); WiiSensBarPos->SetSelection(SConfig::GetInstance().m_SYSCONF->GetData<u8>("BT.BAR"));
WiiSensBarSens->SetValue(SConfig::GetInstance().m_SYSCONF->GetData<u32>("BT.SENS")); WiiSensBarSens->SetValue(SConfig::GetInstance().m_SYSCONF->GetData<u32>("BT.SENS"));
WiimoteMotor->SetValue(SConfig::GetInstance().m_SYSCONF->GetData<bool>("BT.MOT")); WiimoteMotor->SetValue(SConfig::GetInstance().m_SYSCONF->GetData<bool>("BT.MOT"));
if (SConfig::GetInstance().m_WiimoteSpeaker == 1)
WiimoteSpeaker->Set3StateValue(wxCHK_CHECKED);
else if (SConfig::GetInstance().m_WiimoteSpeaker == 2)
WiimoteSpeaker->Set3StateValue(wxCHK_UNDETERMINED);
else
WiimoteSpeaker->Set3StateValue(wxCHK_UNCHECKED);
WiimoteReconnectOnLoad->SetValue(SConfig::GetInstance().m_WiimoteReconnectOnLoad); WiimoteReconnectOnLoad->SetValue(SConfig::GetInstance().m_WiimoteReconnectOnLoad);
// Wii - Misc // Wii - Misc
@ -832,7 +825,6 @@ void CConfigMain::CreateGUIControls()
WiiSensBarPos = new wxChoice(WiiPage, ID_WII_BT_BAR, wxDefaultPosition, wxDefaultSize, arrayStringFor_WiiSensBarPos, 0, wxDefaultValidator); WiiSensBarPos = new wxChoice(WiiPage, ID_WII_BT_BAR, wxDefaultPosition, wxDefaultSize, arrayStringFor_WiiSensBarPos, 0, wxDefaultValidator);
WiiSensBarSens = new wxSlider(WiiPage, ID_WII_BT_SENS, 0, 0, 4); WiiSensBarSens = new wxSlider(WiiPage, ID_WII_BT_SENS, 0, 0, 4);
WiimoteMotor = new wxCheckBox(WiiPage, ID_WII_BT_MOT, _("Wiimote Motor"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); WiimoteMotor = new wxCheckBox(WiiPage, ID_WII_BT_MOT, _("Wiimote Motor"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
WiimoteSpeaker = new wxCheckBox(WiiPage, ID_WII_WIIMOTE_SPEAKER, _("Wiimote Speaker"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
WiimoteReconnectOnLoad = new wxCheckBox(WiiPage, ID_WII_WIIMOTE_RECONNECT, _("Reconnect Wiimote On Load State"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); WiimoteReconnectOnLoad = new wxCheckBox(WiiPage, ID_WII_WIIMOTE_RECONNECT, _("Reconnect Wiimote On Load State"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
// Misc Settings // Misc Settings
@ -854,8 +846,7 @@ void CConfigMain::CreateGUIControls()
wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL|wxALL, 5); wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL|wxALL, 5);
sWiimoteSettings->Add(WiiSensBarSens, wxGBPosition(1, 1), wxDefaultSpan, wxEXPAND|wxALL, 5); sWiimoteSettings->Add(WiiSensBarSens, wxGBPosition(1, 1), wxDefaultSpan, wxEXPAND|wxALL, 5);
sWiimoteSettings->Add(WiimoteMotor, wxGBPosition(2, 0), wxGBSpan(1, 2), wxALL, 5); sWiimoteSettings->Add(WiimoteMotor, wxGBPosition(2, 0), wxGBSpan(1, 2), wxALL, 5);
sWiimoteSettings->Add(WiimoteSpeaker, wxGBPosition(3, 0), wxGBSpan(1, 2), wxALL, 5); sWiimoteSettings->Add(WiimoteReconnectOnLoad, wxGBPosition(3, 0), wxGBSpan(1, 2), wxALL, 5);
sWiimoteSettings->Add(WiimoteReconnectOnLoad, wxGBPosition(4, 0), wxGBSpan(1, 2), wxALL, 5);
sbWiimoteSettings = new wxStaticBoxSizer(wxHORIZONTAL, WiiPage, _("Wiimote Settings")); sbWiimoteSettings = new wxStaticBoxSizer(wxHORIZONTAL, WiiPage, _("Wiimote Settings"));
sbWiimoteSettings->Add(sWiimoteSettings); sbWiimoteSettings->Add(sWiimoteSettings);
@ -1276,14 +1267,6 @@ void CConfigMain::WiiSettingsChanged(wxCommandEvent& event)
case ID_WII_BT_MOT: case ID_WII_BT_MOT:
SConfig::GetInstance().m_SYSCONF->SetData("BT.MOT", WiimoteMotor->IsChecked()); SConfig::GetInstance().m_SYSCONF->SetData("BT.MOT", WiimoteMotor->IsChecked());
break; break;
case ID_WII_WIIMOTE_SPEAKER:
if (WiimoteSpeaker->Get3StateValue() == wxCHK_CHECKED)
SConfig::GetInstance().m_WiimoteSpeaker = 1;
else if (WiimoteSpeaker->Get3StateValue() == wxCHK_UNDETERMINED)
SConfig::GetInstance().m_WiimoteSpeaker = 2;
else
SConfig::GetInstance().m_WiimoteSpeaker = 0;
break;
case ID_WII_WIIMOTE_RECONNECT: case ID_WII_WIIMOTE_RECONNECT:
SConfig::GetInstance().m_WiimoteReconnectOnLoad = WiimoteReconnectOnLoad->IsChecked(); SConfig::GetInstance().m_WiimoteReconnectOnLoad = WiimoteReconnectOnLoad->IsChecked();
break; break;

View File

@ -117,7 +117,6 @@ private:
ID_WII_BT_BAR, ID_WII_BT_BAR,
ID_WII_BT_SENS, ID_WII_BT_SENS,
ID_WII_BT_MOT, ID_WII_BT_MOT,
ID_WII_WIIMOTE_SPEAKER,
ID_WII_WIIMOTE_RECONNECT, ID_WII_WIIMOTE_RECONNECT,
ID_WII_IPL_SSV, ID_WII_IPL_SSV,
@ -220,7 +219,6 @@ private:
wxChoice* WiiSensBarPos; wxChoice* WiiSensBarPos;
wxSlider* WiiSensBarSens; wxSlider* WiiSensBarSens;
wxCheckBox* WiimoteMotor; wxCheckBox* WiimoteMotor;
wxCheckBox* WiimoteSpeaker;
wxCheckBox* WiimoteReconnectOnLoad; wxCheckBox* WiimoteReconnectOnLoad;
// Misc // Misc