Added UDPWii support to the new plugin. Hopefully I didn't made a mess... Nunchuck support not implemented yet. I want to make it a separate extension.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5835 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
dapetcu21
2010-07-05 10:46:32 +00:00
parent fccacd7f62
commit ca827b9930
16 changed files with 715 additions and 18 deletions

View File

@ -45,6 +45,7 @@ enum
GROUP_TYPE_TILT,
GROUP_TYPE_CURSOR,
GROUP_TYPE_TRIGGERS,
GROUP_TYPE_UDPWII
};
const char * const named_directions[] =
@ -117,8 +118,8 @@ public:
ControlGroup( const char* const _name, const unsigned int _type = GROUP_TYPE_OTHER ) : name(_name), type(_type) {}
virtual ~ControlGroup();
void LoadConfig(IniFile::Section *sec, const std::string& defdev = "", const std::string& base = "" );
void SaveConfig(IniFile::Section *sec, const std::string& defdev = "", const std::string& base = "" );
virtual void LoadConfig(IniFile::Section *sec, const std::string& defdev = "", const std::string& base = "" );
virtual void SaveConfig(IniFile::Section *sec, const std::string& defdev = "", const std::string& base = "" );
const char* const name;
const unsigned int type;
@ -422,8 +423,8 @@ public:
virtual void LoadDefaults() {}
void LoadConfig(IniFile::Section *sec, const std::string& base = "");
void SaveConfig(IniFile::Section *sec, const std::string& base = "");
virtual void LoadConfig(IniFile::Section *sec, const std::string& base = "");
virtual void SaveConfig(IniFile::Section *sec, const std::string& base = "");
void UpdateDefaultDevice();
void UpdateReferences( ControllerInterface& devi );

View File

@ -8,7 +8,9 @@ files = [
'InputConfig.cpp',
'SDL_Util.cpp',
'ControllerInterface/ControllerInterface.cpp',
'ControllerInterface/SDL/SDL.cpp'
'ControllerInterface/SDL/SDL.cpp',
'UDPWiimote.cpp',
'UDPWrapper.cpp'
]

View File

