First cut of TCP input

This commit is contained in:
sicklittlemonkey 2015-07-09 22:31:04 +12:00
parent 0d7cbfd463
commit fec52f8c39
16 changed files with 5269 additions and 4551 deletions

View File

@ -62,6 +62,7 @@
<ClInclude Include="source\DiskImage.h" />
<ClInclude Include="source\DiskImageHelper.h" />
<ClInclude Include="source\Frame.h" />
<ClInclude Include="source\GenericSocketDriver.h" />
<ClInclude Include="source\Harddisk.h" />
<ClInclude Include="source\Joystick.h" />
<ClInclude Include="source\Keyboard.h" />
@ -137,6 +138,7 @@
<ClCompile Include="source\DiskImage.cpp" />
<ClCompile Include="source\DiskImageHelper.cpp" />
<ClCompile Include="source\Frame.cpp" />
<ClCompile Include="source\GenericSocketDriver.cpp" />
<ClCompile Include="source\Harddisk.cpp" />
<ClCompile Include="source\Joystick.cpp" />
<ClCompile Include="source\Keyboard.cpp" />
@ -342,6 +344,7 @@
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<ShowIncludes>true</ShowIncludes>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>

View File

@ -128,6 +128,7 @@ BEGIN
CONTROL "Spin1",IDC_SPIN_YTRIM,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY,161,53,10,14
CONTROL "Allow cursor keys to be read from keyboard ",IDC_CURSORCONTROL,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,75,155,10
CONTROL "TCP/IP", IDC_TCPIP_JOYSTICK, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 163, 76, 37, 8
CONTROL "Auto-fire (all 3 buttons)", IDC_AUTOFIRE, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 8, 90, 89, 10
CONTROL "Keyboard auto-centering",IDC_CENTERINGCONTROL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,90,96,10
CONTROL "&Scroll Lock acts as toggle for full-speed CPU",IDC_SCROLLLOCK_TOGGLE,

View File

@ -104,6 +104,7 @@
#define IDC_CURSORCONTROL 1066
#define IDC_AUTOFIRE 1067
#define IDC_CENTERINGCONTROL 1068
#define IDC_TCPIP_JOYSTICK 1069
#define IDM_EXIT 40001
#define IDM_HELP 40002
#define IDM_ABOUT 40003

View File

