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

@ -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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// --------------------
// 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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#include <iostream>
//////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Declarations
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#include "Common.h"
#include "Config.h"
#include "StringUtil.h"
@ -34,7 +37,12 @@
#endif
#include "Console.h" // for startConsoleWin, wprintf, GetConsoleHwnd
///////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Declarations and definitions
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
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
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#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);