@ -0,0 +1,302 @@
#include "UDPWiimote.h"
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#define sock_t SOCKET
#define ERRNO WSAGetLastError()
#define EWOULDBLOCK WSAEWOULDBLOCK
#define BAD_SOCK INVALID_SOCKET
#define close(x) closesocket(x)
#define cleanup do {noinst--; if (noinst==0) WSACleanup();} while (0)
#define blockingoff(sock) ioctlsocket(sock, FIONBIO, &iMode)
#define dataz char*
#ifdef _MSC_VER
#pragma comment (lib, "Ws2_32.lib")
#endif
#else
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#define BAD_SOCK -1
#define ERRNO errno
#define cleanup noinst--
#define blockingoff(sock) fcntl(sock, F_SETFL, O_NONBLOCK)
#define dataz void*
#define sock_t int
#endif
#include "Thread.h"
#include <stdio.h>
#include <string.h>
#include <list>
struct UDPWiimote::_d
{
Common::Thread * thread;
std::list<sock_t> sockfds;
Common::CriticalSection termLock,mutex;
volatile bool exit;
};
int UDPWiimote::noinst=0;
void _UDPWiiThread(void* arg)
{
((UDPWiimote*)arg)->mainThread();
//NOTICE_LOG(WIIMOTE,"UDPWii thread stopped");
}
THREAD_RETURN UDPWiiThread(void* arg)
{
_UDPWiiThread(arg);
return 0;
}
UDPWiimote::UDPWiimote(const char *_port) :
d(new _d) ,x(0),y(0),z(0),nunX(0),nunY(0),
pointerX(-0.1),pointerY(-0.1),nunMask(0),mask(0),time(0),port(_port)
{
#ifdef _WIN32
u_long iMode = 1;
#endif
struct addrinfo hints, *servinfo, *p;
int rv;
d->thread=NULL;
#ifdef _WIN32
if (noinst==0)
{
WORD sockVersion;
WSADATA wsaData;
sockVersion = MAKEWORD(2, 2);
WSAStartup(sockVersion, &wsaData);
}
#endif
noinst++;
//PanicAlert("UDPWii instantiated");
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, _port, &hints, &servinfo)) != 0) {
cleanup;
err=-1;
return;
}
// loop through all the results and bind to everything we can
for(p = servinfo; p != NULL; p = p->ai_next) {
sock_t sock;
if ((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == BAD_SOCK) {
continue;
}
if (bind(sock, p->ai_addr, p->ai_addrlen) == -1) {
close(sock);
continue;
}
//NOTICE_LOG(WIIMOTE,"UDPWii new listening sock");
d->sockfds.push_back(sock);
}
if (d->sockfds.empty()) {
cleanup;
err=-2;
return;
}
freeaddrinfo(servinfo);
err=0;
d->exit=false;
// NOTICE_LOG(WIIMOTE,"UDPWii thread starting");
d->termLock.Enter();
d->thread = new Common::Thread(UDPWiiThread,this);
d->termLock.Leave();
return;
}
void UDPWiimote::mainThread()
{
d->termLock.Enter();
// NOTICE_LOG(WIIMOTE,"UDPWii thread started");
fd_set fds;
struct timeval timeout;
timeout.tv_sec=1;
timeout.tv_usec=500000;
//Common::Thread * thisthr= d->thread;
do
{
int maxfd=0;
FD_ZERO(&fds);
for (std::list<sock_t>::iterator i=d->sockfds.begin(); i!=d->sockfds.end(); i++)
{
FD_SET(*i,&fds);
#ifndef _WIN32
if (*i>=maxfd)
maxfd=(*i)+1;
#endif
}
d->termLock.Leave();
if (d->exit) return;
int rt=select(maxfd,&fds,NULL,NULL,&timeout);
if (d->exit) return;
d->termLock.Enter();
if (d->exit) return;
if (rt)
{
for (std::list<sock_t>::iterator i=d->sockfds.begin(); i!=d->sockfds.end(); i++)
if (FD_ISSET(*i,&fds))
{
sock_t fd=*i;
u8 bf[64];
int size=60;
size_t addr_len;
struct sockaddr_storage their_addr;
addr_len = sizeof their_addr;
if ((size = recvfrom(fd, (dataz)bf, size , 0,(struct sockaddr *)&their_addr, (socklen_t*)&addr_len)) == -1)
{
ERROR_LOG(WIIMOTE,"UDPWii Packet error");
}
else
{
d->mutex.Enter();
if (pharsePacket(bf,size)==0)
{
//NOTICE_LOG(WIIMOTE,"UDPWII New pack");
} else {
//NOTICE_LOG(WIIMOTE,"UDPWII Wrong pack format... ignoring");
}
d->mutex.Leave();
}
}
} else {
broadcastPresence();
}
} while (!(d->exit));
d->termLock.Leave();
//delete thisthr;
}
UDPWiimote::~UDPWiimote()
{
d->exit=true;
d->termLock.Enter();
d->termLock.Leave();
for (std::list<sock_t>::iterator i=d->sockfds.begin(); i!=d->sockfds.end(); i++)
close(*i);
cleanup;
delete d;
//PanicAlert("UDPWii destructed");
}
#define ACCEL_FLAG (1<<0)
#define BUTT_FLAG (1<<1)
#define IR_FLAG (1<<2)
#define NUN_FLAG (1<<3)
int UDPWiimote::pharsePacket(u8 * bf, size_t size)
{
if (size<3) return -1;
if (bf[0]!=0xde)
return -1;
if (bf[1]==0)
time=0;
if (bf[1]<time)
return -1;
time=bf[1];
u32 *p=(u32*)(&bf[3]);
if (bf[2]&ACCEL_FLAG)
{
if ((size-(((u8*)p)-bf))<12) return -1;
double ux,uy,uz;
ux=(double)((s32)ntohl(*p)); p++;
uy=(double)((s32)ntohl(*p)); p++;
uz=(double)((s32)ntohl(*p)); p++;
x=ux/1048576; //packet accel data
y=uy/1048576;
z=uz/1048576;
}
if (bf[2]&BUTT_FLAG)
{
if ((size-(((u8*)p)-bf))<4) return -1;
mask=ntohl(*p); p++;
}
if (bf[2]&IR_FLAG)
{
if ((size-(((u8*)p)-bf))<8) return -1;
pointerX=((double)((s32)ntohl(*p)))/1048576; p++;
pointerY=((double)((s32)ntohl(*p)))/1048576; p++;
}
if (bf[2]&NUN_FLAG)
{
if ((size-(((u8*)p)-bf))<9) return -1;
nunMask=*((u8*)p); p=(u32*)(((u8*)p)+1);
nunX=((double)((s32)ntohl(*p)))/1048576; p++;
nunY=((double)((s32)ntohl(*p)))/1048576; p++;
}
return 0;
}
void UDPWiimote::broadcastPresence()
{
// NOTICE_LOG(WIIMOTE,"UDPWii broadcasting presence");
}
void UDPWiimote::getAccel(float &_x, float &_y, float &_z)
{
d->mutex.Enter();
_x=x;
_y=y;
_z=z;
d->mutex.Leave();
//NOTICE_LOG(WIIMOTE,"%lf %lf %lf",_x, _y, _z);
}
u32 UDPWiimote::getButtons()
{
u32 msk;
d->mutex.Enter();
msk=mask;
d->mutex.Leave();
return msk;
}
void UDPWiimote::getIR(float &_x, float &_y)
{
d->mutex.Enter();
_x=(float)pointerX;
_y=(float)pointerY;
d->mutex.Leave();
}
void UDPWiimote::getNunchuck(float &_x, float &_y, u8 &_mask)
{
d->mutex.Enter();
_x=(float)nunX;
_y=(float)nunY;
_mask=nunMask;
d->mutex.Leave();
}
const char * UDPWiimote::getPort()
{
return port.c_str();
}

