1) I fixed the emulated Nunchuck in Zelda - TP, however I chose the minimum workable delay time that worked in my PC, in fact it's so short that the Nunchuck still fails sometimes. If you have a very fast PC or something like that so that the Nunchuck still don't work please let me know.

2) I also made the Wiimote work after Stop and Start

3) I changed /Dev/USB to initialize the emulated Wiimote directly after ScanEnable, not wait for any countdown

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1814 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
John Peterson 2009-01-07 02:59:19 +00:00
parent 6125efabb1
commit fa27a97fbb
30 changed files with 1346 additions and 893 deletions

View File

@ -123,7 +123,7 @@ int wprintf(char *fmt, ...)
if(__fStdOut)
{
fprintf(__fStdOut, s);
//fflush(__fStdOut); // Write file now, don't wait
fflush(__fStdOut); // Write file now, don't wait
}
return(cnt);

View File

@ -16,11 +16,14 @@
// http://code.google.com/p/dolphin-emu/
#ifndef MM_COMMON_H
#define MM_COMMON_H
//////////////////////////////////////////////////////////////////////////////////////////
// Declarations and definitions
// ¯¯¯¯¯¯¯¯¯¯
void StartConsoleWin(int width, int height, char* fname);
void StartConsoleWin(int width = 100, int height = 2000, char* fname = "Console");
int wprintf(char *fmt, ...);
//////////////////////////////////
#endif // MM_COMMON_H

View File

@ -442,7 +442,11 @@ void CFrame::MM_OnLog(wxCommandEvent& event)
MusicMod::bShowConsole = !MusicMod::bShowConsole;
if(MusicMod::bShowConsole)
{ MusicMod::ShowConsole(); Player_Console(true); }
/* What we do here is run StartConsoleWin() in Common directly after each
other first in the exe then in the DLL, sometimes this would give me a rampant memory
usage increase until the exe crashed at 700 MB memory usage or something like that.
For that reason I'm trying to sleep for a moment between them here. */
{ MusicMod::ShowConsole(); Sleep(100); Player_Console(true); }
else
{
#if defined (_WIN32)

View File

@ -70,6 +70,23 @@ extern int GlobalVolume;
//////////////////////////////////
// =======================================================================================
// Supported music files
// ---------------------------------------------------------------------------------------
bool CheckFileEnding(std::string FileName)
{
if (
(FileName.find(".adp") != std::string::npos) // 1080 Avalanche, Crash Bandicoot etc
|| (FileName.find(".afc") != std::string::npos) // Zelda WW
|| (FileName.find(".ast") != std::string::npos) // Zelda TP, Mario Kart
|| (FileName.find(".dsp") != std::string::npos) // Metroid Prime
|| (FileName.find(".hps") != std::string::npos) // SSB Melee
)
return true;
return false;
}
// =======================================================================================
// =======================================================================================
// A function to sort the filelist table after offset
@ -187,25 +204,6 @@ void Main(std::string FileName)
}
// =======================================================================================
// Supported music files
// ---------------------------------------------------------------------------------------
bool CheckFileEnding(std::string FileName)
{
if (
(FileName.find(".adp") != std::string::npos) // 1080 Avalanche, Crash Bandicoot etc
|| (FileName.find(".afc") != std::string::npos) // Zelda WW
|| (FileName.find(".ast") != std::string::npos) // Zelda TP, Mario Kart
|| (FileName.find(".dsp") != std::string::npos) // Metroid Prime
|| (FileName.find(".hps") != std::string::npos) // SSB Melee
)
return true;
return false;
}
// =======================================================================================
// =======================================================================================
// Check if we should play this file
// ---------------------------------------------------------------------------------------

View File