@ -74,6 +74,7 @@ static double g_fMHz = 1.0; // Affected by Config dialog's speed slider bar
int g_nCpuCyclesFeedback = 0;
DWORD g_dwCyclesThisFrame = 0;
INT64 g_nCyclesTotal = 0;
FILE* g_fh = NULL;
bool g_bDisableDirectInput = false;
@ -225,6 +226,7 @@ void ContinueExecution(void)
SpkrUpdate(cyclenum);
sg_SSC.CommUpdate(cyclenum);
PrintUpdate(cyclenum);
TcpIpJoystickUpdate();
//
@ -247,6 +249,7 @@ void ContinueExecution(void)
if (g_dwCyclesThisFrame >= dwClksPerFrame)
{
g_dwCyclesThisFrame -= dwClksPerFrame;
g_nCyclesTotal += dwClksPerFrame;
VideoUpdateFlash();
static BOOL lastupdates[2] = {0,0};
@ -541,6 +544,8 @@ void LoadConfiguration(void)
if(REGLOAD(TEXT(REGVALUE_CURSOR_CONTROL), &dwTmp))
sg_PropertySheet.SetJoystickCursorControl(dwTmp);
if (REGLOAD(TEXT(REGVALUE_TCPIPJOYSTICK), &dwTmp))
sg_PropertySheet.SetTcpIpJoystock(dwTmp);
if (REGLOAD(TEXT(REGVALUE_AUTOFIRE), &dwTmp))
sg_PropertySheet.SetAutofire(dwTmp);
if(REGLOAD(TEXT(REGVALUE_CENTERING_CONTROL), &dwTmp))

View File

@ -37,6 +37,7 @@ extern double g_fCurrentCLK6502;
extern int g_nCpuCyclesFeedback;
extern DWORD g_dwCyclesThisFrame;
extern INT64 g_nCyclesTotal;
extern FILE* g_fh; // Filehandle for log file
extern bool g_bDisableDirectInput; // Cmd line switch: don't init DI (so no DIMouse support)

View File

@ -88,6 +88,7 @@ enum AppMode_e
#define REGVALUE_SCROLLLOCK_TOGGLE "ScrollLock Toggle"
#define REGVALUE_CURSOR_CONTROL "Joystick Cursor Control"
#define REGVALUE_CENTERING_CONTROL "Joystick Centering Control"
#define REGVALUE_TCPIPJOYSTICK "TCP/IP Joystick"
#define REGVALUE_AUTOFIRE "Autofire"
#define REGVALUE_MOUSE_CROSSHAIR "Mouse crosshair"
#define REGVALUE_MOUSE_RESTRICT_TO_WINDOW "Mouse restrict to window"

View File

@ -12,6 +12,8 @@ __interface IPropertySheet
void SetJoystickCursorControl(UINT uValue);
UINT GetJoystickCenteringControl(void);
void SetJoystickCenteringControl(UINT uValue);
UINT GetTcpIpJoystock(void);
void SetTcpIpJoystock(UINT uValue);
UINT GetAutofire(UINT uButton);
void SetAutofire(UINT uValue);
UINT GetMouseShowCrosshair(void);

View File

@ -165,6 +165,7 @@ BOOL CPageInput::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPARAM
SendDlgItemMessage(hWnd, IDC_SPIN_YTRIM, UDM_SETPOS, 0, MAKELONG(JoyGetTrim(false),0));
CheckDlgButton(hWnd, IDC_CURSORCONTROL, m_uCursorControl ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(hWnd, IDC_TCPIP_JOYSTICK, m_uTcpIpJoystick ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(hWnd, IDC_AUTOFIRE, m_bmAutofire ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(hWnd, IDC_CENTERINGCONTROL, m_uCenteringControl == JOYSTICK_MODE_CENTERING ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(hWnd, IDC_SCROLLLOCK_TOGGLE, m_uScrollLockToggle ? BST_CHECKED : BST_UNCHECKED);
@ -198,6 +199,7 @@ void CPageInput::DlgOK(HWND hWnd)
JoySetTrim((short)SendDlgItemMessage(hWnd, IDC_SPIN_YTRIM, UDM_GETPOS, 0, 0), false);
m_uCursorControl = IsDlgButtonChecked(hWnd, IDC_CURSORCONTROL) ? 1 : 0;
m_uTcpIpJoystick = IsDlgButtonChecked(hWnd, IDC_TCPIP_JOYSTICK) ? 1 : 0;
m_bmAutofire = IsDlgButtonChecked(hWnd, IDC_AUTOFIRE) ? 7 : 0; // bitmap of 3 bits
m_uCenteringControl = IsDlgButtonChecked(hWnd, IDC_CENTERINGCONTROL) ? 1 : 0;
m_uMouseShowCrosshair = IsDlgButtonChecked(hWnd, IDC_MOUSE_CROSSHAIR) ? 1 : 0;
@ -207,6 +209,7 @@ void CPageInput::DlgOK(HWND hWnd)
REGSAVE(TEXT(REGVALUE_PDL_YTRIM), JoyGetTrim(false));
REGSAVE(TEXT(REGVALUE_SCROLLLOCK_TOGGLE), m_uScrollLockToggle);
REGSAVE(TEXT(REGVALUE_CURSOR_CONTROL), m_uCursorControl);
REGSAVE(TEXT(REGVALUE_TCPIPJOYSTICK), m_uTcpIpJoystick);
REGSAVE(TEXT(REGVALUE_AUTOFIRE), m_bmAutofire);
REGSAVE(TEXT(REGVALUE_CENTERING_CONTROL), m_uCenteringControl);
REGSAVE(TEXT(REGVALUE_MOUSE_CROSSHAIR), m_uMouseShowCrosshair);

View File

@ -15,6 +15,7 @@ public:
m_uScrollLockToggle(0),
m_uCursorControl(1),
m_uCenteringControl(JOYSTICK_MODE_CENTERING),
m_uTcpIpJoystick(0),
m_bmAutofire(0),
m_uMouseShowCrosshair(0),
m_uMouseRestrictToWindow(0),
@ -32,6 +33,8 @@ public:
void SetJoystickCursorControl(UINT uValue){ m_uCursorControl = uValue; }
UINT GetJoystickCenteringControl(void){ return m_uCenteringControl; }
void SetJoystickCenteringControl(UINT uValue){ m_uCenteringControl = uValue; }
UINT GetTcpIpJoystick(void){ return m_uTcpIpJoystick; }
void SetTcpIpJoystick(UINT uValue){ m_uTcpIpJoystick = uValue; }
UINT GetAutofire(UINT uButton) { return (m_bmAutofire >> uButton) & 1; } // Get a specific button
void SetAutofire(UINT uValue) { m_bmAutofire = uValue; } // Set all buttons
UINT GetMouseShowCrosshair(void){ return m_uMouseShowCrosshair; }
@ -82,6 +85,7 @@ private:
UINT m_bmAutofire; // bitmask b2:0
UINT m_uMouseShowCrosshair;
UINT m_uMouseRestrictToWindow;
UINT m_uTcpIpJoystick;
enum CPMCHOICE {CPM_SLOT4=0, CPM_SLOT5, CPM_UNPLUGGED, CPM_UNAVAILABLE, _CPM_MAX_CHOICES};
TCHAR m_szCPMSlotChoices[_CPM_MAX_CHOICES * MaxMenuChoiceLen];

View File

@ -31,6 +31,8 @@ public:
virtual void SetJoystickCursorControl(UINT uValue){ m_PageInput.SetJoystickCursorControl(uValue); }
virtual UINT GetJoystickCenteringControl(void){ return m_PageInput.GetJoystickCenteringControl(); }
virtual void SetJoystickCenteringControl(UINT uValue){ m_PageInput.SetJoystickCenteringControl(uValue); }
virtual UINT GetTcpIpJoystock(void){ return m_PageInput.GetTcpIpJoystick(); }
virtual void SetTcpIpJoystock(UINT uValue){ m_PageInput.SetTcpIpJoystick(uValue); }
virtual UINT GetAutofire(UINT uButton) { return m_PageInput.GetAutofire(uButton); }
virtual void SetAutofire(UINT uValue) { m_PageInput.SetAutofire(uValue); }
virtual UINT GetMouseShowCrosshair(void){ return m_PageInput.GetMouseShowCrosshair(); }

View File

@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "StdAfx.h"
#include "DiskImage.h"
#include "CPU.h"
#include "..\resource\resource.h"
#define LOG_DISK_ENABLED 0
@ -104,6 +105,8 @@ static BOOL floppywritemode = 0;
static WORD phases; // state bits for stepper magnet phases 0 - 3
static bool g_bSaveDiskImage = true; // Save the DiskImage name to Registry
static DWORD nCyclesLastStep = 0;
static void CheckSpinning();
static Disk_Status_e GetDriveLightStatus( const int iDrive );
static bool IsDriveValid( const int iDrive );
@ -319,7 +322,7 @@ static void ReadTrack(const int iDrive)
if (pFloppy->trackimage && pFloppy->imagehandle)
{
LOG_DISK("read track %2X%s\r", pFloppy->track, (pFloppy->phase & 1) ? ".5" : "");
LOG_DISK("track %02X%s read\r", pFloppy->track, (pFloppy->phase & 1) ? ".5" : " ");
ImageReadTrack(
pFloppy->imagehandle,
@ -406,6 +409,7 @@ void DiskBoot(void)
static BYTE __stdcall DiskControlMotor(WORD, WORD address, BYTE, BYTE, ULONG)
{
floppymotoron = address & 1;
LOG_DISK("motor %s\r", (floppymotoron) ? "on" : "off");
CheckSpinning();
return MemReturnRandomData(1);
}
@ -415,22 +419,19 @@ static BYTE __stdcall DiskControlMotor(WORD, WORD address, BYTE, BYTE, ULONG)
static BYTE __stdcall DiskControlStepper(WORD, WORD address, BYTE, BYTE, ULONG)
{
Disk_t * fptr = &g_aFloppyDisk[currdrive];
#if 1
int phase = (address >> 1) & 3;
int phase_bit = (1 << phase);
#if 1
// update the magnet states
if (address & 1)
{
// phase on
phases |= phase_bit;
LOG_DISK("track %02X phases %X phase %d on address $C0E%X\r", fptr->phase, phases, phase, address & 0xF);
}
else
{
// phase off
phases &= ~phase_bit;
LOG_DISK("track %02X phases %X phase %d off address $C0E%X\r", fptr->phase, phases, phase, address & 0xF);
}
// check for any stepping effect from a magnet
@ -451,9 +452,11 @@ static BYTE __stdcall DiskControlStepper(WORD, WORD address, BYTE, BYTE, ULONG)
const int nNumTracksInImage = ImageGetNumTracks(fptr->imagehandle);
const int newtrack = (nNumTracksInImage == 0) ? 0
: MIN(nNumTracksInImage-1, fptr->phase >> 1); // (round half tracks down)
LOG_DISK("newtrack %2X%s\r", newtrack, (fptr->phase & 1) ? ".5" : "");
if (newtrack != fptr->track)
{
if (address & 1 == 0)
LOG_DISK("phase off stepped\r");
if (fptr->trackimage && fptr->trackimagedirty)
{
WriteTrack(currdrive);
@ -465,7 +468,6 @@ static BYTE __stdcall DiskControlStepper(WORD, WORD address, BYTE, BYTE, ULONG)
#else // Old 1.13.1 code for Chessmaster 2000 to work! (see bug#18109)
const int nNumTracksInImage = ImageGetNumTracks(fptr->imagehandle);
if (address & 1) {
int phase = (address >> 1) & 3;
int direction = 0;
if (phase == ((fptr->phase+1) & 3))
direction = 1;
@ -485,6 +487,22 @@ static BYTE __stdcall DiskControlStepper(WORD, WORD address, BYTE, BYTE, ULONG)
}
}
#endif
if (address & 1)
{
// phase on
phases |= phase_bit;
LOG_DISK("track %02X%s phases %d%d%d%d phase %d on address $C0E%X at %08X\r",
fptr->phase >> 1, (fptr->phase & 1) ? ".5" : " ", phases >> 3, (phases >> 2) & 1, (phases >> 1) & 1, phases & 1, phase, address & 0xF, ((DWORD)g_nCyclesTotal + g_dwCyclesThisFrame) - nCyclesLastStep);
nCyclesLastStep = g_nCyclesTotal + g_dwCyclesThisFrame;
}
else
{
// phase off
phases &= ~phase_bit;
LOG_DISK("track %02X%s phases %d%d%d%d phase %d off address $C0E%X at %08X\r",
fptr->phase >> 1, (fptr->phase & 1) ? ".5" : " ", phases >> 3, (phases >> 2) & 1, (phases >> 1) & 1, phases & 1, phase, address & 0xF, ((DWORD)g_nCyclesTotal + g_dwCyclesThisFrame) - nCyclesLastStep);
nCyclesLastStep = g_nCyclesTotal + g_dwCyclesThisFrame;
}
return (address == 0xE0) ? 0xFF : MemReturnRandomData(1);
}
@ -802,6 +820,9 @@ static BYTE __stdcall DiskReadWrite (WORD programcounter, WORD, BYTE, BYTE, ULON
}
else
{
if (!floppymotoron)
LOG_DISK("reading with motor off at $%04X\r", regs.pc);
result = *(fptr->trackimage + fptr->byte);
}
}

View File

@ -0,0 +1,454 @@
/*
GSport - an Apple //gs Emulator
Copyright (C) 2010 - 2012 by GSport contributors
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* This file contains the socket calls */
#include "StdAfx.h"
#include "GenericSocketDriver.h"
#define fatal_printf(...)
#if !(defined _MSC_VER || defined __CYGWIN__)
extern int h_errno;
#else
#define socklen_t int
#endif
int g_wsastartup_called;
/* Usage: socket_init() called to init socket mode */
/* At all times, we try to have a listen running on the incoming socket */
/* If we want to dial out, we close the incoming socket and create a new */
/* outgoing socket. Any hang-up causes the socket to be closed and it will */
/* then re-open on a subsequent call to scc_socket_open */
void
socket_init(SocketInfo *socket_info_ptr)
{
#ifdef _WIN32
WSADATA wsadata;
int ret;
if(g_wsastartup_called == 0) {
ret = WSAStartup(MAKEWORD(2,0), &wsadata);
printf("WSAStartup ret: %d\n", ret);
g_wsastartup_called = 1;
}
#endif
socket_info_ptr->host_handle = NULL;
socket_info_ptr->sockfd = -1; /* Indicate no socket open yet */
socket_info_ptr->rdwrfd = -1; /* Indicate no socket open yet */
socket_info_ptr->host_addrlen = sizeof(struct sockaddr_in);
socket_info_ptr->host_handle = malloc(socket_info_ptr->host_addrlen); /* Used in accept, freed in shutdown */
/* Real init will be done when bytes need to be read/write from skt */
socket_info_ptr->in_rdptr = 0;
socket_info_ptr->in_wrptr = 0;
socket_info_ptr->out_rdptr = 0;
socket_info_ptr->out_wrptr = 0;
}
void
socket_shutdown(SocketInfo *socket_info_ptr)
{
free(socket_info_ptr->host_handle);
socket_info_ptr->host_handle = NULL;
}
static int
socket_close_handle(SOCKET sockfd)
{
#if defined(_WIN32) || defined (__OS2__)
return closesocket(sockfd); // a Windows socket handle is not a file descriptor
#else
return close(sockfd);
#endif
}
void
socket_maybe_open_incoming(SocketInfo *socket_info_ptr, double dcycs)
{
struct sockaddr_in sa_in;
int on;
int ret;
SOCKET sockfd;
int inc;
inc = 0;
if(socket_info_ptr->sockfd != -1) {
/* it's already open, get out */
return;
}
if (socket_info_ptr-> listen_tries == 0) {
return; // too many retries
}
socket_close(socket_info_ptr, dcycs);
memset(socket_info_ptr->host_handle, 0, socket_info_ptr->host_addrlen);
while(1) {
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == -1) {
printf("socket ret: %d, errno: %d\n", sockfd, errno);
socket_close(socket_info_ptr, dcycs);
return;
}
printf("%s opened socket ret: %d\n", socket_info_ptr->device_name, sockfd);
on = 1;
ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on));
if(ret < 0) {
printf("setsockopt REUSEADDR ret: %d, err:%d\n",
ret, errno);
socket_close(socket_info_ptr, dcycs);
return;
}
memset(&sa_in, 0, sizeof(sa_in));
sa_in.sin_family = AF_INET;
sa_in.sin_port = htons(socket_info_ptr->listen_port);
sa_in.sin_addr.s_addr = htonl(INADDR_ANY);
ret = bind(sockfd, (struct sockaddr *)&sa_in, sizeof(sa_in));
if(ret >= 0) {
ret = listen(sockfd, 1);
break;
}
/* else ret to bind was < 0 */
printf("bind ret: %d, errno: %d\n", ret, errno);
printf("%s failed to listen on TCP port %d\n", socket_info_ptr->device_name, socket_info_ptr->listen_port);
//inc++;
socket_close_handle(sockfd);
// TODO: add port increment as an option?
//printf("Trying next port: %d\n", SCC_LISTEN_PORT + port);
//if(inc >= 10) {
//printf("Too many retries, quitting\n");
if (socket_info_ptr->listen_tries > 0)
--socket_info_ptr->listen_tries;
socket_close(socket_info_ptr, dcycs);
return;
//}
}
printf("%s listening on TCP port %d\n", socket_info_ptr->device_name, socket_info_ptr->listen_port);
socket_info_ptr->sockfd = sockfd;
socket_make_nonblock(socket_info_ptr, dcycs);
}
void
socket_open_outgoing(SocketInfo *socket_info_ptr, double dcycs)
{
struct sockaddr_in sa_in;
struct hostent *hostentptr;
int on;
int ret;
SOCKET sockfd;
//printf("socket_close being called from socket_open_outgoing\n");
socket_close(socket_info_ptr, dcycs);
memset(socket_info_ptr->host_handle, 0, socket_info_ptr->host_addrlen);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == -1) {
printf("%s failed to open outgoing socket ret: %d, errno: %d\n", socket_info_ptr->device_name, sockfd, errno);
socket_close(socket_info_ptr, dcycs);
return;
}
printf("%s opened outgoing sockfd ret: %d\n", socket_info_ptr->device_name, sockfd);
on = 1;
ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on));
if(ret < 0) {
printf("setsockopt REUSEADDR ret: %d, err:%d\n",
ret, errno);
socket_close(socket_info_ptr, dcycs); // TODO: why was this port 1?
return;
}
memset(&sa_in, 0, sizeof(sa_in));
sa_in.sin_family = AF_INET;
sa_in.sin_port = htons(23);
hostentptr = gethostbyname((const char*)&socket_info_ptr->hostname[0]); // OG Added Cast
if(hostentptr == 0) {
#if defined(_WIN32) || defined (__OS2__)
fatal_printf("Lookup host %s failed\n",
&socket_info_ptr->hostname[0]);
#else
fatal_printf("Lookup host %s failed, herrno: %d\n",
&socket_info_ptr->hostname[0], h_errno);
#endif
socket_close_handle(sockfd);
socket_close(socket_info_ptr, dcycs); // TODO: why was this port 1?
//x_show_alert(0, 0);
return;
}
memcpy(&sa_in.sin_addr.s_addr, hostentptr->h_addr,
hostentptr->h_length);
/* The above copies the 32-bit internet address into */
/* sin_addr.s_addr. It's in correct network format */
ret = connect(sockfd, (struct sockaddr *)&sa_in, sizeof(sa_in));
if(ret < 0) {
printf("connect ret: %d, errno: %d\n", ret, errno);
socket_close_handle(sockfd);
socket_close(socket_info_ptr, dcycs); // TODO: why was this port 1?
return;
}
printf("%s socket is now outgoing to %s\n", socket_info_ptr->device_name, &socket_info_ptr->hostname[0]);
socket_info_ptr->sockfd = sockfd;
socket_make_nonblock(socket_info_ptr, dcycs);
socket_info_ptr->rdwrfd = socket_info_ptr->sockfd;
}
void
socket_make_nonblock(SocketInfo *socket_info_ptr, double dcycs)
{
SOCKET sockfd;
int ret;
#if defined(_WIN32) || defined (__OS2__)
u_long flags;
#else
int flags;
#endif
sockfd = socket_info_ptr->sockfd;
#if defined(_WIN32) || defined (__OS2__)
flags = 1;
ret = ioctlsocket(sockfd, FIONBIO, &flags);
if(ret != 0) {
printf("ioctlsocket ret: %d\n", ret);
}
#else
flags = fcntl(sockfd, F_GETFL, 0);
if(flags == -1) {
printf("fcntl GETFL ret: %d, errno: %d\n", flags, errno);
socket_close(socket_info_ptr, dcycs);
return;
}
ret = fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
if(ret == -1) {
printf("fcntl SETFL ret: %d, errno: %d\n", ret, errno);
socket_close(socket_info_ptr, dcycs);
return;
}
#endif
}
void
socket_close(SocketInfo *socket_info_ptr, double dcycs)
{
int rdwrfd;
SOCKET sockfd;
rdwrfd = socket_info_ptr->rdwrfd;
if(rdwrfd >= 0) {
printf("socket_close: rdwrfd=%d, closing\n", rdwrfd);
socket_close_handle(rdwrfd);
}
sockfd = socket_info_ptr->sockfd;
if(sockfd != -1) {
printf("socket_close: sockfd=%d, closing\n", sockfd);
socket_close_handle(sockfd);
}
socket_info_ptr->rdwrfd = -1;
socket_info_ptr->sockfd = -1;
}
void
socket_accept(SocketInfo *socket_info_ptr, double dcycs)
{
#ifdef SOCKET_INFO
int flags;
int rdwrfd;
int ret;
if(socket_info_ptr->sockfd == -1) {
socket_maybe_open_incoming(socket_info_ptr, dcycs);
}
if(socket_info_ptr->sockfd == -1) {
return; /* just give up */
}
if(socket_info_ptr->rdwrfd == -1) {
rdwrfd = accept(socket_info_ptr->sockfd, (struct sockaddr*)socket_info_ptr->host_handle,
(socklen_t*)&(socket_info_ptr->host_addrlen));
if(rdwrfd < 0) {
return;
}
flags = 0;
ret = 0;
#if !defined(_WIN32) && !defined(__OS2__)
/* For Linux, we need to set O_NONBLOCK on the rdwrfd */
flags = fcntl(rdwrfd, F_GETFL, 0);
if(flags == -1) {
printf("fcntl GETFL ret: %d, errno: %d\n", flags,errno);
return;
}
ret = fcntl(rdwrfd, F_SETFL, flags | O_NONBLOCK);
if(ret == -1) {
printf("fcntl SETFL ret: %d, errno: %d\n", ret, errno);
return;
}
#endif
socket_info_ptr->rdwrfd = rdwrfd;
printf("%s connected on rdwrfd=%d\n", socket_info_ptr->device_name, rdwrfd);
}
#endif
}
void
socket_fill_readbuf(SocketInfo *socket_info_ptr, int space_left, double dcycs)
{
#ifdef SOCKET_INFO
byte tmp_buf[256];
int rdwrfd;
int ret;
int i;
socket_accept(socket_info_ptr, dcycs);
rdwrfd = socket_info_ptr->rdwrfd;
if(rdwrfd < 0) {
return; /* just get out */
}
/* Try reading some bytes */
space_left = MIN(space_left, 256);
ret = recv(rdwrfd, (char*)tmp_buf, space_left, 0); // OG Added cast
if(ret > 0) {
for(i = 0; i < ret; i++) {
byte c = tmp_buf[i];
socket_recvd_char(socket_info_ptr, c, dcycs);
}
} else if(ret == 0) {
/* assume socket close */
printf("%s disconnecting from rdwrfd=%d (recv got 0)\n", socket_info_ptr->device_name, rdwrfd);
socket_close(socket_info_ptr, dcycs);
}
#endif
}
void
socket_recvd_char(SocketInfo *socket_info_ptr, int c, double dcycs)
{
int handled_externally = 0; // TODO: would prefer bool or BOOL, but not sure about non-Windows builds
// TODO: should we add if(socket_info_ptr->sockfd == -1) {
socket_maybe_open_incoming(socket_info_ptr, dcycs);
if (socket_info_ptr->rx_handler != NULL) {
handled_externally = socket_info_ptr->rx_handler(socket_info_ptr, c);
}
if (!handled_externally) {
// we handle this
// TODO: implement the read buffer
//scc_add_to_readbuf(port, c, dcycs);
}
}
void
socket_empty_writebuf(SocketInfo *socket_info_ptr, double dcycs)
{
#ifdef SOCKET_INFO
# if !defined(_WIN32) && !defined(__OS2__)
struct sigaction newact, oldact;
# endif
int rdptr;
int wrptr;
int rdwrfd;
int done;
int ret;
int len;
/* Try writing some bytes */
done = 0;
while(!done) {
rdptr = socket_info_ptr->out_rdptr;
wrptr = socket_info_ptr->out_wrptr;
if(rdptr == wrptr) {
done = 1;
break;
}
rdwrfd = socket_info_ptr->rdwrfd;
len = wrptr - rdptr;
if(len < 0) {
len = SOCKET_OUTBUF_SIZE - rdptr;
}
if(len > 32) {
len = 32;
}
if(len <= 0) {
done = 1;
break;
}
if(rdwrfd == -1) {
socket_maybe_open_incoming(socket_info_ptr, dcycs);
return;
}
#if defined(_WIN32) || defined (__OS2__)
ret = send(rdwrfd, (const char*)&(socket_info_ptr->out_buf[rdptr]), len, 0); // OG Added Cast
# else
/* ignore SIGPIPE around writes to the socket, so we */
/* can catch a closed socket and prepare to accept */
/* a new connection. Otherwise, SIGPIPE kills GSport */
sigemptyset(&newact.sa_mask);
newact.sa_handler = SIG_IGN;
newact.sa_flags = 0;
sigaction(SIGPIPE, &newact, &oldact);
ret = send(rdwrfd, &(socket_info_ptr->out_buf[rdptr]), len, 0);
sigaction(SIGPIPE, &oldact, 0);
/* restore previous SIGPIPE behavior */
# endif /* WIN32 */
#if 0
printf("sock output: %02x\n", socket_info_ptr->out_buf[rdptr]);
#endif
if(ret == 0) {
done = 1; /* give up for now */
break;
} else if(ret < 0) {
/* assume socket is dead */
printf("socket write failed on rdwrfd=%d, closing\n", rdwrfd);
socket_close(socket_info_ptr, dcycs);
done = 1;
break;
} else {
rdptr = rdptr + ret;
if(rdptr >= SOCKET_OUTBUF_SIZE) {
rdptr = rdptr - SOCKET_OUTBUF_SIZE;
}
socket_info_ptr->out_rdptr = rdptr;
}
}
#endif
}

View File

@ -0,0 +1,79 @@
/*
GSport - an Apple //gs Emulator
Copyright (C) 2010 by GSport contributors
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SOCKET_INFO
#define SOCKET_INFO
#include <ctype.h>
#ifdef _WIN32
# include <winsock2.h>
#else
# include <sys/socket.h>
# include <netinet/in.h>
# include <netdb.h>
# ifndef SOCKET
# define SOCKET word32 /* for non-windows */
# endif
#endif
#define SOCKET_INBUF_SIZE 1024 /* must be a power of 2 */
#define SOCKET_OUTBUF_SIZE 1024 /* must be a power of 2 */
#define MAX_HOSTNAME_SIZE 256
typedef struct SocketInfo {
char* device_name;
void* device_data;
SOCKET sockfd;
int listen_port;
int listen_tries; // -1 = infinite
int rdwrfd;
void *host_handle;
int host_addrlen;
int rx_queue_depth;
byte rx_queue[4];
BOOL (*rx_handler)(SocketInfo *socket_info_ptr, int c);
int in_rdptr;
int in_wrptr;
byte in_buf[SOCKET_INBUF_SIZE];
int out_rdptr;
int out_wrptr;
byte out_buf[SOCKET_OUTBUF_SIZE];
byte hostname[MAX_HOSTNAME_SIZE];
} SocketInfo;
/* generic_socket_driver.c */
void socket_init(SocketInfo *socket_info_ptr);
void socket_shutdown(SocketInfo *socket_info_ptr);
void socket_maybe_open_incoming(SocketInfo *socket_info_ptr, double dcycs);
void socket_open_outgoing(SocketInfo *socket_info_ptr, double dcycs);
void socket_make_nonblock(SocketInfo *socket_info_ptr, double dcycs);
void socket_close(SocketInfo *socket_info_ptr, double dcycs);
void socket_accept(SocketInfo *socket_info_ptr, double dcycs);
void socket_fill_readbuf(SocketInfo *socket_info_ptr, int space_left, double dcycs);
void socket_recvd_char(SocketInfo *socket_info_ptr, int c, double dcycs);
void socket_empty_writebuf(SocketInfo *socket_info_ptr, double dcycs);
#endif // SOCKET_INFO

View File

@ -40,6 +40,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "StdAfx.h"
#include "MouseInterface.h"
#include "Configuration\PropertySheet.h"
#include "GenericSocketDriver.h"
#define BUTTONTIME 5000 // TODO: Describe this magic number
@ -105,6 +106,136 @@ static UINT g_bJoyportEnabled = 0; // Set to use Joyport to drive the 3 button i
static UINT g_uJoyportActiveStick = 0;
static UINT g_uJoyportReadMode = JOYPORT_LEFTRIGHT;
//===========================================================================
// TCP/IP Joystick
static char joystick_device_name[] = "TCP/IP Joystick";
static SocketInfo TcpIpJoystickSocketInfo[1];
static int const TcpIpJoystickCommandMaxLength = 1 << 5; // must be a power of 2
static char TcpIpJoystickCommandBuffer[TcpIpJoystickCommandMaxLength] = "J1 65535 65535 15\n"; // sample data
static int TcpIpJoystickCommandLength = 0;
static bool TcpIpJoystickInitialized = false;
BOOL TcpIpJoystickSocketRxHandler(SocketInfo *socket_info_ptr, int c)
{
if (c != '\n') {
TcpIpJoystickCommandBuffer[TcpIpJoystickCommandLength++] = c;
TcpIpJoystickCommandLength &= (TcpIpJoystickCommandMaxLength - 1);
return TRUE; // we handled this
}
char *token;
int device = 0;
int x = 0, y = 0, buttons = 0;
TcpIpJoystickCommandBuffer[TcpIpJoystickCommandLength] = '\0';
TcpIpJoystickCommandLength = 0;
//printf("TCP/IP joystick command=%s\n", TcpIpJoystickCommandBuffer);
token = strtok(TcpIpJoystickCommandBuffer, " ");
if (token != NULL) {
// Device ID: J1, J2, P1, P2, M1
if (strlen(token) == 2) {
device = token[0] + (token[1] & 0xF);
}
token = strtok(NULL, " ");
}
if (token != NULL) {
x = atoi(token) >> 8; // 0 to 65335 -> 0 to 255
token = strtok(NULL, " ");
}
if (token != NULL) {
y = atoi(token) >> 8; // 0 to 65335 -> 0 to 255
token = strtok(NULL, " ");
}
if (token != NULL) {
buttons = atoi(token); // bitfield: 1=SW0 2=SW1 4=SW2 8=SW3
}
switch (device)
{
case 'J' + 1:
xpos[0] = x;
ypos[0] = y;
joybutton[0] = buttons & 0x1;
joybutton[1] = buttons & 0x2;
break;
case 'J' + 2:
xpos[1] = x;
ypos[1] = y;
joybutton[2] = buttons & 0x1;
break;
case 'P' + 1:
xpos[0] = x;
joybutton[0] = buttons & 0x1;
break;
case 'P' + 2:
ypos[0] = x;
joybutton[1] = buttons & 0x1;
break;
case 'M' + 1:
int iX, iMinX, iMaxX;
int iY, iMinY, iMaxY;
sg_Mouse.GetXY(iX, iMinX, iMaxX, iY, iMinY, iMaxY);
float fScaleX = (float)x / (float)255;
float fScaleY = (float)y / (float)255;
int iAppleX = iMinX + (int)(fScaleX * (float)(iMaxX - iMinX));
int iAppleY = iMinY + (int)(fScaleY * (float)(iMaxY - iMinY));
sg_Mouse.SetCursorPos(iAppleX, iAppleY); // Set new entry position
sg_Mouse.SetButton(BUTTON0, (buttons & 0x1) ? BUTTON_DOWN : BUTTON_UP);
sg_Mouse.SetButton(BUTTON1, (buttons & 0x2) ? BUTTON_DOWN : BUTTON_UP);
break;
}
return TRUE; // we handled this
}
void TcpIpJoystickShutdown()
{
if (TcpIpJoystickInitialized)
{
socket_close(&TcpIpJoystickSocketInfo[0], 0);
socket_shutdown(&TcpIpJoystickSocketInfo[0]);
TcpIpJoystickInitialized = false;
}
}
void TcpIpJoystickInit()
{
if (TcpIpJoystickInitialized)
return;
TcpIpJoystickSocketInfo[0].device_name = joystick_device_name;
TcpIpJoystickSocketInfo[0].device_data = NULL;
TcpIpJoystickSocketInfo[0].listen_port = 6503;
TcpIpJoystickSocketInfo[0].listen_tries = 2;
TcpIpJoystickSocketInfo[0].rx_handler = TcpIpJoystickSocketRxHandler;
if (sg_PropertySheet.GetTcpIpJoystock())
{
socket_init(&TcpIpJoystickSocketInfo[0]);
TcpIpJoystickInitialized = true;
}
}
void TcpIpJoystickUpdate()
{
if (sg_PropertySheet.GetTcpIpJoystock())
{
if (TcpIpJoystickInitialized)
socket_fill_readbuf(&TcpIpJoystickSocketInfo[0], 100, 0);
else
TcpIpJoystickInit();
}
else
{
if (TcpIpJoystickInitialized)
TcpIpJoystickShutdown();
}
}
//===========================================================================
void CheckJoystick0()
{
@ -240,6 +371,8 @@ void JoyInitialize()
joytype[1] = J1C_DISABLED;
}
}
TcpIpJoystickInit();
}
//===========================================================================
@ -486,6 +619,8 @@ BYTE __stdcall JoyReadButton(WORD pc, WORD address, BYTE, BYTE, ULONG nCyclesLef
{
address &= 0xFF;
TcpIpJoystickUpdate();
if(joyinfo[joytype[0]] == DEVICE_JOYSTICK)
CheckJoystick0();
if(joyinfo[joytype[1]] == DEVICE_JOYSTICK)
@ -557,6 +692,8 @@ static const double PDL_CNTR_INTERVAL = 2816.0 / 255.0; // 11.04 (From KEGS)
BYTE __stdcall JoyReadPosition(WORD programcounter, WORD address, BYTE, BYTE, ULONG nCyclesLeft)
{
TcpIpJoystickUpdate();
int nJoyNum = (address & 2) ? 1 : 0; // $C064..$C067
CpuCalcCycles(nCyclesLeft);

View File

@ -9,6 +9,8 @@ extern DWORD joytype[2];
enum {JOYSTICK_MODE_FLOATING=0, JOYSTICK_MODE_CENTERING}; // Joystick centering control
void TcpIpJoystickUpdate();
void JoyInitialize();
BOOL JoyProcessKey(int,BOOL,BOOL,BOOL);
void JoyReset();

View File

@ -13,6 +13,8 @@
#define WM_MOUSEWHEEL 0x020A
#endif
#include <winsock2.h>
// Not needed in VC7.1, but needed in VC Express
#include <tchar.h>