View File

@ -0,0 +1,50 @@
#ifndef UDPWIIMOTE_H
#define UDPWIIMOTE_H
#include "Common.h"
#include <string>
#define UDPWM_B1 (1<<0)
#define UDPWM_B2 (1<<1)
#define UDPWM_BA (1<<2)
#define UDPWM_BB (1<<3)
#define UDPWM_BP (1<<4)
#define UDPWM_BM (1<<5)
#define UDPWM_BH (1<<6)
#define UDPWM_BU (1<<7)
#define UDPWM_BD (1<<8)
#define UDPWM_BL (1<<9)
#define UDPWM_BR (1<<10)
#define UDPWM_SK (1<<11)
#define UDPWM_NC (1<<0)
#define UDPWM_NZ (1<<1)
class UDPWiimote
{
public:
UDPWiimote(const char * port);
virtual ~UDPWiimote();
void getAccel(float &x, float &y, float &z);
u32 getButtons();
void getNunchuck(float &x, float &y, u8 &mask);
void getIR(float &x, float &y);
int getErrNo() {return err;};
const char * getPort();
private:
std::string port;
int pharsePacket(u8 * data, size_t size);
void mainThread();
struct _d; //using pimpl because Winsock2.h doesen't have include guards -_-
_d *d;
double x,y,z;
double nunX,nunY;
double pointerX,pointerY;
u8 nunMask;
u32 mask;
int err;
static int noinst;
friend void _UDPWiiThread(void* arg);
void broadcastPresence();
u8 time;
};
#endif

View File