@ -15,6 +15,19 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
//////////////////////////////////////////////////////////////////////////////////////////
// File description
/* ¯¯¯¯¯¯¯¯¯¯¯¯¯
All plugins from Core > Plugins are loaded and unloaded with this class when Dolpin is started
and stopped.
//////////////////////////////////////*/
//////////////////////////////////////////////////////////////////////////////////////////
// Includes
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
#include <string.h>
#ifdef _WIN32
#include <windows.h>
@ -27,6 +40,9 @@
#include "FileUtil.h"
#include "StringUtil.h"
#include "DynamicLibrary.h"
#include "../../../../Branches/MusicMod/Common/Src/Console.h"
///////////////////////////////////
DynamicLibrary::DynamicLibrary()
{
@ -138,9 +154,10 @@ void* DynamicLibrary::Get(const char* funcname) const
retval = dlsym(library, funcname);
#endif
if (!retval) {
if (!retval)
{
LOG(MASTER_LOG, "Symbol %s missing in %s (error: %s)\n", funcname, library_file.c_str(), GetLastErrorAsString().c_str());
PanicAlert("Symbol %s missing in %s (error: %s)\n", funcname, library_file.c_str(), GetLastErrorAsString().c_str());
//PanicAlert("Symbol %s missing in %s (error: %s)\n", funcname, library_file.c_str(), GetLastErrorAsString().c_str());
}
return retval;

View File

@ -121,6 +121,10 @@ bool CBoot::LoadMapFromFilename(const std::string &_rFilename, const char *_game
return success;
}
//////////////////////////////////////////////////////////////////////////////////////////
// Load a GC or Wii BIOS file
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
bool CBoot::Load_BIOS(const std::string& _rBiosFilename)
{
bool bResult = false;
@ -129,6 +133,7 @@ bool CBoot::Load_BIOS(const std::string& _rBiosFilename)
{
if (pFile->GetSize() >= 1024*1024*2)
{
// Write it to memory
u32 CopySize = (u32)pFile->GetSize() - 0x820;
u8* pData = pFile->Lock(0x820, CopySize);
Memory::WriteBigEData(pData, 0x81300000, CopySize);
@ -143,7 +148,12 @@ bool CBoot::Load_BIOS(const std::string& _rBiosFilename)
delete pFile;
return bResult;
}
/////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Third boot step after BootManager and Core. See Call schedule in BootManager.cpp
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
bool CBoot::BootUp(const SCoreStartupParameter& _StartupPara)
{
const bool bDebugIsoBootup = false;
@ -188,6 +198,7 @@ bool CBoot::BootUp(const SCoreStartupParameter& _StartupPara)
}
else
{
// If we can't load the BIOS file we use the HLE BIOS instead
if (!Load_BIOS(_StartupPara.m_strBios))
{
// fails to load a BIOS so HLE it

View File

@ -41,7 +41,9 @@ void CBoot::RunFunction(u32 _iAddr)
PowerPC::SingleStep();
}
// BIOS HLE:
// __________________________________________________________________________________________________
//
// GameCube BIOS HLE:
// copy the apploader to 0x81200000
// execute the apploader, function by function, using the above utility.
void CBoot::EmulatedBIOS(bool _bDebug)
@ -159,7 +161,7 @@ void CBoot::EmulatedBIOS(bool _bDebug)
// __________________________________________________________________________________________________
//
// BIOS HLE:
// Wii BIOS HLE:
// copy the apploader to 0x81200000
// execute the apploader
//
@ -167,6 +169,7 @@ bool CBoot::EmulatedBIOS_Wii(bool _bDebug)
{
LOG(BOOT, "Faking Wii BIOS...");
// See if we have a memory dump to boot
FILE* pDump = fopen(FULL_WII_SYS_DIR "dump_0x0000_0x4000.bin", "rb");
if (pDump != NULL)
{
@ -301,10 +304,11 @@ bool CBoot::EmulatedBIOS_Wii(bool _bDebug)
after this check during booting. */
VolumeHandler::ReadToPtr(Memory::GetPointer(0x3180), 0, 4);
Memory::Write_U8(0x80, 0x00003184);
// ================
}
}
// apploader
// Execute the apploader
if (VolumeHandler::IsValid() && VolumeHandler::IsWii())
{
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
@ -345,12 +349,16 @@ bool CBoot::EmulatedBIOS_Wii(bool _bDebug)
u32 iAppLoaderClose = Memory::ReadUnchecked_U32(iAppLoaderFuncAddr+8);
// iAppLoaderInit
LOG(BOOT, "Call iAppLoaderInit");
LOG(BOOT, "Run iAppLoaderInit");
PowerPC::ppcState.gpr[3] = 0x81300000;
RunFunction(iAppLoaderInit);
// iAppLoaderMain
LOG(BOOT, "Call iAppLoaderMain");
/* Let the apploader load the exe to memory. At this point I get an unknwon IPC command
(command zero) when I load Wii Sports or other games a second time. I don't notice
any side effects however. It's a little disconcerning however that Start after Stop
behaves differently than the first Start after starting Dolphin. It means something
was not reset correctly. */
LOG(BOOT, "Run iAppLoaderMain");
do
{
PowerPC::ppcState.gpr[3] = 0x81300004;
@ -368,7 +376,7 @@ bool CBoot::EmulatedBIOS_Wii(bool _bDebug)
} while(PowerPC::ppcState.gpr[3] != 0x00);
// iAppLoaderClose
LOG(BOOT, "call iAppLoaderClose");
LOG(BOOT, "Run iAppLoaderClose");
RunFunction(iAppLoaderClose);
// Load patches and run startup patches

View File

@ -94,7 +94,6 @@ void Callback_WiimoteInput(u16 _channelID, const void* _pData, u32 _Size);
// For keyboard shortcuts.
void Callback_KeyPress(int key, bool shift, bool control);
TPeekMessages Callback_PeekMessages = NULL;
TUpdateFPSDisplay g_pUpdateFPSDisplay = NULL;
@ -106,6 +105,7 @@ TUpdateFPSDisplay g_pUpdateFPSDisplay = NULL;
void Stop();
bool g_bHwInit = false;
bool g_bRealWiimote = false;
HWND g_pWindowHandle = NULL;
Common::Thread* g_pThread = NULL;
@ -115,13 +115,50 @@ Common::Event emuThreadGoing;
//////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Display messages and return values
// ¯¯¯¯¯¯¯¯¯¯
bool PanicAlertToVideo(const char* text, bool yes_no)
{
DisplayMessage(text, 3000);
return true;
}
// Called from GUI thread
void DisplayMessage(const std::string &message, int time_in_ms)
{
PluginVideo::Video_AddMessage(message.c_str(), time_in_ms);
}
void DisplayMessage(const char *message, int time_in_ms)
{
PluginVideo::Video_AddMessage(message, time_in_ms);
}
void Callback_DebuggerBreak()
{
CCPU::EnableStepping(true);
}
const SCoreStartupParameter& GetStartupParameter()
{
return g_CoreStartupParameter;
}
void* GetWindowHandle()
{
return g_pWindowHandle;
}
bool GetRealWiimote()
{
return g_bRealWiimote;
}
/////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// This is called from the GUI thread. See the booting call schedule in BootManager.cpp
// ¯¯¯¯¯¯¯¯¯¯
bool Init(const SCoreStartupParameter _CoreParameter)
{
if (g_pThread != NULL) {
@ -153,6 +190,7 @@ bool Init(const SCoreStartupParameter _CoreParameter)
emuThreadGoing.Init();
// This will execute EmuThread() further down in this file
g_pThread = new Common::Thread(EmuThread, (void*)&g_CoreStartupParameter);
emuThreadGoing.Wait();
@ -168,16 +206,6 @@ bool Init(const SCoreStartupParameter _CoreParameter)
return true;
}
void DisplayMessage(const std::string &message, int time_in_ms)
{
PluginVideo::Video_AddMessage(message.c_str(), time_in_ms);
}
void DisplayMessage(const char *message, int time_in_ms)
{
PluginVideo::Video_AddMessage(message, time_in_ms);
}
// Called from GUI thread or VI thread
void Stop() // - Hammertime!
@ -213,21 +241,6 @@ void Stop() // - Hammertime!
Host_SetWaitCursor(false);
}
void Callback_DebuggerBreak()
{
CCPU::EnableStepping(true);
}
const SCoreStartupParameter& GetStartupParameter()
{
return g_CoreStartupParameter;
}
void* GetWindowHandle()
{
return g_pWindowHandle;
}
//////////////////////////////////////////////////////////////////////////////////////////
// Create the CPU thread
@ -280,7 +293,7 @@ THREAD_RETURN CpuThread(void *pArg)
//////////////////////////////////////////////////////////////////////////////////////////
// Initalize plugins and create emulation thread
// ¯¯¯¯¯¯¯¯¯¯
/* Call browser: Init():g_pThread(). See the BootManager.cpp file description for a completel
/* Call browser: Init():g_pThread(). See the BootManager.cpp file description for a complete
call schedule. */
THREAD_RETURN EmuThread(void *pArg)
{
@ -348,7 +361,8 @@ THREAD_RETURN EmuThread(void *pArg)
WiimoteInitialize.hWnd = g_pWindowHandle;
WiimoteInitialize.pLog = Callback_WiimoteLog;
WiimoteInitialize.pWiimoteInput = Callback_WiimoteInput;
PluginWiimote::Wiimote_Initialize(WiimoteInitialize);
// Wait for Wiiuse to find the number of connected Wiimotes
g_bRealWiimote = PluginWiimote::Wiimote_Initialize(WiimoteInitialize);
}
// The hardware is initialized.

View File

@ -51,13 +51,14 @@ namespace Core
void SaveState();
void LoadState();
// get core parameters
// Get core parameters
extern SCoreStartupParameter g_CoreStartupParameter; //uck
const SCoreStartupParameter& GetStartupParameter();
// make a screen shot
// Make a screen shot
bool MakeScreenshot(const std::string& _rFilename);
void* GetWindowHandle();
bool GetRealWiimote();
extern bool bReadTrace;
extern bool bWriteTrace;

View File

@ -15,6 +15,51 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
/////////////////////////////////////////////////////////////////////////////
// File description: This file control all system timers
/* -------------
"Time" is measured in frames, not time: These update frequencies are determined by the passage
of frames. So if a game runs slow, on a slow computer for example, these updates will occur
less frequently. This makes sense because almost all console games are controlled by frames
rather than time, so if a game can't keep up with the normal framerate all animations and
actions slows down and the game runs to slow. This is different from PC games that are are
often controlled by time instead and may not have maximum framerates.
However, I'm not sure if the Bluetooth communication for the Wiimote is entirely frame
dependent, the timing problems with the ack command in Zelda - TP may be related to
time rather than frames? For now the IPC_HLE_PERIOD is frame dependet, but bcause of
different conditions on the way to PluginWiimote::Wiimote_Update() the updates may actually
be time related after all, or not?
I'm not sure about this but the text below seems to assume that 60 fps means that the game
runs in the normal intended speed. In that case an update time of [GetTicksPerSecond() / 60]
would mean one update per frame and [GetTicksPerSecond() / 60] would mean four updates per
frame.
IPC_HLE_PERIOD: For the Wiimote this is the call scedule:
IPC_HLE_UpdateCallback() // In this file
// This function seems to call all devices' Update() function four times per frame
WII_IPC_HLE_Interface::Update()
// If the AclFrameQue is empty this will call Wiimote_Update() and make it send
the current input status to the game. I'm not sure if this occurs approximately
once every frame or if the frequency is not exactly tied to rendered frames
CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
PluginWiimote::Wiimote_Update()
// This is also a device updated by WII_IPC_HLE_Interface::Update() but it doesn't
seem to ultimately call PluginWiimote::Wiimote_Update(). However it can be called
by the /dev/usb/oh1 device if the AclFrameQue is empty.
CWII_IPC_HLE_WiiMote::Update()
//////////////////////////*/
/////////////////////////////////////////////////////////////////////////////
// Inlude
// -------------
#include "Common.h"
#include "../PatchEngine.h"
#include "SystemTimers.h"
@ -32,10 +77,15 @@
#include "../IPC_HLE/WII_IPC_HLE.h"
#include "Thread.h"
#include "Timer.h"
/////////////////////////////
namespace SystemTimers
{
/////////////////////////////////////////////////////////////////////////////
// Declarations and definitions
// -------------
u32 CPU_CORE_CLOCK = 486000000u; // 486 mhz (its not 485, stop bugging me!)
s64 fakeDec;
@ -85,6 +135,8 @@ int
// Once every 2 frame-period should be enough.
// Assuming game's frame-finish-watchdog wait more than 2 emulated frame-period before starting its mess.
FAKE_GP_WATCHDOG_PERIOD = GetTicksPerSecond() / 30;
///////////////////////////////////
u32 GetTicksPerSecond()
{

View File

@ -399,8 +399,11 @@ void ExecuteCommand(u32 _Address)
break;
default:
_dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown Command %i (0x%08x)", Command, _Address);
CCPU::Break();
_dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown IPC Command %i (0x%08x)", Command, _Address);
// Break on the same terms as the _dbg_assert_msg_, if LOGGING was defined
#ifdef LOGGING
CCPU::Break();
#endif
break;
}

View File

@ -15,16 +15,28 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
//////////////////////////////////////////////////////////////////////////////////////////
// Include
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
#include "WII_IPC_HLE_Device_usb.h"
#include "../Plugins/Plugin_Wiimote.h"
#include "../Core.h" // Local core functions
#include "../Debugger/Debugger_SymbolMap.h"
#include "../Host.h"
#include "../../../../Branches/MusicMod/Common/Src/Console.h"
///////////////////////
// ugly hacks for "SendEventNumberOfCompletedPackets"
// Ugly hacks for "SendEventNumberOfCompletedPackets"
int g_HCICount = 0;
int g_GlobalHandle = 0;
//////////////////////////////////////////////////////////////////////////////////////////
// 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)
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
, m_PINType(0)
@ -58,6 +70,7 @@ CWII_IPC_HLE_Device_usb_oh1_57e_305::CWII_IPC_HLE_Device_usb_oh1_57e_305(u32 _De
CWII_IPC_HLE_Device_usb_oh1_57e_305::~CWII_IPC_HLE_Device_usb_oh1_57e_305()
{}
///////////////////////////
// ===================================================
@ -290,7 +303,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLFrame(u16 _ConnectionHandle, u8
// ===================================================
/* This is called from WII_IPC_HLE_Interface::Update() */
/* See IPC_HLE_PERIOD in SystemTimers.cpp for a documentation of this update. */
// ----------------
u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
{
@ -387,19 +400,27 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
before we initiate the connection. To avoid doing this for GC games we also
want m_LocalName from CommandWriteLocalName() to be "Wii".
FiRES: TODO find a good solution to do this */
FiRES: TODO find a good solution to do this
JP: Solution to what? When to run SendEventRequestConnection()?
*/
// -------------------------
static bool test = true;
// Why do we need this? 0 worked with the emulated wiimote in all games I tried
static int counter = 1000;
/* I disabled this and disable m_ScanEnable instead to avoid running SendEventRequestConnection()
again. */
//static bool test = true;
if (test && !strcasecmp(m_LocalName, "Wii") && (m_ScanEnable & 0x2))
/* Why do we need this? 0 worked with the emulated wiimote in all games I tried. Do we have to
wait for wiiuse_init() and wiiuse_find() for a real Wiimote here? I'm testing
this new method of not waiting at all if there are no real Wiimotes. Please let me know
if it doesn't work. */
static int counter = (Core::GetRealWiimote() ? 1000 : 0);
if (!strcasecmp(m_LocalName, "Wii") && (m_ScanEnable & 0x2))
{
counter--;
if (counter < 0)
{
test = false;
//test = false;
for (size_t i=0; i < m_WiiMotes.size(); i++)
{
if (m_WiiMotes[i].EventPagingChanged(2))
@ -564,8 +585,15 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventRemoteNameReq(bdaddr_t _bd)
return true;
}
/////////////////////////////////////////////////////////////
/* This is called from Update() after ScanEnable has been enabled. */
// ¯¯¯¯¯¯¯¯¯
bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventRequestConnection(CWII_IPC_HLE_WiiMote& _rWiiMote)
{
// We have to disable scan now to avoid running this function over and over again
m_ScanEnable = 0;
SQueuedEvent Event(sizeof(SHCIEventRequestConnection), 0);
SHCIEventRequestConnection* pEventRequestConnection = (SHCIEventRequestConnection*)Event.m_buffer;
@ -601,6 +629,8 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventRequestConnection(CWII_IPC_HL
return true;
};
//////////////////////////////
bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventRequestLinkKey(bdaddr_t _bd)
{
@ -1377,7 +1407,9 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWritePageTimeOut(u8* _Input)
}
/////////////////////////////////////////////////////////////
/* This will enable ScanEnable so that Update() can start the Wiimote. */
// ¯¯¯¯¯¯¯¯¯
void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteScanEnable(u8* _Input)
{
// Command parameters
@ -1404,7 +1436,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteScanEnable(u8* _Input)
SendEventCommandComplete(HCI_CMD_WRITE_SCAN_ENABLE, &Reply, sizeof(hci_write_scan_enable_rp));
}
/////////////////////////////
void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteInquiryMode(u8* _Input)

View File

@ -29,7 +29,7 @@ void UnloadPlugin();
// Function Types
typedef void (__cdecl* TGetDllInfo)(PLUGIN_INFO*);
typedef void (__cdecl* TDllConfig)(HWND);
typedef void (__cdecl* TWiimote_Initialize)(SWiimoteInitialize);
typedef bool (__cdecl* TWiimote_Initialize)(SWiimoteInitialize);
typedef void (__cdecl* TWiimote_Shutdown)();
typedef void (__cdecl* TWiimote_Update)();
typedef void (__cdecl* TWiimote_Output)(u16 _channelID, const void* _pData, u32 _Size);

View File

@ -30,7 +30,8 @@
BootManager.cpp BootCore
Core Core.cpp Init Thread creation
EmuThread Calls CBoot::BootUp
Boot.cpp
Boot.cpp CBoot::BootUp()
CBoot::EmulatedBIOS_Wii() / GC() or Load_BIOS()
*/
// =============
@ -54,6 +55,7 @@
#include "ConfigMain.h"
#include "Frame.h"
#include "CodeWindow.h"
#include "../../../../Branches/MusicMod/Common/Src/Console.h"
#ifdef MUSICMOD
#include "../../../Branches/MusicMod/Main/Src/Main.h" // MusicMod
#endif

View File

@ -56,6 +56,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DolphinWX", "Core\DolphinWX
ProjectSection(ProjectDependencies) = postProject
{48AD7E0A-25B1-4974-A1E3-03F8C438D34F} = {48AD7E0A-25B1-4974-A1E3-03F8C438D34F}
{0318BA30-EF48-441A-9E10-DC85EFAE39F0} = {0318BA30-EF48-441A-9E10-DC85EFAE39F0}
{8D612734-FAA5-4B8A-804F-4DEA2367D495} = {8D612734-FAA5-4B8A-804F-4DEA2367D495}
{71B16F46-0B00-4EDA-B253-D6D9D03A215C} = {71B16F46-0B00-4EDA-B253-D6D9D03A215C}
{33546D62-7F34-4EA6-A88E-D538B36E16BF} = {33546D62-7F34-4EA6-A88E-D538B36E16BF}
{DE7C596C-CBC4-4278-8909-146D63990803} = {DE7C596C-CBC4-4278-8909-146D63990803}
@ -240,7 +241,6 @@ Global
{CFDCEE0E-FA45-4F72-9FCC-0B88F5A75160}.DebugFast|Win32.ActiveCfg = DebugFast|Win32
{CFDCEE0E-FA45-4F72-9FCC-0B88F5A75160}.DebugFast|x64.ActiveCfg = DebugFast|x64
{CFDCEE0E-FA45-4F72-9FCC-0B88F5A75160}.Release|Win32.ActiveCfg = Release|Win32
{CFDCEE0E-FA45-4F72-9FCC-0B88F5A75160}.Release|Win32.Build.0 = Release|Win32
{CFDCEE0E-FA45-4F72-9FCC-0B88F5A75160}.Release|x64.ActiveCfg = Release|x64
{CFDCEE0E-FA45-4F72-9FCC-0B88F5A75160}.Release|x64.Build.0 = Release|x64
{C573CAF7-EE6A-458E-8049-16C0BF34C2E9}.Debug|Win32.ActiveCfg = Debug|Win32
@ -322,8 +322,10 @@ Global
{8D612734-FAA5-4B8A-804F-4DEA2367D495}.Debug|Win32.ActiveCfg = Debug|Win32
{8D612734-FAA5-4B8A-804F-4DEA2367D495}.Debug|x64.ActiveCfg = Debug|x64
{8D612734-FAA5-4B8A-804F-4DEA2367D495}.DebugFast|Win32.ActiveCfg = DebugFast|Win32
{8D612734-FAA5-4B8A-804F-4DEA2367D495}.DebugFast|Win32.Build.0 = DebugFast|Win32
{8D612734-FAA5-4B8A-804F-4DEA2367D495}.DebugFast|x64.ActiveCfg = DebugFast|x64
{8D612734-FAA5-4B8A-804F-4DEA2367D495}.Release|Win32.ActiveCfg = Release|Win32
{8D612734-FAA5-4B8A-804F-4DEA2367D495}.Release|Win32.Build.0 = Release|Win32
{8D612734-FAA5-4B8A-804F-4DEA2367D495}.Release|x64.ActiveCfg = Release|x64
{8D612734-FAA5-4B8A-804F-4DEA2367D495}.Release|x64.Build.0 = Release|x64
{C6CC7A52-0FDD-433A-B2CF-9C6F187DA807}.Debug|Win32.ActiveCfg = Debug|Win32
@ -377,11 +379,9 @@ Global
{0D14F1E9-490B-4A2D-A4EF-0535E8B3C718}.Debug|x64.ActiveCfg = Debug|x64
{0D14F1E9-490B-4A2D-A4EF-0535E8B3C718}.Debug|x64.Build.0 = Debug|x64
{0D14F1E9-490B-4A2D-A4EF-0535E8B3C718}.DebugFast|Win32.ActiveCfg = Debug|Win32
{0D14F1E9-490B-4A2D-A4EF-0535E8B3C718}.DebugFast|Win32.Build.0 = Debug|Win32
{0D14F1E9-490B-4A2D-A4EF-0535E8B3C718}.DebugFast|x64.ActiveCfg = Debug|x64
{0D14F1E9-490B-4A2D-A4EF-0535E8B3C718}.DebugFast|x64.Build.0 = Debug|x64
{0D14F1E9-490B-4A2D-A4EF-0535E8B3C718}.Release|Win32.ActiveCfg = Release|Win32
{0D14F1E9-490B-4A2D-A4EF-0535E8B3C718}.Release|Win32.Build.0 = Release|Win32
{0D14F1E9-490B-4A2D-A4EF-0535E8B3C718}.Release|x64.ActiveCfg = Release|x64
{0D14F1E9-490B-4A2D-A4EF-0535E8B3C718}.Release|x64.Build.0 = Release|x64
{DE7C596C-CBC4-4278-8909-146D63990803}.Debug|Win32.ActiveCfg = Debug|Win32

View File

@ -1,3 +1,21 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
//__________________________________________________________________________________________________
// Common wiimote plugin spec, unversioned
//
@ -8,9 +26,10 @@
#include "PluginSpecs.h"
#include "ExportProlog.h"
typedef void (*TLogv)(const char* _pMessage, int _v);
// Called when the Wiimote sends input reports to the Core.
// This is called when the Wiimote sends input reports to the Core.
// Payload: an L2CAP packet.
typedef void (*TWiimoteInput)(u16 _channelID, const void* _pData, u32 _Size);
@ -22,6 +41,7 @@ typedef struct
TWiimoteInput pWiimoteInput;
} SWiimoteInitialize;
/////////////////////////////////////////////////////////////////////////////////////////////////////
// I N T E R F A C E ////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
@ -57,9 +77,9 @@ EXPORT void CALL DllDebugger(HWND _hParent, bool Show);
// Function:
// Purpose:
// input: WiimoteInitialize
// output: none
// output: If at least one real Wiimote was found or not
//
EXPORT void CALL Wiimote_Initialize(SWiimoteInitialize _WiimoteInitialize);
EXPORT bool CALL Wiimote_Initialize(SWiimoteInitialize _WiimoteInitialize);
// __________________________________________________________________________________________________
// Function: Wiimote_Shutdown

View File

@ -15,12 +15,20 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
/////////////////////////////////////////////////////////////////////////
// Include
// ------------
//#include "Common.h" // for u16
#include "ConfigDlg.h"
#include "Config.h"
#include "EmuSubroutines.h" // for WmRequestStatus
/////////////////////////////
/////////////////////////////////////////////////////////////////////////
// Event table
// ------------
BEGIN_EVENT_TABLE(ConfigDialog,wxDialog)
EVT_CLOSE(ConfigDialog::OnClose)
EVT_BUTTON(ID_CLOSE, ConfigDialog::CloseClick)
@ -30,6 +38,8 @@ BEGIN_EVENT_TABLE(ConfigDialog,wxDialog)
EVT_CHECKBOX(ID_NUNCHUCKCONNECTED, ConfigDialog::GeneralSettingsChanged)
EVT_CHECKBOX(ID_CLASSICCONTROLLERCONNECTED, ConfigDialog::GeneralSettingsChanged)
END_EVENT_TABLE()
/////////////////////////////
ConfigDialog::ConfigDialog(wxWindow *parent, wxWindowID id, const wxString &title, const wxPoint &position, const wxSize& size, long style)
: wxDialog(parent, id, title, position, size, style)
@ -42,6 +52,10 @@ ConfigDialog::~ConfigDialog()
{
}
/////////////////////////////////////////////////////////////////////////
// Create GUI
// ------------
void ConfigDialog::CreateGUIControls()
{
// Notebook
@ -120,6 +134,7 @@ void ConfigDialog::AboutClick(wxCommandEvent& WXUNUSED (event))
{
}
//////////////////////////
// ===================================================
@ -159,8 +174,12 @@ void ConfigDialog::GeneralSettingsChanged(wxCommandEvent& event)
g_Config.bClassicControllerConnected = false;
// Disconnect the extension so that the game recognize the change
DoExtensionConnectedDisconnected();
/* It doesn't seem to be needed but shouldn't it at least take 25 ms to
reconnect an extension after we disconnected another? */
Sleep(25);
}
// Update status
g_Config.bNunchuckConnected = m_NunchuckConnected->IsChecked();
// Generate connect/disconnect status event

View File

@ -16,37 +16,75 @@
// http://code.google.com/p/dolphin-emu/
// --------------------
//////////////////////////////////////////////////////////////////////////////////////////
// Includes
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
#include <string>
#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#include <windows.h>
#endif
#include "StringUtil.h"
#define HAVE_WX 1
#if defined(HAVE_WX) && HAVE_WX // wxWidgets
#include <wx/datetime.h> // for the timestamps
#endif
///////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Settings
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
// --------------------
// On and off
bool g_consoleEnable = true;
int gSaveFile = 0;
#define DEBUG_WIIMOTE
bool gSaveFile = true;
#define DEBUG_WIIMOTE // On or off
const int nFiles = 1;
// --------------------
// Settings
int nFiles = 1;
// --------------------
// Create handles
#ifdef DEBUG_WIIMOTE
FILE* __fStdOut[1]; // you have to update this manually, we can't place a nFiles in there
FILE* __fStdOut[nFiles];
#endif
#ifdef _WIN32
HANDLE __hStdOut = NULL;
#endif
//////////////////////////////
// =======================================================================================
/* Get Timestamp */
// -------------
std::string Tm(bool Ms)
{
#if defined(HAVE_WX) && HAVE_WX
std::string Tmp;
if(Ms)
{
wxDateTime datetime = wxDateTime::UNow(); // Get timestamp
Tmp = StringFromFormat("%02i:%02i:%03i",
datetime.GetMinute(), datetime.GetSecond(), datetime.GetMillisecond());
}
else
{
wxDateTime datetime = wxDateTime::Now(); // Get timestamp
Tmp = StringFromFormat("%02i:%02i",
datetime.GetMinute(), datetime.GetSecond());
}
return Tmp;
#else
std::string Tmp = "";
return Tmp;
#endif
}
// ===========================
// =======================================================================================
/* Start console window - width and height is the size of console window, if you specify
@ -69,7 +107,7 @@ void startConsoleWin(int width, int height, char* fname)
SetConsoleWindowInfo(__hStdOut, TRUE, &coo);
// ---------------------------------------------------------------------------------------
// Write to a file
// Create a file for this
if(fname)
{
for(int i = 0; i < nFiles; i++)
@ -107,6 +145,7 @@ int aprintf(int a, char *fmt, ...)
if(__fStdOut[a]) // TODO: make this work, we have to set all default values to NULL
//to make it work
fprintf(__fStdOut[a], s);
fflush(__fStdOut[0]); // Write file now, don't wait
// -------------
return(cnt);
@ -135,14 +174,20 @@ int wprintf(const char *fmt, ...)
cnt = vsnprintf(s, 500, fmt, argptr);
va_end(argptr);
DWORD cCharsWritten;
DWORD cCharsWritten; // We will get a value back here
// ---------------------------------------------------------------------------------------
// ------------------------------------------
// Write to console
// ----------------
if(__hStdOut)
{
WriteConsole(__hStdOut, s, strlen(s), &cCharsWritten, NULL);
}
// -------------
// ----------------------------------------
// Write to file
// ----------------
aprintf(0, s);
return(cnt);
#else

View File

@ -15,7 +15,19 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef WIIMOTE_CONSOLE_H
#define WIIMOTE_CONSOLE_H
//////////////////////////////////////////////////////////////////////////////////////////
// Includes
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
#include <iostream>
//////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Declarations
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
std::string Tm(bool Ms = false);
void startConsoleWin(int width, int height, char* fname);
int wprintf(const char *fmt, ...);
int aprintf(int a, const char *fmt, ...);
@ -24,3 +36,6 @@ void ClearScreen();
#ifdef _WIN32
HWND GetConsoleHwnd(void);
#endif
///////////////////////////////
#endif // WIIMOTE_CONSOLE_H

View File

@ -20,14 +20,18 @@
// ===================================================
/* Data reports guide. The different structures location in the Input reports. The ? in
the IR coordinates is the High coordinates that are four in one byte. */
the IR coordinates is the High coordinates that are four in one byte.
0x37: For the data reportingmode 0x37 there are five unused IR bytes in the end (represented)
by "..." below, it seems like they can be set to either 0xff or 0x00 without affecting the
IR emulation. */
// ----------------
/* 0x33
[c.left etc] [c.a etc] acc.x y z ir0.x y ? ir1.x y ? ir2.x y ? ir3.x y ?
0x37
[c.left etc] [c.a etc] acc.x y z ir0.x1 y1 ? x2 y2 ir1.x1 y1 ? x2 y2 ext.jx jy ax ay az bt
[c.left etc] [c.a etc] acc.x y z ir0.x1 y1 ? x2 y2 ir1.x1 y1 ? x2 y2 ... ext.jx jy ax ay az bt
The Data Report's path from here is
@ -43,23 +47,32 @@
//////////////////////////////////////////////////////////////////////////////////////////
// Includes
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
#include "pluginspecs_wiimote.h"
#include <vector>
#include <string>
#include "Common.h"
#include "wiimote_hid.h"
#include "Common.h" // Common
#include "StringUtil.h" // for ArrayToString
#include "wiimote_hid.h" // Local
#include "EmuMain.h"
#include "EmuSubroutines.h"
#include "EmuDefinitions.h"
#include "Encryption.h" // for extension encryption
#include "Console.h" // for startConsoleWin, wprintf, GetConsoleHwnd
#include "Config.h" // for g_Config
///////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Declarations and definitions
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
extern SWiimoteInitialize g_WiimoteInitialize;
//extern void __Log(int log, const char *format, ...);
//extern void __Log(int log, int v, const char *format, ...);
///////////////////////////////
namespace WiiMoteEmu
@ -78,13 +91,13 @@ void WmDataReporting(u16 _channelID, wm_data_reporting* dr)
LOG(WII_IPC_WIIMOTE, " Continuous: %x", dr->continuous);
LOG(WII_IPC_WIIMOTE, " All The Time: %x (not only on data change)", dr->all_the_time);
LOG(WII_IPC_WIIMOTE, " Mode: 0x%02x", dr->mode);
wprintf("\nData reporting mode: 0x%02x", dr->mode);
wprintf("\nData reporting channel: 0x%04x\n", _channelID);
//wprintf("Data reporting mode: 0x%02x\n", dr->mode);
//wprintf("Data reporting channel: 0x%04x\n", _channelID);
g_ReportingMode = dr->mode;
g_ReportingChannel = _channelID;
switch(dr->mode) { //see Wiimote_Update()
switch(dr->mode) // See Wiimote_Update()
{
case WM_REPORT_CORE:
case WM_REPORT_CORE_ACCEL:
case WM_REPORT_CORE_ACCEL_IR12:
@ -270,7 +283,7 @@ void SendReportCoreAccelIr10Ext(u16 _channelID)
#ifdef _WIN32
/*if(GetAsyncKeyState('V'))
{
std::string Temp = WiiMoteEmu::ArrayToString(DataFrame, Offset, 0, 30);
std::string Temp = ArrayToString(DataFrame, Offset, 0, 30);
wprintf("DataFrame: %s\n", Temp.c_str());
}*/
#endif

View File

@ -15,8 +15,11 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _EMU_DECLARATIONS_
#define _EMU_DECLARATIONS_
//////////////////////////////////////////////////////////////////////////////////////////
// Includes
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
#ifndef _EMU_DEFINITIONS_
#define _EMU_DEFINITIONS_
#include "pluginspecs_wiimote.h"
@ -27,6 +30,7 @@
#include "EmuDefinitions.h"
#include "Encryption.h"
#include "Console.h" // for startConsoleWin, wprintf, GetConsoleHwnd
//////////////////////////
extern SWiimoteInitialize g_WiimoteInitialize;
@ -43,16 +47,18 @@ u8 g_SpeakerVoice = 0x1; // 1 = on
u8 g_IR = 0x1; // 1 = on
u8 g_Eeprom[WIIMOTE_EEPROM_SIZE];
u8 g_RegSpeaker[WIIMOTE_REG_SPEAKER_SIZE];
u8 g_RegExt[WIIMOTE_REG_EXT_SIZE];
u8 g_RegExtTmp[WIIMOTE_REG_EXT_SIZE];
u8 g_RegExtTmpReport[WIIMOTE_REG_EXT_SIZE];
u8 g_RegIr[WIIMOTE_REG_IR_SIZE];
u8 g_ReportingMode; // the reporting mode and channel id
u8 g_ReportingMode; // The reporting mode and channel id
u16 g_ReportingChannel;
wiimote_key g_ExtKey; // the extension encryption key
std::vector<wm_ackdelay> AckDelay;
wiimote_key g_ExtKey; // The extension encryption key
} // namespace

View File

@ -15,15 +15,18 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _EMU_DEFINITIONS_
#define _EMU_DEFINITIONS_
#ifndef _EMU_DECLARATIONS_
#define _EMU_DECLARATIONS_
#include "pluginspecs_wiimote.h"
#include <vector>
#include <string>
#include "Common.h"
#include "wiimote_hid.h"
#include "Encryption.h"
#include "Console.h" // for startConsoleWin, wprintf, GetConsoleHwnd
extern SWiimoteInitialize g_WiimoteInitialize;
@ -52,12 +55,106 @@ namespace WiiMoteEmu
#define wBOTTOM 625
#define wSENSOR_BAR_RADIUS 200
// vars
// Registry sizes
#define WIIMOTE_EEPROM_SIZE (16*1024)
#define WIIMOTE_REG_SPEAKER_SIZE 10
#define WIIMOTE_REG_EXT_SIZE 0x100
#define WIIMOTE_REG_IR_SIZE 0x34
extern u8 g_Leds;
extern u8 g_Speaker;
extern u8 g_SpeakerVoice;
extern u8 g_IR;
extern u8 g_Eeprom[WIIMOTE_EEPROM_SIZE];
extern u8 g_RegSpeaker[WIIMOTE_REG_SPEAKER_SIZE];
extern u8 g_RegExt[WIIMOTE_REG_EXT_SIZE];
extern u8 g_RegExtTmp[WIIMOTE_REG_EXT_SIZE];
extern u8 g_RegExtTmpReport[WIIMOTE_REG_EXT_SIZE];
extern u8 g_RegIr[WIIMOTE_REG_IR_SIZE];
extern u8 g_ReportingMode;
extern u16 g_ReportingChannel;
struct wm_ackdelay // Ack delay
{
u8 Delay;
u8 ReportID;
u16 ChannelID;
bool Sent;
};
extern std::vector<wm_ackdelay> AckDelay;
extern wiimote_key g_ExtKey; // extension encryption key
static const u8 EepromData_0[] = {
0xA1, 0xAA, 0x8B, 0x99, 0xAE, 0x9E, 0x78, 0x30,
0xA7, 0x74, 0xD3, 0xA1, 0xAA, 0x8B, 0x99, 0xAE,
0x9E, 0x78, 0x30, 0xA7, 0x74, 0xD3, 0x82, 0x82,
0x82, 0x15, 0x9C, 0x9C, 0x9E, 0x38, 0x40, 0x3E,
0x82, 0x82, 0x82, 0x15, 0x9C, 0x9C, 0x9E, 0x38,
0x40, 0x3E
};
static const u8 EepromData_16D0[] = {
0x00, 0x00, 0x00, 0xFF, 0x11, 0xEE, 0x00, 0x00,
0x33, 0xCC, 0x44, 0xBB, 0x00, 0x00, 0x66, 0x99,
0x77, 0x88, 0x00, 0x00, 0x2B, 0x01, 0xE8, 0x13
};
/* Default calibration for the nunchuck. It should be written to 0x20 - 0x3f of the
extension register. 0x80 is the neutral x and y accelerators and 0xb3 is the
neutral z accelerometer that is adjusted for gravity. */
static const u8 nunchuck_calibration[] =
{
0x80,0x80,0x80,0x00, 0xb3,0xb3,0xb3,0x00,
0xe0,0x20,0x80,0xe0, 0x20,0x80,0xee,0x43,
0x80,0x80,0x80,0x00, 0xb3,0xb3,0xb3,0x00,
0xe0,0x20,0x80,0xe0, 0x20,0x80,0xee,0x43
};
/* Classic Controller calibration. 0x80 is the neutral for the analog triggers and
sticks. The left analog range is 0x1c - 0xe4 and the right is 0x28 - 0xd8.
We use this range because it's closest to the GC controller range. */
static const u8 classic_calibration[] =
{
0xe4,0x1c,0x80,0xe4, 0x1c,0x80,0xd8,0x28,
0x80,0xd8,0x28,0x80, 0x20,0x20,0x95,0xea,
0xe4,0x1c,0x80,0xe4, 0x1c,0x80,0xd8,0x28,
0x80,0xd8,0x28,0x80, 0x20,0x20,0x95,0xea
};
/* The Nunchuck id. It should be written to the last bytes of the
extension register */
static const u8 nunchuck_id[] =
{
0x00, 0x00, 0xa4, 0x20, 0x00, 0x00
};
/* The Classic Controller id. It should be written to the last bytes of the
extension register */
static const u8 classic_id[] =
{
0x00, 0x00, 0xa4, 0x20, 0x01, 0x01
};
/* The id for nothing inserted */
static const u8 nothing_id[] =
{
0x00, 0x00, 0x00, 0x00, 0x2e, 0x2e
};
/* The id for a partially inserted extension */
static const u8 partially_id[] =
{
0x00, 0x00, 0x00, 0x00, 0xff, 0xff
};
} // namespace

View File

@ -16,6 +16,9 @@
// http://code.google.com/p/dolphin-emu/
//////////////////////////////////////////////////////////////////////////////////////////
// Includes
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
#include "pluginspecs_wiimote.h"
#include <vector>
@ -31,492 +34,341 @@
#include "Encryption.h" // for extension encryption
#include "Console.h" // for startConsoleWin, wprintf, GetConsoleHwnd
#include "Config.h" // for g_Config
////////////////////////////////////
extern SWiimoteInitialize g_WiimoteInitialize;
namespace WiiMoteEmu
{
//******************************************************************************
// Subroutines
//******************************************************************************
// ===================================================
/* Here we process the Output Reports that the Wii sends. Our response will be an Input Report
back to the Wii. Input and Output is from the Wii's perspective, Output means data to
the Wiimote (from the Wii), Input means data from the Wiimote.
The call browser:
1. Wiimote_InterruptChannel > InterruptChannel > HidOutputReport
2. Wiimote_ControlChannel > ControlChannel > HidOutputReport */
// ----------------
void HidOutputReport(u16 _channelID, wm_report* sr) {
LOGV(WII_IPC_WIIMOTE, 0, "===========================================================");
LOGV(WII_IPC_WIIMOTE, 0, "HidOutputReport (0x%02x)", sr->channel);
switch(sr->channel)
{
case 0x10:
LOGV(WII_IPC_WIIMOTE, 0, "HidOutputReport: unknown sr->channel 0x10");
break;
case WM_LEDS: // 0x11
WmLeds(_channelID, (wm_leds*)sr->data);
break;
case WM_DATA_REPORTING: // 0x12
WmDataReporting(_channelID, (wm_data_reporting*)sr->data);
break;
case WM_REQUEST_STATUS: // 0x15
WmRequestStatus(_channelID, (wm_request_status*)sr->data);
break;
case WM_READ_DATA: // 0x17
WmReadData(_channelID, (wm_read_data*)sr->data);
break;
/* This enables or disables the IR lights, we update the global variable g_IR
so that WmRequestStatus() knows about it */
case WM_IR_PIXEL_CLOCK: // 0x13
case WM_IR_LOGIC: // 0x1a
LOGV(WII_IPC_WIIMOTE, 0, " IR Enable 0x%02x: 0x%02x", sr->channel, sr->data[0]);
//wprintf("IR Enable/Disable 0x%02x: 0x%02x\n", sr->channel, sr->data[0]);
if(sr->data[0] == 0x02) g_IR = 0;
else if(sr->data[0] == 0x06) g_IR = 1;
break;
case WM_WRITE_DATA: // 0x16
WmWriteData(_channelID, (wm_write_data*)sr->data);
break;
case WM_SPEAKER_ENABLE: // 0x14
LOGV(WII_IPC_WIIMOTE, 1, " WM Speaker Enable 0x%02x: 0x%02x", sr->channel, sr->data[0]);
//wprintf("Speaker Enable/Disable 0x%02x: 0x%02x\n", sr->channel, sr->data[0]);
if(sr->data[0] == 0x02) g_Speaker = 0;
else if(sr->data[0] == 0x06) g_Speaker = 1;
break;
case WM_SPEAKER_MUTE:
LOGV(WII_IPC_WIIMOTE, 1, " WM Mute Enable 0x%02x: 0x%02x", sr->channel, sr->data[0]);
//wprintf("Speaker Mute/Unmute 0x%02x: 0x%02x\n", sr->channel, sr->data[0]);
if(sr->data[0] == 0x02) g_SpeakerVoice = 0;
else if(sr->data[0] == 0x06) g_SpeakerVoice = 1;
break;
default:
PanicAlert("HidOutputReport: Unknown channel 0x%02x", sr->channel);
return;
}
LOGV(WII_IPC_WIIMOTE, 0, "===========================================================");
/* Bit shift conversions */
// -------------
u32 convert24bit(const u8* src) {
return (src[0] << 16) | (src[1] << 8) | src[2];
}
// ===================================================
/* Generate the right address for wm reports. */
// ----------------
int WriteWmReport(u8* dst, u8 channel) {
u32 Offset = 0;
hid_packet* pHidHeader = (hid_packet*)(dst + Offset);
Offset += sizeof(hid_packet);
pHidHeader->type = HID_TYPE_DATA;
pHidHeader->param = HID_PARAM_INPUT;
wm_report* pReport = (wm_report*)(dst + Offset);
Offset += sizeof(wm_report);
pReport->channel = channel;
return Offset;
u16 convert16bit(const u8* src) {
return (src[0] << 8) | src[1];
}
// ==============
// ===================================================
/* LED (blue lights) report. */
/* Calibrate the mouse position to the emulation window. */
// ----------------
void WmLeds(u16 _channelID, wm_leds* leds) {
LOGV(WII_IPC_WIIMOTE, 0, "===========================================================");
LOG(WII_IPC_WIIMOTE, " Set LEDs");
LOG(WII_IPC_WIIMOTE, " Leds: %x", leds->leds);
LOG(WII_IPC_WIIMOTE, " Rumble: %x", leds->rumble);
g_Leds = leds->leds;
LOGV(WII_IPC_WIIMOTE, 0, "===========================================================");
}
// ===================================================
/* This will generate the 0x22 acknowledgment after all Input reports. It will
have the form a1 22 00 00 _reportID 00. The first two bytes are unknown but
00 00 seems to work fine. */
// ----------------
void WmSendAck(u16 _channelID, u8 _reportID, u32 address)
void GetMousePos(float& x, float& y)
{
u8 DataFrame[1024];
u32 Offset = 0;
#ifdef _WIN32
POINT point;
// Header
hid_packet* pHidHeader = (hid_packet*)(DataFrame + Offset);
pHidHeader->type = HID_TYPE_DATA;
pHidHeader->param = HID_PARAM_INPUT;
Offset += sizeof(hid_packet);
GetCursorPos(&point);
ScreenToClient(g_WiimoteInitialize.hWnd, &point);
wm_acknowledge* pData = (wm_acknowledge*)(DataFrame + Offset);
pData->Channel = WM_WRITE_DATA_REPLY;
pData->unk0 = 0;
pData->unk1 = 0;
pData->reportID = _reportID;
pData->errorID = 0;
Offset += sizeof(wm_acknowledge);
RECT Rect;
GetClientRect(g_WiimoteInitialize.hWnd, &Rect);
LOGV(WII_IPC_WIIMOTE, 2, " WMSendAck()");
LOGV(WII_IPC_WIIMOTE, 2, " Report ID: %02x", _reportID);
//std::string Temp = WiiMoteEmu::ArrayToString(DataFrame, Offset, 0);
//LOGV(WII_IPC_WIIMOTE, 2, " Data: %s", Temp.c_str());
int width = Rect.right - Rect.left;
int height = Rect.bottom - Rect.top;
/* Debug. Write the report for extension registry writes.
if((_reportID == 0x16 || _reportID == 0x17) && ((address >> 16) & 0xfe) == 0xa4)
{
wprintf("\nWMSendAck Report ID: %02x Encryption: %02x\n", _reportID, g_RegExt[0xf0]);
wprintf("Data: %s\n", Temp.c_str());
}*/
g_WiimoteInitialize.pWiimoteInput(_channelID, DataFrame, Offset);
x = point.x / (float)width;
y = point.y / (float)height;
#else
// TODO fix on linux
x = 0.5f;
y = 0.5f;
#endif
}
// ===================================================
/* Read data from Wiimote and Extensions registers. */
/* Homebrew encryption for 0x00000000 encryption keys. */
// ----------------
void WmReadData(u16 _channelID, wm_read_data* rd)
void CryptBuffer(u8* _buffer, u8 _size)
{
LOGV(WII_IPC_WIIMOTE, 0, "===========================================================");
u32 address = convert24bit(rd->address);
u16 size = convert16bit(rd->size);
std::string Temp;
LOG(WII_IPC_WIIMOTE, "Read data");
LOG(WII_IPC_WIIMOTE, " Address space: %x", rd->space);
LOG(WII_IPC_WIIMOTE, " Address: 0x%06x", address);
LOG(WII_IPC_WIIMOTE, " Size: 0x%04x", size);
LOG(WII_IPC_WIIMOTE, " Rumble: %x", rd->rumble);
//u32 _address = address;
/* Now we determine what address space we are reading from. Space 0 is Eeprom and
space 1 and 2 is the registers. */
if(rd->space == 0)
for (int i=0; i<_size; i++)
{
if (address + size > WIIMOTE_EEPROM_SIZE)
{
PanicAlert("WmReadData: address + size out of bounds!");
return;
}
SendReadDataReply(_channelID, g_Eeprom+address, address, (u8)size);
}
else if(rd->space == WM_SPACE_REGS1 || rd->space == WM_SPACE_REGS2)
{
u8* block;
u32 blockSize;
switch((address >> 16) & 0xFE)
{
case 0xA2:
block = g_RegSpeaker;
blockSize = WIIMOTE_REG_SPEAKER_SIZE;
LOGV(WII_IPC_WIIMOTE, 0, " Case 0xa2: g_RegSpeaker");
//Temp = WiiMoteEmu::ArrayToString(g_RegSpeaker, size, (address & 0xffff));
//LOGV(WII_IPC_WIIMOTE, 0, " Data: %s", Temp.c_str());
break;
case 0xA4:
block = g_RegExt;
blockSize = WIIMOTE_REG_EXT_SIZE;
LOGV(WII_IPC_WIIMOTE, 0, " Case 0xa4: Read ExtReg ****************************");
//Temp = WiiMoteEmu::ArrayToString(g_RegExt, size, (address & 0xffff));
//LOGV(WII_IPC_WIIMOTE, 0, " Data: %s", Temp.c_str());
break;
case 0xB0:
block = g_RegIr;
blockSize = WIIMOTE_REG_IR_SIZE;
LOGV(WII_IPC_WIIMOTE, 0, " Case: 0xb0 g_RegIr");
//Temp = WiiMoteEmu::ArrayToString(g_RegIr, size, (address & 0xffff));
//LOGV(WII_IPC_WIIMOTE, 0, " Data: %s", Temp.c_str());
break;
default:
PanicAlert("WmWriteData: bad register block!");
return;
}
// -----------------------------------------
// Encrypt data that is read from the Wiimote Extension Register
// -------------
if(((address >> 16) & 0xfe) == 0xa4)
{
wprintf("\n\nWmReadData Address: %08x Offset: %08x Size: %i byte\n",
address, address & 0xffff, (u8)size);
/* Debugging
u32 offset = address & 0xffff;
std::string Temp = WiiMoteEmu::ArrayToString(g_RegExt, size, offset);
wprintf("Unencrypted data:\n%s\n", Temp.c_str());*/
// Check if encrypted reads is on
if(g_RegExt[0xf0] == 0xaa)
{
// Copy g_RegExt to g_RegExtTmp
memcpy(g_RegExtTmp, g_RegExt, sizeof(g_RegExt));
// Copy the registry to a temporary space
memcpy(g_RegExtTmp, g_RegExt, sizeof(g_RegExt));
// Encrypt the read
wiimote_encrypt(&g_ExtKey, &g_RegExtTmp[address & 0xffff], (address & 0xffff), (u8)size);
/* Debugging
wprintf("\nEncrypted data:\n");
for (int i = 0; i < (u8)size; i++)
{
wprintf("%02x ", g_RegExtTmp[i + offset]);
if((i + 1) % 20 == 0) wprintf("\n");
}*/
// Update the block that SendReadDataReply will eventually send to the Wii
block = g_RegExtTmp;
}
}
//---------
address &= 0xFFFF;
if(address + size > blockSize) {
PanicAlert("WmReadData: address + size out of bounds!");
return;
}
// Let this function process the message and send it to the Wii
SendReadDataReply(_channelID, block+address, address, (u8)size);
}
else
{
PanicAlert("WmReadData: unimplemented parameters (size: %i, addr: 0x%x!", size, rd->space);
_buffer[i] = ((_buffer[i] - 0x17) ^ 0x17) & 0xFF;
}
// Acknowledge the 0x17 read, we will do this from InterruptChannel()
//WmSendAck(_channelID, WM_READ_DATA, _address);
LOGV(WII_IPC_WIIMOTE, 0, "===========================================================");
}
// ===================================================
/* Write data to Wiimote and Extensions registers. */
// ----------------
void WmWriteData(u16 _channelID, wm_write_data* wd)
void WriteCrypted16(u8* _baseBlock, u16 _address, u16 _value)
{
LOGV(WII_IPC_WIIMOTE, 0, "========================================================");
u32 address = convert24bit(wd->address);
LOG(WII_IPC_WIIMOTE, "Write data");
LOG(WII_IPC_WIIMOTE, " Address space: %x", wd->space);
LOG(WII_IPC_WIIMOTE, " Address: 0x%06x", address);
LOG(WII_IPC_WIIMOTE, " Size: 0x%02x", wd->size);
LOG(WII_IPC_WIIMOTE, " Rumble: %x", wd->rumble);
//std::string Temp = ArrayToString(wd->data, wd->size);
//LOGV(WII_IPC_WIIMOTE, 0, " Data: %s", Temp.c_str());
u16 cryptedValue = _value;
CryptBuffer((u8*)&cryptedValue, sizeof(u16));
// Write to EEPROM
if(wd->size <= 16 && wd->space == WM_SPACE_EEPROM)
{
if(address + wd->size > WIIMOTE_EEPROM_SIZE) {
PanicAlert("WmWriteData: address + size out of bounds!");
return;
}
memcpy(g_Eeprom + address, wd->data, wd->size);
}
// Write to registers
else if(wd->size <= 16 && (wd->space == WM_SPACE_REGS1 || wd->space == WM_SPACE_REGS2))
{
u8* block;
u32 blockSize;
switch((address >> 16) & 0xFE)
{
case 0xA2:
block = g_RegSpeaker;
blockSize = WIIMOTE_REG_SPEAKER_SIZE;
LOGV(WII_IPC_WIIMOTE, 0, " Case 0xa2: RegSpeaker");
//wprintf("\n\nWrite to RegSpeaker: Size: %i, Address: %08x, Offset: %08x\n",
// wd->size, address, (address & 0xffff));
//wprintf("Data: %s\n", Temp.c_str());
break;
case 0xA4:
block = g_RegExt; // Extension Controller register
blockSize = WIIMOTE_REG_EXT_SIZE;
//LOGV(WII_IPC_WIIMOTE, 0, " *******************************************************");
LOGV(WII_IPC_WIIMOTE, 0, " Case 0xa4: ExtReg");
//LOGV(WII_IPC_WIIMOTE, 0, " *******************************************************");
//wprintf("\n\nWmWriteData Size: %i Address: %08x Offset: %08x \n",
// wd->size, address, (address & 0xffff));
break;
case 0xB0:
block = g_RegIr;
blockSize = WIIMOTE_REG_IR_SIZE;
LOGV(WII_IPC_WIIMOTE, 0, " Case 0xb0: RegIr");
break;
default:
PanicAlert("WmWriteData: bad register block!");
return;
}
// Remove for example 0xa40000 from the address
address &= 0xFFFF;
// Check if the address is within bounds
if(address + wd->size > blockSize) {
PanicAlert("WmWriteData: address + size out of bounds!");
return;
}
// Finally write the registers to the right structure
memcpy(block + address, wd->data, wd->size);
// -----------------------------------------
// Generate key for the Wiimote Extension
// -------------
if(blockSize == WIIMOTE_REG_EXT_SIZE)
{
/* Debugging. Write the data.
wprintf("Data: %s\n", Temp.c_str());
wprintf("Current address: %08x\n", address); */
/* Run the key generation on all writes in the key area, it doesn't matter
that we send it parts of a key, only the last full key will have an
effect */
if(address >= 0x40 && address <= 0x4c)
wiimote_gen_key(&g_ExtKey, &g_RegExt[0x40]);
}
// -------------
} else {
PanicAlert("WmWriteData: unimplemented parameters!");
}
/* Just added for home brew... Isn't it enough that we call this from
InterruptChannel()? Or is there a separate route here that don't pass though
InterruptChannel()? */
//WmSendAck(_channelID, WM_WRITE_DATA, _address);
LOGV(WII_IPC_WIIMOTE, 0, "==========================================================");
}
// ===================================================
/* Here we produce the actual 0x21 Input report that we send to the Wii. The message
is divided into 16 bytes pieces and sent piece by piece. There will be five formatting
bytes at the begging of all reports. A common format is 00 00 f0 00 20, the 00 00
means that no buttons are pressed, the f means 16 bytes in the message, the 0
means no error, the 00 20 means that the message is at the 00 20 offest in the
registry that was read. */
// ----------------
void SendReadDataReply(u16 _channelID, void* _Base, u16 _Address, u8 _Size)
{
LOGV(WII_IPC_WIIMOTE, 0, "=========================================");
int dataOffset = 0;
while (_Size > 0)
{
u8 DataFrame[1024];
u32 Offset = WriteWmReport(DataFrame, WM_READ_DATA_REPLY);
int copySize = _Size;
if (copySize > 16)
{
copySize = 16;
}
wm_read_data_reply* pReply = (wm_read_data_reply*)(DataFrame + Offset);
Offset += sizeof(wm_read_data_reply);
pReply->buttons = 0;
pReply->error = 0;
pReply->size = (copySize - 1) & 0xF;
pReply->address = Common::swap16(_Address + dataOffset);
// Write a pice
memcpy(pReply->data + dataOffset, _Base, copySize);
if(copySize < 16) // check if we have less than 16 bytes left to send
{
memset(pReply->data + copySize, 0, 16 - copySize);
}
dataOffset += copySize;
LOG(WII_IPC_WIIMOTE, " SendReadDataReply()");
LOG(WII_IPC_WIIMOTE, " Buttons: 0x%04x", pReply->buttons);
LOG(WII_IPC_WIIMOTE, " Error: 0x%x", pReply->error);
LOG(WII_IPC_WIIMOTE, " Size: 0x%x", pReply->size);
LOG(WII_IPC_WIIMOTE, " Address: 0x%04x", pReply->address);
// Send a piece
g_WiimoteInitialize.pWiimoteInput(_channelID, DataFrame, Offset);
_Size -= copySize;
}
if (_Size != 0)
{
PanicAlert("WiiMote-Plugin: SendReadDataReply() failed");
}
LOGV(WII_IPC_WIIMOTE, 0, "==========================================");
*(u16*)(_baseBlock + _address) = cryptedValue;
//PanicAlert("Converted %04x to %04x", _value, cryptedValue);
}
// ================
// ===================================================
/* Here we produce a 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. */
/* Write initial values to Eeprom and registers. */
// ----------------
void WmRequestStatus(u16 _channelID, wm_request_status* rs)
void Initialize()
{
//PanicAlert("WmRequestStatus");
LOGV(WII_IPC_WIIMOTE, 0, "================================================");
LOGV(WII_IPC_WIIMOTE, 0, " Request Status");
LOGV(WII_IPC_WIIMOTE, 0, " Rumble: %x", rs->rumble);
LOGV(WII_IPC_WIIMOTE, 0, " Channel: %04x", _channelID);
memset(g_Eeprom, 0, WIIMOTE_EEPROM_SIZE);
memcpy(g_Eeprom, EepromData_0, sizeof(EepromData_0));
memcpy(g_Eeprom + 0x16D0, EepromData_16D0, sizeof(EepromData_16D0));
//SendStatusReport();
u8 DataFrame[1024];
u32 Offset = WriteWmReport(DataFrame, WM_STATUS_REPORT);
g_ReportingMode = 0;
wm_status_report* pStatus = (wm_status_report*)(DataFrame + Offset);
Offset += sizeof(wm_status_report);
memset(pStatus, 0, sizeof(wm_status_report)); // fill the status report with zeroes
// Status values
pStatus->battery_low = 0; // battery is okay
pStatus->leds = g_Leds; // leds are 4 bit
pStatus->ir = g_IR; // 1 bit
pStatus->speaker = g_Speaker; // 1 bit
/* Battery levels in voltage
0x00 - 0x32: level 1
0x33 - 0x43: level 2
0x33 - 0x54: level 3
0x55 - 0xff: level 4 */
pStatus->battery = 0x5f; // fully charged
/* Extension data for homebrew applications that use the 0x00000000 key. This
writes 0x0000 in encrypted form (0xfefe) to 0xfe in the extension register. */
//WriteCrypted16(g_RegExt, 0xfe, 0x0000); // Fully inserted Nunchuk
// Read config value for this one
if(g_Config.bNunchuckConnected || g_Config.bClassicControllerConnected)
pStatus->extension = 1;
else
pStatus->extension = 0;
LOGV(WII_IPC_WIIMOTE, 0, " Extension: %x", pStatus->extension);
LOGV(WII_IPC_WIIMOTE, 0, " SendStatusReport()");
LOGV(WII_IPC_WIIMOTE, 0, " Flags: 0x%02x", pStatus->padding1[2]);
LOGV(WII_IPC_WIIMOTE, 0, " Battery: %d", pStatus->battery);
// Copy extension id and calibration to its register
if(g_Config.bNunchuckConnected)
{
memcpy(g_RegExt + 0x20, nunchuck_calibration, sizeof(nunchuck_calibration));
memcpy(g_RegExt + 0xfa, nunchuck_id, sizeof(nunchuck_id));
}
else if(g_Config.bClassicControllerConnected)
{
memcpy(g_RegExt + 0x20, classic_calibration, sizeof(classic_calibration));
memcpy(g_RegExt + 0xfa, classic_id, sizeof(classic_id));
}
g_WiimoteInitialize.pWiimoteInput(_channelID, DataFrame, Offset);
LOGV(WII_IPC_WIIMOTE, 0, "=================================================");
// g_RegExt[0xfd] = 0x1e;
// g_RegExt[0xfc] = 0x9a;
}
// ================
void DoState(void* ptr, int mode)
{
//TODO: implement
}
/* We don't need to do anything here. All values will be reset as FreeLibrary() is called
when we stop a game */
void Shutdown(void)
{
}
// ===================================================
/* An ack delay of 1 was not small enough, but 2 seemed to work, that was about between 20 ms and
100 ms in my case. I'm not sure what it means in frame delays. */
// ----------------
void CreateAckDelay(u8 _ChannelID, u16 _ReportID)
{
// Settings
int GlobalDelay = 2;
// Queue an acknowledgment
wm_ackdelay Tmp;
Tmp.Delay = GlobalDelay;
Tmp.ChannelID = _ChannelID;
Tmp.ReportID = _ReportID;
AckDelay.push_back(Tmp);
}
void CheckAckDelay()
{
for (int i = 0; i < AckDelay.size(); i++)
{
// See if there are any acks to send
if (AckDelay.at(i).Delay >= 0)
{
if(AckDelay.at(i).Delay == 0)
{
WmSendAck(AckDelay.at(i).ChannelID, AckDelay.at(i).ReportID, 0);
AckDelay.erase(AckDelay.begin() + i);
continue;
}
AckDelay.at(i).Delay--;
//wprintf("%i 0x%04x 0x%02x", i, AckDelay.at(i).ChannelID, AckDelay.at(i).ReportID);
}
}
}
// ================
// ===================================================
/* This function produce Wiimote Input, i.e. reports from the Wiimote in response
to Output from the Wii. */
// ----------------
void InterruptChannel(u16 _channelID, const void* _pData, u32 _Size)
{
LOGV(WII_IPC_WIIMOTE, 3, "=============================================================");
LOGV(WII_IPC_WIIMOTE, 3, "Wiimote_Input");
const u8* data = (const u8*)_pData;
// -----------------------------------------------------
/* Debugging. We have not yet decided how much of 'data' we will use, it's not determined
by sizeof(data). We have to determine it by looking at the data cases. */
// -----------------
/*int size;
switch(data[1])
{
case 0x10:
size = 4; // I don't know the size
break;
case WM_LEDS: // 0x11
size = sizeof(wm_leds);
break;
case WM_DATA_REPORTING: // 0x12
size = sizeof(wm_data_reporting);
break;
case WM_REQUEST_STATUS: // 0x15
size = sizeof(wm_request_status);
break;
case WM_WRITE_DATA: // 0x16
size = sizeof(wm_write_data);
break;
case WM_READ_DATA: // 0x17
size = sizeof(wm_read_data);
break;
case WM_IR_PIXEL_CLOCK: // 0x13
case WM_IR_LOGIC: // 0x1a
case WM_SPEAKER_ENABLE: // 0x14
case WM_SPEAKER_MUTE:
size = 1;
break;
default:
PanicAlert("HidOutputReport: Unknown channel 0x%02x", data[1]);
return;
}
std::string Temp = ArrayToString(data, size + 2, 0, 30);
//LOGV(WII_IPC_WIIMOTE, 3, " Data: %s", Temp.c_str());
wprintf("\n%s: InterruptChannel: %s\n", Tm(true).c_str(), Temp.c_str());*/
// -----------------------------------
hid_packet* hidp = (hid_packet*) data;
switch(hidp->type)
{
case HID_TYPE_DATA:
{
switch(hidp->param)
{
case HID_PARAM_OUTPUT:
{
wm_report* sr = (wm_report*)hidp->data;
HidOutputReport(_channelID, sr);
/* This is the 0x22 answer to all Inputs. In most games it didn't matter
if it was written before or after HidOutputReport(), but Wii Sports
and Mario Galaxy would stop working if it was placed before
HidOutputReport(). Zelda - TP is even more sensitive and require
a delay after the Input for the Nunchuck to work. It seemed to be
enough to delay only the Nunchuck registry reads and writes but
for now I'm delaying all inputs. Both for status changes and Eeprom
and registry reads and writes. */
// Limit the delay to certain registry reads and writes
//if((data[1] == WM_WRITE_DATA || data[1] == WM_READ_DATA)
// && data[3] == 0xa4)
//{
CreateAckDelay(_channelID, sr->channel);
//}
//else
//{
//wm_write_data *wd = (wm_write_data*)sr->data;
//u32 address = convert24bit(wd->address);
//WmSendAck(_channelID, sr->channel, address);
//}
}
break;
default:
PanicAlert("HidInput: HID_TYPE_DATA - param 0x%02x", hidp->type, hidp->param);
break;
}
}
break;
default:
PanicAlert("HidInput: Unknown type 0x%02x and param 0x%02x", hidp->type, hidp->param);
break;
}
LOGV(WII_IPC_WIIMOTE, 3, "=============================================================");
}
void ControlChannel(u16 _channelID, const void* _pData, u32 _Size)
{
const u8* data = (const u8*)_pData;
// dump raw data
{
LOG(WII_IPC_WIIMOTE, "Wiimote_ControlChannel");
std::string Temp = ArrayToString(data, 0, _Size);
wprintf("\n%s: ControlChannel: %s\n", Tm().c_str(), Temp.c_str());
LOG(WII_IPC_WIIMOTE, " Data: %s", Temp.c_str());
}
hid_packet* hidp = (hid_packet*) data;
switch(hidp->type)
{
case HID_TYPE_HANDSHAKE:
if (hidp->param == HID_PARAM_INPUT)
{
PanicAlert("HID_TYPE_HANDSHAKE - HID_PARAM_INPUT");
}
else
{
PanicAlert("HID_TYPE_HANDSHAKE - HID_PARAM_OUTPUT");
}
break;
case HID_TYPE_SET_REPORT:
if (hidp->param == HID_PARAM_INPUT)
{
PanicAlert("HID_TYPE_SET_REPORT input");
}
else
{
HidOutputReport(_channelID, (wm_report*)hidp->data);
//return handshake
u8 handshake = 0;
g_WiimoteInitialize.pWiimoteInput(_channelID, &handshake, 1);
}
break;
case HID_TYPE_DATA:
PanicAlert("HID_TYPE_DATA %s", hidp->type, hidp->param == HID_PARAM_INPUT ? "input" : "output");
break;
default:
PanicAlert("HidControlChanel: Unknown type %x and param %x", hidp->type, hidp->param);
break;
}
}
// ===================================================
/* This is called from Wiimote_Update(). See SystemTimers.cpp for a documentation. I'm
not sure exactly how often this function is called but I think it's tied to the frame
rate of the game rather than a certain amount of times per second. */
// ----------------
void Update()
{
//LOG(WII_IPC_WIIMOTE, "Wiimote_Update");
switch(g_ReportingMode)
{
case 0:
break;
case WM_REPORT_CORE: SendReportCore(g_ReportingChannel); break;
case WM_REPORT_CORE_ACCEL: SendReportCoreAccel(g_ReportingChannel); break;
case WM_REPORT_CORE_ACCEL_IR12: SendReportCoreAccelIr12(g_ReportingChannel);break;
case WM_REPORT_CORE_ACCEL_EXT16: SendReportCoreAccelExt16(g_ReportingChannel);break;
case WM_REPORT_CORE_ACCEL_IR10_EXT6: SendReportCoreAccelIr10Ext(g_ReportingChannel);break;
}
// Potentially send a delayed acknowledgement to an InterruptChannel() Output
CheckAckDelay();
}
} // end of namespace

View File

@ -24,6 +24,10 @@
namespace WiiMoteEmu
{
u32 convert24bit(const u8* src);
u16 convert16bit(const u8* src);
void GetMousePos(float& x, float& y);
void Initialize();
void DoState(void* ptr, int mode);
void Shutdown(void);

View File

@ -36,7 +36,9 @@
// ================
//////////////////////////////////////////////////////////////////////////////////////////
// Includes
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
#include "pluginspecs_wiimote.h"
#include <vector>
@ -51,243 +53,504 @@
#include "EmuDefinitions.h"
#include "Console.h" // for startConsoleWin, wprintf, GetConsoleHwnd
#include "Config.h" // for g_Config
/////////////////////////////////
extern SWiimoteInitialize g_WiimoteInitialize;
namespace WiiMoteEmu
{
//******************************************************************************
// Subroutine declarations
// Subroutines
//******************************************************************************
u32 convert24bit(const u8* src) {
return (src[0] << 16) | (src[1] << 8) | src[2];
}
u16 convert16bit(const u8* src) {
return (src[0] << 8) | src[1];
}
// ===================================================
/* Calibrate the mouse position to the emulation window. */
/* Here we process the Output Reports that the Wii sends. Our response will be an Input Report
back to the Wii. Input and Output is from the Wii's perspective, Output means data to
the Wiimote (from the Wii), Input means data from the Wiimote.
The call browser:
1. Wiimote_InterruptChannel > InterruptChannel > HidOutputReport
2. Wiimote_ControlChannel > ControlChannel > HidOutputReport
The IR lights and speaker enable/disable and mute/unmute values are
0x2 = Disable
0x6 = Enable */
// ----------------
void GetMousePos(float& x, float& y)
{
#ifdef _WIN32
POINT point;
void HidOutputReport(u16 _channelID, wm_report* sr) {
LOGV(WII_IPC_WIIMOTE, 0, "===========================================================");
LOGV(WII_IPC_WIIMOTE, 0, "HidOutputReport (0x%02x)", sr->channel);
std::string Temp;
GetCursorPos(&point);
ScreenToClient(g_WiimoteInitialize.hWnd, &point);
RECT Rect;
GetClientRect(g_WiimoteInitialize.hWnd, &Rect);
int width = Rect.right - Rect.left;
int height = Rect.bottom - Rect.top;
x = point.x / (float)width;
y = point.y / (float)height;
#else
// TODO fix on linux
x = 0.5f;
y = 0.5f;
#endif
}
// ===================================================
/* Homebrew encryption for 0x00000000 encryption keys. */
// ----------------
void CryptBuffer(u8* _buffer, u8 _size)
{
for (int i=0; i<_size; i++)
switch(sr->channel)
{
_buffer[i] = ((_buffer[i] - 0x17) ^ 0x17) & 0xFF;
case 0x10:
LOGV(WII_IPC_WIIMOTE, 0, "HidOutputReport: unknown sr->channel 0x10");
break;
case WM_LEDS: // 0x11
WmLeds(_channelID, (wm_leds*)sr->data);
break;
case WM_DATA_REPORTING: // 0x12
WmDataReporting(_channelID, (wm_data_reporting*)sr->data);
break;
case WM_REQUEST_STATUS: // 0x15
WmRequestStatus(_channelID, (wm_request_status*)sr->data);
//Temp = ArrayToString(sr->data, sizeof(wm_request_status), 0);
//wprintf("\n%s: InterruptChannel: %s\n", Tm().c_str(), Temp.c_str());
break;
case WM_READ_DATA: // 0x17
WmReadData(_channelID, (wm_read_data*)sr->data);
break;
/* This enables or disables the IR lights, we update the global variable g_IR
so that WmRequestStatus() knows about it */
case WM_IR_PIXEL_CLOCK: // 0x13
case WM_IR_LOGIC: // 0x1a
LOGV(WII_IPC_WIIMOTE, 0, " IR Enable 0x%02x: 0x%02x", sr->channel, sr->data[0]);
wprintf("IR Enable/Disable 0x%02x: 0x%02x\n", sr->channel, sr->data[0]);
if(sr->data[0] == 0x02) g_IR = 0;
else if(sr->data[0] == 0x06) g_IR = 1;
break;
case WM_WRITE_DATA: // 0x16
WmWriteData(_channelID, (wm_write_data*)sr->data);
break;
case WM_SPEAKER_ENABLE: // 0x14
LOGV(WII_IPC_WIIMOTE, 1, " WM Speaker Enable 0x%02x: 0x%02x", sr->channel, sr->data[0]);
wprintf("Speaker Enable/Disable 0x%02x: 0x%02x\n", sr->channel, sr->data[0]);
if(sr->data[0] == 0x02) g_Speaker = 0;
else if(sr->data[0] == 0x06) g_Speaker = 1;
break;
case WM_SPEAKER_MUTE:
LOGV(WII_IPC_WIIMOTE, 1, " WM Mute Enable 0x%02x: 0x%02x", sr->channel, sr->data[0]);
wprintf("Speaker Mute/Unmute 0x%02x: 0x%02x\n", sr->channel, sr->data[0]);
if(sr->data[0] == 0x02) g_SpeakerVoice = 0; // g_SpeakerVoice
else if(sr->data[0] == 0x06) g_SpeakerVoice = 1;
break;
default:
PanicAlert("HidOutputReport: Unknown channel 0x%02x", sr->channel);
return;
}
}
void WriteCrypted16(u8* _baseBlock, u16 _address, u16 _value)
{
u16 cryptedValue = _value;
CryptBuffer((u8*)&cryptedValue, sizeof(u16));
*(u16*)(_baseBlock + _address) = cryptedValue;
//PanicAlert("Converted %04x to %04x", _value, cryptedValue);
}
// ================
// ===================================================
/* Write initial values to Eeprom and registers. */
// ----------------
void Initialize()
{
memset(g_Eeprom, 0, WIIMOTE_EEPROM_SIZE);
memcpy(g_Eeprom, EepromData_0, sizeof(EepromData_0));
memcpy(g_Eeprom + 0x16D0, EepromData_16D0, sizeof(EepromData_16D0));
g_ReportingMode = 0;
/* Extension data for homebrew applications that use the 0x00000000 key. This
writes 0x0000 in encrypted form (0xfefe) to 0xfe in the extension register. */
//WriteCrypted16(g_RegExt, 0xfe, 0x0000); // Fully inserted Nunchuk
// Copy extension id and calibration to its register
if(g_Config.bNunchuckConnected)
{
memcpy(g_RegExt + 0x20, nunchuck_calibration, sizeof(nunchuck_calibration));
memcpy(g_RegExt + 0xfa, nunchuck_id, sizeof(nunchuck_id));
}
else if(g_Config.bClassicControllerConnected)
{
memcpy(g_RegExt + 0x20, classic_calibration, sizeof(classic_calibration));
memcpy(g_RegExt + 0xfa, classic_id, sizeof(classic_id));
}
// g_RegExt[0xfd] = 0x1e;
// g_RegExt[0xfc] = 0x9a;
}
// ================
void DoState(void* ptr, int mode)
{
//TODO: implement
}
void Shutdown(void)
{
LOGV(WII_IPC_WIIMOTE, 0, "===========================================================");
}
// ===================================================
/* This function produce Wiimote Input, i.e. reports from the Wiimote in response
to Output from the Wii. */
/* Generate the right address for wm reports. */
// ----------------
void InterruptChannel(u16 _channelID, const void* _pData, u32 _Size)
int WriteWmReport(u8* dst, u8 channel) {
u32 Offset = 0;
hid_packet* pHidHeader = (hid_packet*)(dst + Offset);
Offset += sizeof(hid_packet);
pHidHeader->type = HID_TYPE_DATA;
pHidHeader->param = HID_PARAM_INPUT;
wm_report* pReport = (wm_report*)(dst + Offset);
Offset += sizeof(wm_report);
pReport->channel = channel;
return Offset;
}
// ===================================================
/* LED (blue lights) report. */
// ----------------
void WmLeds(u16 _channelID, wm_leds* leds) {
LOGV(WII_IPC_WIIMOTE, 0, "===========================================================");
LOG(WII_IPC_WIIMOTE, " Set LEDs");
LOG(WII_IPC_WIIMOTE, " Leds: %x", leds->leds);
LOG(WII_IPC_WIIMOTE, " Rumble: %x", leds->rumble);
g_Leds = leds->leds;
LOGV(WII_IPC_WIIMOTE, 0, "===========================================================");
}
// ===================================================
/* This will generate the 0x22 acknowledgment after all Input reports. It will
have the form a1 22 00 00 _reportID 00. The first two bytes are the core buttons data,
they are 00 00 when nothing is pressed. The last byte is the success code 00. */
// ----------------
void WmSendAck(u16 _channelID, u8 _reportID, u32 address)
{
LOGV(WII_IPC_WIIMOTE, 3, "=============================================================");
const u8* data = (const u8*)_pData;
u8 DataFrame[1024];
u32 Offset = 0;
// Debugging. Dump raw data.
LOGV(WII_IPC_WIIMOTE, 3, "Wiimote_Input");
//std::string Temp = ArrayToString(data, sizeof(data), 0, 30);
//LOGV(WII_IPC_WIIMOTE, 3, " Data: %s", Temp.c_str());
// Header
hid_packet* pHidHeader = (hid_packet*)(DataFrame + Offset);
pHidHeader->type = HID_TYPE_DATA;
pHidHeader->param = HID_PARAM_INPUT;
Offset += sizeof(hid_packet);
hid_packet* hidp = (hid_packet*) data;
wm_acknowledge* pData = (wm_acknowledge*)(DataFrame + Offset);
pData->Channel = WM_WRITE_DATA_REPLY;
pData->unk0 = 0;
pData->unk1 = 0;
pData->reportID = _reportID;
pData->errorID = 0;
Offset += sizeof(wm_acknowledge);
switch(hidp->type)
LOGV(WII_IPC_WIIMOTE, 2, " WMSendAck()");
LOGV(WII_IPC_WIIMOTE, 2, " Report ID: %02x", _reportID);
//std::string Temp = ArrayToString(DataFrame, Offset, 0);
//LOGV(WII_IPC_WIIMOTE, 2, " Data: %s", Temp.c_str());
//wprintf("%s: WMSendAck: %s\n", Tm(true).c_str(), Temp.c_str());
/* Debug. Write the report for extension registry writes.
if((_reportID == 0x16 || _reportID == 0x17) && ((address >> 16) & 0xfe) == 0xa4)
{
case HID_TYPE_DATA:
wprintf("\nWMSendAck Report ID: %02x Encryption: %02x\n", _reportID, g_RegExt[0xf0]);
wprintf("Data: %s\n", Temp.c_str());
}*/
g_WiimoteInitialize.pWiimoteInput(_channelID, DataFrame, Offset);
}
// ===================================================
/* Read data from Wiimote and Extensions registers. */
// ----------------
void WmReadData(u16 _channelID, wm_read_data* rd)
{
LOGV(WII_IPC_WIIMOTE, 0, "===========================================================");
u32 address = convert24bit(rd->address);
u16 size = convert16bit(rd->size);
std::string Temp;
LOG(WII_IPC_WIIMOTE, "Read data");
LOG(WII_IPC_WIIMOTE, " Address space: %x", rd->space);
LOG(WII_IPC_WIIMOTE, " Address: 0x%06x", address);
LOG(WII_IPC_WIIMOTE, " Size: 0x%04x", size);
LOG(WII_IPC_WIIMOTE, " Rumble: %x", rd->rumble);
//u32 _address = address;
std::string Tmp; // Debugging
/* Now we determine what address space we are reading from. Space 0 is Eeprom and
space 1 and 2 is the registers. */
if(rd->space == 0)
{
if (address + size > WIIMOTE_EEPROM_SIZE)
{
switch(hidp->param)
PanicAlert("WmReadData: address + size out of bounds!");
return;
}
SendReadDataReply(_channelID, g_Eeprom+address, address, (u8)size);
}
else if(rd->space == WM_SPACE_REGS1 || rd->space == WM_SPACE_REGS2)
{
u8* block;
u32 blockSize;
switch((address >> 16) & 0xFE)
{
case 0xA2:
block = g_RegSpeaker;
blockSize = WIIMOTE_REG_SPEAKER_SIZE;
LOGV(WII_IPC_WIIMOTE, 0, " Case 0xa2: g_RegSpeaker");
//Tmp = ArrayToString(g_RegSpeaker, size, (address & 0xffff));
//LOGV(WII_IPC_WIIMOTE, 0, " Data: %s", Temp.c_str());
//wprintf("Read RegSpkr: Size %i Address %08x Offset %08x\nData %s\n",
// size, address, (address & 0xffff), Tmp.c_str());
break;
case 0xA4:
block = g_RegExt;
blockSize = WIIMOTE_REG_EXT_SIZE;
LOGV(WII_IPC_WIIMOTE, 0, " Case 0xa4: Read ExtReg ****************************");
//Tmp = ArrayToString(g_RegExt, size, (address & 0xffff));
//LOGV(WII_IPC_WIIMOTE, 0, " Data: %s", Temp.c_str());
//wprintf("Read RegExt: Size %i Address %08x Offset %08x\nData %s\n",
// size, address, (address & 0xffff), Tmp.c_str());
break;
case 0xB0:
block = g_RegIr;
blockSize = WIIMOTE_REG_IR_SIZE;
LOGV(WII_IPC_WIIMOTE, 0, " Case: 0xb0 g_RegIr");
//Tmp = ArrayToString(g_RegIr, size, (address & 0xffff));
//LOGV(WII_IPC_WIIMOTE, 0, " Data: %s", Temp.c_str());
//wprintf("Read RegIR: Size %i Address %08x Offset %08x\nData %s\n",
// size, address, (address & 0xffff), Tmp.c_str());
break;
default:
PanicAlert("WmWriteData: bad register block!");
return;
}
// -----------------------------------------
// Encrypt data that is read from the Wiimote Extension Register
// -------------
if(((address >> 16) & 0xfe) == 0xa4)
{
/* Debugging
wprintf("\n\nWmReadData Address: %08x Offset: %08x Size: %i byte\n",
address, address & 0xffff, (u8)size);
// Debugging
u32 offset = address & 0xffff;
std::string Temp = ArrayToString(g_RegExt, size, offset);
wprintf("Unencrypted data:\n%s\n", Temp.c_str());*/
// Check if encrypted reads is on
if(g_RegExt[0xf0] == 0xaa)
{
case HID_PARAM_OUTPUT:
{
wm_report* sr = (wm_report*)hidp->data;
HidOutputReport(_channelID, sr);
/* Copy the registry to a temporary space. We don't want to change the unencrypted
data in the registry */
memcpy(g_RegExtTmp, g_RegExt, sizeof(g_RegExt));
/* This is the 0x22 answer to all Inputs. In most games it didn't matter
if it was written before or after HidOutputReport(), but Wii Sports
and Mario Galaxy would stop working if it was placed before
HidOutputReport(). */
wm_write_data *wd = (wm_write_data*)sr->data;
u32 address = convert24bit(wd->address);
WmSendAck(_channelID, sr->channel, address);
}
break;
// Encrypt g_RegExtTmp at that location
wiimote_encrypt(&g_ExtKey, &g_RegExtTmp[address & 0xffff], (address & 0xffff), (u8)size);
default:
PanicAlert("HidInput: HID_TYPE_DATA - param 0x%02x", hidp->type, hidp->param);
break;
/* Debugging: Show the encrypted data
std::string Temp = ArrayToString(g_RegExtTmp, size, offset);
wprintf("Encrypted data:\n%s\n", Temp.c_str());*/
// Update the block that SendReadDataReply will eventually send to the Wii
block = g_RegExtTmp;
}
}
break;
default:
PanicAlert("HidInput: Unknown type 0x%02x and param 0x%02x", hidp->type, hidp->param);
break;
}
LOGV(WII_IPC_WIIMOTE, 3, "=============================================================");
}
//---------
void ControlChannel(u16 _channelID, const void* _pData, u32 _Size)
{
const u8* data = (const u8*)_pData;
// dump raw data
address &= 0xFFFF;
if(address + size > blockSize) {
PanicAlert("WmReadData: address + size out of bounds!");
return;
}
// Let this function process the message and send it to the Wii
SendReadDataReply(_channelID, block+address, address, (u8)size);
}
else
{
LOG(WII_IPC_WIIMOTE, "Wiimote_ControlChannel");
std::string Temp;
for (u32 j=0; j<_Size; j++)
{
char Buffer[128];
sprintf(Buffer, "%02x ", data[j]);
Temp.append(Buffer);
}
LOG(WII_IPC_WIIMOTE, " Data: %s", Temp.c_str());
PanicAlert("WmReadData: unimplemented parameters (size: %i, addr: 0x%x!", size, rd->space);
}
hid_packet* hidp = (hid_packet*) data;
switch(hidp->type)
{
case HID_TYPE_HANDSHAKE:
if (hidp->param == HID_PARAM_INPUT)
{
PanicAlert("HID_TYPE_HANDSHAKE - HID_PARAM_INPUT");
}
else
{
PanicAlert("HID_TYPE_HANDSHAKE - HID_PARAM_OUTPUT");
}
break;
case HID_TYPE_SET_REPORT:
if (hidp->param == HID_PARAM_INPUT)
{
PanicAlert("HID_TYPE_SET_REPORT input");
}
else
{
HidOutputReport(_channelID, (wm_report*)hidp->data);
//return handshake
u8 handshake = 0;
g_WiimoteInitialize.pWiimoteInput(_channelID, &handshake, 1);
}
break;
case HID_TYPE_DATA:
PanicAlert("HID_TYPE_DATA %s", hidp->type, hidp->param == HID_PARAM_INPUT ? "input" : "output");
break;
default:
PanicAlert("HidControlChanel: Unknown type %x and param %x", hidp->type, hidp->param);
break;
}
// Acknowledge the 0x17 read, we will do this from InterruptChannel()
//WmSendAck(_channelID, WM_READ_DATA, _address);
LOGV(WII_IPC_WIIMOTE, 0, "===========================================================");
}
void Update()
// ===================================================
/* Write data to Wiimote and Extensions registers. */
// ----------------
void WmWriteData(u16 _channelID, wm_write_data* wd)
{
//LOG(WII_IPC_WIIMOTE, "Wiimote_Update");
LOGV(WII_IPC_WIIMOTE, 0, "========================================================");
u32 address = convert24bit(wd->address);
LOG(WII_IPC_WIIMOTE, "Write data");
LOG(WII_IPC_WIIMOTE, " Address space: %x", wd->space);
LOG(WII_IPC_WIIMOTE, " Address: 0x%06x", address);
LOG(WII_IPC_WIIMOTE, " Size: 0x%02x", wd->size);
LOG(WII_IPC_WIIMOTE, " Rumble: %x", wd->rumble);
//std::string Temp = ArrayToString(wd->data, wd->size);
//LOGV(WII_IPC_WIIMOTE, 0, " Data: %s", Temp.c_str());
switch(g_ReportingMode) {
case 0:
break;
case WM_REPORT_CORE: SendReportCore(g_ReportingChannel); break;
case WM_REPORT_CORE_ACCEL: SendReportCoreAccel(g_ReportingChannel); break;
case WM_REPORT_CORE_ACCEL_IR12: SendReportCoreAccelIr12(g_ReportingChannel);break;
case WM_REPORT_CORE_ACCEL_EXT16: SendReportCoreAccelExt16(g_ReportingChannel);break;
case WM_REPORT_CORE_ACCEL_IR10_EXT6: SendReportCoreAccelIr10Ext(g_ReportingChannel);break;
// Write to EEPROM
if(wd->size <= 16 && wd->space == WM_SPACE_EEPROM)
{
if(address + wd->size > WIIMOTE_EEPROM_SIZE) {
PanicAlert("WmWriteData: address + size out of bounds!");
return;
}
memcpy(g_Eeprom + address, wd->data, wd->size);
}
// g_ReportingMode = 0;
// Write to registers
else if(wd->size <= 16 && (wd->space == WM_SPACE_REGS1 || wd->space == WM_SPACE_REGS2))
{
u8* block;
u32 blockSize;
switch((address >> 16) & 0xFE)
{
case 0xA2:
block = g_RegSpeaker;
blockSize = WIIMOTE_REG_SPEAKER_SIZE;
LOGV(WII_IPC_WIIMOTE, 0, " Case 0xa2: RegSpeaker");
//wprintf("Write RegSpeaker: Size: %i, Address: %08x, Offset: %08x\n",
// wd->size, address, (address & 0xffff));
//wprintf("Data: %s\n", Temp.c_str());
break;
case 0xA4:
block = g_RegExt; // Extension Controller register
blockSize = WIIMOTE_REG_EXT_SIZE;
//LOGV(WII_IPC_WIIMOTE, 0, " *******************************************************");
LOGV(WII_IPC_WIIMOTE, 0, " Case 0xa4: ExtReg");
//LOGV(WII_IPC_WIIMOTE, 0, " *******************************************************");
/*wprintf("Write RegExt Size: %i Address: %08x Offset: %08x \n",
wd->size, address, (address & 0xffff));
wprintf("Data: %s\n", Temp.c_str());*/
break;
case 0xB0:
block = g_RegIr;
blockSize = WIIMOTE_REG_IR_SIZE;
LOGV(WII_IPC_WIIMOTE, 0, " Case 0xb0: RegIr");
/*wprintf("Write RegIR Size: %i Address: %08x Offset: %08x \n",
wd->size, address, (address & 0xffff));
wprintf("Data: %s\n", Temp.c_str());*/
break;
default:
PanicAlert("WmWriteData: bad register block!");
return;
}
// Remove for example 0xa40000 from the address
address &= 0xFFFF;
// Check if the address is within bounds
if(address + wd->size > blockSize) {
PanicAlert("WmWriteData: address + size out of bounds!");
return;
}
// Finally write the registers to the right structure
memcpy(block + address, wd->data, wd->size);
// -----------------------------------------
// Generate key for the Wiimote Extension
// -------------
if(blockSize == WIIMOTE_REG_EXT_SIZE)
{
/* Debugging. Write the data.
wprintf("Data: %s\n", Temp.c_str());
wprintf("Current address: %08x\n", address); */
/* Run the key generation on all writes in the key area, it doesn't matter
that we send it parts of a key, only the last full key will have an
effect */
if(address >= 0x40 && address <= 0x4c)
wiimote_gen_key(&g_ExtKey, &g_RegExt[0x40]);
}
// -------------
} else {
PanicAlert("WmWriteData: unimplemented parameters!");
}
/* Just added for home brew... Isn't it enough that we call this from
InterruptChannel()? Or is there a separate route here that don't pass though
InterruptChannel()? */
//WmSendAck(_channelID, WM_WRITE_DATA, _address);
LOGV(WII_IPC_WIIMOTE, 0, "==========================================================");
}
// ===================================================
/* Here we produce the actual 0x21 Input report that we send to the Wii. The message
is divided into 16 bytes pieces and sent piece by piece. There will be five formatting
bytes at the begging of all reports. A common format is 00 00 f0 00 20, the 00 00
means that no buttons are pressed, the f means 16 bytes in the message, the 0
means no error, the 00 20 means that the message is at the 00 20 offest in the
registry that was read. */
// ----------------
void SendReadDataReply(u16 _channelID, void* _Base, u16 _Address, u8 _Size)
{
LOGV(WII_IPC_WIIMOTE, 0, "=========================================");
int dataOffset = 0;
while (_Size > 0)
{
u8 DataFrame[1024];
u32 Offset = WriteWmReport(DataFrame, WM_READ_DATA_REPLY);
int copySize = _Size;
if (copySize > 16)
{
copySize = 16;
}
wm_read_data_reply* pReply = (wm_read_data_reply*)(DataFrame + Offset);
Offset += sizeof(wm_read_data_reply);
pReply->buttons = 0;
pReply->error = 0;
pReply->size = (copySize - 1) & 0xF;
pReply->address = Common::swap16(_Address + dataOffset);
// Write a pice
memcpy(pReply->data + dataOffset, _Base, copySize);
if(copySize < 16) // check if we have less than 16 bytes left to send
{
memset(pReply->data + copySize, 0, 16 - copySize);
}
dataOffset += copySize;
LOG(WII_IPC_WIIMOTE, " SendReadDataReply()");
LOG(WII_IPC_WIIMOTE, " Buttons: 0x%04x", pReply->buttons);
LOG(WII_IPC_WIIMOTE, " Error: 0x%x", pReply->error);
LOG(WII_IPC_WIIMOTE, " Size: 0x%x", pReply->size);
LOG(WII_IPC_WIIMOTE, " Address: 0x%04x", pReply->address);
// Send a piece
g_WiimoteInitialize.pWiimoteInput(_channelID, DataFrame, Offset);
_Size -= copySize;
}
if (_Size != 0)
{
PanicAlert("WiiMote-Plugin: SendReadDataReply() failed");
}
LOGV(WII_IPC_WIIMOTE, 0, "==========================================");
}
// ================
// ===================================================
/* Here we produce a 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 WmRequestStatus(u16 _channelID, wm_request_status* rs)
{
//PanicAlert("WmRequestStatus");
LOGV(WII_IPC_WIIMOTE, 0, "================================================");
LOGV(WII_IPC_WIIMOTE, 0, " Request Status");
LOGV(WII_IPC_WIIMOTE, 0, " Rumble: %x", rs->rumble);
LOGV(WII_IPC_WIIMOTE, 0, " Channel: %04x", _channelID);
//SendStatusReport();
u8 DataFrame[1024];
u32 Offset = WriteWmReport(DataFrame, WM_STATUS_REPORT);
wm_status_report* pStatus = (wm_status_report*)(DataFrame + Offset);
Offset += sizeof(wm_status_report);
memset(pStatus, 0, sizeof(wm_status_report)); // fill the status report with zeroes
// Status values
pStatus->battery_low = 0; // battery is okay
pStatus->leds = g_Leds; // leds are 4 bit
pStatus->ir = g_IR; // 1 bit
pStatus->speaker = g_Speaker; // 1 bit
/* Battery levels in voltage
0x00 - 0x32: level 1
0x33 - 0x43: level 2
0x33 - 0x54: level 3
0x55 - 0xff: level 4 */
pStatus->battery = 0x5f; // fully charged
// Read config value for this one
if(g_Config.bNunchuckConnected || g_Config.bClassicControllerConnected)
pStatus->extension = 1;
else
pStatus->extension = 0;
LOGV(WII_IPC_WIIMOTE, 0, " Extension: %x", pStatus->extension);
LOGV(WII_IPC_WIIMOTE, 0, " SendStatusReport()");
LOGV(WII_IPC_WIIMOTE, 0, " Flags: 0x%02x", pStatus->padding1[2]);
LOGV(WII_IPC_WIIMOTE, 0, " Battery: %d", pStatus->battery);
g_WiimoteInitialize.pWiimoteInput(_channelID, DataFrame, Offset);
LOGV(WII_IPC_WIIMOTE, 0, "=================================================");
}
} // WiiMoteEmu

View File

@ -15,115 +15,38 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _EMU_DECLARATIONS_
#define _EMU_DECLARATIONS_
//////////////////////////////////////////////////////////////////////////////////////////
// Include
// ¯¯¯¯¯¯¯¯¯
#ifndef _EMU_SUBFUNCTIONS_
#define _EMU_SUBFUNCTIONS_
#include "pluginspecs_wiimote.h"
#include <vector>
#include <string>
#include "Common.h"
#include "wiimote_hid.h"
#include "Common.h" // Common
#include "wiimote_hid.h" // Local
#include "EmuDefinitions.h"
#include "Encryption.h"
#include "Console.h" // for startConsoleWin, wprintf, GetConsoleHwnd
////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Declarations and definitions
// ¯¯¯¯¯¯¯¯¯
extern SWiimoteInitialize g_WiimoteInitialize;
//extern void __Log(int log, const char *format, ...);
//extern void __Log(int log, int v, const char *format, ...);
///////////////////////////////
namespace WiiMoteEmu
{
//******************************************************************************
// Definitions and variable declarations
//******************************************************************************
extern u8 g_Leds;
extern u8 g_Speaker;
extern u8 g_SpeakerVoice;
extern u8 g_IR;
extern u8 g_Eeprom[WIIMOTE_EEPROM_SIZE];
extern u8 g_RegSpeaker[WIIMOTE_REG_SPEAKER_SIZE];
extern u8 g_RegExt[WIIMOTE_REG_EXT_SIZE];
extern u8 g_RegExtTmp[WIIMOTE_REG_EXT_SIZE];
extern u8 g_RegIr[WIIMOTE_REG_IR_SIZE];
extern u8 g_ReportingMode;
extern u16 g_ReportingChannel;
extern wiimote_key g_ExtKey; // extension encryption key
static const u8 EepromData_0[] = {
0xA1, 0xAA, 0x8B, 0x99, 0xAE, 0x9E, 0x78, 0x30,
0xA7, 0x74, 0xD3, 0xA1, 0xAA, 0x8B, 0x99, 0xAE,
0x9E, 0x78, 0x30, 0xA7, 0x74, 0xD3, 0x82, 0x82,
0x82, 0x15, 0x9C, 0x9C, 0x9E, 0x38, 0x40, 0x3E,
0x82, 0x82, 0x82, 0x15, 0x9C, 0x9C, 0x9E, 0x38,
0x40, 0x3E
};
static const u8 EepromData_16D0[] = {
0x00, 0x00, 0x00, 0xFF, 0x11, 0xEE, 0x00, 0x00,
0x33, 0xCC, 0x44, 0xBB, 0x00, 0x00, 0x66, 0x99,
0x77, 0x88, 0x00, 0x00, 0x2B, 0x01, 0xE8, 0x13
};
/* Default calibration for the nunchuck. It should be written to 0x20 - 0x3f of the
extension register. 0x80 is the neutral x and y accelerators and 0xb3 is the
neutral z accelerometer that is adjusted for gravity. */
static const u8 nunchuck_calibration[] =
{
0x80,0x80,0x80,0x00, 0xb3,0xb3,0xb3,0x00,
0xe0,0x20,0x80,0xe0, 0x20,0x80,0xee,0x43,
0x80,0x80,0x80,0x00, 0xb3,0xb3,0xb3,0x00,
0xe0,0x20,0x80,0xe0, 0x20,0x80,0xee,0x43
};
/* Classic Controller calibration. 0x80 is the neutral for the analog triggers and
sticks. The left analog range is 0x1c - 0xe4 and the right is 0x28 - 0xd8.
We use this range because it's closest to the GC controller range. */
static const u8 classic_calibration[] =
{
0xe4,0x1c,0x80,0xe4, 0x1c,0x80,0xd8,0x28,
0x80,0xd8,0x28,0x80, 0x20,0x20,0x95,0xea,
0xe4,0x1c,0x80,0xe4, 0x1c,0x80,0xd8,0x28,
0x80,0xd8,0x28,0x80, 0x20,0x20,0x95,0xea
};
/* The Nunchuck id. It should be written to the last bytes of the
extension register */
static const u8 nunchuck_id[] =
{
0x00, 0x00, 0xa4, 0x20, 0x00, 0x00
};
/* The Classic Controller id. It should be written to the last bytes of the
extension register */
static const u8 classic_id[] =
{
0x00, 0x00, 0xa4, 0x20, 0x01, 0x01
};
/* The id for nothing inserted */
static const u8 nothing_id[] =
{
0x00, 0x00, 0x00, 0x00, 0x2e, 0x2e
};
/* The id for a partially inserted extension */
static const u8 partially_id[] =
{
0x00, 0x00, 0x00, 0x00, 0xff, 0xff
};
void HidOutputReport(u16 _channelID, wm_report* sr);
@ -144,7 +67,6 @@ void SendReportCoreAccelIr10Ext(u16 _channelID);
int WriteWmReport(u8* dst, u8 channel);
void WmSendAck(u16 _channelID, u8 _reportID, u32 address);
void FillReportAcc(wm_accel& _acc);
void FillReportInfo(wm_core& _core);
void FillReportIR(wm_ir_extended& _ir0, wm_ir_extended& _ir1);
@ -152,10 +74,6 @@ void FillReportIRBasic(wm_ir_basic& _ir0, wm_ir_basic& _ir1);
void FillReportExtension(wm_extension& _ext);
void FillReportClassicExtension(wm_classic_extension& _ext);
u32 convert24bit(const u8* src);
u16 convert16bit(const u8* src);
void GetMousePos(float& x, float& y);
} // namespace
#endif //_EMU_DECLARATIONS_

View File

@ -16,22 +16,28 @@
// http://code.google.com/p/dolphin-emu/
//////////////////////////////////////////////////////////////////////////////////////////
// Includes
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
#include <wx/msgdlg.h>
#include "pluginspecs_wiimote.h"
#include <vector>
#include <string>
#include "Common.h"
#include "Common.h" // Common
#include "pluginspecs_wiimote.h"
#include "StringUtil.h" // For ArrayToString
#include "wiimote_hid.h"
#include "EmuMain.h"
#include "EmuSubroutines.h"
#include "EmuDefinitions.h"
#include "Console.h" // for startConsoleWin, wprintf, GetConsoleHwnd
#include "Config.h" // for g_Config
#include "Console.h" // For startConsoleWin, wprintf, GetConsoleHwnd
#include "Config.h" // For g_Config
//////////////////////////////////
extern SWiimoteInitialize g_WiimoteInitialize;
namespace WiiMoteEmu
{
@ -42,10 +48,12 @@ namespace WiiMoteEmu
void FillReportInfo(wm_core& _core)
{
/* This has to be filled with zeroes because when no buttons are pressed the
value is 00 00 */
memset(&_core, 0x00, sizeof(wm_core));
#ifdef _WIN32
// allow both mouse buttons and keyboard to press a and b
// Allow both mouse buttons and keyboard to press a and b
if(GetAsyncKeyState(VK_LBUTTON) ? 1 : 0 || GetAsyncKeyState('A') ? 1 : 0)
_core.a = 1;
@ -295,9 +303,9 @@ void FillReportIR(wm_ir_extended& _ir0, wm_ir_extended& _ir1)
Bottom = BOTTOM; SensorBarRadius = SENSOR_BAR_RADIUS;
}
// Fill with 0xff if empty
memset(&_ir0, 0xFF, sizeof(wm_ir_extended));
memset(&_ir1, 0xFF, sizeof(wm_ir_extended));
// Fill with 0xff (0r 0x00?) if empty
memset(&_ir0, 0x00, sizeof(wm_ir_extended));
memset(&_ir1, 0x00, sizeof(wm_ir_extended));
float MouseX, MouseY;
GetMousePos(MouseX, MouseY);
@ -378,9 +386,9 @@ void FillReportIRBasic(wm_ir_basic& _ir0, wm_ir_basic& _ir1)
Bottom = BOTTOM; SensorBarRadius = SENSOR_BAR_RADIUS;
}
// Fill with 0xff if empty
memset(&_ir0, 0xff, sizeof(wm_ir_basic));
memset(&_ir1, 0xff, sizeof(wm_ir_basic));
// Fill with 0x00 if empty
memset(&_ir0, 0x00, sizeof(wm_ir_basic));
memset(&_ir1, 0x00, sizeof(wm_ir_basic));
float MouseX, MouseY;
GetMousePos(MouseX, MouseY);
@ -449,7 +457,7 @@ void FillReportIRBasic(wm_ir_basic& _ir0, wm_ir_basic& _ir1)
);*/
}
int abc = 0;
// ===================================================
/* Generate the 6 byte extension report, encrypted. The bytes are JX JY AX AY AZ BT. */
// ----------------
@ -463,6 +471,12 @@ void FillReportExtension(wm_extension& _ext)
_ext.az = 0xb3;
_ext.ax += abc;
abc ++;
if (abc > 50) abc = 0;
_ext.jx = 0x80; // these are the default values unless we use them
_ext.jy = 0x80;
_ext.bt = 0x03; // 0x03 means no button pressed, the button is zero active
@ -496,19 +510,30 @@ void FillReportExtension(wm_extension& _ext)
// TODO linux port
#endif
// Clear g_RegExtTmp by copying zeroes to it
memset(g_RegExtTmp, 0, sizeof(g_RegExtTmp));
/* Here we use g_RegExtTmpReport as a temporary storage for the enryption function because
the type if array may have some importance for wiimote_encrypt(). We avoid using
g_RegExtTmp that is used in EmuMain.cpp because if this runs on a different thread
there is a small chance that they may interfer with each other. */
// Clear g_RegExtTmpReport by copying zeroes to it, this may not be needed
memset(g_RegExtTmpReport, 0, sizeof(g_RegExtTmp));
/* Write the nunchuck inputs to it. We begin writing at 0x08, but it could also be
0x00, the important thing is that we begin at an address evenly divisible
by 0x08 */
memcpy(g_RegExtTmp + 0x08, &_ext, sizeof(_ext));
memcpy(g_RegExtTmpReport + 0x08, &_ext, sizeof(_ext));
/**/if(GetAsyncKeyState('V')) // Log
{
std::string Temp = ArrayToString(g_RegExtTmpReport, sizeof(_ext), 0x08);
wprintf("Nunchuck DataFrame: %s\n", Temp.c_str());
}
// Encrypt it
wiimote_encrypt(&g_ExtKey, &g_RegExtTmp[0x08], 0x08, sizeof(_ext));
wiimote_encrypt(&g_ExtKey, &g_RegExtTmpReport[0x08], 0x08, sizeof(_ext));
// Write it back
memcpy(&_ext, &g_RegExtTmp[0x08], sizeof(_ext));
// Write it back to the extension
memcpy(&_ext, &g_RegExtTmpReport[0x08], sizeof(_ext));
}
@ -675,18 +700,17 @@ void FillReportClassicExtension(wm_classic_extension& _ext)
// TODO linux port
#endif
// Clear g_RegExtTmp by copying zeroes to it
memset(g_RegExtTmp, 0, sizeof(g_RegExtTmp));
memset(g_RegExtTmpReport, 0, sizeof(g_RegExtTmp));
/* Write the nunchuck inputs to it. We begin writing at 0x08, see comment above. */
memcpy(g_RegExtTmp + 0x08, &_ext, sizeof(_ext));
memcpy(g_RegExtTmpReport + 0x08, &_ext, sizeof(_ext));
// Encrypt it
wiimote_encrypt(&g_ExtKey, &g_RegExtTmp[0x08], 0x08, 0x06);
wiimote_encrypt(&g_ExtKey, &g_RegExtTmpReport[0x08], 0x08, 0x06);
// Write it back
memcpy(&_ext, &g_RegExtTmp[0x08], sizeof(_ext));
memcpy(&_ext, &g_RegExtTmpReport[0x08], sizeof(_ext));
}

View File

@ -16,6 +16,9 @@
// http://code.google.com/p/dolphin-emu/
//////////////////////////////////////////////////////////////////////////////////////////
// Includes
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
#include "Common.h"
#include "Config.h"
#include "StringUtil.h"
@ -34,7 +37,12 @@
#endif
#include "Console.h" // for startConsoleWin, wprintf, GetConsoleHwnd
///////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Declarations and definitions
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
SWiimoteInitialize g_WiimoteInitialize;
bool g_UseRealWiiMote = false;
@ -53,7 +61,12 @@ IMPLEMENT_APP_NO_MAIN(wxDLLApp)
WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst);
#endif
////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Main function and WxWidgets initialization
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
#ifdef _WIN32
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, // DLL module handle
DWORD dwReason, // reason called
@ -83,6 +96,9 @@ BOOL APIENTRY DllMain(HINSTANCE hinstDLL, // DLL module handle
return TRUE;
}
#endif
/////////////////////////////////////
//******************************************************************************
// Exports
//******************************************************************************
@ -119,27 +135,34 @@ extern "C" void DllConfig(HWND _hParent)
#endif
}
extern "C" void Wiimote_Initialize(SWiimoteInitialize _WiimoteInitialize)
extern "C" bool Wiimote_Initialize(SWiimoteInitialize _WiimoteInitialize)
{
// ----------------------------------------
// Debugging window
// ----------
/*startConsoleWin(100, 750, "Wiimote"); // give room for 20 rows
wprintf("Wiimote console opened\n");
// Move window, TODO: make this
//MoveWindow(GetConsoleHwnd(), 0,400, 100*8,10*14, true); // small window
MoveWindow(GetConsoleHwnd(), 400,0, 100*8,70*14, true); // big window*/
// ---------------
g_WiimoteInitialize = _WiimoteInitialize;
/* We will run WiiMoteReal::Initialize() even if we are not using a real wiimote,
we will initiate wiiuse.dll, but we will return before creating a new thread
for it in that case */
for it if we find no real Wiimotes. Then g_UseRealWiiMote will also be false
This function call will be done instantly if there is no real Wiimote connected.
I'm not sure how long time it takes if a Wiimote is connected. */
#if HAVE_WIIUSE
g_UseRealWiiMote = WiiMoteReal::Initialize() > 0;
#endif
g_Config.Load(); // load config settings
WiiMoteEmu::Initialize();
WiiMoteEmu::Initialize();
// Debugging window
/*startConsoleWin(100, 750, "Wiimote"); // give room for 20 rows
wprintf("Wiimote console opened\n");
// move window, TODO: make this
//MoveWindow(GetConsoleHwnd(), 0,400, 100*8,10*14, true); // small window
MoveWindow(GetConsoleHwnd(), 400,0, 100*8,70*14, true); // big window*/
return g_UseRealWiiMote;
}
@ -176,6 +199,7 @@ extern "C" void Wiimote_InterruptChannel(u16 _channelID, const void* _pData, u32
LOGV(WII_IPC_WIIMOTE, 3, " Data: %s", Temp.c_str());
}
// Decice where to send the message
if (! g_UseRealWiiMote)
WiiMoteEmu::InterruptChannel(_channelID, _pData, _Size);
#if HAVE_WIIUSE
@ -209,6 +233,11 @@ extern "C" void Wiimote_ControlChannel(u16 _channelID, const void* _pData, u32 _
LOGV(WII_IPC_WIIMOTE, 3, "=============================================================");
}
// ===================================================
/* This sends a Data Report from the Wiimote. See SystemTimers.cpp for the documentation of this
update. */
// ----------------
extern "C" void Wiimote_Update()
{
if (! g_UseRealWiiMote)
@ -223,6 +252,7 @@ extern "C" unsigned int Wiimote_GetAttachedControllers()
{
return 1;
}
// ================
// ===================================================

View File

@ -101,7 +101,7 @@ struct wm_write_data
struct wm_acknowledge
{
u8 Channel;
u8 unk0;
u8 unk0; // Core buttons state (wm_core), can be zero
u8 unk1;
u8 reportID;
u8 errorID;

View File

@ -214,6 +214,8 @@ namespace WiiMoteReal
int Initialize()
{
memset(g_WiiMotes, 0, sizeof(CWiiMote*) * MAX_WIIMOTES);
// Call Wiiuse.dll
g_WiiMotesFromWiiUse = wiiuse_init(MAX_WIIMOTES);
g_NumberOfWiiMotes = wiiuse_find(g_WiiMotesFromWiiUse, MAX_WIIMOTES, 5);