diff --git a/project/vs2010_mfc/VBA2010.vcxproj b/project/vs2010_mfc/VBA2010.vcxproj
index 8abe4400..9ca2dec7 100644
--- a/project/vs2010_mfc/VBA2010.vcxproj
+++ b/project/vs2010_mfc/VBA2010.vcxproj
@@ -201,7 +201,6 @@
-
@@ -349,7 +348,6 @@
_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
-
Create
diff --git a/project/vs2010_mfc/VBA2010.vcxproj.filters b/project/vs2010_mfc/VBA2010.vcxproj.filters
index ec1637f6..70ddff39 100644
--- a/project/vs2010_mfc/VBA2010.vcxproj.filters
+++ b/project/vs2010_mfc/VBA2010.vcxproj.filters
@@ -208,9 +208,6 @@
Linking
-
- Linking
-
Linking
@@ -625,9 +622,6 @@
Linking
-
- Linking
-
Linking
diff --git a/src/gba/GBA.cpp b/src/gba/GBA.cpp
index 4a6183e7..aebffcdb 100644
--- a/src/gba/GBA.cpp
+++ b/src/gba/GBA.cpp
@@ -3591,7 +3591,7 @@ void CPULoop(int ticks)
#ifndef NO_LINK
// shuffle2: what's the purpose?
- //if(gba_link_enabled)
+ //if(GetLinkMode() != LINK_DISCONNECTED)
//cpuNextEvent = 1;
#endif
@@ -4042,11 +4042,8 @@ void CPULoop(int ticks)
ticks -= clockTicks;
#ifndef NO_LINK
- if (gba_link_enabled)
+ if (GetLinkMode() != LINK_DISCONNECTED)
LinkUpdate(clockTicks);
-
- if (gba_joybus_enabled)
- JoyBusUpdate(clockTicks);
#endif
cpuNextEvent = CPUUpdateTicks();
@@ -4064,7 +4061,7 @@ void CPULoop(int ticks)
#ifndef NO_LINK
// shuffle2: what's the purpose?
- if(gba_link_enabled || gba_joybus_active)
+ if (GetLinkMode() != LINK_DISCONNECTED || gba_joybus_active)
cpuNextEvent = 1;
#endif
diff --git a/src/gba/GBALink.cpp b/src/gba/GBALink.cpp
index 62c6df32..5c83b88f 100644
--- a/src/gba/GBALink.cpp
+++ b/src/gba/GBALink.cpp
@@ -10,7 +10,11 @@
#include
#endif
-int vbaid = 0;
+#ifdef _MSC_VER
+#define snprintf _snprintf
+#endif
+
+static int vbaid = 0;
const char *MakeInstanceFilename(const char *Input)
{
if (vbaid == 0)
@@ -42,6 +46,9 @@ bool gba_link_enabled = false;
#include "GBA.h"
#include "GBALink.h"
#include "GBASockClient.h"
+
+#include
+
#ifdef ENABLE_NLS
#include
#define _(x) gettext(x)
@@ -49,6 +56,9 @@ bool gba_link_enabled = false;
#define _(x) x
#endif
#define N_(x) x
+
+
+
#if (defined __WIN32__ || defined _WIN32)
#include
#else
@@ -57,6 +67,8 @@ bool gba_link_enabled = false;
#include
#include
#include
+
+
#define ReleaseSemaphore(sem, nrel, orel) do { \
for(int i = 0; i < nrel; i++) \
sem_post(sem); \
@@ -158,57 +170,191 @@ int WaitForSingleObject(sem_t *s, int t)
#endif
#endif
+#define UNSUPPORTED -1
+#define MULTIPLAYER 0
+#define NORMAL8 1
+#define NORMAL32 2
+#define UART 3
+#define JOYBUS 4
+#define GP 5
+
+#define RFU_INIT 0
+#define RFU_COMM 1
+#define RFU_SEND 2
+#define RFU_RECV 3
+
+static ConnectionState InitIPC();
+static ConnectionState InitSocket();
+static ConnectionState JoyBusConnect();
+
+static void JoyBusShutdown();
+static void CloseIPC();
+static void CloseSocket();
+
+static void StartCableSocket(u16 siocnt);
+static void StartRFU(u16 siocnt);
+static void StartCableIPC(u16 siocnt);
+
+static void JoyBusUpdate(int ticks);
+static void UpdateCableIPC(int ticks);
+static void UpdateRFUIPC(int ticks);
+static void UpdateSocket(int ticks);
+
+static ConnectionState ConnectUpdateSocket(char * const message, size_t size);
+
+struct LinkDriver {
+ typedef ConnectionState (ConnectFunc)();
+ typedef ConnectionState (ConnectUpdateFunc)(char * const message, size_t size);
+ typedef void (StartFunc)(u16 siocnt);
+ typedef void (UpdateFunc)(int ticks);
+ typedef void (CloseFunc)();
+
+ LinkMode mode;
+ ConnectFunc *connect;
+ ConnectUpdateFunc *connectUpdate;
+ StartFunc *start;
+ UpdateFunc *update;
+ CloseFunc *close;
+};
+static const LinkDriver linkDrivers[] =
+{
+ { LINK_CABLE_IPC, InitIPC, NULL, StartCableIPC, UpdateCableIPC, CloseIPC },
+ { LINK_CABLE_SOCKET, InitSocket, ConnectUpdateSocket, StartCableSocket, UpdateSocket, CloseSocket },
+ { LINK_RFU_IPC, InitIPC, NULL, StartRFU, UpdateRFUIPC, CloseIPC },
+ { LINK_GAMECUBE_DOLPHIN, JoyBusConnect, NULL, NULL, JoyBusUpdate, JoyBusShutdown }
+};
+
+
+enum
+{
+ JOY_CMD_RESET = 0xff,
+ JOY_CMD_STATUS = 0x00,
+ JOY_CMD_READ = 0x14,
+ JOY_CMD_WRITE = 0x15
+};
+
#define UPDATE_REG(address, value) WRITE16LE(((u16 *)&ioMem[address]),value)
-int linktime = 0;
+typedef struct {
+ u16 linkdata[5];
+ u16 linkcmd;
+ u16 numtransfers;
+ int lastlinktime;
+ u8 numgbas;
+ u8 trgbas;
+ u8 linkflags;
+ int rfu_q[4];
+ u8 rfu_request[4];
+ int rfu_linktime[4];
+ u32 rfu_bdata[4][7];
+ u32 rfu_data[4][32];
+} LINKDATA;
-GBASockClient* dol = NULL;
-sf::IPAddress joybusHostAddr = sf::IPAddress::LocalHost;
+typedef struct {
+ sf::SocketTCP tcpsocket;
+ int numslaves;
+ int connectedSlaves;
+ int type;
+ bool server;
+ bool speed;
+} LANLINKDATA;
+
+class lserver{
+ int numbytes;
+ sf::Selector fdset;
+ //timeval udptimeout;
+ char inbuffer[256], outbuffer[256];
+ s32 *intinbuffer;
+ u16 *u16inbuffer;
+ s32 *intoutbuffer;
+ u16 *u16outbuffer;
+ int counter;
+ int done;
+public:
+ int howmanytimes;
+ sf::SocketTCP tcpsocket[4];
+ sf::IPAddress udpaddr[4];
+ lserver(void);
+ void Send(void);
+ void Recv(void);
+};
+
+class lclient{
+ sf::Selector fdset;
+ char inbuffer[256], outbuffer[256];
+ s32 *intinbuffer;
+ u16 *u16inbuffer;
+ s32 *intoutbuffer;
+ u16 *u16outbuffer;
+ int numbytes;
+public:
+ sf::IPAddress serveraddr;
+ unsigned short serverport;
+ int numtransfers;
+ lclient(void);
+ void Send(void);
+ void Recv(void);
+ void CheckConn(void);
+};
+
+static const LinkDriver *linkDriver = NULL;
+static ConnectionState gba_connection_state = LINK_OK;
+
+LinkMode GetLinkMode() {
+ if (linkDriver && gba_connection_state == LINK_OK)
+ return linkDriver->mode;
+ else
+ return LINK_DISCONNECTED;
+}
+
+static int linktime = 0;
+
+static GBASockClient* dol = NULL;
+static sf::IPAddress joybusHostAddr = sf::IPAddress::LocalHost;
// Hodgepodge
-u8 tspeed = 3;
-u8 transfer = 0;
-LINKDATA *linkmem = NULL;
-int linkid = 0;
+static u8 tspeed = 3;
+static u8 transfer = 0;
+static LINKDATA *linkmem = NULL;
+static int linkid = 0;
#if (defined __WIN32__ || defined _WIN32)
-HANDLE linksync[4];
+static HANDLE linksync[4];
#else
-sem_t *linksync[4];
+static sem_t *linksync[4];
#endif
-int savedlinktime = 0;
+static int savedlinktime = 0;
#if (defined __WIN32__ || defined _WIN32)
-HANDLE mmf = NULL;
+static HANDLE mmf = NULL;
#else
-int mmf = -1;
+static int mmf = -1;
#endif
-char linkevent[] =
+static char linkevent[] =
#if !(defined __WIN32__ || defined _WIN32)
"/"
#endif
"VBA link event ";
static int i, j;
-int linktimeout = 1000;
-LANLINKDATA lanlink;
-u16 linkdata[4];
-lserver ls;
-lclient lc;
-bool oncewait = false, after = false;
+static int linktimeout = 1000;
+static LANLINKDATA lanlink;
+static u16 linkdata[4];
+static lserver ls;
+static lclient lc;
+static bool oncewait = false, after = false;
// RFU crap (except for numtransfers note...should probably check that out)
-bool rfu_enabled = false;
-u8 rfu_cmd, rfu_qsend, rfu_qrecv;
-int rfu_state, rfu_polarity, rfu_counter, rfu_masterq;
+static u8 rfu_cmd, rfu_qsend, rfu_qrecv;
+static int rfu_state, rfu_polarity, rfu_counter, rfu_masterq;
// numtransfers seems to be used interchangeably with linkmem->numtransfers
// in rfu code; probably a bug?
-int rfu_transfer_end;
+static int rfu_transfer_end;
// in local comm, setting this keeps slaves from trying to communicate even
// when master isn't
-u16 numtransfers = 0;
-u32 rfu_masterdata[32];
+static u16 numtransfers = 0;
+static u32 rfu_masterdata[32];
// time to end of single GBA's transfer, in 16.78 MHz clock ticks
// first index is GBA #
-int trtimedata[4][4] = {
+static const int trtimedata[4][4] = {
// 9600 38400 57600 115200
{34080, 8520, 5680, 2840},
{65536, 16384, 10923, 5461},
@@ -221,38 +367,281 @@ int trtimedata[4][4] = {
// for < 3 slaves, this is time to transfer last machine + time to detect lack
// of start bit from next slave
// first index is (# of slaves) - 1
-int trtimeend[3][4] = {
+static const int trtimeend[3][4] = {
// 9600 38400 57600 115200
{72527, 18132, 12088, 6044},
{106608, 26652, 17768, 8884},
{133692, 33423, 22282, 11141}
};
-int gbtime = 1024;
+static int GetSIOMode(u16, u16);
-int GetSIOMode(u16, u16);
-
-void LinkClientThread(void *);
-void LinkServerThread(void *);
-
-int StartServer(void);
-
-u16 StartRFU(u16);
-
-void StartLink(u16 value)
+// The GBA wireless RFU (see adapter3.txt)
+// Just try to avert your eyes for now ^^ (note, it currently can be called, tho)
+static void StartRFU(u16 siocnt)
{
- if (ioMem == NULL)
- return;
+ switch (GetSIOMode(siocnt, READ16LE(&ioMem[COMM_RCNT]))) {
+ case NORMAL8:
+ rfu_polarity = 0;
+ break;
- if (rfu_enabled) {
- UPDATE_REG(COMM_SIOCNT, StartRFU(value));
- return;
+ case NORMAL32:
+ if (siocnt & 8)
+ siocnt &= 0xfffb; // A kind of acknowledge procedure
+ else
+ siocnt |= 4;
+
+ if (siocnt & 0x80)
+ {
+ if ((siocnt&3) == 1)
+ rfu_transfer_end = 2048;
+ else
+ rfu_transfer_end = 256;
+
+ u16 a = READ16LE(&ioMem[COMM_SIODATA32_H]);
+
+ switch (rfu_state) {
+ case RFU_INIT:
+ if (READ32LE(&ioMem[COMM_SIODATA32_L]) == 0xb0bb8001)
+ rfu_state = RFU_COMM; // end of startup
+
+ UPDATE_REG(COMM_SIODATA32_H, READ16LE(&ioMem[COMM_SIODATA32_L]));
+ UPDATE_REG(COMM_SIODATA32_L, a);
+ break;
+
+ case RFU_COMM:
+ if (a == 0x9966)
+ {
+ rfu_cmd = ioMem[COMM_SIODATA32_L];
+ if ((rfu_qsend=ioMem[0x121]) != 0) {
+ rfu_state = RFU_SEND;
+ rfu_counter = 0;
+ }
+ if (rfu_cmd == 0x25 || rfu_cmd == 0x24) {
+ linkmem->rfu_q[vbaid] = rfu_qsend;
+ }
+ UPDATE_REG(COMM_SIODATA32_L, 0);
+ UPDATE_REG(COMM_SIODATA32_H, 0x8000);
+ }
+ else if (a == 0x8000)
+ {
+ switch (rfu_cmd) {
+ case 0x1a: // check if someone joined
+ if (linkmem->rfu_request[vbaid] != 0) {
+ rfu_state = RFU_RECV;
+ rfu_qrecv = 1;
+ }
+ linkid = -1;
+ rfu_cmd |= 0x80;
+ break;
+
+ case 0x1e: // receive broadcast data
+ case 0x1d: // no visible difference
+ rfu_polarity = 0;
+ rfu_state = RFU_RECV;
+ rfu_qrecv = 7;
+ rfu_counter = 0;
+ rfu_cmd |= 0x80;
+ break;
+
+ case 0x30:
+ linkmem->rfu_request[vbaid] = 0;
+ linkmem->rfu_q[vbaid] = 0;
+ linkid = 0;
+ numtransfers = 0;
+ rfu_cmd |= 0x80;
+ if (linkmem->numgbas == 2)
+ ReleaseSemaphore(linksync[1-vbaid], 1, NULL);
+ break;
+
+ case 0x11: // ? always receives 0xff - I suspect it's something for 3+ players
+ case 0x13: // unknown
+ case 0x20: // this has something to do with 0x1f
+ case 0x21: // this too
+ rfu_cmd |= 0x80;
+ rfu_polarity = 0;
+ rfu_state = 3;
+ rfu_qrecv = 1;
+ break;
+
+ case 0x26:
+ if(linkid>0){
+ rfu_qrecv = rfu_masterq;
+ }
+ if((rfu_qrecv=linkmem->rfu_q[1-vbaid])!=0){
+ rfu_state = RFU_RECV;
+ rfu_counter = 0;
+ }
+ rfu_cmd |= 0x80;
+ break;
+
+ case 0x24: // send data
+ if((numtransfers++)==0) linktime = 1;
+ linkmem->rfu_linktime[vbaid] = linktime;
+ if(linkmem->numgbas==2){
+ ReleaseSemaphore(linksync[1-vbaid], 1, NULL);
+ WaitForSingleObject(linksync[vbaid], linktimeout);
+ }
+ rfu_cmd |= 0x80;
+ linktime = 0;
+ linkid = -1;
+ break;
+
+ case 0x25: // send & wait for data
+ case 0x1f: // pick a server
+ case 0x10: // init
+ case 0x16: // send broadcast data
+ case 0x17: // setup or something ?
+ case 0x27: // wait for data ?
+ case 0x3d: // init
+ default:
+ rfu_cmd |= 0x80;
+ break;
+
+ case 0xa5: // 2nd part of send&wait function 0x25
+ case 0xa7: // 2nd part of wait function 0x27
+ if (linkid == -1) {
+ linkid++;
+ linkmem->rfu_linktime[vbaid] = 0;
+ }
+ if (linkid&&linkmem->rfu_request[1-vbaid] == 0) {
+ linkmem->rfu_q[1-vbaid] = 0;
+ rfu_transfer_end = 256;
+ rfu_polarity = 1;
+ rfu_cmd = 0x29;
+ linktime = 0;
+ break;
+ }
+ if ((numtransfers++) == 0)
+ linktime = 0;
+ linkmem->rfu_linktime[vbaid] = linktime;
+ if (linkmem->numgbas == 2) {
+ if (!linkid || (linkid && numtransfers))
+ ReleaseSemaphore(linksync[1-vbaid], 1, NULL);
+ WaitForSingleObject(linksync[vbaid], linktimeout);
+ }
+ if ( linkid > 0) {
+ memcpy(rfu_masterdata, linkmem->rfu_data[1-vbaid], 128);
+ rfu_masterq = linkmem->rfu_q[1-vbaid];
+ }
+ rfu_transfer_end = linkmem->rfu_linktime[1-vbaid] - linktime + 256;
+
+ if (rfu_transfer_end < 256)
+ rfu_transfer_end = 256;
+
+ linktime = -rfu_transfer_end;
+ rfu_polarity = 1;
+ rfu_cmd = 0x28;
+ break;
+ }
+ UPDATE_REG(COMM_SIODATA32_H, 0x9966);
+ UPDATE_REG(COMM_SIODATA32_L, (rfu_qrecv<<8) | rfu_cmd);
+
+ } else {
+
+ UPDATE_REG(COMM_SIODATA32_L, 0);
+ UPDATE_REG(COMM_SIODATA32_H, 0x8000);
+ }
+ break;
+
+ case RFU_SEND:
+ if(--rfu_qsend == 0)
+ rfu_state = RFU_COMM;
+
+ switch (rfu_cmd) {
+ case 0x16:
+ linkmem->rfu_bdata[vbaid][rfu_counter++] = READ32LE(&ioMem[COMM_SIODATA32_L]);
+ break;
+
+ case 0x17:
+ linkid = 1;
+ break;
+
+ case 0x1f:
+ linkmem->rfu_request[1-vbaid] = 1;
+ break;
+
+ case 0x24:
+ case 0x25:
+ linkmem->rfu_data[vbaid][rfu_counter++] = READ32LE(&ioMem[COMM_SIODATA32_L]);
+ break;
+ }
+ UPDATE_REG(COMM_SIODATA32_L, 0);
+ UPDATE_REG(COMM_SIODATA32_H, 0x8000);
+ break;
+
+ case RFU_RECV:
+ if (--rfu_qrecv == 0)
+ rfu_state = RFU_COMM;
+
+ switch (rfu_cmd) {
+ case 0x9d:
+ case 0x9e:
+ if (rfu_counter == 0) {
+ UPDATE_REG(COMM_SIODATA32_L, 0x61f1);
+ UPDATE_REG(COMM_SIODATA32_H, 0);
+ rfu_counter++;
+ break;
+ }
+ UPDATE_REG(COMM_SIODATA32_L, linkmem->rfu_bdata[1-vbaid][rfu_counter-1]&0xffff);
+ UPDATE_REG(COMM_SIODATA32_H, linkmem->rfu_bdata[1-vbaid][rfu_counter-1]>>16);
+ rfu_counter++;
+ break;
+
+ case 0xa6:
+ if (linkid>0) {
+ UPDATE_REG(COMM_SIODATA32_L, rfu_masterdata[rfu_counter]&0xffff);
+ UPDATE_REG(COMM_SIODATA32_H, rfu_masterdata[rfu_counter++]>>16);
+ } else {
+ UPDATE_REG(COMM_SIODATA32_L, linkmem->rfu_data[1-vbaid][rfu_counter]&0xffff);
+ UPDATE_REG(COMM_SIODATA32_H, linkmem->rfu_data[1-vbaid][rfu_counter++]>>16);
+ }
+ break;
+
+ case 0x93: // it seems like the game doesn't care about this value
+ UPDATE_REG(COMM_SIODATA32_L, 0x1234); // put anything in here
+ UPDATE_REG(COMM_SIODATA32_H, 0x0200); // also here, but it should be 0200
+ break;
+
+ case 0xa0:
+ case 0xa1:
+ UPDATE_REG(COMM_SIODATA32_L, 0x641b);
+ UPDATE_REG(COMM_SIODATA32_H, 0x0000);
+ break;
+
+ case 0x9a:
+ UPDATE_REG(COMM_SIODATA32_L, 0x61f9);
+ UPDATE_REG(COMM_SIODATA32_H, 0);
+ break;
+
+ case 0x91:
+ UPDATE_REG(COMM_SIODATA32_L, 0x00ff);
+ UPDATE_REG(COMM_SIODATA32_H, 0x0000);
+ break;
+
+ default:
+ UPDATE_REG(COMM_SIODATA32_L, 0x0173);
+ UPDATE_REG(COMM_SIODATA32_H, 0x0000);
+ break;
+ }
+ break;
+ }
+ transfer = 1;
+ }
+
+ if (rfu_polarity)
+ siocnt ^= 4; // sometimes it's the other way around
+ break;
}
+ UPDATE_REG(COMM_SIOCNT, siocnt);
+}
+
+static void StartCableIPC(u16 value)
+{
switch (GetSIOMode(value, READ16LE(&ioMem[COMM_RCNT]))) {
case MULTIPLAYER: {
- bool start = (value & 0x80) && !linkid && !transfer && gba_link_enabled;
- u16 si = value & 4;
+ bool start = (value & 0x80) && !linkid && !transfer;
// clear start, seqno, si (RO on slave, start = pulse on master)
value &= 0xff4b;
// get current si. This way, on slaves, it is low during xfer
@@ -263,27 +652,7 @@ void StartLink(u16 value)
value |= READ16LE(&ioMem[COMM_SIOCNT]) & 4;
}
if (start) {
- if (lanlink.active)
- {
- if (lanlink.connected)
- {
- linkdata[0] = READ16LE(&ioMem[COMM_SIODATA8]);
- savedlinktime = linktime;
- tspeed = value & 3;
- ls.Send();
- transfer = 1;
- linktime = 0;
- UPDATE_REG(COMM_SIOMULTI0, linkdata[0]);
- UPDATE_REG(COMM_SIOMULTI1, 0xffff);
- WRITE32LE(&ioMem[COMM_SIOMULTI2], 0xffffffff);
- if (lanlink.speed&&oncewait == false)
- ls.howmanytimes++;
- after = false;
- value &= ~0x40;
- } else
- value |= 0x40; // comm error
- }
- else if (linkmem->numgbas > 1)
+ if (linkmem->numgbas > 1)
{
// find first active attached GBA
// doing this first reduces the potential
@@ -326,6 +695,8 @@ void StartLink(u16 value)
WRITE32LE(&ioMem[COMM_SIOMULTI0], 0xffffffff);
WRITE32LE(&ioMem[COMM_SIOMULTI2], 0xffffffff);
value &= ~0x40;
+ } else {
+ value |= 0x40; // comm error
}
}
value |= (transfer != 0) << 7;
@@ -352,6 +723,68 @@ void StartLink(u16 value)
}
}
+void StartCableSocket(u16 value)
+{
+ switch (GetSIOMode(value, READ16LE(&ioMem[COMM_RCNT]))) {
+ case MULTIPLAYER: {
+ bool start = (value & 0x80) && !linkid && !transfer;
+ // clear start, seqno, si (RO on slave, start = pulse on master)
+ value &= 0xff4b;
+ // get current si. This way, on slaves, it is low during xfer
+ if(linkid) {
+ if(!transfer)
+ value |= 4;
+ else
+ value |= READ16LE(&ioMem[COMM_SIOCNT]) & 4;
+ }
+ if (start) {
+ linkdata[0] = READ16LE(&ioMem[COMM_SIODATA8]);
+ savedlinktime = linktime;
+ tspeed = value & 3;
+ ls.Send();
+ transfer = 1;
+ linktime = 0;
+ UPDATE_REG(COMM_SIOMULTI0, linkdata[0]);
+ UPDATE_REG(COMM_SIOMULTI1, 0xffff);
+ WRITE32LE(&ioMem[COMM_SIOMULTI2], 0xffffffff);
+ if (lanlink.speed && oncewait == false)
+ ls.howmanytimes++;
+ after = false;
+ value &= ~0x40;
+ }
+ value |= (transfer != 0) << 7;
+ value |= (linkid && !transfer ? 0xc : 8); // set SD (high), SI (low on master)
+ value |= linkid << 4; // set seq
+ UPDATE_REG(COMM_SIOCNT, value);
+ if (linkid)
+ // SC low -> transfer in progress
+ // not sure why SO is low
+ UPDATE_REG(COMM_RCNT, transfer ? 6 : 7);
+ else
+ // SI is always low on master
+ // SO, SC always low during transfer
+ // not sure why SO low otherwise
+ UPDATE_REG(COMM_RCNT, transfer ? 2 : 3);
+ break;
+ }
+ case NORMAL8:
+ case NORMAL32:
+ case UART:
+ default:
+ UPDATE_REG(COMM_SIOCNT, value);
+ break;
+ }
+}
+
+void StartLink(u16 siocnt)
+{
+ if (!linkDriver || !linkDriver->start) {
+ return;
+ }
+
+ linkDriver->start(siocnt);
+}
+
void StartGPLink(u16 value)
{
UPDATE_REG(COMM_RCNT, value);
@@ -369,21 +802,27 @@ void StartGPLink(u16 value)
break;
case GP:
- if (rfu_enabled)
+ if (GetLinkMode() == LINK_RFU_IPC)
rfu_state = RFU_INIT;
break;
}
}
-void JoyBusConnect()
+static ConnectionState JoyBusConnect()
{
delete dol;
dol = NULL;
dol = new GBASockClient(joybusHostAddr);
+ if (dol) {
+ return LINK_OK;
+ }
+ else {
+ return LINK_ERROR;
+ }
}
-void JoyBusShutdown()
+static void JoyBusShutdown()
{
delete dol;
dol = NULL;
@@ -399,7 +838,7 @@ static u32 nextjoybusupdate = 0;
static u32 lastcommand = 0;
static bool booted = false;
-void JoyBusUpdate(int ticks)
+static void JoyBusUpdate(int ticks)
{
lastjoybusupdate += ticks;
lastcommand += ticks;
@@ -519,101 +958,11 @@ void JoyBusUpdate(int ticks)
static void ReInitLink();
-void LinkUpdate(int ticks)
+static void UpdateCableIPC(int ticks)
{
if (((READ16LE(&ioMem[COMM_RCNT])) >> 14) == 3)
return;
- // this actually gets called every single instruction, so keep default
- // path as short as possible
-
- linktime += ticks;
-
- if (rfu_enabled)
- {
- rfu_transfer_end -= ticks;
- if (transfer && rfu_transfer_end <= 0)
- {
- transfer = 0;
- if (READ16LE(&ioMem[COMM_SIOCNT]) & 0x4000)
- {
- IF |= 0x80;
- UPDATE_REG(0x202, IF);
- }
- UPDATE_REG(COMM_SIOCNT, READ16LE(&ioMem[COMM_SIOCNT]) & 0xff7f);
- }
- return;
- }
-
- if (lanlink.active)
- {
- if (lanlink.connected)
- {
- if (after)
- {
- if (linkid && linktime > 6044) {
- lc.Recv();
- oncewait = true;
- }
- else
- return;
- }
-
- if (linkid && !transfer && lc.numtransfers > 0 && linktime >= savedlinktime)
- {
- linkdata[linkid] = READ16LE(&ioMem[COMM_SIODATA8]);
-
- lc.Send();
-
- UPDATE_REG(COMM_SIODATA32_L, linkdata[0]);
- UPDATE_REG(COMM_SIOCNT, READ16LE(&ioMem[COMM_SIOCNT]) | 0x80);
- transfer = 1;
- if (lc.numtransfers==1)
- linktime = 0;
- else
- linktime -= savedlinktime;
- }
-
- if (transfer && linktime >= trtimeend[lanlink.numslaves-1][tspeed])
- {
- if (READ16LE(&ioMem[COMM_SIOCNT]) & 0x4000)
- {
- IF |= 0x80;
- UPDATE_REG(0x202, IF);
- }
-
- UPDATE_REG(COMM_SIOCNT, (READ16LE(&ioMem[COMM_SIOCNT]) & 0xff0f) | (linkid << 4));
- transfer = 0;
- linktime -= trtimeend[lanlink.numslaves-1][tspeed];
- oncewait = false;
-
- if (!lanlink.speed)
- {
- if (linkid)
- lc.Recv();
- else
- ls.Recv(); // WTF is the point of this?
-
- UPDATE_REG(COMM_SIOMULTI1, linkdata[1]);
- UPDATE_REG(COMM_SIOMULTI2, linkdata[2]);
- UPDATE_REG(COMM_SIOMULTI3, linkdata[3]);
- oncewait = true;
-
- } else {
-
- after = true;
- if (lanlink.numslaves == 1)
- {
- UPDATE_REG(COMM_SIOMULTI1, linkdata[1]);
- UPDATE_REG(COMM_SIOMULTI2, linkdata[2]);
- UPDATE_REG(COMM_SIOMULTI3, linkdata[3]);
- }
- }
- }
- }
- return;
- }
-
// slave startup depends on detecting change in numtransfers
// and syncing clock with master (after first transfer)
// this will fail if > ~2 minutes have passed since last transfer due
@@ -752,11 +1101,105 @@ void LinkUpdate(int ticks)
UPDATE_REG(0x202, IF);
}
}
-
- return;
}
-inline int GetSIOMode(u16 siocnt, u16 rcnt)
+static void UpdateRFUIPC(int ticks)
+{
+ rfu_transfer_end -= ticks;
+
+ if (transfer && rfu_transfer_end <= 0)
+ {
+ transfer = 0;
+ if (READ16LE(&ioMem[COMM_SIOCNT]) & 0x4000)
+ {
+ IF |= 0x80;
+ UPDATE_REG(0x202, IF);
+ }
+ UPDATE_REG(COMM_SIOCNT, READ16LE(&ioMem[COMM_SIOCNT]) & 0xff7f);
+ }
+}
+
+static void UpdateSocket(int ticks)
+{
+ if (after)
+ {
+ if (linkid && linktime > 6044) {
+ lc.Recv();
+ oncewait = true;
+ }
+ else
+ return;
+ }
+
+ if (linkid && !transfer && lc.numtransfers > 0 && linktime >= savedlinktime)
+ {
+ linkdata[linkid] = READ16LE(&ioMem[COMM_SIODATA8]);
+
+ lc.Send();
+
+ UPDATE_REG(COMM_SIODATA32_L, linkdata[0]);
+ UPDATE_REG(COMM_SIOCNT, READ16LE(&ioMem[COMM_SIOCNT]) | 0x80);
+ transfer = 1;
+ if (lc.numtransfers==1)
+ linktime = 0;
+ else
+ linktime -= savedlinktime;
+ }
+
+ if (transfer && linktime >= trtimeend[lanlink.numslaves-1][tspeed])
+ {
+ if (READ16LE(&ioMem[COMM_SIOCNT]) & 0x4000)
+ {
+ IF |= 0x80;
+ UPDATE_REG(0x202, IF);
+ }
+
+ UPDATE_REG(COMM_SIOCNT, (READ16LE(&ioMem[COMM_SIOCNT]) & 0xff0f) | (linkid << 4));
+ transfer = 0;
+ linktime -= trtimeend[lanlink.numslaves-1][tspeed];
+ oncewait = false;
+
+ if (!lanlink.speed)
+ {
+ if (linkid)
+ lc.Recv();
+ else
+ ls.Recv(); // WTF is the point of this?
+
+ UPDATE_REG(COMM_SIOMULTI1, linkdata[1]);
+ UPDATE_REG(COMM_SIOMULTI2, linkdata[2]);
+ UPDATE_REG(COMM_SIOMULTI3, linkdata[3]);
+ oncewait = true;
+
+ } else {
+
+ after = true;
+ if (lanlink.numslaves == 1)
+ {
+ UPDATE_REG(COMM_SIOMULTI1, linkdata[1]);
+ UPDATE_REG(COMM_SIOMULTI2, linkdata[2]);
+ UPDATE_REG(COMM_SIOMULTI3, linkdata[3]);
+ }
+ }
+ }
+}
+
+
+void LinkUpdate(int ticks)
+{
+ if (!linkDriver) {
+ return;
+ }
+
+ // this actually gets called every single instruction, so keep default
+ // path as short as possible
+
+ linktime += ticks;
+
+ linkDriver->update(ticks);
+}
+
+inline static int GetSIOMode(u16 siocnt, u16 rcnt)
{
if (!(rcnt & 0x8000))
{
@@ -774,280 +1217,13 @@ inline int GetSIOMode(u16 siocnt, u16 rcnt)
return GP;
}
-// The GBA wireless RFU (see adapter3.txt)
-// Just try to avert your eyes for now ^^ (note, it currently can be called, tho)
-u16 StartRFU(u16 value)
-{
- switch (GetSIOMode(value, READ16LE(&ioMem[COMM_RCNT]))) {
- case NORMAL8:
- rfu_polarity = 0;
- return value;
- break;
-
- case NORMAL32:
- if (value & 8)
- value &= 0xfffb; // A kind of acknowledge procedure
- else
- value |= 4;
-
- if (value & 0x80)
- {
- if ((value&3) == 1)
- rfu_transfer_end = 2048;
- else
- rfu_transfer_end = 256;
-
- u16 a = READ16LE(&ioMem[COMM_SIODATA32_H]);
-
- switch (rfu_state) {
- case RFU_INIT:
- if (READ32LE(&ioMem[COMM_SIODATA32_L]) == 0xb0bb8001)
- rfu_state = RFU_COMM; // end of startup
-
- UPDATE_REG(COMM_SIODATA32_H, READ16LE(&ioMem[COMM_SIODATA32_L]));
- UPDATE_REG(COMM_SIODATA32_L, a);
- break;
-
- case RFU_COMM:
- if (a == 0x9966)
- {
- rfu_cmd = ioMem[COMM_SIODATA32_L];
- if ((rfu_qsend=ioMem[0x121]) != 0) {
- rfu_state = RFU_SEND;
- rfu_counter = 0;
- }
- if (rfu_cmd == 0x25 || rfu_cmd == 0x24) {
- linkmem->rfu_q[vbaid] = rfu_qsend;
- }
- UPDATE_REG(COMM_SIODATA32_L, 0);
- UPDATE_REG(COMM_SIODATA32_H, 0x8000);
- }
- else if (a == 0x8000)
- {
- switch (rfu_cmd) {
- case 0x1a: // check if someone joined
- if (linkmem->rfu_request[vbaid] != 0) {
- rfu_state = RFU_RECV;
- rfu_qrecv = 1;
- }
- linkid = -1;
- rfu_cmd |= 0x80;
- break;
-
- case 0x1e: // receive broadcast data
- case 0x1d: // no visible difference
- rfu_polarity = 0;
- rfu_state = RFU_RECV;
- rfu_qrecv = 7;
- rfu_counter = 0;
- rfu_cmd |= 0x80;
- break;
-
- case 0x30:
- linkmem->rfu_request[vbaid] = 0;
- linkmem->rfu_q[vbaid] = 0;
- linkid = 0;
- numtransfers = 0;
- rfu_cmd |= 0x80;
- if (linkmem->numgbas == 2)
- ReleaseSemaphore(linksync[1-vbaid], 1, NULL);
- break;
-
- case 0x11: // ? always receives 0xff - I suspect it's something for 3+ players
- case 0x13: // unknown
- case 0x20: // this has something to do with 0x1f
- case 0x21: // this too
- rfu_cmd |= 0x80;
- rfu_polarity = 0;
- rfu_state = 3;
- rfu_qrecv = 1;
- break;
-
- case 0x26:
- if(linkid>0){
- rfu_qrecv = rfu_masterq;
- }
- if((rfu_qrecv=linkmem->rfu_q[1-vbaid])!=0){
- rfu_state = RFU_RECV;
- rfu_counter = 0;
- }
- rfu_cmd |= 0x80;
- break;
-
- case 0x24: // send data
- if((numtransfers++)==0) linktime = 1;
- linkmem->rfu_linktime[vbaid] = linktime;
- if(linkmem->numgbas==2){
- ReleaseSemaphore(linksync[1-vbaid], 1, NULL);
- WaitForSingleObject(linksync[vbaid], linktimeout);
- }
- rfu_cmd |= 0x80;
- linktime = 0;
- linkid = -1;
- break;
-
- case 0x25: // send & wait for data
- case 0x1f: // pick a server
- case 0x10: // init
- case 0x16: // send broadcast data
- case 0x17: // setup or something ?
- case 0x27: // wait for data ?
- case 0x3d: // init
- default:
- rfu_cmd |= 0x80;
- break;
-
- case 0xa5: // 2nd part of send&wait function 0x25
- case 0xa7: // 2nd part of wait function 0x27
- if (linkid == -1) {
- linkid++;
- linkmem->rfu_linktime[vbaid] = 0;
- }
- if (linkid&&linkmem->rfu_request[1-vbaid] == 0) {
- linkmem->rfu_q[1-vbaid] = 0;
- rfu_transfer_end = 256;
- rfu_polarity = 1;
- rfu_cmd = 0x29;
- linktime = 0;
- break;
- }
- if ((numtransfers++) == 0)
- linktime = 0;
- linkmem->rfu_linktime[vbaid] = linktime;
- if (linkmem->numgbas == 2) {
- if (!linkid || (linkid && numtransfers))
- ReleaseSemaphore(linksync[1-vbaid], 1, NULL);
- WaitForSingleObject(linksync[vbaid], linktimeout);
- }
- if ( linkid > 0) {
- memcpy(rfu_masterdata, linkmem->rfu_data[1-vbaid], 128);
- rfu_masterq = linkmem->rfu_q[1-vbaid];
- }
- rfu_transfer_end = linkmem->rfu_linktime[1-vbaid] - linktime + 256;
-
- if (rfu_transfer_end < 256)
- rfu_transfer_end = 256;
-
- linktime = -rfu_transfer_end;
- rfu_polarity = 1;
- rfu_cmd = 0x28;
- break;
- }
- UPDATE_REG(COMM_SIODATA32_H, 0x9966);
- UPDATE_REG(COMM_SIODATA32_L, (rfu_qrecv<<8) | rfu_cmd);
-
- } else {
-
- UPDATE_REG(COMM_SIODATA32_L, 0);
- UPDATE_REG(COMM_SIODATA32_H, 0x8000);
- }
- break;
-
- case RFU_SEND:
- if(--rfu_qsend == 0)
- rfu_state = RFU_COMM;
-
- switch (rfu_cmd) {
- case 0x16:
- linkmem->rfu_bdata[vbaid][rfu_counter++] = READ32LE(&ioMem[COMM_SIODATA32_L]);
- break;
-
- case 0x17:
- linkid = 1;
- break;
-
- case 0x1f:
- linkmem->rfu_request[1-vbaid] = 1;
- break;
-
- case 0x24:
- case 0x25:
- linkmem->rfu_data[vbaid][rfu_counter++] = READ32LE(&ioMem[COMM_SIODATA32_L]);
- break;
- }
- UPDATE_REG(COMM_SIODATA32_L, 0);
- UPDATE_REG(COMM_SIODATA32_H, 0x8000);
- break;
-
- case RFU_RECV:
- if (--rfu_qrecv == 0)
- rfu_state = RFU_COMM;
-
- switch (rfu_cmd) {
- case 0x9d:
- case 0x9e:
- if (rfu_counter == 0) {
- UPDATE_REG(COMM_SIODATA32_L, 0x61f1);
- UPDATE_REG(COMM_SIODATA32_H, 0);
- rfu_counter++;
- break;
- }
- UPDATE_REG(COMM_SIODATA32_L, linkmem->rfu_bdata[1-vbaid][rfu_counter-1]&0xffff);
- UPDATE_REG(COMM_SIODATA32_H, linkmem->rfu_bdata[1-vbaid][rfu_counter-1]>>16);
- rfu_counter++;
- break;
-
- case 0xa6:
- if (linkid>0) {
- UPDATE_REG(COMM_SIODATA32_L, rfu_masterdata[rfu_counter]&0xffff);
- UPDATE_REG(COMM_SIODATA32_H, rfu_masterdata[rfu_counter++]>>16);
- } else {
- UPDATE_REG(COMM_SIODATA32_L, linkmem->rfu_data[1-vbaid][rfu_counter]&0xffff);
- UPDATE_REG(COMM_SIODATA32_H, linkmem->rfu_data[1-vbaid][rfu_counter++]>>16);
- }
- break;
-
- case 0x93: // it seems like the game doesn't care about this value
- UPDATE_REG(COMM_SIODATA32_L, 0x1234); // put anything in here
- UPDATE_REG(COMM_SIODATA32_H, 0x0200); // also here, but it should be 0200
- break;
-
- case 0xa0:
- case 0xa1:
- UPDATE_REG(COMM_SIODATA32_L, 0x641b);
- UPDATE_REG(COMM_SIODATA32_H, 0x0000);
- break;
-
- case 0x9a:
- UPDATE_REG(COMM_SIODATA32_L, 0x61f9);
- UPDATE_REG(COMM_SIODATA32_H, 0);
- break;
-
- case 0x91:
- UPDATE_REG(COMM_SIODATA32_L, 0x00ff);
- UPDATE_REG(COMM_SIODATA32_H, 0x0000);
- break;
-
- default:
- UPDATE_REG(COMM_SIODATA32_L, 0x0173);
- UPDATE_REG(COMM_SIODATA32_H, 0x0000);
- break;
- }
- break;
- }
- transfer = 1;
- }
-
- if (rfu_polarity)
- value ^= 4; // sometimes it's the other way around
-
- default:
- return value;
- }
-}
-
-//////////////////////////////////////////////////////////////////////////
-// Probably from here down needs to be replaced with SFML goodness :)
-// tjm: what SFML goodness? SFML for network, yes, but not for IPC
-
-bool InitLink()
-{
+static ConnectionState InitIPC() {
linkid = 0;
#if (defined __WIN32__ || defined _WIN32)
if((mmf=CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(LINKDATA), LOCAL_LINK_NAME))==NULL){
systemMessage(0, N_("Error creating file mapping"));
- return false;
+ return LINK_ERROR;
}
if(GetLastError() == ERROR_ALREADY_EXISTS)
@@ -1059,7 +1235,7 @@ bool InitLink()
if((linkmem=(LINKDATA *)MapViewOfFile(mmf, FILE_MAP_WRITE, 0, 0, sizeof(LINKDATA)))==NULL){
CloseHandle(mmf);
systemMessage(0, N_("Error mapping file"));
- return false;
+ return LINK_ERROR;
}
#else
if((mmf = shm_open("/" LOCAL_LINK_NAME, O_RDWR|O_CREAT|O_EXCL, 0777)) < 0) {
@@ -1109,7 +1285,7 @@ bool InitLink()
close(mmf);
#endif
systemMessage(0, N_("5 or more GBAs not supported."));
- return false;
+ return LINK_ERROR;
}
if(vbaid == n)
linkmem->numgbas = n + 1;
@@ -1130,7 +1306,7 @@ bool InitLink()
CloseHandle(linksync[j]);
}
systemMessage(0, N_("Error opening event"));
- return false;
+ return LINK_ERROR;
}
#else
if((linksync[i] = sem_open(linkevent,
@@ -1148,13 +1324,227 @@ bool InitLink()
}
}
systemMessage(0, N_("Error opening event"));
- return false;
+ return LINK_ERROR;
}
#endif
}
- for(i=0;i<4;i++)
+
+ return LINK_OK;
+}
+
+static ConnectionState InitSocket() {
+ linkid = 0;
+
+ for(int i = 0; i < 4; i++)
linkdata[i] = 0xffff;
- return true;
+
+ if (lanlink.server) {
+ lanlink.connectedSlaves = 0;
+ // should probably use GetPublicAddress()
+ //sid->ShowServerIP(sf::IPAddress::GetLocalAddress());
+
+ // too bad Listen() doesn't take an address as well
+ // then again, old code used INADDR_ANY anyway
+ if (!lanlink.tcpsocket.Listen(IP_LINK_PORT))
+ // Note: old code closed socket & retried once on bind failure
+ return LINK_ERROR; // FIXME: error code?
+ else
+ return LINK_NEEDS_UPDATE;
+ } else {
+ lc.serverport = IP_LINK_PORT;
+
+ if (!lc.serveraddr.IsValid()) {
+ return LINK_ERROR;
+ } else {
+ lanlink.tcpsocket.SetBlocking(false);
+ sf::Socket::Status status = lanlink.tcpsocket.Connect(lc.serverport, lc.serveraddr);
+
+ if (status == sf::Socket::Error || status == sf::Socket::Disconnected)
+ return LINK_ERROR;
+ else
+ return LINK_NEEDS_UPDATE;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Probably from here down needs to be replaced with SFML goodness :)
+// tjm: what SFML goodness? SFML for network, yes, but not for IPC
+
+ConnectionState InitLink(LinkMode mode)
+{
+ // Do nothing if we are already connected
+ if (GetLinkMode() != LINK_DISCONNECTED) {
+ systemMessage(0, N_("Error, link already connected"));
+ return LINK_ERROR;
+ }
+
+ // Find the link driver
+ linkDriver = NULL;
+ for (u8 i = 0; i < sizeof(linkDrivers) / sizeof(linkDrivers[0]); i++) {
+ if (linkDrivers[i].mode == mode) {
+ linkDriver = &linkDrivers[i];
+ break;
+ }
+ }
+
+ if (linkDriver == NULL) {
+ systemMessage(0, N_("Unable to find link driver"));
+ return LINK_ERROR;
+ }
+
+ // Connect the link
+ gba_connection_state = linkDriver->connect();
+
+ if (gba_connection_state == LINK_ERROR) {
+ CloseLink();
+ }
+
+ return gba_connection_state;
+}
+
+static ConnectionState ConnectUpdateSocket(char * const message, size_t size) {
+ ConnectionState newState = LINK_NEEDS_UPDATE;
+
+ if (lanlink.server) {
+ sf::Selector fdset;
+ fdset.Add(lanlink.tcpsocket);
+
+ if (fdset.Wait(0.1) == 1) {
+ int nextSlave = lanlink.connectedSlaves + 1;
+
+ sf::Socket::Status st = lanlink.tcpsocket.Accept(ls.tcpsocket[nextSlave]);
+
+ if (st == sf::Socket::Error) {
+ for (int j = 1; j < nextSlave; j++)
+ ls.tcpsocket[j].Close();
+
+ snprintf(message, size, N_("Network error."));
+ newState = LINK_ERROR;
+ } else {
+ sf::Packet packet;
+ packet << static_cast(nextSlave)
+ << static_cast(lanlink.numslaves);
+
+ ls.tcpsocket[nextSlave].Send(packet);
+
+ snprintf(message, size, N_("Player %d connected"), nextSlave);
+
+ lanlink.connectedSlaves++;
+ }
+ }
+
+ if (lanlink.numslaves == lanlink.connectedSlaves) {
+ for (int i = 1; i <= lanlink.numslaves; i++) {
+ sf::Packet packet;
+ packet << true;
+
+ ls.tcpsocket[i].Send(packet);
+ }
+
+ snprintf(message, size, N_("All players connected"));
+ newState = LINK_OK;
+ }
+ } else {
+
+ sf::Packet packet;
+ sf::Socket::Status status = lanlink.tcpsocket.Receive(packet);
+
+ if (status == sf::Socket::Error || status == sf::Socket::Disconnected) {
+ snprintf(message, size, N_("Network error."));
+ newState = LINK_ERROR;
+ } else if (status == sf::Socket::Done) {
+
+ if (linkid == 0) {
+ sf::Uint16 receivedId, receivedSlaves;
+ packet >> receivedId >> receivedSlaves;
+
+ if (packet) {
+ linkid = receivedId;
+ lanlink.numslaves = receivedSlaves;
+
+ snprintf(message, size, N_("Connected as #%d, Waiting for %d players to join"),
+ linkid + 1, lanlink.numslaves - linkid);
+ }
+ } else {
+ bool gameReady;
+ packet >> gameReady;
+
+ if (packet && gameReady) {
+ newState = LINK_OK;
+ snprintf(message, size, N_("All players joined."));
+ }
+ }
+
+ sf::Selector fdset;
+ fdset.Add(lanlink.tcpsocket);
+ fdset.Wait(0.1);
+ }
+ }
+
+ return newState;
+}
+
+ConnectionState ConnectLinkUpdate(char * const message, size_t size)
+{
+ message[0] = '\0';
+
+ if (!linkDriver || gba_connection_state != LINK_NEEDS_UPDATE) {
+ gba_connection_state = LINK_ERROR;
+ snprintf(message, size, N_("Link connection does not need updates."));
+
+ return LINK_ERROR;
+ }
+
+ gba_connection_state = linkDriver->connectUpdate(message, size);
+
+ return gba_connection_state;
+}
+
+void EnableLinkServer(bool enable, int numSlaves) {
+ lanlink.server = enable;
+ lanlink.numslaves = numSlaves;
+}
+
+void EnableSpeedHacks(bool enable) {
+ lanlink.speed = enable;
+}
+
+bool SetLinkServerHost(const char *host) {
+ sf::IPAddress addr = sf::IPAddress(host);
+
+ lc.serveraddr = addr;
+ joybusHostAddr = addr;
+
+ return addr.IsValid();
+}
+
+void GetLinkServerHost(char * const host, size_t size) {
+ if (host == NULL || size == 0)
+ return;
+
+ host[0] = '\0';
+
+ if (linkDriver && linkDriver->mode == LINK_GAMECUBE_DOLPHIN)
+ strncpy(host, joybusHostAddr.ToString().c_str(), size);
+ else if (lanlink.server)
+ strncpy(host, sf::IPAddress::GetLocalAddress().ToString().c_str(), size);
+ else
+ strncpy(host, lc.serveraddr.ToString().c_str(), size);
+}
+
+void SetLinkTimeout(int value) {
+ linktimeout = value;
+}
+
+int GetLinkPlayerId() {
+ if (GetLinkMode() == LINK_DISCONNECTED) {
+ return -1;
+ } else if (linkid > 0) {
+ return linkid;
+ } else {
+ return vbaid;
+ }
}
static void ReInitLink()
@@ -1172,26 +1562,7 @@ static void ReInitLink()
systemScreenMessage(_("Lost link; reconnected"));
}
-void CloseLink(void){
- if(lanlink.connected){
- if(linkid){
- char outbuffer[4];
- outbuffer[0] = 4;
- outbuffer[1] = -32;
- if(lanlink.type==0) lanlink.tcpsocket.Send(outbuffer, 4);
- } else {
- char outbuffer[12];
- int i;
- outbuffer[0] = 12;
- outbuffer[1] = -32;
- for(i=1;i<=lanlink.numslaves;i++){
- if(lanlink.type==0){
- ls.tcpsocket[i].Send(outbuffer, 12);
- }
- ls.tcpsocket[i].Close();
- }
- }
- }
+static void CloseIPC() {
int f = linkmem->linkflags;
f &= ~(1 << linkid);
if(f & 0xf) {
@@ -1231,6 +1602,37 @@ void CloseLink(void){
munmap(linkmem, sizeof(LINKDATA));
close(mmf);
#endif
+}
+
+static void CloseSocket() {
+ if(linkid){
+ char outbuffer[4];
+ outbuffer[0] = 4;
+ outbuffer[1] = -32;
+ if(lanlink.type==0) lanlink.tcpsocket.Send(outbuffer, 4);
+ } else {
+ char outbuffer[12];
+ int i;
+ outbuffer[0] = 12;
+ outbuffer[1] = -32;
+ for(i=1;i<=lanlink.numslaves;i++){
+ if(lanlink.type==0){
+ ls.tcpsocket[i].Send(outbuffer, 12);
+ }
+ ls.tcpsocket[i].Close();
+ }
+ }
+ lanlink.tcpsocket.Close();
+}
+
+void CloseLink(void){
+ if (!linkDriver) {
+ return; // Nothing to do
+ }
+
+ linkDriver->close();
+ linkDriver = NULL;
+
return;
}
@@ -1257,81 +1659,6 @@ lserver::lserver(void){
oncewait = false;
}
-bool lserver::Init(ServerInfoDisplay *sid){
- // too bad Listen() doesn't take an address as well
- // then again, old code used INADDR_ANY anyway
- if(!lanlink.tcpsocket.Listen(IP_LINK_PORT))
- // Note: old code closed socket & retried once on bind failure
- return false; // FIXME: error code?
-
- if(lanlink.thread!=NULL){
- lanlink.terminate = true;
- WaitForSingleObject(linksync[vbaid], 500);
- lanlink.thread = NULL;
- }
- lanlink.terminate = false;
- linkid = 0;
-
- // should probably use GetPublicAddress()
- sid->ShowServerIP(sf::IPAddress::GetLocalAddress());
-
- lanlink.thread = new sf::Thread(LinkServerThread, sid);
- lanlink.thread->Launch();
-
- return true;
-
-}
-
-void LinkServerThread(void *_sid){
- ServerInfoDisplay *sid = (ServerInfoDisplay *)_sid;
- sf::Selector fdset;
- char inbuffer[256], outbuffer[256];
- s32 *intinbuffer = (s32*)inbuffer;
- u16 *u16inbuffer = (u16*)inbuffer;
- s32 *intoutbuffer = (s32*)outbuffer;
- u16 *u16outbuffer = (u16*)outbuffer;
-
- i = 0;
-
- while(iShowConnect(i);
- }
- }
- sid->Ping();
- }
-
- lanlink.connected = true;
-
- sid->Connected();
-
- for(i=1;i<=lanlink.numslaves;i++){
- outbuffer[0] = 4;
- ls.tcpsocket[i].Send(outbuffer, 4);
- }
-
-CloseInfoDisplay:
- delete sid;
- return;
-}
-
void lserver::Send(void){
if(lanlink.type==0){ // TCP
if(savedlinktime==-1){
@@ -1398,7 +1725,6 @@ void lserver::Recv(void){
if(howmanytimes>1) memmove(inbuffer, inbuffer+inbuffer[0]*(howmanytimes-1), inbuffer[0]);
if(inbuffer[1]==-32){
char message[30];
- lanlink.connected = false;
sprintf(message, _("Player %d disconnected."), i+2);
systemScreenMessage(message);
outbuffer[0] = 4;
@@ -1409,6 +1735,7 @@ void lserver::Recv(void){
tcpsocket[i].Receive(inbuffer, 256, nr);
tcpsocket[i].Close();
}
+ CloseLink();
return;
}
linkdata[i+1] = READ16LE(&u16inbuffer[1]);
@@ -1419,6 +1746,13 @@ void lserver::Recv(void){
return;
}
+void CheckLinkConnection() {
+ if (GetLinkMode() == LINK_CABLE_SOCKET) {
+ if (linkid && lc.numtransfers == 0) {
+ lc.CheckConn();
+ }
+ }
+}
// Client
lclient::lclient(void){
@@ -1430,92 +1764,6 @@ lclient::lclient(void){
return;
}
-bool lclient::Init(sf::IPAddress addr, ClientInfoDisplay *cid){
- serveraddr = addr;
- serverport = IP_LINK_PORT;
- lanlink.tcpsocket.SetBlocking(false);
-
- if(lanlink.thread!=NULL){
- lanlink.terminate = true;
- WaitForSingleObject(linksync[vbaid], 500);
- lanlink.thread = NULL;
- }
-
- cid->ConnectStart(addr);
- lanlink.terminate = false;
- lanlink.thread = new sf::Thread(LinkClientThread, cid);
- lanlink.thread->Launch();
- return true;
-}
-
-void LinkClientThread(void *_cid){
- ClientInfoDisplay *cid = (ClientInfoDisplay *)_cid;
- sf::Selector fdset;
- int numbytes;
- char inbuffer[16];
- u16 *u16inbuffer = (u16*)inbuffer;
- unsigned long block = 0;
-
- while(lanlink.tcpsocket.Connect(lc.serverport, lc.serveraddr) != sf::Socket::Done) {
- // stupid SFML has no way of giving what sort of error occurred
- // so we'll just have to do a retry loop, I guess.
- cid->Ping();
- if(lanlink.terminate)
- goto CloseInfoDisplay;
- // old code had broken sleep on socket, which isn't
- // even connected yet
- // corrected sleep on socket worked, but this is more sane
- // and probably less portable... works with mingw32 at least
-#if (defined __WIN32__ || defined _WIN32)
- Sleep(100); // in milliseconds
-#else
- usleep(100000); // in microseconds
-#endif
- }
-
- numbytes = 0;
- size_t got;
- while(numbytes<4) {
- lanlink.tcpsocket.Receive(inbuffer+numbytes, 4 - numbytes, got);
- numbytes += got;
- fdset.Clear();
- fdset.Add(lanlink.tcpsocket);
- fdset.Wait(0.1);
- cid->Ping();
- if(lanlink.terminate) {
- lanlink.tcpsocket.Close();
- goto CloseInfoDisplay;
- }
- }
- linkid = (int)READ16LE(&u16inbuffer[0]);
- lanlink.numslaves = (int)READ16LE(&u16inbuffer[1]);
-
- cid->ShowConnect(linkid + 1, lanlink.numslaves - linkid);
-
- numbytes = 0;
- inbuffer[0] = 1;
- while(numbytesPing();
- if(lanlink.terminate) {
- lanlink.tcpsocket.Close();
- goto CloseInfoDisplay;
- }
- }
-
- lanlink.connected = true;
-
- cid->Connected();
-
-CloseInfoDisplay:
- delete cid;
- return;
-}
-
void lclient::CheckConn(void){
size_t nr;
lanlink.tcpsocket.Receive(inbuffer, 1, nr);
@@ -1528,8 +1776,8 @@ void lclient::CheckConn(void){
if(inbuffer[1]==-32){
outbuffer[0] = 4;
lanlink.tcpsocket.Send(outbuffer, 4);
- lanlink.connected = false;
systemScreenMessage(_("Server disconnected."));
+ CloseLink();
return;
}
numtransfers = 1;
@@ -1567,8 +1815,8 @@ void lclient::Recv(void){
if(inbuffer[1]==-32){
outbuffer[0] = 4;
lanlink.tcpsocket.Send(outbuffer, 4);
- lanlink.connected = false;
systemScreenMessage(_("Server disconnected."));
+ CloseLink();
return;
}
tspeed = inbuffer[1] & 3;
diff --git a/src/gba/GBALink.h b/src/gba/GBALink.h
index e9291605..bce14942 100644
--- a/src/gba/GBALink.h
+++ b/src/gba/GBALink.h
@@ -1,32 +1,152 @@
#ifndef GBA_GBALINK_H
#define GBA_GBALINK_H
-#pragma once
+/**
+ * Link modes to be passed to InitLink
+ */
+enum LinkMode
+{
+ LINK_DISCONNECTED,
+ LINK_CABLE_IPC,
+ LINK_CABLE_SOCKET,
+ LINK_RFU_IPC,
+ LINK_GAMECUBE_DOLPHIN
+};
-// register definitions; these are always present
+/**
+ * State of the connection attempt
+ */
+enum ConnectionState
+{
+ LINK_OK,
+ LINK_ERROR,
+ LINK_NEEDS_UPDATE,
+ LINK_ABORT
+};
-#define UNSUPPORTED -1
-#define MULTIPLAYER 0
-#define NORMAL8 1
-#define NORMAL32 2
-#define UART 3
-#define JOYBUS 4
-#define GP 5
+/**
+ * Initialize GBA linking
+ *
+ * @param mode Device to emulate, plugged to the GBA link port.
+ * @return success
+ */
+extern ConnectionState InitLink(LinkMode mode);
-#define RFU_INIT 0
-#define RFU_COMM 1
-#define RFU_SEND 2
-#define RFU_RECV 3
+/**
+ * Update a link connection request
+ *
+ * @param message Information message
+ * @param size Maximum message size
+ */
+extern ConnectionState ConnectLinkUpdate(char * const message, size_t size);
+/**
+ * Get the currently enabled link mode
+ *
+ * @return link mode
+ */
+extern LinkMode GetLinkMode();
+
+/**
+ * Is this instance going to host a LAN link server?
+ *
+ * @param enabled Server mode
+ * @param numSlaves Number of expected clients
+ */
+extern void EnableLinkServer(bool enable, int numSlaves);
+
+/**
+ * Should speed hacks be used?
+ *
+ * @param enabled Speed hacks
+ */
+extern void EnableSpeedHacks(bool enable);
+
+/**
+ * Set the host to connect to when in socket mode
+ *
+ * @return false if the address is invalid
+ */
+extern bool SetLinkServerHost(const char *host);
+
+/**
+ * Get the host relevant to context
+ *
+ * If in lan server mode, returns the external IP adress
+ * If in lan client mode, returns the IP adress of the host to connect to
+ * If in gamecube mode, returns the IP adress of the dolphin host
+ *
+ */
+extern void GetLinkServerHost(char * const host, size_t size);
+
+/**
+ * Set the value in milliseconds of the timeout after which a connection is
+ * deemed lost.
+ *
+ * @param value timeout
+ */
+extern void SetLinkTimeout(int value);
+
+/**
+ * Verify that the link between the emulators is still active
+ */
+extern void CheckLinkConnection();
+
+/**
+ * Set the current link mode to LINK_DISCONNECTED
+ */
+extern void CloseLink();
+
+/**
+ * Get the id of the player of this VBA instance
+ *
+ * @return id -1 means disconnected, 0 means master, > 0 means slave
+ */
+extern int GetLinkPlayerId();
+
+/**
+ * Start a link transfer
+ *
+ * @param siocnt the value of SIOCNT to be written
+ */
+extern void StartLink(u16 siocnt);
+
+/**
+ * Start a general purpose link transfer
+ *
+ * @param rcnt the value of RCNT to be written
+ */
+extern void StartGPLink(u16 rcnt);
+
+/**
+ * Emulate the linked device
+ */
+extern void LinkUpdate(int);
+
+/**
+ * Clean up IPC shared memory
+ */
+extern void CleanLocalLink();
+
+/**
+ * Append the current VBA ID to a filemane
+ *
+ * @param Input filename to complete
+ * @return completed filename
+ */
+
+extern const char *MakeInstanceFilename(const char *Input);
+
+// register definitions
#define COMM_SIODATA32_L 0x120
#define COMM_SIODATA32_H 0x122
#define COMM_SIOCNT 0x128
#define COMM_SIODATA8 0x12a
-#define COMM_SIOMLT_SEND 0x12a
-#define COMM_SIOMULTI0 0x120
-#define COMM_SIOMULTI1 0x122
-#define COMM_SIOMULTI2 0x124
-#define COMM_SIOMULTI3 0x126
+#define COMM_SIOMLT_SEND 0x12a
+#define COMM_SIOMULTI0 0x120
+#define COMM_SIOMULTI1 0x122
+#define COMM_SIOMULTI2 0x124
+#define COMM_SIOMULTI3 0x126
#define COMM_RCNT 0x134
#define COMM_JOYCNT 0x140
#define COMM_JOY_RECV_L 0x150
@@ -43,146 +163,4 @@
#define JOYCNT_SEND_COMPLETE 4
#define JOYCNT_INT_ENABLE 0x40
-enum
-{
- JOY_CMD_RESET = 0xff,
- JOY_CMD_STATUS = 0x00,
- JOY_CMD_READ = 0x14,
- JOY_CMD_WRITE = 0x15
-};
-
-extern const char *MakeInstanceFilename(const char *Input);
-
-#ifndef NO_LINK
-// Link implementation
-#include
-#include
-
-class ServerInfoDisplay
-{
-public:
- virtual void ShowServerIP(const sf::IPAddress& addr) = 0;
- virtual void ShowConnect(const int player) = 0;
- virtual void Ping() = 0;
- virtual void Connected() = 0;
-};
-
-typedef struct {
- u16 linkdata[5];
- u16 linkcmd;
- u16 numtransfers;
- int lastlinktime;
- u8 numgbas;
- u8 trgbas;
- u8 linkflags;
- int rfu_q[4];
- u8 rfu_request[4];
- int rfu_linktime[4];
- u32 rfu_bdata[4][7];
- u32 rfu_data[4][32];
-} LINKDATA;
-
-class lserver{
- int numbytes;
- sf::Selector fdset;
- //timeval udptimeout;
- char inbuffer[256], outbuffer[256];
- s32 *intinbuffer;
- u16 *u16inbuffer;
- s32 *intoutbuffer;
- u16 *u16outbuffer;
- int counter;
- int done;
-public:
- int howmanytimes;
- sf::SocketTCP tcpsocket[4];
- sf::IPAddress udpaddr[4];
- lserver(void);
- bool Init(ServerInfoDisplay *);
- void Send(void);
- void Recv(void);
-};
-
-class ClientInfoDisplay {
-public:
- virtual void ConnectStart(const sf::IPAddress& addr) = 0;
- virtual void Ping() = 0;
- virtual void ShowConnect(const int player, const int togo) = 0;
- virtual void Connected() = 0;
-};
-
-class lclient{
- sf::Selector fdset;
- char inbuffer[256], outbuffer[256];
- s32 *intinbuffer;
- u16 *u16inbuffer;
- s32 *intoutbuffer;
- u16 *u16outbuffer;
- int numbytes;
-public:
- sf::IPAddress serveraddr;
- unsigned short serverport;
- sf::SocketTCP noblock;
- int numtransfers;
- lclient(void);
- bool Init(sf::IPAddress, ClientInfoDisplay *);
- void Send(void);
- void Recv(void);
- void CheckConn(void);
-};
-
-typedef struct {
- sf::SocketTCP tcpsocket;
- //sf::SocketUDP udpsocket;
- int numslaves;
- sf::Thread *thread;
- int type;
- bool server;
- bool terminate;
- bool connected;
- bool speed;
- bool active;
-} LANLINKDATA;
-
-extern bool gba_joybus_enabled;
-extern bool gba_joybus_active;
-extern bool gba_link_enabled;
-
-extern sf::IPAddress joybusHostAddr;
-extern void JoyBusConnect();
-extern void JoyBusShutdown();
-extern void JoyBusUpdate(int ticks);
-
-extern bool InitLink();
-extern void CloseLink();
-extern void StartLink(u16);
-extern void StartGPLink(u16);
-extern void LinkUpdate(int);
-extern void CleanLocalLink();
-extern LANLINKDATA lanlink;
-extern int vbaid;
-extern bool rfu_enabled;
-extern int linktimeout;
-extern lclient lc;
-extern lserver ls;
-extern int linkid;
-
-#else
-
-// stubs to keep #ifdef's out of mainline
-const bool gba_joybus_enabled = false;
-const bool gba_link_enabled = false;
-
-inline void JoyBusConnect() { }
-inline void JoyBusShutdown() { }
-inline void JoyBusUpdate(int) { }
-
-inline bool InitLink() { return true; }
-inline void CloseLink() { }
-inline void StartLink(u16) { }
-inline void StartGPLink(u16) { }
-inline void LinkUpdate(int) { }
-inline void CleanLocalLink() { }
-#endif
-
#endif /* GBA_GBALINK_H */
diff --git a/src/gba/GBASockClient.h b/src/gba/GBASockClient.h
index fb4bdd24..4c96367c 100644
--- a/src/gba/GBASockClient.h
+++ b/src/gba/GBASockClient.h
@@ -3,12 +3,13 @@
#include
#include "../common/Types.h"
-class GBASockClient : public sf::SocketTCP
+class GBASockClient
{
public:
- GBASockClient(sf::IPAddress server_addr);
+ GBASockClient(sf::IPAddress _server_addr);
~GBASockClient();
+ bool Connect(sf::IPAddress server_addr);
void Send(std::vector data);
char ReceiveCmd(char* data_in, bool block);
void ReceiveClock(bool block);
diff --git a/src/win32/JoybusOptions.cpp b/src/win32/JoybusOptions.cpp
deleted file mode 100644
index fe3e1c76..00000000
--- a/src/win32/JoybusOptions.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-#ifndef NO_LINK
-
-#include "stdafx.h"
-#include "vba.h"
-#include "JoybusOptions.h"
-#include "../gba/GBALink.h"
-
-// JoybusOptions dialog
-
-IMPLEMENT_DYNAMIC(JoybusOptions, CDialog)
-
-JoybusOptions::JoybusOptions(CWnd* pParent /*=NULL*/)
- : CDialog(JoybusOptions::IDD, pParent)
-{
-}
-
-JoybusOptions::~JoybusOptions()
-{
-}
-
-void JoybusOptions::DoDataExchange(CDataExchange* pDX)
-{
- CDialog::DoDataExchange(pDX);
- DDX_Control(pDX, IDC_JOYBUS_ENABLE, enable_check);
- DDX_Control(pDX, IDC_JOYBUS_HOSTNAME, hostname);
-}
-
-BEGIN_MESSAGE_MAP(JoybusOptions, CDialog)
- ON_BN_CLICKED(IDC_JOYBUS_ENABLE, &JoybusOptions::OnBnClickedJoybusEnable)
- ON_BN_CLICKED(IDOK, &JoybusOptions::OnBnClickedOk)
-END_MESSAGE_MAP()
-
-BOOL JoybusOptions::OnInitDialog()
-{
- CDialog::OnInitDialog();
-
- enable_check.SetCheck(gba_joybus_enabled ? BST_CHECKED : BST_UNCHECKED);
-
- hostname.EnableWindow(enable_check.GetCheck() == BST_CHECKED);
-
- hostname.SetWindowText(joybusHostAddr.ToString().c_str());
-
- return TRUE;
-}
-
-void JoybusOptions::OnBnClickedJoybusEnable()
-{
- hostname.EnableWindow(enable_check.GetCheck() == BST_CHECKED);
-}
-
-void JoybusOptions::OnBnClickedOk()
-{
- if ( (hostname.GetWindowTextLength() == 0)
- && (enable_check.GetCheck() == BST_CHECKED) )
- {
- hostname.SetWindowText("Enter IP or Hostname");
- return;
- }
-
- gba_joybus_enabled = enable_check.GetCheck() == BST_CHECKED;
-
- CString address;
- hostname.GetWindowText(address);
-
- sf::IPAddress new_server;
- new_server = std::string(address);
-
- if (!new_server.IsValid())
- {
- hostname.SetWindowText("Enter IP or Hostname");
- return;
- }
-
- joybusHostAddr = new_server;
- JoyBusConnect();
-
- OnOK();
-}
-
-#endif // NO_LINK
diff --git a/src/win32/JoybusOptions.h b/src/win32/JoybusOptions.h
deleted file mode 100644
index bfbda832..00000000
--- a/src/win32/JoybusOptions.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#pragma once
-#include "afxwin.h"
-
-// JoybusOptions dialog
-
-class JoybusOptions : public CDialog
-{
- DECLARE_DYNAMIC(JoybusOptions)
-
-public:
- JoybusOptions(CWnd* pParent = NULL); // standard constructor
- virtual ~JoybusOptions();
-
-// Dialog Data
- enum { IDD = IDD_JOYBUS_DIALOG };
-
-protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
-
- DECLARE_MESSAGE_MAP()
-public:
- virtual BOOL OnInitDialog();
- afx_msg void OnBnClickedJoybusEnable();
- CButton enable_check;
- CEdit hostname;
- afx_msg void OnBnClickedOk();
-};
diff --git a/src/win32/LinkOptions.cpp b/src/win32/LinkOptions.cpp
index dd04a08e..463936df 100644
--- a/src/win32/LinkOptions.cpp
+++ b/src/win32/LinkOptions.cpp
@@ -5,39 +5,46 @@
#include "LinkOptions.h"
#include "../gba/GBALink.h"
-extern lserver ls;
-
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
+template
+void DDX_CBData(CDataExchange* pDX, int nIDC, T& data)
+{
+ HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
+ if (pDX->m_bSaveAndValidate)
+ {
+ int index = static_cast(::SendMessage(hWndCtrl, CB_GETCURSEL, 0, 0L));
+ data = (index == CB_ERR ? NULL : static_cast(::SendMessage(hWndCtrl, CB_GETITEMDATA, index, 0L)));
+ }
+ else
+ {
+ int count = static_cast(::SendMessage(hWndCtrl, CB_GETCOUNT, 0, 0L));
+ for (int i = 0; i != count; ++i)
+ {
+ if (static_cast(::SendMessage(hWndCtrl, CB_GETITEMDATA, i, 0L)) == data)
+ {
+ ::SendMessage(hWndCtrl, CB_SETCURSEL, i, 0L);
+ return;
+ }
+ }
+ ::SendMessage(hWndCtrl, CB_SETCURSEL, -1, 0L);
+ }
+}
+
/////////////////////////////////////////////////////////////////////////////
// LinkOptions dialog
-CMyTabCtrl::CMyTabCtrl(){
- m_tabdialog[0] = new LinkGeneral;
- m_tabdialog[1] = new LinkServer;
- m_tabdialog[2] = new LinkClient;
-}
-
-CMyTabCtrl::~CMyTabCtrl()
-{
- m_tabdialog[0]->DestroyWindow();
- m_tabdialog[1]->DestroyWindow();
- m_tabdialog[2]->DestroyWindow();
-
- delete m_tabdialog[0];
- delete m_tabdialog[1];
- delete m_tabdialog[2];
-}
-
LinkOptions::LinkOptions(CWnd* pParent /*=NULL*/)
: CDialog(LinkOptions::IDD, pParent)
{
//{{AFX_DATA_INIT(LinkOptions)
- // NOTE: the ClassWizard will add member initialization here
+ m_numplayers = 0;
+ m_type = theApp.linkMode;
+ m_server = FALSE;
//}}AFX_DATA_INIT
}
@@ -46,55 +53,52 @@ void LinkOptions::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(LinkOptions)
+ DDX_CBData(pDX, IDC_LINK_MODE, m_type);
+ DDX_Control(pDX, IDC_LINKTIMEOUT, m_timeout);
+ DDX_Control(pDX, IDC_LINK_MODE, m_mode);
+ DDX_Control(pDX, IDC_SERVERIP, m_serverip);
+ DDX_Check(pDX, IDC_SSPEED, m_hacks);
+ DDX_Radio(pDX, IDC_LINK2P, m_numplayers);
+ DDX_Radio(pDX, IDC_LINK_CLIENT, m_server);
//}}AFX_DATA_MAP
}
BOOL LinkOptions::OnInitDialog(){
- TCITEM tabitem;
- char tabtext[3][8] = {"General", "Server", "Client"};
- int i;
+ char timeout[6];
CDialog::OnInitDialog();
- m_tabctrl.SubclassDlgItem(IDC_TAB1, this);
+ AddMode("Nothing (Disconnect)", LINK_DISCONNECTED);
+ AddMode("Cable - Single Computer", LINK_CABLE_IPC);
+ AddMode("Cable - Network", LINK_CABLE_SOCKET);
+ AddMode("GameCube - Dolphin", LINK_GAMECUBE_DOLPHIN);
+ AddMode("Wireless adapter - Single Computer", LINK_RFU_IPC);
- tabitem.mask = TCIF_TEXT;
+ sprintf(timeout, "%d", theApp.linkTimeout);
- for(i=0;i<3;i++){
- tabitem.pszText = tabtext[i];
- m_tabctrl.InsertItem(i, &tabitem);
- }
- m_tabctrl.m_tabdialog[0]->Create(IDD_LINKTAB1, this);
- m_tabctrl.m_tabdialog[1]->Create(IDD_LINKTAB2, this);
- m_tabctrl.m_tabdialog[2]->Create(IDD_LINKTAB3, this);
+ m_timeout.LimitText(5);
+ m_timeout.SetWindowText(timeout);
- m_tabctrl.m_tabdialog[0]->ShowWindow(SW_SHOW);
- m_tabctrl.m_tabdialog[1]->ShowWindow(SW_HIDE);
- m_tabctrl.m_tabdialog[2]->ShowWindow(SW_HIDE);
+ m_serverip.SetWindowText(theApp.linkHost);
- m_tabctrl.SetCurSel(0);
- m_tabctrl.OnSwitchTabs();
+ UpdateAvailability();
+
+ UpdateData(FALSE);
return TRUE;
}
- BOOL LinkOptions::PreTranslateMessage(MSG* pMsg)
- {
- return m_tabctrl.TranslatePropSheetMsg(pMsg) ? TRUE :
- CDialog::PreTranslateMessage(pMsg);
- }
-
-
-
-
-BEGIN_MESSAGE_MAP(LinkOptions, CDialog)
+ BEGIN_MESSAGE_MAP(LinkOptions, CDialog)
//{{AFX_MSG_MAP(LinkOptions)
- ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, OnSelchangeTab1)
+ ON_CBN_SELCHANGE(IDC_LINK_MODE, &LinkOptions::OnCbnSelchangeLinkMode)
ON_BN_CLICKED(ID_OK, OnOk)
ON_BN_CLICKED(ID_CANCEL, OnCancel)
+ ON_BN_CLICKED(IDC_LINK_SERVER, &LinkOptions::OnBnClickedLinkServer)
+ ON_BN_CLICKED(IDC_LINK_CLIENT, &LinkOptions::OnBnClickedLinkClient)
//}}AFX_MSG_MAP
-END_MESSAGE_MAP()
+
+ END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// LinkOptions message handlers
@@ -102,584 +106,123 @@ END_MESSAGE_MAP()
// LinkGeneral dialog
-LinkGeneral::LinkGeneral(CWnd* pParent /*=NULL*/)
- : CDialog(LinkGeneral::IDD, pParent)
-{
- //{{AFX_DATA_INIT(LinkGeneral)
- //}}AFX_DATA_INIT
+void LinkOptions::AddMode(LPCTSTR name, int value) {
+ m_mode.AddString(name);
+ int index = m_mode.FindStringExact(-1, name);
+ m_mode.SetItemData(index, value);
}
-void LinkGeneral::DoDataExchange(CDataExchange* pDX)
-{
- CDialog::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(LinkGeneral)
- DDX_Radio(pDX, IDC_LINK_SINGLE, m_type);
- DDX_Control(pDX, IDC_LINKTIMEOUT, m_timeout);
- //}}AFX_DATA_MAP
-}
-
-
-BEGIN_MESSAGE_MAP(LinkGeneral, CDialog)
- //{{AFX_MSG_MAP(LinkGeneral)
- ON_BN_CLICKED(IDC_LINK_SINGLE, OnRadio1)
- ON_BN_CLICKED(IDC_LINK_LAN, OnRadio2)
- //}}AFX_MSG_MAP
-END_MESSAGE_MAP()
-
-/////////////////////////////////////////////////////////////////////////////
-// LinkGeneral message handlers
-/////////////////////////////////////////////////////////////////////////////
-// LinkServer dialog
-
-
-LinkServer::LinkServer(CWnd* pParent /*=NULL*/)
- : CDialog(LinkServer::IDD, pParent)
-{
- //{{AFX_DATA_INIT(LinkServer)
- m_numplayers = -1;
- m_prottype = -1;
- m_speed = FALSE;
- //}}AFX_DATA_INIT
-}
-
-
-void LinkServer::DoDataExchange(CDataExchange* pDX)
-{
- CDialog::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(LinkServer)
- DDX_Radio(pDX, IDC_LINK2P, m_numplayers);
- DDX_Radio(pDX, IDC_LINKTCP, m_prottype);
- DDX_Check(pDX, IDC_SSPEED, m_speed);
- //}}AFX_DATA_MAP
-}
-
-
-BEGIN_MESSAGE_MAP(LinkServer, CDialog)
- //{{AFX_MSG_MAP(LinkServer)
- ON_BN_CLICKED(IDC_SERVERSTART, OnServerStart)
- //}}AFX_MSG_MAP
-END_MESSAGE_MAP()
-
-/////////////////////////////////////////////////////////////////////////////
-// LinkServer message handlers
-
-LinkClient::LinkClient(CWnd* pParent /*=NULL*/)
- : CDialog(LinkClient::IDD, pParent)
-{
- //{{AFX_DATA_INIT(LinkClient)
- m_prottype = -1;
- m_hacks = -1;
- //}}AFX_DATA_INIT
-}
-
-
-void LinkClient::DoDataExchange(CDataExchange* pDX)
-{
- CDialog::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(LinkClient)
- DDX_Control(pDX, IDC_SERVERIP, m_serverip);
- DDX_Radio(pDX, IDC_CLINKTCP, m_prottype);
- DDX_Radio(pDX, IDC_SPEEDOFF, m_hacks);
- //}}AFX_DATA_MAP
-}
-
-
-BEGIN_MESSAGE_MAP(LinkClient, CDialog)
- //{{AFX_MSG_MAP(LinkClient)
- ON_BN_CLICKED(IDC_LINKCONNECT, OnLinkConnect)
- //}}AFX_MSG_MAP
-END_MESSAGE_MAP()
-
-/////////////////////////////////////////////////////////////////////////////
-// LinkClient message handlers
-
-BOOL LinkServer::OnInitDialog()
-{
- CDialog::OnInitDialog();
-
- m_numplayers = lanlink.numslaves;
- m_prottype = lanlink.type;
- m_speed = lanlink.speed;
-
- UpdateData(FALSE);
-
- return TRUE;
-}
-
-void LinkOptions::OnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult)
-{
- m_tabctrl.OnSwitchTabs();
- *pResult = 0;
-}
-
-IMPLEMENT_DYNAMIC(CMyTabCtrl, CTabCtrl)
-BEGIN_MESSAGE_MAP(CMyTabCtrl, CTabCtrl)
- ON_NOTIFY_REFLECT(TCN_SELCHANGING, OnSelChanging)
-END_MESSAGE_MAP()
-
-BOOL CMyTabCtrl::SubclassDlgItem(UINT nID, CWnd* pParent)
-{
- if (!CTabCtrl::SubclassDlgItem(nID, pParent))
- return FALSE;
-
- ModifyStyle(0, TCS_OWNERDRAWFIXED);
-
- // If first tab is disabled, go to next enabled tab
- if (!IsTabEnabled(0)) {
- int iTab = NextEnabledTab(0, TRUE);
- SetActiveTab(iTab);
- }
- return TRUE;
-}
-
-BOOL CMyTabCtrl::IsTabEnabled(int iTab)
-{
- if (!lanlink.active && iTab > 0)
- return false;
- return true;
-}
-
-//////////////////
-// Draw the tab: mimic SysTabControl32, except use gray if tab is disabled
-//
-void CMyTabCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
-{
- DRAWITEMSTRUCT& ds = *lpDrawItemStruct;
-
- int iItem = ds.itemID;
-
- // Get tab item info
- char text[128];
- TCITEM tci;
- tci.mask = TCIF_TEXT;
- tci.pszText = text;
- tci.cchTextMax = sizeof(text);
- GetItem(iItem, &tci);
-
- // use draw item DC
- CDC dc;
- dc.Attach(ds.hDC);
-
- // calculate text rectangle and color
- CRect rc = ds.rcItem;
- rc += CPoint(1,4); // ?? by trial and error
-
- // draw the text
- OnDrawText(dc, rc, text, !IsTabEnabled(iItem));
-
- dc.Detach();
-}
-
-//////////////////
-// Draw tab text. You can override to use different color/font.
-//
-void CMyTabCtrl::OnDrawText(CDC& dc, CRect rc,
- CString sText, BOOL bDisabled)
-{
- dc.SetTextColor(GetSysColor(bDisabled ? COLOR_3DHILIGHT : COLOR_BTNTEXT));
- dc.DrawText(sText, &rc, DT_CENTER|DT_VCENTER);
-
- if (bDisabled) {
- // disabled: draw again shifted northwest for shadow effect
- rc += CPoint(-1,-1);
- dc.SetTextColor(GetSysColor(COLOR_GRAYTEXT));
- dc.DrawText(sText, &rc, DT_CENTER|DT_VCENTER);
- }
-}
-
-//////////////////
-// Selection is changing: disallow if tab is disabled
-//
-void CMyTabCtrl::OnSelChanging(NMHDR* pnmh, LRESULT* pRes)
-{
- TRACE("CMyTabCtrl::OnSelChanging\n");
-
- // Figure out index of new tab we are about to go to, as opposed
- // to the current one we're at. Believe it or not, Windows doesn't
- // pass this info
- //
- TC_HITTESTINFO htinfo;
- GetCursorPos(&htinfo.pt);
- ScreenToClient(&htinfo.pt);
- int iNewTab = HitTest(&htinfo);
-
- if (iNewTab >= 0 && !IsTabEnabled(iNewTab))
- *pRes = TRUE; // tab disabled: prevent selection
-}
-
-//////////////////
-// Trap arrow-left key to skip disabled tabs.
-// This is the only way to know where we're coming from--ie from
-// arrow-left (prev) or arrow-right (next).
-//
-BOOL CMyTabCtrl::PreTranslateMessage(MSG* pMsg)
-{
- if (pMsg->message == WM_KEYDOWN &&
- (pMsg->wParam == VK_LEFT || pMsg->wParam == VK_RIGHT)) {
-
- int iNewTab = (pMsg->wParam == VK_LEFT) ?
- PrevEnabledTab(GetCurSel(), FALSE) :
- NextEnabledTab(GetCurSel(), FALSE);
- if (iNewTab >= 0)
- SetActiveTab(iNewTab);
- return TRUE;
- }
- return CTabCtrl::PreTranslateMessage(pMsg);
-}
-
-////////////////
-// Translate parent property sheet message. Translates Control-Tab and
-// Control-Shift-Tab keys. These are normally handled by the property
-// sheet, so you must call this function from your prop sheet's
-// PreTranslateMessage function.
-//
-BOOL CMyTabCtrl::TranslatePropSheetMsg(MSG* pMsg)
-{
- WPARAM key = pMsg->wParam;
- if (pMsg->message == WM_KEYDOWN && GetAsyncKeyState(VK_CONTROL) < 0 &&
- (key == VK_TAB || key == VK_PRIOR || key == VK_NEXT)) {
-
- int iNewTab = (key==VK_PRIOR || GetAsyncKeyState(VK_SHIFT) < 0) ?
- PrevEnabledTab(GetCurSel(), TRUE) :
- NextEnabledTab(GetCurSel(), TRUE);
- if (iNewTab >= 0)
- SetActiveTab(iNewTab);
- return TRUE;
- }
- return FALSE;
-}
-
-//////////////////
-// Helper to set the active page, when moving backwards (left-arrow and
-// Control-Shift-Tab). Must simulate Windows messages to tell parent I
-// am changing the tab; SetCurSel does not do this!!
-//
-// In normal operation, this fn will always succeed, because I don't call it
-// unless I already know IsTabEnabled() = TRUE; but if you call SetActiveTab
-// with a random value, it could fail.
-//
-BOOL CMyTabCtrl::SetActiveTab(UINT iNewTab)
-{
- TRACE("CMyTabCtrl::SetActiveTab\n");
-
- // send the parent TCN_SELCHANGING
- NMHDR nmh;
- nmh.hwndFrom = m_hWnd;
- nmh.idFrom = GetDlgCtrlID();
- nmh.code = TCN_SELCHANGING;
-
- if (GetParent()->SendMessage(WM_NOTIFY, nmh.idFrom, (LPARAM)&nmh) >=0) {
- // OK to change: set the new tab
- SetCurSel(iNewTab);
-
- // send parent TCN_SELCHANGE
- nmh.code = TCN_SELCHANGE;
- GetParent()->SendMessage(WM_NOTIFY, nmh.idFrom, (LPARAM)&nmh);
- return TRUE;
- }
- return FALSE;
-}
-
-/////////////////
-// Return the index of the next enabled tab after a given index, or -1 if none
-// (0 = first tab).
-// If bWrap is TRUE, wrap from beginning to end; otherwise stop at zero.
-//
-int CMyTabCtrl::NextEnabledTab(int iCurrentTab, BOOL bWrap)
-{
- int nTabs = GetItemCount();
- for (int iTab = iCurrentTab+1; iTab != iCurrentTab; iTab++) {
- if (iTab >= nTabs) {
- if (!bWrap)
- return -1;
- iTab = 0;
- }
- if (IsTabEnabled(iTab)) {
- return iTab;
- }
- }
- return -1;
-}
-
-/////////////////
-// Return the index of the previous enabled tab before a given index, or -1.
-// (0 = first tab).
-// If bWrap is TRUE, wrap from beginning to end; otherwise stop at zero.
-//
-int CMyTabCtrl::PrevEnabledTab(int iCurrentTab, BOOL bWrap)
-{
- for (int iTab = iCurrentTab-1; iTab != iCurrentTab; iTab--) {
- if (iTab < 0) {
- if (!bWrap)
- return -1;
- iTab = GetItemCount() - 1;
- }
- if (IsTabEnabled(iTab)) {
- return iTab;
- }
- }
- return -1;
-}
-
-
-void CMyTabCtrl::OnSwitchTabs(void)
-{
- CRect clientRect, wndRect;
- int i;
-
- GetClientRect(clientRect);
- AdjustRect(FALSE, clientRect);
- GetWindowRect(wndRect);
- GetParent()->ScreenToClient(wndRect);
- clientRect.OffsetRect(wndRect.left, wndRect.top);
-
- if(lanlink.active==0)
- SetCurSel(0);
-
- for(i=0;i<3;i++){
- if(i==GetCurSel()){
- m_tabdialog[i]->SetWindowPos(&wndTop, clientRect.left, clientRect.top, clientRect.Width(), clientRect.Height(), SWP_SHOWWINDOW);
- } else {
- m_tabdialog[i]->ShowWindow(SW_HIDE);
- }
- }
- return;
-}
-
-
void LinkOptions::OnOk()
{
- GetAllData((LinkGeneral*)m_tabctrl.m_tabdialog[0]);
+ static const int length = 256;
+ int timeout;
+ CString timeoutStr;
+ CString host;
+ CString title;
+ CString addressMessage;
+
+ UpdateData(TRUE);
+
+ // Close any previous link
+ CloseLink();
+
+ m_serverip.GetWindowText(host);
+ m_timeout.GetWindowText(timeoutStr);
+ sscanf(timeoutStr, "%d", &timeout);
+ SetLinkTimeout(timeout);
+
+ LinkMode newMode = (LinkMode) m_type;
+ bool needsServerHost = newMode == LINK_GAMECUBE_DOLPHIN || (newMode == LINK_CABLE_SOCKET && !m_server);
+
+ if (needsServerHost) {
+ bool valid = SetLinkServerHost(host);
+ if (!valid) {
+ AfxMessageBox("You must enter a valid host name", MB_OK | MB_ICONSTOP);
+ return;
+ }
+ }
+
+ EnableSpeedHacks(m_hacks);
+ EnableLinkServer(m_server, m_numplayers + 1);
+
+ if (m_server) {
+ char localhost[length];
+ GetLinkServerHost(localhost, length);
+
+ title = "Waiting for clients...";
+ addressMessage.Format("Server IP address is: %s\n", localhost);
+ } else {
+ title = "Waiting for connection...";
+ addressMessage.Format("Connecting to %s\n", host);
+ }
+
+ // Init link
+ ConnectionState state = InitLink(newMode);
+
+ // Display a progress dialog while the connection is establishing
+ if (state == LINK_NEEDS_UPDATE) {
+ ServerWait *dlg = new ServerWait();
+ dlg->Create(ServerWait::IDD, this);
+ dlg->m_plconn[1] = title;
+ dlg->m_serveraddress = addressMessage;
+ dlg->ShowWindow(SW_SHOW);
+
+ while (state == LINK_NEEDS_UPDATE) {
+ // Ask the core for updates
+ char message[length];
+ state = ConnectLinkUpdate(message, length);
+
+ // Update the wait message
+ if (strlen(message)) {
+ dlg->m_plconn[1] = message;
+ }
+
+ // Step the progress bar and update dialog data
+ dlg->m_prgctrl.StepIt();
+ dlg->UpdateData(false);
+
+ // Process Windows messages
+ MSG msg;
+ while (PeekMessage (&msg, 0, 0, 0, PM_NOREMOVE)) {
+ AfxGetApp()->PumpMessage();
+ }
+
+ // Check whether the user has aborted
+ if (dlg->m_userAborted) {
+ state = LINK_ABORT;
+ }
+ }
+
+ delete dlg;
+ }
+
+ // The user canceled the connection attempt
+ if (state == LINK_ABORT) {
+ CloseLink();
+ return;
+ }
+
+ // Something failed during init
+ if (state == LINK_ERROR) {
+ AfxMessageBox("Error occurred.\nPlease try again.", MB_OK | MB_ICONSTOP);
+ return;
+ }
+
+ theApp.linkTimeout = timeout;
+ theApp.linkMode = GetLinkMode();
+ theApp.linkHost = host;
+
CDialog::OnOK();
return;
}
-void LinkGeneral::OnRadio1()
-{
- m_type = 0;
- lanlink.active = 0;
- GetParent()->Invalidate();
-}
-
-void LinkGeneral::OnRadio2()
-{
- m_type = 1;
- lanlink.active = 1;
- GetParent()->Invalidate();
-}
-
-BOOL LinkGeneral::OnInitDialog(){
-
- char timeout[6];
-
- CDialog::OnInitDialog();
-
- m_timeout.LimitText(5);
- sprintf(timeout, "%d", linktimeout);
- m_timeout.SetWindowText(timeout);
-
- m_type = lanlink.active;
-
- UpdateData(FALSE);
-
- return TRUE;
-}
-
-
void LinkOptions::OnCancel()
{
CDialog::OnCancel();
return;
}
-class Win32ServerInfoDisplay : public ServerInfoDisplay
-{
-public:
- Win32ServerInfoDisplay(ServerWait *_dlg)
- {
- dlg = _dlg;
- }
- ~Win32ServerInfoDisplay()
- {
- if (dlg)
- {
- // not connected
- MessageBox(NULL, "Failed to connect.", "Link", MB_OK);
- dlg->SendMessage(WM_CLOSE, 0, 0);
- }
-
- delete dlg;
- dlg = NULL;
- }
-
- void ShowServerIP(const sf::IPAddress& addr)
- {
- dlg->m_serveraddress.Format("Server IP address is: %s", addr.ToString());
- }
-
- void ShowConnect(const int player)
- {
- dlg->m_plconn[0].Format("Player %d connected", player);
- dlg->UpdateData(false);
- }
-
- void Ping()
- {
- dlg->m_prgctrl.StepIt();
- }
-
- void Connected()
- {
- MessageBox(NULL, "All players connected", "Link", MB_OK);
- dlg->SendMessage(WM_CLOSE, 0, 0);
- delete dlg;
- dlg = NULL;
- }
-
-private:
- ServerWait *dlg;
-};
-
-void LinkServer::OnServerStart()
-{
- UpdateData(TRUE);
-
- lanlink.numslaves = m_numplayers+1;
- lanlink.type = m_prottype;
- lanlink.server = true;
- lanlink.speed = m_speed==1 ? true : false;
- sf::IPAddress addr;
-
- // These must be created on the heap - referenced from the connection thread
- ServerWait *dlg = new ServerWait();
- dlg->Create(IDD_SERVERWAIT, this);
- dlg->ShowWindow(SW_SHOW);
-
- // Owns the ServerWait*
- Win32ServerInfoDisplay *dlginfo = new Win32ServerInfoDisplay(dlg);
-
- // ls thread will own the dlginfo
- if (!ls.Init(dlginfo))
- {
- // Thread didn't get created
- delete dlginfo;
- MessageBox("Error occurred.\nPlease try again.", "Error", MB_OK);
- }
-
- return;
-}
-
-BOOL LinkClient::OnInitDialog()
-{
- CDialog::OnInitDialog();
-
- m_prottype = lanlink.type;
- m_hacks = lanlink.speed;
-
- UpdateData(FALSE);
-
- return TRUE;
-}
-
-class Win32ClientInfoDisplay : public ClientInfoDisplay
-{
-public:
- Win32ClientInfoDisplay(ServerWait *_dlg)
- {
- dlg = _dlg;
- }
-
- ~Win32ClientInfoDisplay()
- {
- if (dlg)
- {
- // not connected
- MessageBox(NULL, "Failed to connect.", "Link", MB_OK);
- dlg->SendMessage(WM_CLOSE, 0, 0);
- }
-
- delete dlg;
- dlg = NULL;
- }
-
- void ConnectStart(const sf::IPAddress& addr)
- {
- dlg->SetWindowText("Connecting...");
- }
-
- void ShowConnect(const int player, const int togo)
- {
- dlg->m_serveraddress.Format("Connected as #%d", player);
- if (togo)
- dlg->m_plconn[0].Format("Waiting for %d players to join", togo);
- else
- dlg->m_plconn[0].Format("All players joined.");
- }
-
- void Ping()
- {
- dlg->m_prgctrl.StepIt();
- }
-
- void Connected()
- {
- MessageBox(NULL, "Connected.", "Link", MB_OK);
- dlg->SendMessage(WM_CLOSE, 0, 0);
- delete dlg;
- dlg = NULL;
- }
-
-private:
- ServerWait *dlg;
-};
-
-void LinkClient::OnLinkConnect()
-{
- char ipaddress[31];
-
- UpdateData(TRUE);
-
- lanlink.type = m_prottype;
- lanlink.server = false;
- lanlink.speed = m_hacks==1 ? true : false;
-
- m_serverip.GetWindowText(ipaddress, 30);
-
- // These must be created on the heap - referenced from the connection thread
- ServerWait *dlg = new ServerWait();
- dlg->Create(IDD_SERVERWAIT, this);
- dlg->ShowWindow(SW_SHOW);
-
- // Owns the ServerWait*
- Win32ClientInfoDisplay *dlginfo = new Win32ClientInfoDisplay(dlg);
-
- // lc thread will own the dlginfo
- if (!lc.Init(sf::IPAddress(std::string(ipaddress)), dlginfo))
- {
- // Thread didn't get created
- delete dlginfo;
- MessageBox("Error occurred.\nPlease try again.", "Error", MB_OK);
- }
-
- return;
-}
-
-void LinkOptions::GetAllData(LinkGeneral *src)
-{
- char timeout[6];
-
- src->UpdateData(true);
-
- src->m_timeout.GetWindowText(timeout, 5);
- sscanf(timeout, "%d", &linktimeout);
-
- if(src->m_type==0){
- lanlink.speed = 0;
- }
-
- return;
-}
/////////////////////////////////////////////////////////////////////////////
// ServerWait dialog
@@ -693,6 +236,8 @@ ServerWait::ServerWait(CWnd* pParent /*=NULL*/)
m_plconn[1] = _T("");
m_plconn[2] = _T("");
//}}AFX_DATA_INIT
+
+ m_userAborted = false;
}
@@ -719,35 +264,47 @@ END_MESSAGE_MAP()
void ServerWait::OnCancel()
{
- lanlink.terminate = true;
- CDialog::OnCancel();
+ m_userAborted = true;
+ ShowWindow(SW_HIDE);
}
-BOOL LinkGeneral::PreTranslateMessage(MSG* pMsg)
+void LinkOptions::OnCbnSelchangeLinkMode()
{
- if(pMsg->message==WM_KEYDOWN)
- if(pMsg->wParam==VK_RETURN||pMsg->wParam==VK_ESCAPE)
- pMsg->wParam = NULL;
-
- return CDialog::PreTranslateMessage(pMsg);
+ UpdateData(TRUE);
+ UpdateAvailability();
}
-BOOL LinkClient::PreTranslateMessage(MSG* pMsg)
+void LinkOptions::UpdateAvailability()
{
- if(pMsg->message==WM_KEYDOWN)
- if(pMsg->wParam==VK_RETURN||pMsg->wParam==VK_ESCAPE)
- pMsg->wParam = NULL;
+ bool isDisconnected = m_type == LINK_DISCONNECTED;
+ bool isNetwork = m_type == LINK_CABLE_SOCKET;
+ bool canHaveServer = (m_type == LINK_CABLE_SOCKET && !m_server) || m_type == LINK_GAMECUBE_DOLPHIN;
+ bool hasHacks = m_type == LINK_CABLE_SOCKET;
- return CDialog::PreTranslateMessage(pMsg);
-}
+ GetDlgItem(IDC_LINK_CLIENT)->EnableWindow(isNetwork);
+ GetDlgItem(IDC_LINK_SERVER)->EnableWindow(isNetwork);
+ GetDlgItem(IDC_SSPEED)->EnableWindow(isNetwork);
-BOOL LinkServer::PreTranslateMessage(MSG* pMsg)
-{
- if(pMsg->message==WM_KEYDOWN)
- if(pMsg->wParam==VK_RETURN||pMsg->wParam==VK_ESCAPE)
- pMsg->wParam = NULL;
+ m_serverip.EnableWindow(canHaveServer);
+ m_timeout.EnableWindow(!isDisconnected);
- return CDialog::PreTranslateMessage(pMsg);
+ GetDlgItem(IDC_LINK2P)->EnableWindow(isNetwork && m_server);
+ GetDlgItem(IDC_LINK3P)->EnableWindow(isNetwork && m_server);
+ GetDlgItem(IDC_LINK4P)->EnableWindow(isNetwork && m_server);
}
#endif // NO_LINK
+
+
+void LinkOptions::OnBnClickedLinkServer()
+{
+ UpdateData(TRUE);
+ UpdateAvailability();
+}
+
+
+void LinkOptions::OnBnClickedLinkClient()
+{
+ UpdateData(TRUE);
+ UpdateAvailability();
+}
diff --git a/src/win32/LinkOptions.h b/src/win32/LinkOptions.h
index 17d1383c..2bbe3503 100644
--- a/src/win32/LinkOptions.h
+++ b/src/win32/LinkOptions.h
@@ -1,74 +1,5 @@
#pragma once
-class CMyTabCtrl : public CTabCtrl {
- DECLARE_DYNAMIC(CMyTabCtrl)
-public:
- CMyTabCtrl(void);
- ~CMyTabCtrl(void);
-
- BOOL IsTabEnabled(int iTab); // you must override
- BOOL TranslatePropSheetMsg(MSG* pMsg); // call from prop sheet
- BOOL SubclassDlgItem(UINT nID, CWnd* pParent); // non-virtual override
-
- // helpers
- int NextEnabledTab(int iTab, BOOL bWrap); // get next enabled tab
- int PrevEnabledTab(int iTab, BOOL bWrap); // get prev enabled tab
- BOOL SetActiveTab(UINT iNewTab); // set tab (fail if disabled)
-
- CDialog *m_tabdialog[3];
-
- void OnSwitchTabs(void);
-protected:
- DECLARE_MESSAGE_MAP()
- afx_msg void OnSelChanging(NMHDR* pNmh, LRESULT* pRes);
-
- // MFC overrides
- virtual BOOL PreTranslateMessage(MSG* pMsg);
- virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
-
- // override to draw text only; eg, colored text or different font
- virtual void OnDrawText(CDC& dc, CRect rc, CString sText, BOOL bDisabled);
-
-};
-
-/////////////////////////////////////////////////////////////////////////////
-// LinkGeneral dialog
-
-class LinkGeneral : public CDialog
-{
-// Construction
-public:
- LinkGeneral(CWnd* pParent = NULL); // standard constructor
-
-// Dialog Data
- //{{AFX_DATA(LinkGeneral)
- enum { IDD = IDD_LINKTAB1 };
- int m_type;
- CEdit m_timeout;
- //}}AFX_DATA
-
-
-// Overrides
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(LinkGeneral)
- public:
- virtual BOOL PreTranslateMessage(MSG* pMsg);
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- //}}AFX_VIRTUAL
-
-// Implementation
-protected:
-
- // Generated message map functions
- //{{AFX_MSG(LinkGeneral)
- virtual BOOL OnInitDialog();
- afx_msg void OnRadio1();
- afx_msg void OnRadio2();
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-};
-
/////////////////////////////////////////////////////////////////////////////
// LinkOptions dialog
@@ -77,19 +8,22 @@ class LinkOptions : public CDialog
// Construction
public:
LinkOptions(CWnd* pParent = NULL); // standard constructor
- void GetAllData(LinkGeneral*);
// Dialog Data
//{{AFX_DATA(LinkOptions)
enum { IDD = IDD_LINKTAB };
- CMyTabCtrl m_tabctrl;
+ int m_type;
+ CEdit m_timeout;
+ CComboBox m_mode;
+ CEdit m_serverip;
+ BOOL m_server;
+ int m_numplayers;
+ BOOL m_hacks;
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(LinkOptions)
- public:
- virtual BOOL PreTranslateMessage(MSG* pMsg);
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
@@ -97,88 +31,22 @@ public:
// Implementation
protected:
+ void AddMode(LPCTSTR name, int value);
+ void UpdateAvailability();
+
// Generated message map functions
//{{AFX_MSG(LinkOptions)
- afx_msg void OnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult);
+ afx_msg void OnCbnSelchangeLinkMode();
virtual BOOL OnInitDialog();
afx_msg void OnOk();
afx_msg void OnCancel();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
-};
-
-/////////////////////////////////////////////////////////////////////////////
-// LinkServer dialog
-
-class LinkServer : public CDialog
-{
-// Construction
public:
- LinkServer(CWnd* pParent = NULL); // standard constructor
-
-// Dialog Data
- //{{AFX_DATA(LinkServer)
- enum { IDD = IDD_LINKTAB2 };
- int m_numplayers;
- int m_prottype;
- BOOL m_speed;
- //}}AFX_DATA
-
-
-// Overrides
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(LinkServer)
- public:
- virtual BOOL PreTranslateMessage(MSG* pMsg);
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- //}}AFX_VIRTUAL
-
-// Implementation
-protected:
-
- // Generated message map functions
- //{{AFX_MSG(LinkServer)
- virtual BOOL OnInitDialog();
- afx_msg void OnServerStart();
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
+ afx_msg void OnBnClickedLinkServer();
+ afx_msg void OnBnClickedLinkClient();
};
-class LinkClient : public CDialog
-{
-// Construction
-public:
- LinkClient(CWnd* pParent = NULL); // standard constructor
-
-// Dialog Data
- //{{AFX_DATA(LinkClient)
- enum { IDD = IDD_LINKTAB3 };
- CEdit m_serverip;
- int m_prottype;
- int m_hacks;
- //}}AFX_DATA
-
-
-// Overrides
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(LinkClient)
- public:
- virtual BOOL PreTranslateMessage(MSG* pMsg);
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- //}}AFX_VIRTUAL
-
-// Implementation
-protected:
-
- // Generated message map functions
- //{{AFX_MSG(LinkClient)
- virtual BOOL OnInitDialog();
- afx_msg void OnLinkConnect();
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-};
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
@@ -196,10 +64,9 @@ public:
CProgressCtrl m_prgctrl;
CString m_serveraddress;
CString m_plconn[3];
- //CString m_p2conn;
- //CString m_p3conn;
//}}AFX_DATA
+ bool m_userAborted;
// Overrides
// ClassWizard generated virtual function overrides
diff --git a/src/win32/MainWnd.cpp b/src/win32/MainWnd.cpp
index c84dce54..5e6e0d03 100644
--- a/src/win32/MainWnd.cpp
+++ b/src/win32/MainWnd.cpp
@@ -323,11 +323,6 @@ BEGIN_MESSAGE_MAP(MainWnd, CWnd)
ON_UPDATE_COMMAND_UI(ID_OPTIONS_EMULATOR_GAMEOVERRIDES, OnUpdateOptionsEmulatorGameoverrides)
ON_COMMAND(ID_HELP_GNUPUBLICLICENSE, OnHelpGnupubliclicense)
ON_COMMAND(ID_OPTIONS_LINK_OPTIONS, OnLinkOptions)
- ON_COMMAND(ID_OPTIONS_LINK_WIRELESSADAPTER, OnOptionsLinkRFU)
- ON_UPDATE_COMMAND_UI(ID_OPTIONS_LINK_WIRELESSADAPTER, OnUpdateOptionsLinkRFU)
- ON_COMMAND(ID_OPTIONS_LINK_ENABLE, OnOptionsLinkEnable)
- ON_UPDATE_COMMAND_UI(ID_OPTIONS_LINK_ENABLE, OnUpdateOptionsLinkEnable)
- ON_COMMAND(ID_OPTIONS_JOYBUS, &MainWnd::OnOptionsJoybus)
//}}AFX_MSG_MAP
ON_COMMAND_EX_RANGE(ID_FILE_MRU_FILE1, ID_FILE_MRU_FILE10, OnFileRecentFile)
diff --git a/src/win32/MainWnd.h b/src/win32/MainWnd.h
index 49993323..79b895e5 100644
--- a/src/win32/MainWnd.h
+++ b/src/win32/MainWnd.h
@@ -330,11 +330,6 @@ protected:
afx_msg void OnOptionsSoundHardwareacceleration();
afx_msg void OnUpdateOptionsSoundHardwareacceleration(CCmdUI *pCmdUI);
afx_msg void OnLinkOptions();
- afx_msg void OnOptionsLinkRFU();
- afx_msg void OnUpdateOptionsLinkRFU(CCmdUI* pCmdUI);
- afx_msg void OnOptionsLinkEnable();
- afx_msg void OnUpdateOptionsLinkEnable(CCmdUI* pCmdUI);
- afx_msg void OnOptionsJoybus();
afx_msg void OnOutputapiDirectsound();
afx_msg void OnUpdateOutputapiDirectsound(CCmdUI *pCmdUI);
diff --git a/src/win32/MainWndOptions.cpp b/src/win32/MainWndOptions.cpp
index efce4465..4bb7eb8f 100644
--- a/src/win32/MainWndOptions.cpp
+++ b/src/win32/MainWndOptions.cpp
@@ -7,7 +7,6 @@
#include "FileDlg.h"
#include "GameOverrides.h"
#include "LinkOptions.h"
-#include "JoybusOptions.h"
#include "GBColorDlg.h"
#include "Joypad.h"
#include "MaxScale.h"
@@ -1579,42 +1578,8 @@ void MainWnd::OnLinkOptions()
dlg.DoModal();
}
-void MainWnd::OnOptionsLinkRFU()
-{
- if(rfu_enabled) rfu_enabled = false;
- else {
- rfu_enabled = true;
- MessageBox("Please note this is the first version\nof RFU emulation code and it's not 100% bug free.\nAlso only 2 players single computer are supported at this time.", "Warning", MB_OK);
- }
-}
-
-void MainWnd::OnUpdateOptionsLinkEnable(CCmdUI* pCmdUI)
-{
- pCmdUI->SetCheck(gba_link_enabled);
-}
-
-void MainWnd::OnOptionsLinkEnable()
-{
- gba_link_enabled = !gba_link_enabled;
-}
-
-void MainWnd::OnUpdateOptionsLinkRFU(CCmdUI* pCmdUI)
-{
- pCmdUI->SetCheck(rfu_enabled);
-}
-
-void MainWnd::OnOptionsJoybus()
-{
- JoybusOptions dlg;
- dlg.DoModal();
-}
#else
void MainWnd::OnLinkOptions() { }
-void MainWnd::OnOptionsLinkRFU() { }
-void MainWnd::OnUpdateOptionsLinkEnable(CCmdUI*) { }
-void MainWnd::OnOptionsLinkEnable() { }
-void MainWnd::OnUpdateOptionsLinkRFU(CCmdUI*) { }
-void MainWnd::OnOptionsJoybus() { }
#endif
void MainWnd::OnOptionsEmulatorGameoverrides()
diff --git a/src/win32/VBA.cpp b/src/win32/VBA.cpp
index 0a0c245e..88fa05fd 100644
--- a/src/win32/VBA.cpp
+++ b/src/win32/VBA.cpp
@@ -119,9 +119,6 @@ void winlog(const char *msg, ...);
/* Link
---------------------*/
-extern bool InitLink(void);
-extern void CloseLink(void);
-//extern int linkid;
extern char inifile[];
/* ------------------- */
#ifdef _DEBUG
@@ -358,7 +355,7 @@ VBA::~VBA()
regInit(winBuffer);
- JoyBusShutdown();
+ CloseLink();
saveSettings();
@@ -453,9 +450,6 @@ BOOL VBA::InitInstance()
if(p)
*p = 0;
- if(!InitLink())
- return FALSE;
-
bool force = false;
if (m_lpCmdLine[0])
@@ -485,7 +479,7 @@ BOOL VBA::InitInstance()
loadSettings();
- if(!initDisplay()) {
+ if(!initDisplay()) {
if(videoOption >= VIDEO_320x240) {
regSetDwordValue("video", VIDEO_2X);
}
@@ -1280,8 +1274,8 @@ BOOL VBA::OnIdle(LONG lCount)
emulator.emuMain(emulator.emuCount);
#ifndef NO_LINK
- if (lanlink.connected && linkid && lc.numtransfers == 0)
- lc.CheckConn();
+ if (GetLinkMode() != LINK_DISCONNECTED)
+ CheckLinkConnection();
#endif
if(rewindSaveNeeded && rewindMemory && emulator.emuWriteMemState) {
@@ -1647,18 +1641,12 @@ void VBA::loadSettings()
updateThrottle( (unsigned short)regQueryDwordValue( "throttle", 0 ) );
#ifndef NO_LINK
- linktimeout = regQueryDwordValue("LinkTimeout", 1000);
+ linkTimeout = regQueryDwordValue("LinkTimeout", 1000);
- rfu_enabled = regQueryDwordValue("RFU", false) ? true : false;
- gba_link_enabled = regQueryDwordValue("linkEnabled", false) ? true : false;
- gba_joybus_enabled = regQueryDwordValue("joybusEnabled", false) ? true : false;
- buffer = regQueryStringValue("joybusHostAddr", "");
+ linkMode = regQueryDwordValue("LinkMode", LINK_DISCONNECTED);
- if(!buffer.IsEmpty()) {
- joybusHostAddr = std::string(buffer);
- }
+ linkHost = regQueryStringValue("LinkHostAddr", "localhost");
- lanlink.active = regQueryDwordValue("LAN", 0) ? true : false;
#endif
Sm60FPS::bSaveMoreCPU = regQueryDwordValue("saveMoreCPU", 0);
@@ -2585,11 +2573,9 @@ void VBA::saveSettings()
regSetDwordValue("saveMoreCPU", Sm60FPS::bSaveMoreCPU);
#ifndef NO_LINK
- regSetDwordValue("LinkTimeout", linktimeout);
- regSetDwordValue("RFU", rfu_enabled);
- regSetDwordValue("linkEnabled", gba_link_enabled);
- regSetDwordValue("joybusEnabled", gba_joybus_enabled);
- regSetStringValue("joybusHostAddr", joybusHostAddr.ToString().c_str());
+ regSetDwordValue("LinkTimeout", linkTimeout);
+ regSetDwordValue("LinkMode", linkMode);
+ regSetStringValue("LinkHostAddr", linkHost);
#endif
regSetDwordValue("lastFullscreen", lastFullscreen);
diff --git a/src/win32/VBA.h b/src/win32/VBA.h
index 96f5bba0..06f9a613 100644
--- a/src/win32/VBA.h
+++ b/src/win32/VBA.h
@@ -207,6 +207,10 @@ class VBA : public CWinApp
CString wndClass;
+ int linkTimeout;
+ int linkMode;
+ CString linkHost;
+
public:
VBA();
~VBA();
diff --git a/src/win32/VBA.rc b/src/win32/VBA.rc
index 2157b05a..1cf9078c 100644
--- a/src/win32/VBA.rc
+++ b/src/win32/VBA.rc
@@ -112,54 +112,28 @@ BEGIN
LTEXT "Please select filter plugin:",IDC_STATIC,6,6,162,8
END
-IDD_LINKTAB DIALOGEX 0, 0, 254, 203
+IDD_LINKTAB DIALOGEX 0, 0, 254, 198
STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Link Options"
+CAPTION "Connect Link"
FONT 8, "MS Sans Serif", 0, 0, 0x1
BEGIN
- CONTROL "Tab1",IDC_TAB1,"SysTabControl32",0x0,9,7,240,162
- PUSHBUTTON "OK",ID_OK,57,180,60,15
- PUSHBUTTON "Cancel",ID_CANCEL,140,180,57,15
-END
-
-IDD_LINKTAB1 DIALOGEX 0, 0, 184, 79
-STYLE DS_SETFONT | WS_CHILD | WS_VISIBLE
-FONT 8, "MS Sans Serif", 0, 0, 0x1
-BEGIN
- LTEXT "Link timeout (in milliseconds)",IDC_STATIC,17,12,92,16
- EDITTEXT IDC_LINKTIMEOUT,116,10,53,14,ES_AUTOHSCROLL | ES_NUMBER
- CONTROL "Single Computer",IDC_LINK_SINGLE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,17,27,71,16
- CONTROL "Network",IDC_LINK_LAN,"Button",BS_AUTORADIOBUTTON,17,43,70,16
-END
-
-IDD_LINKTAB2 DIALOGEX 0, 0, 210, 113
-STYLE DS_SETFONT | WS_CHILD
-FONT 8, "MS Sans Serif", 0, 0, 0x0
-BEGIN
- CONTROL "2",IDC_LINK2P,"Button",BS_AUTORADIOBUTTON | WS_GROUP,46,16,21,13
- CONTROL "3",IDC_LINK3P,"Button",BS_AUTORADIOBUTTON,94,16,21,13
- CONTROL "4",IDC_LINK4P,"Button",BS_AUTORADIOBUTTON,142,16,21,13
- CONTROL "TCP/IP",IDC_LINKTCP,"Button",BS_AUTORADIOBUTTON | WS_GROUP,54,47,42,14
- CONTROL "UDP",IDC_LINKUDP,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,121,47,33,14
- PUSHBUTTON "Start!",IDC_SERVERSTART,79,89,50,17,WS_DISABLED
- LTEXT "Select number of players:",IDC_STATIC,60,7,89,10
- LTEXT "Select protocol:",IDC_STATIC,78,33,53,11
- CONTROL "Speed hacks",IDC_SSPEED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,76,70,57,12
-END
-
-IDD_LINKTAB3 DIALOGEX 0, 0, 188, 108
-STYLE DS_SETFONT | WS_CHILD
-FONT 8, "MS Sans Serif", 0, 0, 0x1
-BEGIN
- CONTROL "TCP/IP",IDC_CLINKTCP,"Button",BS_AUTORADIOBUTTON | WS_GROUP,58,20,39,12
- CONTROL "UDP",IDC_CLINKUDP,"Button",BS_AUTORADIOBUTTON | WS_DISABLED,118,20,32,12
- EDITTEXT IDC_SERVERIP,84,39,79,12,ES_AUTOHSCROLL | WS_GROUP
- PUSHBUTTON "Connect",IDC_LINKCONNECT,75,81,59,16,WS_DISABLED
- LTEXT "Select protocol:",IDC_STATIC,78,7,53,9
- LTEXT "Server IP address or hostname:",IDC_STATIC,7,37,62,18
- LTEXT "Speed hacks:",IDC_STATIC,7,64,47,10
- CONTROL "Off (accurate)",IDC_SPEEDOFF,"Button",BS_AUTORADIOBUTTON | WS_GROUP,60,63,57,12
- CONTROL "On (fast)",IDC_SPEEDON,"Button",BS_AUTORADIOBUTTON,128,63,48,12
+ CONTROL "Client",IDC_LINK_CLIENT,"Button",BS_AUTORADIOBUTTON | WS_GROUP,53,46,33,10
+ CONTROL "Server",IDC_LINK_SERVER,"Button",BS_AUTORADIOBUTTON,95,46,37,10
+ LTEXT "Link with",IDC_LINK_WITH,11,10,38,10
+ COMBOBOX IDC_LINK_MODE,50,8,194,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Link timeout (in milliseconds)",IDC_STATIC_TIMEOUT,11,153,92,12
+ EDITTEXT IDC_LINKTIMEOUT,111,150,53,14,ES_AUTOHSCROLL | ES_NUMBER
+ LTEXT "Server IP address or hostname:",IDC_STATIC,25,70,75,18
+ EDITTEXT IDC_SERVERIP,114,73,105,12,ES_AUTOHSCROLL | WS_GROUP
+ LTEXT "Expected number of players:",IDC_STATIC,25,94,89,10
+ CONTROL "2",IDC_LINK2P,"Button",BS_AUTORADIOBUTTON | WS_GROUP,53,106,21,13
+ CONTROL "3",IDC_LINK3P,"Button",BS_AUTORADIOBUTTON,99,106,21,13
+ CONTROL "4",IDC_LINK4P,"Button",BS_AUTORADIOBUTTON,145,106,21,13
+ CONTROL "Enable speed hacks",IDC_SSPEED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,121,138,12
+ PUSHBUTTON "OK",ID_OK,60,176,60,15
+ PUSHBUTTON "Cancel",ID_CANCEL,136,176,57,15
+ GROUPBOX "Network options",IDC_GROUP_NETWORK,11,28,231,113
+ LTEXT "Role:",IDC_LINK_ROLE,25,46,18,8
END
IDD_SERVERWAIT DIALOG 0, 0, 186, 90
@@ -1203,17 +1177,6 @@ BEGIN
COMBOBOX IDC_SAMPLE_RATE,66,54,66,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
END
-IDD_JOYBUS_DIALOG DIALOGEX 0, 0, 209, 57
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
-EXSTYLE WS_EX_TOOLWINDOW
-CAPTION "Joybus Options"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- DEFPUSHBUTTON "OK",IDOK,152,36,50,14
- CONTROL "Enable Joybus Connection",IDC_JOYBUS_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,195,10
- EDITTEXT IDC_JOYBUS_HOSTNAME,7,20,195,14,ES_AUTOHSCROLL
-END
-
/////////////////////////////////////////////////////////////////////////////
//
@@ -1243,15 +1206,7 @@ BEGIN
BEGIN
END
- IDD_LINKTAB1, DIALOG
- BEGIN
- END
-
- IDD_LINKTAB2, DIALOG
- BEGIN
- END
-
- IDD_LINKTAB3, DIALOG
+ IDD_SERVERWAIT, DIALOG
BEGIN
END
@@ -1587,14 +1542,6 @@ BEGIN
TOPMARGIN, 7
BOTTOMMARGIN, 163
END
-
- IDD_JOYBUS_DIALOG, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 202
- TOPMARGIN, 7
- BOTTOMMARGIN, 50
- END
END
#endif // APSTUDIO_INVOKED
@@ -1653,6 +1600,8 @@ BEGIN
MENUITEM "Open GB...", ID_FILE_OPEN_GB
MENUITEM "Close", ID_FILE_CLOSE
MENUITEM SEPARATOR
+ MENUITEM "&Link with...", ID_OPTIONS_LINK_OPTIONS
+ MENUITEM SEPARATOR
POPUP "Recent"
BEGIN
MENUITEM "&Reset", ID_FILE_RECENT_RESET
@@ -1977,14 +1926,6 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "&Colors...", ID_OPTIONS_GAMEBOY_COLORS
END
- POPUP "&Link"
- BEGIN
- MENUITEM "Enable GBA Linking", ID_OPTIONS_LINK_ENABLE
- MENUITEM "&Wireless Adapter", ID_OPTIONS_LINK_WIRELESSADAPTER
- MENUITEM "&Options...", ID_OPTIONS_LINK_OPTIONS
- MENUITEM SEPARATOR
- MENUITEM "&Joybus Options...", ID_OPTIONS_JOYBUS
- END
END
POPUP "&Cheats"
BEGIN
diff --git a/src/win32/resource.h b/src/win32/resource.h
index dc6d820e..286ce5eb 100644
--- a/src/win32/resource.h
+++ b/src/win32/resource.h
@@ -107,7 +107,6 @@
#define IDD_FULLSCREEN 162
#define IDD_XAUDIO2_CONFIG 163
#define IDD_AUDIO_CORE_SETTINGS 164
-#define IDD_JOYBUS_DIALOG 165
#define IDC_R0 1000
#define IDC_EDIT_UP 1000
#define IDC_R1 1001
@@ -564,8 +563,13 @@
#define IDC_SOUND_FILTERING 1294
#define IDC_COMBO1 1296
#define IDC_SAMPLE_RATE 1296
-#define IDC_JOYBUS_HOSTNAME 1297
-#define IDC_JOYBUS_ENABLE 1298
+#define IDC_LINK_MODE 1296
+#define IDC_LINK_WITH 1300
+#define IDC_STATIC_TIMEOUT 1301
+#define IDC_LINK_SERVER 1302
+#define IDC_LINK_CLIENT 1303
+#define IDC_GROUP_NETWORK 1304
+#define IDC_LINK_ROLE 1305
#define IDS_OAL_NODEVICE 2000
#define IDS_OAL_NODLL 2001
#define IDS_AVI_CANNOT_CREATE_AVI 2002
@@ -815,34 +819,26 @@
#define ID_OPTIONS_SOUND_PCMINTERPOLATION_CUBIC 40296
#define ID_OPTIONS_SOUND_PCMINTERPOLATION_FIR 40297
#define ID_OPTIONS_SOUND_PCMINTERPOLATION_LIBRESAMPLE 40298
-#define IDD_LINKTAB1 40300
#define IDD_LINKTAB 40301
-#define IDD_LINKTAB2 40302
-#define IDD_LINKTAB3 40303
#define IDD_SERVERWAIT 40304
#define IDC_TAB1 40305
#define IDC_LINK_SINGLE 40306
#define IDC_LINK_TIMEOUT 40307
+#define IDC_LINK_DISCONNECTED 40307
#define IDC_LINK_LAN 40308
#define IDC_LINK2P 40309
-#define IDC_LINKTCP 40310
+#define IDC_LINK_RFU 40309
+#define IDC_LINK_GAMECUBE 40310
#define IDC_SSPEED 40311
-#define IDC_SERVERSTART 40312
#define IDC_SERVERIP 40313
#define IDC_CLINKIP 40314
-#define IDC_SPEEDOFF 40315
-#define IDC_LINKCONNECT 40316
#define ID_OPTIONS_LINK_OPTIONS 40318
#define ID_OPTIONS_LINK_LOG 40319
#define ID_OPTIONS_LINK_WIRELESSADAPTER 40320
#define IDC_LINKTIMEOUT 40321
-#define IDC_CLINKTCP 40322
#define IDC_SERVERWAIT 40323
-#define IDC_LINKUDP 40324
#define IDC_LINK3P 40325
#define IDC_LINK4P 40326
-#define IDC_CLINKUDP 40327
-#define IDC_SPEEDON 40328
#define ID_OPTIONS_EMULATOR_REMOVEINTROSGBA 40331
#define ID_Menu 40332
#define ID_OPTIONS_VIDEO_RENDEROPTIONS_GLANISOTROPIC 40333
diff --git a/src/wx/cmdevents.cpp b/src/wx/cmdevents.cpp
index 90fe5896..88b7c84a 100644
--- a/src/wx/cmdevents.cpp
+++ b/src/wx/cmdevents.cpp
@@ -1159,16 +1159,18 @@ EVT_HANDLER(JoypadAutofireR, "Autofire R (toggle)")
EVT_HANDLER_MASK(LanLink, "Start LAN link", CMDEN_LINK_ANY)
{
#ifndef NO_LINK
- if(lanlink.connected) {
- // while we could deactivate the command when connected, it is more
- // user-friendly to display a message indidcating why
- wxLogError(_("LAN link is already active. Disable link mode to disconnect."));
- return;
+ LinkMode mode = GetLinkMode();
+
+ if (mode == LINK_CABLE_SOCKET) {
+ // while we could deactivate the command when connected, it is more
+ // user-friendly to display a message indidcating why
+ wxLogError(_("LAN link is already active. Disable link mode to disconnect."));
+ return;
}
- if(rfu_enabled) {
- // see above comment
- wxLogError(_("RFU is currently only supported in local mode."));
- return;
+ if (mode == LINK_RFU_IPC || mode == LINK_GAMECUBE_DOLPHIN) {
+ // see above comment
+ wxLogError(_("RFU and Joybus are only supported in local mode."));
+ return;
}
wxDialog *dlg = GetXRCDialog("NetLink");
ShowModal(dlg);
@@ -2118,33 +2120,38 @@ EVT_HANDLER(JoypadConfigure, "Joypad options...")
EVT_HANDLER(LinkConfigure, "Link options...")
{
#ifndef NO_LINK
- bool jb = gba_joybus_enabled;
wxString jh = gopts.joybus_host;
wxDialog *dlg = GetXRCDialog("LinkConfig");
- if(ShowModal(dlg) != wxID_OK)
- return;
- update_opts();
- if(jb != gba_joybus_enabled) {
- if(gba_joybus_enabled)
- JoyBusConnect();
- else
- JoyBusShutdown();
- } else if(jh != gopts.joybus_host) {
- joybusHostAddr = std::string(gopts.joybus_host.mb_str());
- JoyBusConnect();
- }
- if(gba_link_enabled != did_link_init) {
- if(gba_link_enabled) {
- if((did_link_init = InitLink()))
- cmd_enable |= CMDEN_LINK_ANY;
- } else {
- did_link_init = false;
- CloseLink();
- lanlink.active = false;
- cmd_enable &= ~CMDEN_LINK_ANY;
+ if (ShowModal(dlg) != wxID_OK)
+ return;
+
+ bool valid = SetLinkServerHost(gopts.joybus_host.mb_str());
+ if (!valid) {
+ wxMessageBox(_("You must enter a valid host name"),
+ _("Host name invalid"), wxICON_ERROR | wxOK);
+ return;
}
- enable_menus();
+
+ update_opts();
+
+ SetLinkTimeout(gopts.linktimeout);
+
+ LinkMode oldLinkMode = GetLinkMode();
+ LinkMode newLinkMode = getOptionsLinkMode();
+ bool dolphinHostChanged = jh != gopts.joybus_host;
+
+ if (newLinkMode != oldLinkMode || dolphinHostChanged) {
+ CloseLink();
+ InitLink(newLinkMode);
}
+
+ cmd_enable &= ~CMDEN_LINK_ANY;
+
+ if (GetLinkMode() != LINK_DISCONNECTED) {
+ cmd_enable |= CMDEN_LINK_ANY;
+ }
+
+ enable_menus();
#endif
}
diff --git a/src/wx/guiinit.cpp b/src/wx/guiinit.cpp
index b61594fe..b0551bb9 100644
--- a/src/wx/guiinit.cpp
+++ b/src/wx/guiinit.cpp
@@ -50,7 +50,8 @@ static class NetLink_t : public wxEvtHandler
public:
wxDialog *dlg;
int n_players;
- NetLink_t() : n_players(2) {}
+ bool server;
+ NetLink_t() : n_players(2), server(false) {}
wxButton *okb;
void ServerOKButton(wxCommandEvent &ev)
{
@@ -63,151 +64,80 @@ public:
// attached to OK, so skip when OK
void NetConnect(wxCommandEvent &ev)
{
+ static const int length = 256;
if(!dlg->Validate() || !dlg->TransferDataFromWindow())
return;
+
+ if (!server) {
+ bool valid = SetLinkServerHost(gopts.link_host.mb_str());
+ if (!valid) {
+ wxMessageBox(_("You must enter a valid host name"),
+ _("Host name invalid"), wxICON_ERROR | wxOK);
+ return;
+ }
+ }
+
update_opts(); // save fast flag and client host
- wxString connmsg, pmsg;
+ // Close any previous link
+ CloseLink();
- wxMutex lock;
- wxCondition sig(lock);
- lock.Lock();
+ wxString connmsg;
+ wxString title;
- bool done = false;
+ SetLinkTimeout(gopts.linktimeout);
+ EnableSpeedHacks(gopts.lanlink_speed);
+ EnableLinkServer(server, n_players - 1);
- if(lanlink.server) {
- lanlink.numslaves = n_players - 1;
- class sid_t : public ServerInfoDisplay
- {
- wxMutex *lock;
- wxCondition *sig;
- wxString *connmsg, *pmsg;
- bool *done;
- bool conn[3];
- public:
- sid_t(wxMutex *m, wxCondition *c, wxString *cm, wxString *pm,
- bool *d) :
- lock(m), sig(c), connmsg(cm), pmsg(pm), done(d) {}
- void ShowServerIP(const sf::IPAddress &addr) {
- wxString addr_s(addr.ToString().c_str(), wxConvLibc);
- wxString msg;
- msg.Printf(_("Server IP address is: %s\n"), addr_s.c_str());
- connmsg->append(msg);
- conn[0] = conn[1] = conn[2] = false;
- }
- void ShowConnect(int player) {
- wxString msg;
- conn[player - 1] = true;
- lock->Lock();
- pmsg->clear();
- for(int i = 0; i < 3; i++)
- if(conn[i]) {
- msg.Printf(_("Player %d connected\n"), i + 2);
- pmsg->append(msg);
- }
- sig->Signal();
- lock->Unlock();
- }
- void Ping() {
- lock->Lock();
- sig->Signal();
- if(*done)
- lanlink.terminate = true;
- lock->Unlock();
- }
- void Connected() {
- lock->Lock();
- *done = true;
- sig->Signal();
- lock->Unlock();
- }
- };
-
- sid_t* sid = new sid_t(&lock, &sig, &connmsg, &pmsg, &done);
-
- if (!ls.Init(sid)) {
- wxLogError(_("Error occurred.\nPlease try again."));
- lock.Unlock();
- delete sid;
- return;
- }
-
- wxProgressDialog
- pdlg(_("Waiting for clients..."), connmsg,
- 100, dlg, wxPD_APP_MODAL|wxPD_CAN_ABORT|wxPD_ELAPSED_TIME);
-
- while(!done) {
- if(!pdlg.Pulse(connmsg + pmsg))
- done = true;
- sig.Wait();
- }
+ if (server) {
+ char host[length];
+ GetLinkServerHost(host, length);
+
+ title.Printf(_("Waiting for clients..."));
+ connmsg.Printf(_("Server IP address is: %s\n"), wxString(host, wxConvLibc).c_str());
} else {
- class cid_t : public ClientInfoDisplay
- {
- wxMutex *lock;
- wxCondition *sig;
- wxString *connmsg, *pmsg;
- bool *done;
- public:
- cid_t(wxMutex *m, wxCondition *c, wxString *cm, wxString *pm,
- bool *d) :
- lock(m), sig(c), connmsg(cm), pmsg(pm), done(d) {}
- void ConnectStart(const sf::IPAddress &addr) {
- wxString addr_s(addr.ToString().c_str(), wxConvLibc);
- connmsg->Printf(_("Connecting to %s\n"), addr_s.c_str());
- }
- void ShowConnect(int player, int togo) {
- wxString msg;
- lock->Lock();
- pmsg->Printf(_("Connected as #%d\n"), player);
- if(togo)
- msg.Printf(_("Waiting for %d players to join"), togo);
- else
- msg = _("All players joined.");
- pmsg->append(msg);
- sig->Signal();
- lock->Unlock();
- }
- void Ping() {
- lock->Lock();
- sig->Signal();
- if(*done)
- lanlink.terminate = true;
- lock->Unlock();
- }
- void Connected() {
- lock->Lock();
- *done = true;
- sig->Signal();
- lock->Unlock();
- }
- };
-
- cid_t* cid = new cid_t(&lock, &sig, &connmsg, &pmsg, &done);
-
- if (!lc.Init(sf::IPAddress(std::string(gopts.link_host.mb_str())), cid)) {
- wxLogError(_("Error occurred.\nPlease try again."));
- lock.Unlock();
- delete cid;
- return;
- }
-
- wxProgressDialog
- pdlg(_("Waiting for connection..."), connmsg,
- 100, dlg, wxPD_APP_MODAL|wxPD_CAN_ABORT|wxPD_ELAPSED_TIME);
-
- while(!done) {
- if(!pdlg.Pulse(connmsg + pmsg))
- done = true;
- sig.Wait();
- }
+ title.Printf(_("Waiting for connection..."));
+ connmsg.Printf(_("Connecting to %s\n"), gopts.link_host.c_str());
}
- lock.Unlock();
- if(lanlink.connected) {
- pmsg.Replace(wxT("\n"), wxT(" "));
- systemScreenMessage(pmsg);
- lanlink.active = true;
- ev.Skip(); // all OK
+
+ // Init link
+ ConnectionState state = InitLink(LINK_CABLE_SOCKET);
+
+ // Display a progress dialog while the connection is establishing
+ if (state == LINK_NEEDS_UPDATE) {
+ wxProgressDialog pdlg(title, connmsg,
+ 100, dlg, wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME);
+
+ while (state == LINK_NEEDS_UPDATE) {
+ // Ask the core for updates
+ char message[length];
+ state = ConnectLinkUpdate(message, length);
+
+ connmsg = wxString(message, wxConvLibc);
+
+ // Does the user want to abort?
+ if (!pdlg.Pulse(connmsg)) {
+ state = LINK_ABORT;
+ }
+ }
+ }
+
+ // The user canceled the connection attempt
+ if (state == LINK_ABORT) {
+ CloseLink();
+ }
+
+ // Something failed during init
+ if (state == LINK_ERROR) {
+ CloseLink();
+ wxLogError(_("Error occurred.\nPlease try again."));
+ }
+
+ if(GetLinkMode() != LINK_DISCONNECTED) {
+ connmsg.Replace(wxT("\n"), wxT(" "));
+ systemScreenMessage(connmsg);
+
+ ev.Skip(); // all OK
}
}
} net_link_handler;
@@ -1438,45 +1368,6 @@ public:
}
} JoyPadConfigHandler[4];
-#ifndef NO_LINK
-// tc validator for IP addresses using SFML for validation instead of wx
-class IPHostValidator : public wxValidator
-{
- wxString *valp;
-public:
- IPHostValidator(wxString *v) : wxValidator(), valp(v) {}
- IPHostValidator(const IPHostValidator &e) : wxValidator(), valp(e.valp) {}
- wxObject *Clone() const { return new IPHostValidator(*this); }
- bool Validate(wxWindow *p) {
- wxTextCtrl *tc = wxStaticCast(GetWindow(), wxTextCtrl);
- if(!tc->IsEnabled())
- return true;
- wxString val = tc->GetValue();
- bool isv = true;
- if(val.empty())
- isv = false;
- else {
- sf::IPAddress srv = std::string(val.mb_str());
- isv = srv.IsValid();
- }
- if(!isv)
- wxMessageBox(_("You must enter a valid host name"),
- _("Host name invalid"), wxICON_ERROR|wxOK);
- return isv;
- }
- bool TransferToWindow() {
- wxTextCtrl *tc = wxStaticCast(GetWindow(), wxTextCtrl);
- tc->SetValue(*valp);
- return true;
- }
- bool TransferFromWindow() {
- wxTextCtrl *tc = wxStaticCast(GetWindow(), wxTextCtrl);
- *valp = tc->GetValue();
- return true;
- }
-};
-#endif
-
// manage fullscreen mode widget
// technically, it's more than a validator: it modifies the widget as well
class ScreenModeList : public wxValidator
@@ -2227,7 +2118,7 @@ bool MainFrame::InitMore(void)
// so just set individual flags here
cmd_enable = CMDEN_NGDB_ANY | CMDEN_NREC_ANY;
update_state_ts(true);
- enable_menus();
+
// set pointers for checkable menu items
// and set initial checked status
if(checkable_mi.size()) {
@@ -2464,8 +2355,8 @@ bool MainFrame::InitMore(void)
#ifndef NO_LINK
{
net_link_handler.dlg = d;
- getrbbe("Server", lanlink.server);
- getrbbd("Client", lanlink.server);
+ getrbbe("Server", net_link_handler.server);
+ getrbbd("Client", net_link_handler.server);
getlab("PlayersLab");
addrber(lab, false);
getrbi("Link2P", net_link_handler.n_players, 2);
@@ -2478,9 +2369,8 @@ bool MainFrame::InitMore(void)
addrber(lab, true);
gettc("ServerIP", gopts.link_host);
addrber(tc, true);
- tc->SetValidator(IPHostValidator(&gopts.link_host));
- getrbbr("SpeedOff", lanlink.speed);
- getrbb("SpeedOn", lanlink.speed);
+ getrbbr("SpeedOff", gopts.lanlink_speed);
+ getrbb("SpeedOn", gopts.lanlink_speed);
wxWindow *okb = d->FindWindow(wxID_OK);
if(okb) { // may be gone if style guidlines removed it
net_link_handler.okb = wxStaticCast(okb, wxButton);
@@ -2847,8 +2737,8 @@ bool MainFrame::InitMore(void)
addbier(lab, true);
/// Boot ROM
- getcbbe("BootRomEn", gopts.gb_use_bios);
- getfp("BootRom", gopts.gb_bios);
+ getcbbe("BootRomEn", gopts.gba_use_bios);
+ getfp("BootRom", gopts.gba_bios);
addbe(fp);
getlab("BootRomLab");
addbe(lab);
@@ -3072,18 +2962,17 @@ bool MainFrame::InitMore(void)
#ifndef NO_LINK
LoadXRCDialog("LinkConfig");
{
- getcbbe("Joybus", gba_joybus_enabled);
+ getcbbe("Joybus", gopts.gba_joybus_enabled);
getlab("JoybusHostLab");
addbe(lab);
gettc("JoybusHost", gopts.joybus_host);
- tc->SetValidator(IPHostValidator(&gopts.joybus_host));
addbe(tc);
- getcbbe("Link", gba_link_enabled);
- getcbb("RFU", rfu_enabled);
+ getcbbe("Link", gopts.gba_link_enabled);
+ getcbb("RFU", gopts.rfu_enabled);
addbe(cb);
getlab("LinkTimeoutLab");
addbe(lab);
- getsc("LinkTimeout", linktimeout);
+ getsc("LinkTimeout", gopts.linktimeout);
addbe(sc);
}
#endif
@@ -3205,23 +3094,33 @@ bool MainFrame::InitMore(void)
panel->ShowFullScreen(true);
#ifndef NO_LINK
- if(gba_joybus_enabled) {
- bool isv = !gopts.joybus_host.empty();
- if(isv) {
- joybusHostAddr = std::string(gopts.joybus_host.mb_str());
- isv = joybusHostAddr.IsValid();
- }
- if(!isv) {
- wxLogError(_("JoyBus host invalid; disabling"));
- gba_joybus_enabled = false;
- } else
- JoyBusConnect();
- }
- if(gba_link_enabled)
- if((did_link_init = InitLink()))
- cmd_enable |= CMDEN_LINK_ANY;
+ LinkMode linkMode = getOptionsLinkMode();
+ if (linkMode == LINK_GAMECUBE_DOLPHIN) {
+ bool isv = !gopts.joybus_host.empty();
+ if(isv) {
+ isv = SetLinkServerHost(gopts.joybus_host.mb_str());
+ }
+
+ if(!isv) {
+ wxLogError(_("JoyBus host invalid; disabling"));
+ gopts.gba_joybus_enabled = false;
+ } else {
+ linkMode = LINK_DISCONNECTED;
+ }
+ }
+
+ ConnectionState linkState = InitLink(linkMode);
+ if (linkState != LINK_OK) {
+ CloseLink();
+ }
+
+ if (GetLinkMode() != LINK_DISCONNECTED)
+ cmd_enable |= CMDEN_LINK_ANY;
#endif
+
+ enable_menus();
+
panel->SetFrameTitle();
// All OK; activate idle loop
diff --git a/src/wx/panel.cpp b/src/wx/panel.cpp
index 33f9ae86..98477511 100644
--- a/src/wx/panel.cpp
+++ b/src/wx/panel.cpp
@@ -279,9 +279,10 @@ void GameArea::LoadGame(const wxString &name)
wxString bname = loaded_game.GetFullName();
#ifndef NO_LINK
// MakeInstanceFilename doesn't do wxString, so just add slave ID here
- if(vbaid) {
+ int playerId = GetLinkPlayerId();
+ if(playerId >= 0) {
bname.append(wxT('-'));
- bname.append(wxChar(wxT('1') + vbaid));
+ bname.append(wxChar(wxT('1') + playerId));
}
#endif
bname.append(wxT(".sav"));
@@ -331,10 +332,11 @@ void GameArea::SetFrameTitle()
} else
tit = wxT("VisualBoyAdvance-M " VERSION);
#ifndef NO_LINK
- if(vbaid > 0 || linkid > 0) {
- tit.append(_(" player "));
- tit.append(wxChar(wxT('1') + (linkid > 0 ? linkid : vbaid)));
- }
+ int playerId = GetLinkPlayerId();
+ if (playerId >= 0) {
+ tit.append(_(" player "));
+ tit.append(wxChar(wxT('1') + playerId));
+ }
#endif
wxGetApp().frame->SetTitle(tit);
}
@@ -516,10 +518,11 @@ void GameArea::SaveBattery(bool quiet)
// MakeInstanceFilename doesn't do wxString, so just add slave ID here
wxString bname = game_name();
#ifndef NO_LINK
- if(vbaid) {
- bname.append(wxT('-'));
- bname.append(wxChar(wxT('1') + vbaid));
- }
+ int playerId = GetLinkPlayerId();
+ if (playerId >= 0) {
+ bname.append(wxT('-'));
+ bname.append(wxChar(wxT('1') + playerId));
+ }
#endif
bname.append(wxT(".sav"));
wxFileName bat(batdir, bname);
@@ -836,8 +839,8 @@ void GameArea::OnIdle(wxIdleEvent &event)
}
emusys->emuMain(emusys->emuCount);
#ifndef NO_LINK
- if(loaded == IMAGE_GBA && lanlink.connected && linkid && lc.numtransfers == 0)
- lc.CheckConn();
+ if (loaded == IMAGE_GBA && GetLinkMode() != LINK_DISCONNECTED)
+ CheckLinkConnection();
#endif
} else {
was_paused = true;
diff --git a/src/wx/wxvbam.cpp b/src/wx/wxvbam.cpp
index e4b1b113..33f5a7f0 100644
--- a/src/wx/wxvbam.cpp
+++ b/src/wx/wxvbam.cpp
@@ -391,12 +391,11 @@ bool wxvbamApp::OnCmdLineParsed(wxCmdLineParser &cl)
return true;
}
-MainFrame::MainFrame() : wxFrame(), did_link_init(false), focused(false),
+MainFrame::MainFrame() : wxFrame(), focused(false),
paused(false), menus_opened(0), dialog_opened(0) {}
MainFrame::~MainFrame()
{
- if(did_link_init)
CloseLink();
}
@@ -642,6 +641,18 @@ void MainFrame::StopModal()
panel->Resume();
}
+LinkMode MainFrame::getOptionsLinkMode() {
+ if (gopts.gba_joybus_enabled) {
+ return LINK_GAMECUBE_DOLPHIN;
+ } else if (gopts.rfu_enabled) {
+ return LINK_RFU_IPC;
+ } else if (gopts.gba_link_enabled) {
+ return LINK_CABLE_IPC;
+ }
+
+ return LINK_DISCONNECTED;
+}
+
// global event filter
// apparently required for win32; just setting accel table still misses
// a few keys (e.g. only ctrl-x works for exit, but not esc & ctrl-q;
diff --git a/src/wx/wxvbam.h b/src/wx/wxvbam.h
index f6404e20..d3477c44 100644
--- a/src/wx/wxvbam.h
+++ b/src/wx/wxvbam.h
@@ -205,7 +205,6 @@ public:
// required for event handling
DECLARE_EVENT_TABLE();
private:
- bool did_link_init;
GameArea *panel;
// the various reasons the game might be paused
@@ -244,6 +243,8 @@ private:
void OnDropFile(wxDropFilesEvent&);
// pop up menu in fullscreen mode
void OnMenu(wxContextMenuEvent &);
+ // Returns the link mode to set according to the options
+ LinkMode getOptionsLinkMode();
#include "cmdhandlers.h"
};