@ -0,0 +1,191 @@
#include "UDPWrapper.h"
#include "UDPWiimote.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(HAVE_WX) && HAVE_WX
#include <wx/wx.h>
#include <wx/listbox.h>
#include <wx/textctrl.h>
#include <wx/button.h>
#include <wx/stattext.h>
#include <wx/combobox.h>
#include <wx/checkbox.h>
#include <wx/notebook.h>
#include <wx/panel.h>
#include <wx/spinctrl.h>
#endif
UDPWrapper::UDPWrapper(int indx, const char* const _name) :
updIR(false),updAccel(false),
updButt(false),udpEn(false),inst(NULL),
index(indx),ControllerEmu::ControlGroup(_name,GROUP_TYPE_UDPWII)
{
char s[5];
sprintf(s,"%d",4432+index);
port=s;
//PanicAlert("UDPWrapper #%d ctor",index);
}
void UDPWrapper::LoadConfig(IniFile::Section *sec, const std::string& defdev, const std::string& base )
{
ControlGroup::LoadConfig(sec,defdev,base);
std::string group( base + name ); group += "/";
int _updAccel,_updIR,_updButt,_udpEn;
sec->Get((group + "Enable").c_str(),&_udpEn,0);
char s[5];
sprintf(s,"%d",4432+index);
sec->Get((group + "Port").c_str(),&port,s);
sec->Get((group + "Update_Accel").c_str(),&_updAccel,1);
sec->Get((group + "Update_IR").c_str(),&_updIR,1);
sec->Get((group + "Update_Butt").c_str(),&_updButt,1);
udpEn=(_udpEn>0);
updAccel=(_updAccel>0);
updIR=(_updIR>0);
updButt=(_updButt>0);
Refresh();
}
void UDPWrapper::SaveConfig(IniFile::Section *sec, const std::string& defdev, const std::string& base )
{
ControlGroup::SaveConfig(sec,defdev,base);
std::string group( base + name ); group += "/";
sec->Set((group + "Enable").c_str(),(int)udpEn);
sec->Set((group + "Port").c_str(),port.c_str());
sec->Set((group + "Update_Accel").c_str(),(int)updAccel);
sec->Set((group + "Update_IR").c_str(),(int)updIR);
sec->Set((group + "Update_Butt").c_str(),(int)updButt);
}
void UDPWrapper::Refresh()
{
bool udpAEn=(inst!=NULL);
if (udpEn&&udpAEn)
{
if (strcmp(inst->getPort(),port.c_str()))
{
delete inst;
inst= new UDPWiimote(port.c_str());
}
return;
}
if (!udpEn)
{
if (inst)
delete inst;
inst=NULL;
return;
}
//else
inst= new UDPWiimote(port.c_str());
}
UDPWrapper::~UDPWrapper()
{
if (inst)
delete inst;
}
#if defined(HAVE_WX) && HAVE_WX
#define _connect_macro_(b, f, c, s) (b)->Connect(wxID_ANY, (c), wxCommandEventHandler( f ), (wxObject*)0, (wxEvtHandler*)s)
class UDPConfigDiag : public wxDialog
{
public:
UDPConfigDiag(wxWindow * const parent, UDPWrapper * _wrp);
UDPWrapper * wrp;
void ChangeUpdateFlags(wxCommandEvent & event);
void ChangeState(wxCommandEvent & event);
void OKPressed(wxCommandEvent & event);
wxCheckBox * enable;
wxCheckBox * butt;
wxCheckBox * accel;
wxCheckBox * point;
wxTextCtrl * port_tbox;
};
UDPConfigDiag::UDPConfigDiag(wxWindow * const parent, UDPWrapper * _wrp) :
wxDialog(parent, -1, wxT("UDP Wiimote"), wxDefaultPosition, wxDefaultSize),
wrp(_wrp)
{
wxBoxSizer * outer_sizer = new wxBoxSizer(wxVERTICAL);
wxBoxSizer * sizer1 = new wxBoxSizer(wxVERTICAL);
wxBoxSizer * sizer2 = new wxBoxSizer(wxVERTICAL);
outer_sizer ->Add(sizer1, 0, wxUP | wxLEFT| wxRIGHT | wxEXPAND, 10);
outer_sizer ->Add(sizer2, 1, wxALL | wxEXPAND, 10);
enable = new wxCheckBox(this,wxID_ANY,wxT("Enable"));
butt = new wxCheckBox(this,wxID_ANY,wxT("Update Buttons"));
accel = new wxCheckBox(this,wxID_ANY,wxT("Update Acceleration"));
point = new wxCheckBox(this,wxID_ANY,wxT("Update IR Pointer"));
wxButton * ok_butt = new wxButton(this,wxID_ANY,wxT("OK"));
wxBoxSizer * port_sizer = new wxBoxSizer(wxHORIZONTAL);
port_sizer->Add(new wxStaticText(this , wxID_ANY, wxT("UDP Port:")),0,wxALIGN_CENTER);
port_tbox = new wxTextCtrl(this,wxID_ANY,wxString::FromUTF8(wrp->port.c_str()));
port_sizer->Add(port_tbox,1, wxLEFT | wxEXPAND , 5);
_connect_macro_(enable,UDPConfigDiag::ChangeState ,wxEVT_COMMAND_CHECKBOX_CLICKED, this);
_connect_macro_(butt,UDPConfigDiag::ChangeUpdateFlags ,wxEVT_COMMAND_CHECKBOX_CLICKED, this);
_connect_macro_(accel,UDPConfigDiag::ChangeUpdateFlags ,wxEVT_COMMAND_CHECKBOX_CLICKED, this);
_connect_macro_(point,UDPConfigDiag::ChangeUpdateFlags ,wxEVT_COMMAND_CHECKBOX_CLICKED, this);
_connect_macro_(ok_butt,UDPConfigDiag::OKPressed, wxEVT_COMMAND_BUTTON_CLICKED, this);
_connect_macro_(port_tbox, UDPConfigDiag::ChangeState, wxEVT_COMMAND_TEXT_UPDATED, this);
enable->SetValue(wrp->udpEn);
butt->SetValue(wrp->updButt);
accel->SetValue(wrp->updAccel);
point->SetValue(wrp->updIR);
sizer1->Add(enable,1,wxALL | wxEXPAND,5);
sizer1->Add(port_sizer, 1,wxDOWN | wxLEFT| wxRIGHT | wxEXPAND,5);
sizer2->Add(butt,1,wxALL | wxEXPAND,5);
sizer2->Add(accel,1,wxALL | wxEXPAND,5);
sizer2->Add(point,1,wxALL | wxEXPAND,5);
outer_sizer->Add(ok_butt,0, wxDOWN | wxLEFT| wxRIGHT | wxALIGN_RIGHT,10);
SetSizerAndFit(outer_sizer);
Layout();
}
void UDPConfigDiag::ChangeUpdateFlags(wxCommandEvent & event)
{
wrp->updAccel=accel->GetValue();
wrp->updButt=butt->GetValue();
wrp->updIR=point->GetValue();
}
void UDPConfigDiag::ChangeState(wxCommandEvent & event)
{
wrp->udpEn=enable->GetValue();
wrp->port=port_tbox->GetValue().mb_str(wxConvUTF8);
wrp->Refresh();
}
void UDPConfigDiag::OKPressed(wxCommandEvent & event)
{
Close();
}
void UDPWrapper::Configure(wxWindow * parent)
{
wxDialog * diag = new UDPConfigDiag(parent,this);
diag->ShowModal();
diag->Destroy();
}
#endif

View File

@ -0,0 +1,34 @@
#ifndef UDPWRAPPER_H
#define UDPWRAPPER_H
#include <Common.h>
#include "ControllerEmu.h"
#include <IniFile.h>
#include <string>
#if defined(HAVE_WX) && HAVE_WX
class wxWindow;
#endif
class UDPWiimote;
class Wiimote;
class UDPWrapper : public ControllerEmu::ControlGroup
{
public:
UDPWiimote * inst;
int index;
bool updIR,updAccel,updButt,udpEn; //upd from update and udp from... well... UDP
std::string port;
UDPWrapper(int index, const char* const _name);
virtual void LoadConfig(IniFile::Section *sec, const std::string& defdev = "", const std::string& base = "" );
virtual void SaveConfig(IniFile::Section *sec, const std::string& defdev = "", const std::string& base = "" );
void Refresh();
#if defined(HAVE_WX) && HAVE_WX
void Configure(wxWindow * parent);
#endif
virtual ~UDPWrapper();
};
#endif