Merge from AppleWin-Tom @ 565-614 (Excluded HEAD=615, due to Tree Conflict errors)

Fix for SSC (big transfers): use queue instead of single byte buffer
New switches: -log, -no-mb, -spkr-max, -spkr-inc
Fix for Speaker underflow problem (max=200, inc=20)
SSC: Support 112.5K Baud
Dynamic 'Serial Port' drop-down menu
Save "Serial Port Name" to Registry (instead of drop-down menu index as "Serial Port")
This commit is contained in:
tomch 2009-10-07 21:38:42 +00:00
parent ec0afb8359
commit a769bdf256
13 changed files with 561 additions and 272 deletions

View File

@ -245,8 +245,8 @@ DISK_ICON ICON "DISK.ICO"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,16,1,0
PRODUCTVERSION 1,16,1,0
FILEVERSION 1,16,1,3
PRODUCTVERSION 1,16,1,3
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -264,12 +264,12 @@ BEGIN
VALUE "Comments", "http://applewin.berlios.de"
VALUE "CompanyName", "AppleWin"
VALUE "FileDescription", "Apple //e Emulator for Windows"
VALUE "FileVersion", "1, 16, 1, 0"
VALUE "FileVersion", "1, 16, 1, 3"
VALUE "InternalName", "APPLEWIN"
VALUE "LegalCopyright", " 1994-2009 Michael O'Brien, Oliver Schmidt, Tom Charlesworth, Michael Pohoreski, Nick Westgate, Linards Ticmanis"
VALUE "OriginalFilename", "APPLEWIN.EXE"
VALUE "ProductName", "Apple //e Emulator"
VALUE "ProductVersion", "1, 16, 1, 0"
VALUE "ProductVersion", "1, 16, 1, 3"
END
END
BLOCK "VarFileInfo"

View File

@ -71,6 +71,7 @@ DWORD g_dwCyclesThisFrame = 0;
FILE* g_fh = NULL;
bool g_bDisableDirectSound = false;
bool g_bDisableDirectSoundMockingboard = false;
CSuperSerialCard sg_SSC;
CMouseInterface sg_Mouse;
@ -464,16 +465,22 @@ void LoadConfiguration ()
REGLOAD(TEXT("Joystick 1 Emulation"),&joytype[1]);
REGLOAD(TEXT("Sound Emulation") ,&soundtype);
DWORD dwSerialPort;
if (REGLOAD(TEXT("Serial Port"),&dwSerialPort))
sg_SSC.SetSerialPort(dwSerialPort);
char aySerialPortName[ CSuperSerialCard::SIZEOF_SERIALCHOICE_ITEM ];
if (RegLoadString( TEXT("Configuration"),
TEXT(REGVALUE_SERIAL_PORT_NAME),
TRUE,
aySerialPortName,
sizeof(aySerialPortName) ) )
{
sg_SSC.SetSerialPortName(aySerialPortName);
}
REGLOAD(TEXT("Emulation Speed") ,&g_dwSpeed);
REGLOAD(TEXT("Enhance Disk Speed"),(DWORD *)&enhancedisk);
REGLOAD(TEXT("Emulation Speed") ,&g_dwSpeed);
REGLOAD(TEXT("Enhance Disk Speed"),(DWORD *)&enhancedisk);
Config_Load_Video();
Config_Load_Video();
REGLOAD(TEXT("Uthernet Active") ,(DWORD *)&tfe_enabled);
REGLOAD(TEXT("Uthernet Active") ,(DWORD *)&tfe_enabled);
SetCurrentCLK6502();
@ -760,8 +767,7 @@ int APIENTRY WinMain (HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
{
g_bRegisterFileTypes = false;
}
else
if(strcmp(lpCmdLine, "-d1") == 0)
else if(strcmp(lpCmdLine, "-d1") == 0)
{
lpCmdLine = GetCurrArg(lpNextArg);
lpNextArg = GetNextArg(lpNextArg);
@ -777,7 +783,7 @@ int APIENTRY WinMain (HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
{
bSetFullScreen = true;
}
else if((strcmp(lpCmdLine, "-l") == 0) && (g_fh == NULL))
else if(((strcmp(lpCmdLine, "-l") == 0) || (strcmp(lpCmdLine, "-log") == 0)) && (g_fh == NULL))
{
g_fh = fopen("AppleWin.log", "a+t"); // Open log file (append & text g_nAppMode)
CHAR aDateStr[80], aTimeStr[80];
@ -789,6 +795,10 @@ int APIENTRY WinMain (HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
{
g_bDisableDirectSound = true;
}
else if(strcmp(lpCmdLine, "-no-mb") == 0)
{
g_bDisableDirectSoundMockingboard = true;
}
#ifdef RAMWORKS
else if(strcmp(lpCmdLine, "-r") == 0) // RamWorks size [1..127]
{
@ -813,6 +823,20 @@ int APIENTRY WinMain (HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
{
g_bDisplayPrintScreenFileName = true;
}
else if(strcmp(lpCmdLine, "-spkr-inc") == 0)
{
lpCmdLine = GetCurrArg(lpNextArg);
lpNextArg = GetNextArg(lpNextArg);
const int nErrorInc = atoi(lpCmdLine);
SoundCore_SetErrorInc( nErrorInc );
}
else if(strcmp(lpCmdLine, "-spkr-max") == 0)
{
lpCmdLine = GetCurrArg(lpNextArg);
lpNextArg = GetNextArg(lpNextArg);
const int nErrorMax = atoi(lpCmdLine);
SoundCore_SetErrorMax( nErrorMax );
}
else if(strcmp(lpCmdLine, "-use-real-printer") == 0) // Enable control in Advanced config to allow dumping to a real printer
{
g_bEnableDumpToRealPrinter = true;

View File

@ -40,7 +40,8 @@ extern int g_nCpuCyclesFeedback;
extern DWORD g_dwCyclesThisFrame;
extern FILE* g_fh; // Filehandle for log file
extern bool g_bDisableDirectSound; // Cmd line switch: don't init DS (so no MB support)
extern bool g_bDisableDirectSound; // Cmd line switch: don't init DS (so no MB/Speaker support)
extern bool g_bDisableDirectSoundMockingboard; // Cmd line switch: don't init MB support
// TODO: Make g_CurrentPeripherals[MAX_SLOTS] = { CT_Empty }
extern UINT g_Slot4; // Mockingboard or Mouse in slot4

View File

@ -99,6 +99,7 @@ enum AppMode_e
#define REGVALUE_VIDEO_MODE "Video Emulation"
#define REGVALUE_VIDEO_HALF_SCAN_LINES "Half Scan Lines"
#define REGVALUE_VIDEO_MONO_COLOR "Monochrome Color"
#define REGVALUE_SERIAL_PORT_NAME "Serial Port Name"
// Preferences
#define REG_PREFS "Preferences"

View File

@ -177,7 +177,7 @@ static BYTE g_nPhasorMode = 0; // 0=Mockingboard emulation, 1=Phasor native
static const unsigned short g_nMB_NumChannels = 2;
static const DWORD g_dwDSBufferSize = 16 * 1024 * sizeof(short) * g_nMB_NumChannels;
static const DWORD g_dwDSBufferSize = MAX_SAMPLES * sizeof(short) * g_nMB_NumChannels;
static const SHORT nWaveDataMin = (SHORT)0x8000;
static const SHORT nWaveDataMax = (SHORT)0x7FFF;
@ -733,6 +733,8 @@ static void Votrax_Write(BYTE nDevice, BYTE nValue)
static void MB_Update()
{
char szDbg[200];
if (!MockingboardVoice.bActive)
return;
@ -816,13 +818,27 @@ static void MB_Update()
{
// |-----PxxxxxW-----|
if((dwByteOffset > dwCurrentPlayCursor) && (dwByteOffset < dwCurrentWriteCursor))
{
double fTicksSecs = (double)GetTickCount() / 1000.0;
sprintf(szDbg, "%010.3f: [MBUpdt] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X xxx\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples);
OutputDebugString(szDbg);
if (g_fh) fprintf(g_fh, szDbg);
dwByteOffset = dwCurrentWriteCursor;
}
}
else
{
// |xxW----------Pxxx|
if((dwByteOffset > dwCurrentPlayCursor) || (dwByteOffset < dwCurrentWriteCursor))
{
double fTicksSecs = (double)GetTickCount() / 1000.0;
sprintf(szDbg, "%010.3f: [MBUpdt] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X XXX\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples);
OutputDebugString(szDbg);
if (g_fh) fprintf(g_fh, szDbg);
dwByteOffset = dwCurrentWriteCursor;
}
}
}
@ -831,10 +847,11 @@ static void MB_Update()
nBytesRemaining += g_dwDSBufferSize;
// Calc correction factor so that play-buffer doesn't under/overflow
const int nErrorInc = SoundCore_GetErrorInc();
if(nBytesRemaining < g_dwDSBufferSize / 4)
nNumSamplesError++; // < 0.25 of buffer remaining
nNumSamplesError += nErrorInc; // < 0.25 of buffer remaining
else if(nBytesRemaining > g_dwDSBufferSize / 2)
nNumSamplesError--; // > 0.50 of buffer remaining
nNumSamplesError -= nErrorInc; // > 0.50 of buffer remaining
else
nNumSamplesError = 0; // Acceptable amount of data in buffer
@ -1292,7 +1309,7 @@ static void MB_DSUninit()
void MB_Initialize()
{
if(g_bDisableDirectSound)
if (g_bDisableDirectSound || g_bDisableDirectSoundMockingboard)
{
MockingboardVoice.bMute = true;
g_SoundcardType = SC_NONE;
@ -1312,7 +1329,6 @@ void MB_Initialize()
//
//DSInit();
g_bMBAvailable = MB_DSInit();
MB_Reset();
@ -1334,7 +1350,6 @@ void MB_Reinitialize()
void MB_Destroy()
{
MB_DSUninit();
//DSUninit();
for(int i=0; i<NUM_VOICES; i++)
delete [] ppAYVoiceBuffer[i];

View File

@ -72,13 +72,6 @@ TCHAR* pszJoy1Choices[J1C_MAX] = { szJoyChoice0,
int g_nJoy1ChoiceTranlationTbl[J1C_MAX];
TCHAR joystick1choices[J1C_MAX*g_nMaxJoyChoiceLen];
TCHAR serialchoices[] = TEXT("None\0")
TEXT("COM1\0")
TEXT("COM2\0")
TEXT("COM3\0")
TEXT("COM4\0")
TEXT("TCP\0");
TCHAR soundchoices[] = TEXT("Disabled\0")
TEXT("PC Speaker (direct)\0")
TEXT("PC Speaker (translated)\0")
@ -345,7 +338,11 @@ static void ConfigDlg_OK(HWND window, UINT afterclose)
else
REGSAVE(TEXT(REGVALUE_APPLE2_TYPE),NewApple2Type );
REGSAVE(TEXT("Serial Port") ,sg_SSC.GetSerialPort());
RegSaveString( TEXT("Configuration"),
TEXT(REGVALUE_SERIAL_PORT_NAME),
TRUE,
sg_SSC.GetSerialPortName() );
REGSAVE(TEXT("Custom Speed") ,IsDlgButtonChecked(window,IDC_CUSTOM_SPEED));
REGSAVE(TEXT("Emulation Speed") ,g_dwSpeed);
@ -479,8 +476,10 @@ static BOOL CALLBACK ConfigDlgProc (HWND window,
FillComboBox(window,IDC_VIDEOTYPE,videochoices,g_eVideoType);
CheckDlgButton(window, IDC_CHECK_HALF_SCAN_LINES, g_uHalfScanLines ? BST_CHECKED : BST_UNCHECKED);
FillComboBox(window,IDC_SERIALPORT,serialchoices,sg_SSC.GetSerialPort());
FillComboBox(window,IDC_SERIALPORT, sg_SSC.GetSerialPortChoices(), sg_SSC.GetSerialPort());
EnableWindow(GetDlgItem(window, IDC_SERIALPORT), !sg_SSC.IsActive() ? TRUE : FALSE);
SendDlgItemMessage(window,IDC_SLIDER_CPU_SPEED,TBM_SETRANGE,1,MAKELONG(0,40));
SendDlgItemMessage(window,IDC_SLIDER_CPU_SPEED,TBM_SETPAGESIZE,0,5);
SendDlgItemMessage(window,IDC_SLIDER_CPU_SPEED,TBM_SETTICFREQ,10,0);

View File

@ -4,7 +4,7 @@ AppleWin : An Apple //e emulator for Windows
Copyright (C) 1994-1996, Michael O'Brien
Copyright (C) 1999-2001, Oliver Schmidt
Copyright (C) 2002-2005, Tom Charlesworth
Copyright (C) 2006-2007, Tom Charlesworth, Michael Pohoreski
Copyright (C) 2006-2009, Tom Charlesworth, Michael Pohoreski, Nick Westgate
AppleWin is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -43,7 +43,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "..\resource\resource.h"
//#define SUPPORT_MODEM
#define TCP_SERIAL_OPTION 5
#define TCP_SERIAL_PORT 1977
// Default: 19200-8-N-1
@ -64,31 +63,50 @@ SSC_DIPSW CSuperSerialCard::m_DIPSWDefault =
//===========================================================================
CSuperSerialCard::CSuperSerialCard()
CSuperSerialCard::CSuperSerialCard() :
m_aySerialPortChoices(NULL),
m_uTCPChoiceItemIdx(0)
{
m_dwSerialPort = 0;
GetDIPSW();
m_vRecvBytes = 0;
memset(m_ayCurrentSerialPortName, 0, sizeof(m_ayCurrentSerialPortName));
m_dwSerialPortItem = 0;
m_hCommHandle = INVALID_HANDLE_VALUE;
m_hCommListenSocket = INVALID_SOCKET;
m_hCommAcceptSocket = INVALID_SOCKET;
m_dwCommInactivity = 0;
m_bTxIrqEnabled = false;
m_bRxIrqEnabled = false;
m_bWrittenTx = false;
m_vbCommIRQ = false;
m_hCommThread = NULL;
for (UINT i=0; i<COMMEVT_MAX; i++)
m_hCommEvent[i] = NULL;
memset(&m_o, 0, sizeof(m_o));
InternalReset();
}
void CSuperSerialCard::InternalReset()
{
GetDIPSW();
m_bTxIrqEnabled = false;
m_bRxIrqEnabled = false;
m_bWrittenTx = false;
m_vuRxCurrBuffer = 0;
m_vbTxIrqPending = false;
m_vbRxIrqPending = false;
m_qComSerialBuffer[0].c.clear();
m_qComSerialBuffer[1].c.clear();
m_qTcpSerialBuffer.c.clear();
}
CSuperSerialCard::~CSuperSerialCard()
{
delete [] m_aySerialPortChoices;
}
//===========================================================================
@ -195,91 +213,101 @@ BOOL CSuperSerialCard::CheckComm()
m_dwCommInactivity = 0;
// check for COM or TCP socket handle, and setup if invalid
if ((m_hCommHandle == INVALID_HANDLE_VALUE) && (m_hCommListenSocket == INVALID_SOCKET))
if (IsActive())
return true;
if (m_dwSerialPortItem == m_uTCPChoiceItemIdx)
{
if (m_dwSerialPort == TCP_SERIAL_OPTION)
// init Winsock 1.1 (for Win95, otherwise could use 2.2)
WSADATA wsaData;
if (WSAStartup(MAKEWORD(1, 1), &wsaData) == 0) // or (2, 2) for Winsock 2.2
{
// init Winsock 1.1 (for Win95, otherwise could use 2.2)
WSADATA wsaData;
if (WSAStartup(MAKEWORD(1, 1), &wsaData) == 0) // or (2, 2) for Winsock 2.2
if (wsaData.wVersion != 0x0101) // or 0x0202 for Winsock 2.2
{
if (wsaData.wVersion != 0x0101) // or 0x0202 for Winsock 2.2
{
WSACleanup();
return FALSE;
}
// initialized, so try to create a socket
m_hCommListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_hCommListenSocket == INVALID_SOCKET)
{
WSACleanup();
return FALSE;
}
// have socket so attempt to bind it
SOCKADDR_IN saAddress;
saAddress.sin_family = AF_INET;
saAddress.sin_port = htons(TCP_SERIAL_PORT); // TODO: get from registry / GUI
saAddress.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(m_hCommListenSocket, (LPSOCKADDR)&saAddress, sizeof(saAddress)) == SOCKET_ERROR)
{
m_hCommListenSocket = INVALID_SOCKET;
WSACleanup();
return FALSE;
}
// bound, so listen
if (listen(m_hCommListenSocket, 1) == SOCKET_ERROR)
{
m_hCommListenSocket = INVALID_SOCKET;
WSACleanup();
return FALSE;
}
// now send async events to our app's message handler
if (WSAAsyncSelect(
/* SOCKET s */ m_hCommListenSocket,
/* HWND hWnd */ g_hFrameWindow,
/* unsigned int wMsg */ WM_USER_TCP_SERIAL,
/* long lEvent */ (FD_ACCEPT | FD_CONNECT | FD_READ | FD_CLOSE)) != 0)
{
m_hCommListenSocket = INVALID_SOCKET;
WSACleanup();
return FALSE;
}
WSACleanup();
return FALSE;
}
}
else
{
TCHAR portname[8];
wsprintf(portname, TEXT("COM%u"), m_dwSerialPort);
m_hCommHandle = CreateFile(portname,
GENERIC_READ | GENERIC_WRITE,
0, // exclusive access
(LPSECURITY_ATTRIBUTES)NULL, // default security attributes
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, // required for WaitCommEvent()
NULL);
if (m_hCommHandle != INVALID_HANDLE_VALUE)
// initialized, so try to create a socket
m_hCommListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_hCommListenSocket == INVALID_SOCKET)
{
UpdateCommState();
COMMTIMEOUTS ct;
ZeroMemory(&ct,sizeof(COMMTIMEOUTS));
ct.ReadIntervalTimeout = MAXDWORD;
SetCommTimeouts(m_hCommHandle,&ct);
CommThInit();
WSACleanup();
return FALSE;
}
else
// have socket so attempt to bind it
SOCKADDR_IN saAddress;
saAddress.sin_family = AF_INET;
saAddress.sin_port = htons(TCP_SERIAL_PORT); // TODO: get from registry / GUI
saAddress.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(m_hCommListenSocket, (LPSOCKADDR)&saAddress, sizeof(saAddress)) == SOCKET_ERROR)
{
DWORD uError = GetLastError();
m_hCommListenSocket = INVALID_SOCKET;
WSACleanup();
return FALSE;
}
// bound, so listen
if (listen(m_hCommListenSocket, 1) == SOCKET_ERROR)
{
m_hCommListenSocket = INVALID_SOCKET;
WSACleanup();
return FALSE;
}
// now send async events to our app's message handler
if (WSAAsyncSelect(
/* SOCKET s */ m_hCommListenSocket,
/* HWND hWnd */ g_hFrameWindow,
/* unsigned int wMsg */ WM_USER_TCP_SERIAL,
/* long lEvent */ (FD_ACCEPT | FD_CONNECT | FD_READ | FD_CLOSE)) != 0)
{
m_hCommListenSocket = INVALID_SOCKET;
WSACleanup();
return FALSE;
}
}
}
else
{
_ASSERT(m_dwSerialPortItem);
_ASSERT(m_dwSerialPortItem < m_vecSerialPortsItems.size()-1); // size()-1 is TCP item
TCHAR portname[SIZEOF_SERIALCHOICE_ITEM];
wsprintf(portname, TEXT("COM%u"), m_vecSerialPortsItems[m_dwSerialPortItem]);
return ((m_hCommHandle != INVALID_HANDLE_VALUE) || (m_hCommListenSocket != INVALID_SOCKET));
m_hCommHandle = CreateFile(portname,
GENERIC_READ | GENERIC_WRITE,
0, // exclusive access
(LPSECURITY_ATTRIBUTES)NULL, // default security attributes
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, // required for WaitCommEvent()
NULL);
if (m_hCommHandle != INVALID_HANDLE_VALUE)
{
//BOOL bRes = SetupComm(m_hCommHandle, 8192, 8192);
//_ASSERT(bRes);
UpdateCommState();
// ReadIntervalTimeout=MAXDWORD; ReadTotalTimeoutConstant=ReadTotalTimeoutMultiplier=0:
// Read operation is to return immediately with the bytes that have already been received,
// even if no bytes have been received.
COMMTIMEOUTS ct;
ZeroMemory(&ct,sizeof(COMMTIMEOUTS));
ct.ReadIntervalTimeout = MAXDWORD;
SetCommTimeouts(m_hCommHandle,&ct);
CommThInit();
}
else
{
DWORD uError = GetLastError();
}
}
return IsActive();
}
//===========================================================================
@ -323,9 +351,9 @@ void CSuperSerialCard::CommTcpSerialClose()
closesocket(m_hCommAcceptSocket);
m_hCommAcceptSocket = INVALID_SOCKET;
}
while (!m_TcpSerialBuffer.empty())
while (!m_qTcpSerialBuffer.empty())
{
m_TcpSerialBuffer.pop();
m_qTcpSerialBuffer.pop();
}
}
@ -347,19 +375,18 @@ void CSuperSerialCard::CommTcpSerialReceive()
{
if (m_hCommAcceptSocket != INVALID_SOCKET)
{
char data[0x80];
int received = 0;
while ((received = recv(m_hCommAcceptSocket, data, sizeof(data), 0)) > 0)
char Data[0x80];
int nReceived = 0;
while ((nReceived = recv(m_hCommAcceptSocket, Data, sizeof(Data), 0)) > 0)
{
for (int i = 0; i < received; i++)
for (int i = 0; i < nReceived; i++)
{
m_TcpSerialBuffer.push(data[i]);
m_qTcpSerialBuffer.push(Data[i]);
}
}
if (m_bRxIrqEnabled && !m_TcpSerialBuffer.empty())
if (m_bRxIrqEnabled && !m_qTcpSerialBuffer.empty())
{
m_vbCommIRQ = true;
CpuIrqAssert(IS_SSC);
}
}
@ -509,22 +536,22 @@ BYTE __stdcall CSuperSerialCard::CommControl(WORD, WORD, BYTE write, BYTE value,
// a decent buffer in the device being accessed. The faster Apples
// have no difficulty with this speed, however.
case 0x00: // fall through [16x external clock]
case 0x00: m_uBaudRate = CBR_115200; break; // Internal clk: undoc'd 115.2K (or 16x external clock)
case 0x01: // fall through [50 bps]
case 0x02: // fall through [75 bps]
case 0x03: // fall through [109.92 bps]
case 0x04: // fall through [134.58 bps]
case 0x05: m_uBaudRate = CBR_110; break; // [150 bps]
case 0x06: m_uBaudRate = CBR_300; break;
case 0x07: m_uBaudRate = CBR_600; break;
case 0x08: m_uBaudRate = CBR_1200; break;
case 0x05: m_uBaudRate = CBR_110; break; // [150 bps]
case 0x06: m_uBaudRate = CBR_300; break;
case 0x07: m_uBaudRate = CBR_600; break;
case 0x08: m_uBaudRate = CBR_1200; break;
case 0x09: // fall through [1800 bps]
case 0x0A: m_uBaudRate = CBR_2400; break;
case 0x0A: m_uBaudRate = CBR_2400; break;
case 0x0B: // fall through [3600 bps]
case 0x0C: m_uBaudRate = CBR_4800; break;
case 0x0C: m_uBaudRate = CBR_4800; break;
case 0x0D: // fall through [7200 bps]
case 0x0E: m_uBaudRate = CBR_9600; break;
case 0x0F: m_uBaudRate = CBR_19200; break;
case 0x0E: m_uBaudRate = CBR_9600; break;
case 0x0F: m_uBaudRate = CBR_19200; break;
}
if (m_uControlByte & 0x10)
@ -535,10 +562,10 @@ BYTE __stdcall CSuperSerialCard::CommControl(WORD, WORD, BYTE write, BYTE value,
// UPDATE THE BYTE SIZE
switch (m_uControlByte & 0x60)
{
case 0x00: m_uByteSize = 8; break;
case 0x20: m_uByteSize = 7; break;
case 0x40: m_uByteSize = 6; break;
case 0x60: m_uByteSize = 5; break;
case 0x00: m_uByteSize = 8; break;
case 0x20: m_uByteSize = 7; break;
case 0x40: m_uByteSize = 6; break;
case 0x60: m_uByteSize = 5; break;
}
// UPDATE THE NUMBER OF STOP BITS
@ -564,6 +591,8 @@ BYTE __stdcall CSuperSerialCard::CommControl(WORD, WORD, BYTE write, BYTE value,
//===========================================================================
static UINT g_uDbgTotalSSCRx = 0;
BYTE __stdcall CSuperSerialCard::CommReceive(WORD, WORD, BYTE, BYTE, ULONG)
{
if (!CheckComm())
@ -571,24 +600,40 @@ BYTE __stdcall CSuperSerialCard::CommReceive(WORD, WORD, BYTE, BYTE, ULONG)
BYTE result = 0;
if (!m_TcpSerialBuffer.empty())
if (!m_qTcpSerialBuffer.empty())
{
result = m_TcpSerialBuffer.front();
m_TcpSerialBuffer.pop();
result = m_qTcpSerialBuffer.front();
m_qTcpSerialBuffer.pop();
}
else if (m_vRecvBytes)
else if (m_hCommHandle != INVALID_HANDLE_VALUE) // COM
{
// Don't need critical section in here as CommThread is waiting for ACK
result = m_RecvBuffer[0];
--m_vRecvBytes;
if (m_vbCommIRQ && !m_vRecvBytes)
EnterCriticalSection(&m_CriticalSection);
{
// Read last byte, so get CommThread to call WaitCommEvent() again
OutputDebugString("CommRecv: SetEvent - ACK\n");
SetEvent(m_hCommEvent[COMMEVT_ACK]);
const UINT uCOMIdx = m_vuRxCurrBuffer;
const UINT uSSCIdx = uCOMIdx ^ 1;
if (!m_qComSerialBuffer[uSSCIdx].empty())
{
result = m_qComSerialBuffer[uSSCIdx].front();
m_qComSerialBuffer[uSSCIdx].pop();
UINT uNewSSCIdx = uSSCIdx;
if ( m_qComSerialBuffer[uSSCIdx].empty() && // Current SSC buffer is empty
!m_qComSerialBuffer[uCOMIdx].empty() ) // Current COM buffer has data
{
m_vuRxCurrBuffer = uSSCIdx; // Flip buffers
uNewSSCIdx = uCOMIdx;
}
if (m_bRxIrqEnabled && !m_qComSerialBuffer[uNewSSCIdx].empty())
{
CpuIrqAssert(IS_SSC);
m_vbRxIrqPending = true;
}
}
}
LeaveCriticalSection(&m_CriticalSection);
g_uDbgTotalSSCRx++;
}
return result;
@ -668,11 +713,13 @@ BYTE __stdcall CSuperSerialCard::CommStatus(WORD, WORD, BYTE, BYTE, ULONG)
// . IRQs disabled : always set it [Currently done]
//
// So that /m_vRecvBytes/ doesn't change midway (from 0 to 1):
// . bIRQ=false, but uStatus.ST_RX_FULL=1
bool bComSerialBufferEmpty = true; // Assume true, so if using TCP then logic below works
if (m_hCommHandle != INVALID_HANDLE_VALUE)
{
EnterCriticalSection(&m_CriticalSection);
const UINT uSSCIdx = m_vuRxCurrBuffer ^ 1;
bComSerialBufferEmpty = m_qComSerialBuffer[uSSCIdx].empty();
}
bool bIRQ = false;
@ -680,17 +727,18 @@ BYTE __stdcall CSuperSerialCard::CommStatus(WORD, WORD, BYTE, BYTE, ULONG)
{
bIRQ = true;
}
if (m_bRxIrqEnabled && (m_vRecvBytes || !m_TcpSerialBuffer.empty()))
if (m_bRxIrqEnabled)
{
bIRQ = true;
bIRQ = m_vbRxIrqPending;
m_vbRxIrqPending = false; // Ensure 2 reads of STATUS reg only return ST_IRQ for first read
}
m_bWrittenTx = false; // Read status reg always clears IRQ
m_bWrittenTx = false; // Read status reg always clears IRQ
//
BYTE uStatus = ST_TX_EMPTY
| ((m_vRecvBytes || !m_TcpSerialBuffer.empty()) ? ST_RX_FULL : 0x00)
| ((!bComSerialBufferEmpty || !m_qTcpSerialBuffer.empty()) ? ST_RX_FULL : 0x00)
#ifdef SUPPORT_MODEM
| ((modemstatus & MS_RLSD_ON) ? 0x00 : ST_DCD) // Need 0x00 to allow ZLink to start up
| ((modemstatus & MS_DSR_ON) ? 0x00 : ST_DSR)
@ -798,18 +846,7 @@ void CSuperSerialCard::CommReset()
{
CloseComm();
GetDIPSW();
m_vRecvBytes = 0;
//
m_bTxIrqEnabled = false;
m_bRxIrqEnabled = false;
m_bWrittenTx = false;
m_vbCommIRQ = false;
InternalReset();
}
//===========================================================================
@ -824,27 +861,31 @@ void CSuperSerialCard::CommDestroy()
//===========================================================================
void CSuperSerialCard::CommSetSerialPort(HWND window, DWORD newserialport)
// dwNewSerialPortItem is the drop-down list item
void CSuperSerialCard::CommSetSerialPort(HWND hWindow, DWORD dwNewSerialPortItem)
{
if ((m_hCommHandle == INVALID_HANDLE_VALUE) && (m_hCommListenSocket == INVALID_SOCKET))
{
m_dwSerialPort = newserialport;
}
if (m_dwSerialPortItem == dwNewSerialPortItem)
return;
_ASSERT(!IsActive());
if (IsActive())
return;
m_dwSerialPortItem = dwNewSerialPortItem;
if (m_dwSerialPortItem == m_uTCPChoiceItemIdx)
strcpy(m_ayCurrentSerialPortName, TEXT_SERIAL_TCP);
else if (m_dwSerialPortItem != 0)
sprintf(m_ayCurrentSerialPortName, TEXT_SERIAL_COM"%d", m_vecSerialPortsItems[m_dwSerialPortItem]);
else
{
MessageBox(window,
TEXT("You cannot change the serial port while it is ")
TEXT("in use."),
TEXT("Configuration"),
MB_ICONEXCLAMATION | MB_SETFOREGROUND);
}
m_ayCurrentSerialPortName[0] = 0; // "None"
}
//===========================================================================
void CSuperSerialCard::CommUpdate(DWORD totalcycles)
{
if ((m_hCommHandle == INVALID_HANDLE_VALUE) && (m_hCommListenSocket == INVALID_SOCKET))
if (!IsActive())
return;
if ((m_dwCommInactivity += totalcycles) > 1000000)
@ -871,25 +912,87 @@ void CSuperSerialCard::CommUpdate(DWORD totalcycles)
//===========================================================================
// Had this error when sizeof(m_RecvBuffer)==1 was used
// UPDATE: Fixed by using double-buffered queue
//
// ERROR_OPERATION_ABORTED: CE_RXOVER
//
// Config:
// . DOS Box (laptop) -> ZLink (PC)
// . Baud = 300/4800/9600/19200
// . InQueue size = 0x1000
// . AppleII speed = 1MHz/2MHz/Unthrottled
// . TYPE AW-PascalCrash.txt >COM7
// . NB. AW-PascalCrash.txt is 10020 bytes
//
// Error:
// . Always get ERROR_OPERATION_ABORTED after reading 0x555 total bytes
// . dwErrors = 1 (CE_RXOVER)
// . COMSTAT::InQueue = 0x1000
//
static UINT g_uDbgTotalCOMRx = 0;
void CSuperSerialCard::CheckCommEvent(DWORD dwEvtMask)
{
if (dwEvtMask & EV_RXCHAR)
{
EnterCriticalSection(&m_CriticalSection);
ReadFile(m_hCommHandle, m_RecvBuffer, 1, (DWORD*)&m_vRecvBytes, &m_o);
LeaveCriticalSection(&m_CriticalSection);
char Data[0x80];
DWORD dwReceived = 0;
bool bGotData = false;
if (m_bRxIrqEnabled && m_vRecvBytes)
// Read COM buffer until empty
// NB. Potentially dangerous, as Apple read rate might be too slow, so could run out of memory on PC!
do
{
m_vbCommIRQ = true;
CpuIrqAssert(IS_SSC);
if (!ReadFile(m_hCommHandle, Data, sizeof(Data), &dwReceived, &m_o) || !dwReceived)
break;
g_uDbgTotalCOMRx += dwReceived;
bGotData = true;
EnterCriticalSection(&m_CriticalSection);
{
const UINT uCOMIdx = m_vuRxCurrBuffer;
for (DWORD i = 0; i < dwReceived; i++)
m_qComSerialBuffer[uCOMIdx].push(Data[i]);
}
LeaveCriticalSection(&m_CriticalSection);
}
while(sizeof(Data) == dwReceived);
//
if (bGotData)
{
EnterCriticalSection(&m_CriticalSection);
{
// NB. m_vuRxCurrBuffer may've changed since ReadFile() above -- can change in CommReceive()
// - Maybe buffers have already been flipped
const UINT uCOMIdx = m_vuRxCurrBuffer;
const UINT uSSCIdx = uCOMIdx ^ 1;
if ( m_qComSerialBuffer[uSSCIdx].empty() && // Current SSC buffer is empty
!m_qComSerialBuffer[uCOMIdx].empty() ) // Current COM buffer has data
{
m_vuRxCurrBuffer = uSSCIdx; // Flip buffers
if (m_bRxIrqEnabled)
{
CpuIrqAssert(IS_SSC);
m_vbRxIrqPending = true;
}
}
}
LeaveCriticalSection(&m_CriticalSection);
}
}
//else if (dwEvtMask & EV_TXEMPTY)
//{
// if (m_bTxIrqEnabled)
// {
// m_vbCommIRQ = true;
// m_vbTxIrqPending = true;
// CpuIrqAssert(IS_SSC);
// }
//}
@ -908,19 +1011,9 @@ DWORD WINAPI CSuperSerialCard::CommThread(LPVOID lpParameter)
//
const UINT nNumEvents = 2;
#if 1
HANDLE hCommEvent_Wait[nNumEvents] = {pSSC->m_hCommEvent[COMMEVT_WAIT], pSSC->m_hCommEvent[COMMEVT_TERM]};
HANDLE hCommEvent_Ack[nNumEvents] = {pSSC->m_hCommEvent[COMMEVT_ACK], pSSC->m_hCommEvent[COMMEVT_TERM]};
#else
HANDLE hCommEvent_Wait[nNumEvents];
HANDLE hCommEvent_Ack[nNumEvents];
hCommEvent_Wait[0] = m_hCommEvent[COMMEVT_WAIT];
hCommEvent_Wait[1] = m_hCommEvent[COMMEVT_TERM];
hCommEvent_Ack[0] = m_hCommEvent[COMMEVT_ACK];
hCommEvent_Ack[1] = m_hCommEvent[COMMEVT_TERM];
#endif
while(1)
{
@ -932,10 +1025,25 @@ DWORD WINAPI CSuperSerialCard::CommThread(LPVOID lpParameter)
if (!bRes)
{
DWORD dwRet = GetLastError();
// Got this error once: ERROR_OPERATION_ABORTED
_ASSERT(dwRet == ERROR_IO_PENDING);
if (dwRet != ERROR_IO_PENDING)
{
// Probably: ERROR_OPERATION_ABORTED
DWORD dwErrors;
COMSTAT Stat;
ClearCommError(pSSC->m_hCommHandle, &dwErrors, &Stat);
if (dwErrors)
{
if (dwErrors & CE_RXOVER)
sprintf(szDbg, "CommThread: Err=CE_RXOVER (0x%08X): InQueue=0x%08X\n", dwErrors, Stat.cbInQue);
else
sprintf(szDbg, "CommThread: Err=Other (0x%08X): InQueue=0x%08X, OutQueue=0x%08X\n", dwErrors, Stat.cbInQue, Stat.cbOutQue);
OutputDebugString(szDbg);
if (g_fh)
fprintf(g_fh, szDbg);
}
return -1;
}
//
// Wait for comm event
@ -943,7 +1051,7 @@ DWORD WINAPI CSuperSerialCard::CommThread(LPVOID lpParameter)
while(1)
{
OutputDebugString("CommThread: Wait1\n");
//OutputDebugString("CommThread: Wait1\n");
dwWaitResult = WaitForMultipleObjects(
nNumEvents, // number of handles in array
hCommEvent_Wait, // array of event handles
@ -959,7 +1067,7 @@ DWORD WINAPI CSuperSerialCard::CommThread(LPVOID lpParameter)
}
dwWaitResult -= WAIT_OBJECT_0; // Determine event # that signaled
sprintf(szDbg, "CommThread: GotEvent1: %d\n", dwWaitResult); OutputDebugString(szDbg);
//sprintf(szDbg, "CommThread: GotEvent1: %d\n", dwWaitResult); OutputDebugString(szDbg);
if (dwWaitResult == (nNumEvents-1))
break; // Termination event
@ -967,34 +1075,6 @@ DWORD WINAPI CSuperSerialCard::CommThread(LPVOID lpParameter)
// Comm event
pSSC->CheckCommEvent(dwEvtMask);
if (pSSC->m_vbCommIRQ)
{
//
// Wait for ack
//
while(1)
{
OutputDebugString("CommThread: Wait2\n");
dwWaitResult = WaitForMultipleObjects(
nNumEvents, // number of handles in array
hCommEvent_Ack, // array of event handles
FALSE, // wait until any one is signaled
INFINITE);
if ((dwWaitResult >= WAIT_OBJECT_0) && (dwWaitResult <= WAIT_OBJECT_0+nNumEvents-1))
break;
}
dwWaitResult -= WAIT_OBJECT_0; // Determine event # that signaled
sprintf(szDbg, "CommThread: GotEvent2: %d\n", dwWaitResult); OutputDebugString(szDbg);
if (dwWaitResult == (nNumEvents-1))
break; // Termination event
pSSC->m_vbCommIRQ = false;
}
}
return 0;
@ -1101,6 +1181,112 @@ void CSuperSerialCard::CommThUninit()
//===========================================================================
void CSuperSerialCard::ScanCOMPorts()
{
m_vecSerialPortsItems.clear();
m_vecSerialPortsItems.push_back(SERIALPORTITEM_INVALID_COM_PORT); // "None"
for (UINT i=1; i<32; i++) // Arbitrary upper limit
{
TCHAR portname[SIZEOF_SERIALCHOICE_ITEM];
wsprintf(portname, TEXT("COM%u"), i);
HANDLE hCommHandle = CreateFile(portname,
GENERIC_READ | GENERIC_WRITE,
0, // exclusive access
(LPSECURITY_ATTRIBUTES)NULL, // default security attributes
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, // required for WaitCommEvent()
NULL);
if (hCommHandle != INVALID_HANDLE_VALUE)
{
CloseHandle(hCommHandle);
m_vecSerialPortsItems.push_back(i);
}
}
//
m_vecSerialPortsItems.push_back(SERIALPORTITEM_INVALID_COM_PORT); // "TCP"
m_uTCPChoiceItemIdx = m_vecSerialPortsItems.size()-1;
}
char* CSuperSerialCard::GetSerialPortChoices()
{
if (IsActive())
return m_aySerialPortChoices;
//
ScanCOMPorts(); // Do this every time in case news ones available (eg. for USB COM ports)
delete [] m_aySerialPortChoices;
m_aySerialPortChoices = new TCHAR [ GetNumSerialPortChoices() * SIZEOF_SERIALCHOICE_ITEM + 1 ]; // +1 for final NULL item
TCHAR* pNextSerialChoice = m_aySerialPortChoices;
//
pNextSerialChoice += wsprintf(pNextSerialChoice, TEXT("None"));
pNextSerialChoice++; // Skip NULL char
for (UINT i=1; i<m_uTCPChoiceItemIdx; i++)
{
pNextSerialChoice += wsprintf(pNextSerialChoice, TEXT("COM%u"), m_vecSerialPortsItems[i]);
pNextSerialChoice++; // Skip NULL char
}
pNextSerialChoice += wsprintf(pNextSerialChoice, TEXT("TCP"));
pNextSerialChoice++; // Skip NULL char
*pNextSerialChoice = 0;
//
return m_aySerialPortChoices;
}
void CSuperSerialCard::SetSerialPortName(const char* pSerialPortName)
{
strncpy(m_ayCurrentSerialPortName, pSerialPortName, SIZEOF_SERIALCHOICE_ITEM);
if (m_vecSerialPortsItems.empty())
ScanCOMPorts();
if (strncmp(TEXT_SERIAL_COM, pSerialPortName, sizeof(TEXT_SERIAL_COM)-1) == 0)
{
const char* p = &pSerialPortName[ sizeof(TEXT_SERIAL_COM)-1 ];
const int nCOMPort = atoi(p);
m_dwSerialPortItem = 0;
for (UINT i=0; i<m_vecSerialPortsItems.size(); i++)
{
if (m_vecSerialPortsItems[i] == nCOMPort)
{
m_dwSerialPortItem = i;
break;
}
}
//_ASSERT(m_dwSerialPortItem); // EG. Switched a USB COM port from COM7 to COM8 between AppleWin sessions
if (m_dwSerialPortItem >= GetNumSerialPortChoices())
{
_ASSERT(0);
m_dwSerialPortItem = 0;
}
}
else if (strncmp(TEXT_SERIAL_TCP, pSerialPortName, sizeof(TEXT_SERIAL_TCP)-1) == 0)
{
m_dwSerialPortItem = m_uTCPChoiceItemIdx;
}
else
{
m_ayCurrentSerialPortName[0] = 0; // "None"
m_dwSerialPortItem = 0;
}
}
//===========================================================================
DWORD CSuperSerialCard::CommGetSnapshot(SS_IO_Comms* pSS)
{
pSS->baudrate = m_uBaudRate;
@ -1109,8 +1295,8 @@ DWORD CSuperSerialCard::CommGetSnapshot(SS_IO_Comms* pSS)
pSS->comminactivity = m_dwCommInactivity;
pSS->controlbyte = m_uControlByte;
pSS->parity = m_uParity;
memcpy(pSS->recvbuffer, m_RecvBuffer, uRecvBufferSize);
pSS->recvbytes = m_vRecvBytes;
// memcpy(pSS->recvbuffer, m_RecvBuffer, uRecvBufferSize);
pSS->recvbytes = 0;
pSS->stopbits = m_uStopBits;
return 0;
}
@ -1123,8 +1309,8 @@ DWORD CSuperSerialCard::CommSetSnapshot(SS_IO_Comms* pSS)
m_dwCommInactivity = pSS->comminactivity;
m_uControlByte = pSS->controlbyte;
m_uParity = pSS->parity;
memcpy(m_RecvBuffer, pSS->recvbuffer, uRecvBufferSize);
m_vRecvBytes = pSS->recvbytes;
// memcpy(m_RecvBuffer, pSS->recvbuffer, uRecvBufferSize);
// m_vRecvBytes = pSS->recvbytes;
m_uStopBits = pSS->stopbits;
return 0;
}

View File

@ -20,22 +20,28 @@ typedef struct
bool bInterrupts;
} SSC_DIPSW;
#define TEXT_SERIAL_COM TEXT("COM")
#define TEXT_SERIAL_TCP TEXT("TCP")
class CSuperSerialCard
{
public:
CSuperSerialCard();
virtual ~CSuperSerialCard() {}
virtual ~CSuperSerialCard();
void CommInitialize(LPBYTE pCxRomPeripheral, UINT uSlot);
void CommReset();
void CommDestroy();
void CommSetSerialPort(HWND,DWORD);
void CommSetSerialPort(HWND hWindow, DWORD dwNewSerialPortItem);
void CommUpdate(DWORD);
DWORD CommGetSnapshot(SS_IO_Comms* pSS);
DWORD CommSetSnapshot(SS_IO_Comms* pSS);
DWORD GetSerialPort() { return m_dwSerialPort; }
void SetSerialPort(DWORD dwSerialPort) { m_dwSerialPort = dwSerialPort; }
char* GetSerialPortChoices();
DWORD GetSerialPort() { return m_dwSerialPortItem; } // Drop-down list item
char* GetSerialPortName() { return m_ayCurrentSerialPortName; }
void SetSerialPortName(const char* pSerialPortName);
bool IsActive() { return (m_hCommHandle != INVALID_HANDLE_VALUE) || (m_hCommListenSocket != INVALID_SOCKET); }
void CommTcpSerialAccept();
void CommTcpSerialReceive();
@ -53,6 +59,7 @@ private:
BYTE __stdcall CommStatus(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
BYTE __stdcall CommTransmit(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
void InternalReset();
void GetDIPSW();
void SetDIPSWDefaults();
BYTE GenerateControl();
@ -64,11 +71,22 @@ private:
static DWORD WINAPI CommThread(LPVOID lpParameter);
bool CommThInit();
void CommThUninit();
UINT GetNumSerialPortChoices() { return m_vecSerialPortsItems.size(); }
void ScanCOMPorts();
//
public:
static const UINT SIZEOF_SERIALCHOICE_ITEM = 8*sizeof(char);
private:
DWORD m_dwSerialPort;
char m_ayCurrentSerialPortName[SIZEOF_SERIALCHOICE_ITEM];
DWORD m_dwSerialPortItem;
static const UINT SERIALPORTITEM_INVALID_COM_PORT = 0;
std::vector<UINT> m_vecSerialPortsItems; // Includes "None" & "TCP" items
char* m_aySerialPortChoices;
UINT m_uTCPChoiceItemIdx;
static SSC_DIPSW m_DIPSWDefault;
SSC_DIPSW m_DIPSWCurrent;
@ -95,20 +113,22 @@ private:
//
CRITICAL_SECTION m_CriticalSection; // To guard /g_vRecvBytes/
BYTE m_RecvBuffer[uRecvBufferSize]; // NB: More work required if >1 is used
queue<BYTE> m_TcpSerialBuffer;
volatile DWORD m_vRecvBytes;
queue<BYTE> m_qComSerialBuffer[2];
volatile UINT m_vuRxCurrBuffer; // Written to on COM recv. SSC reads from other one
queue<BYTE> m_qTcpSerialBuffer;
//
bool m_bTxIrqEnabled;
bool m_bRxIrqEnabled;
volatile bool m_vbTxIrqPending;
volatile bool m_vbRxIrqPending;
bool m_bWrittenTx;
//
volatile bool m_vbCommIRQ;
HANDLE m_hCommThread;
HANDLE m_hCommEvent[COMMEVT_MAX];

View File

@ -572,6 +572,33 @@ LONG NewVolume(DWORD dwVolume, DWORD dwVolumeMax)
//=============================================================================
static int g_nErrorInc = 20; // Old: 1
static int g_nErrorMax = 200; // Old: 50
int SoundCore_GetErrorInc()
{
return g_nErrorInc;
}
void SoundCore_SetErrorInc(const int nErrorInc)
{
g_nErrorInc = nErrorInc < g_nErrorMax ? nErrorInc : g_nErrorMax;
if(g_fh) fprintf(g_fh, "Speaker/MB Error Inc = %d\n", g_nErrorInc);
}
int SoundCore_GetErrorMax()
{
return g_nErrorMax;
}
void SoundCore_SetErrorMax(const int nErrorMax)
{
g_nErrorMax = nErrorMax < MAX_SAMPLES ? nErrorMax : MAX_SAMPLES;
if(g_fh) fprintf(g_fh, "Speaker/MB Error Max = %d\n", g_nErrorMax);
}
//=============================================================================
static DWORD g_dwAdviseToken;
static IReferenceClock *g_pRefClock = NULL;
static HANDLE g_hSemaphore = NULL;

View File

@ -1,5 +1,7 @@
#pragma once
#define MAX_SAMPLES (16*1024)
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
// Define max 1 of these:
@ -35,6 +37,11 @@ void SoundCore_SetFade(eFADE FadeType);
bool SoundCore_GetTimerState();
void SoundCore_TweakVolumes();
int SoundCore_GetErrorInc();
void SoundCore_SetErrorInc(const int nErrorInc);
int SoundCore_GetErrorMax();
void SoundCore_SetErrorMax(const int nErrorMax);
bool DSInit();
void DSUninit();

View File

@ -49,7 +49,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#define SOUND_WAVE 3
static const unsigned short g_nSPKR_NumChannels = 1;
static const DWORD g_dwDSSpkrBufferSize = 16 * 1024 * sizeof(short) * g_nSPKR_NumChannels;
static const DWORD g_dwDSSpkrBufferSize = MAX_SAMPLES * sizeof(short) * g_nSPKR_NumChannels;
//-------------------------------------
@ -207,7 +207,6 @@ static void InitRemainderBuffer()
void SpkrDestroy ()
{
Spkr_DSUninit();
//DSUninit();
//
@ -248,7 +247,6 @@ void SpkrInitialize ()
}
else
{
//DSInit();
g_bSpkrAvailable = Spkr_DSInit();
}
@ -802,7 +800,7 @@ static ULONG Spkr_SubmitWaveBuffer_FullSpeed(short* pSpeakerBuffer, ULONG nNumSa
static ULONG Spkr_SubmitWaveBuffer(short* pSpeakerBuffer, ULONG nNumSamples)
{
//char szDbg[200];
char szDbg[200];
nDbgSpkrCnt++;
if(!SpeakerVoice.bActive)
@ -849,7 +847,11 @@ static ULONG Spkr_SubmitWaveBuffer(short* pSpeakerBuffer, ULONG nNumSamples)
// |-----PxxxxxW-----|
if((dwByteOffset > dwCurrentPlayCursor) && (dwByteOffset < dwCurrentWriteCursor))
{
//sprintf(szDbg, "[Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X xxx\n", dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); OutputDebugString(szDbg);
double fTicksSecs = (double)GetTickCount() / 1000.0;
sprintf(szDbg, "%010.3f: [Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X xxx\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples);
OutputDebugString(szDbg);
if (g_fh) fprintf(g_fh, szDbg);
dwByteOffset = dwCurrentWriteCursor;
nNumSamplesError = 0;
bBufferError = true;
@ -860,7 +862,11 @@ static ULONG Spkr_SubmitWaveBuffer(short* pSpeakerBuffer, ULONG nNumSamples)
// |xxW----------Pxxx|
if((dwByteOffset > dwCurrentPlayCursor) || (dwByteOffset < dwCurrentWriteCursor))
{
//sprintf(szDbg, "[Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X XXX\n", dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); OutputDebugString(szDbg);
double fTicksSecs = (double)GetTickCount() / 1000.0;
sprintf(szDbg, "%010.3f: [Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X XXX\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples);
OutputDebugString(szDbg);
if (g_fh) fprintf(g_fh, szDbg);
dwByteOffset = dwCurrentWriteCursor;
nNumSamplesError = 0;
bBufferError = true;
@ -876,16 +882,17 @@ static ULONG Spkr_SubmitWaveBuffer(short* pSpeakerBuffer, ULONG nNumSamples)
nBytesRemaining = g_dwDSSpkrBufferSize; // Case when complete buffer is to be played
// Calc correction factor so that play-buffer doesn't under/overflow
const int nErrorInc = SoundCore_GetErrorInc();
if(nBytesRemaining < g_dwDSSpkrBufferSize / 4)
nNumSamplesError++; // < 1/4 of play-buffer remaining (need *more* data)
nNumSamplesError += nErrorInc; // < 1/4 of play-buffer remaining (need *more* data)
else if(nBytesRemaining > g_dwDSSpkrBufferSize / 2)
nNumSamplesError--; // > 1/2 of play-buffer remaining (need *less* data)
nNumSamplesError -= nErrorInc; // > 1/2 of play-buffer remaining (need *less* data)
else
nNumSamplesError = 0; // Acceptable amount of data in buffer
const int nMaxError = 50; // Cap feedback to +/-nMaxError units
if(nNumSamplesError < -nMaxError) nNumSamplesError = -nMaxError;
if(nNumSamplesError > nMaxError) nNumSamplesError = nMaxError;
const int nErrorMax = SoundCore_GetErrorMax(); // Cap feedback to +/-nMaxError units
if(nNumSamplesError < -nErrorMax) nNumSamplesError = -nErrorMax;
if(nNumSamplesError > nErrorMax) nNumSamplesError = nErrorMax;
g_nCpuCyclesFeedback = (int) ((double)nNumSamplesError * g_fClksPerSpkrSample);
//

View File

@ -10,6 +10,8 @@ void SpkrReset();
BOOL SpkrSetEmulationType (HWND,DWORD);
void SpkrUpdate (DWORD);
void SpkrUpdate_Timer();
void Spkr_SetErrorInc(const int nErrorInc);
void Spkr_SetErrorMax(const int nErrorMax);
DWORD SpkrGetVolume();
void SpkrSetVolume(DWORD dwVolume, DWORD dwVolumeMax);
void Spkr_Mute();

View File

@ -483,7 +483,7 @@ int tfe_activate_i(void)
if (tfe==NULL)
{
#ifdef TFE_DEBUG_INIT
if(g_fh) fprintf(g_fh, "tfe_activate_i: Allocating tfe failed.");
if(g_fh) fprintf(g_fh, "tfe_activate_i: Allocating tfe failed.\n");
#endif
tfe_enabled = 0;
return 0;
@ -495,7 +495,7 @@ int tfe_activate_i(void)
if (tfe_packetpage==NULL)
{
#ifdef TFE_DEBUG_INIT
if(g_fh) fprintf(g_fh, "tfe_activate: Allocating tfe_packetpage failed.");
if(g_fh) fprintf(g_fh, "tfe_activate: Allocating tfe_packetpage failed.\n");
#endif
lib_free(tfe);
tfe=NULL;
@ -504,8 +504,8 @@ int tfe_activate_i(void)
}
#ifdef TFE_DEBUG_INIT
if(g_fh) fprintf(g_fh, "tfe_activate: Allocated memory successfully.");
if(g_fh) fprintf(g_fh, "\ttfe at $%08X, tfe_packetpage at $%08X", tfe, tfe_packetpage );
if(g_fh) fprintf(g_fh, "tfe_activate: Allocated memory successfully.\n");
if(g_fh) fprintf(g_fh, "\ttfe at $%08X, tfe_packetpage at $%08X\n", tfe, tfe_packetpage );
#endif
#ifdef DOS_TFE
@ -862,7 +862,7 @@ void tfe_sideeffects_write_pp_on_txframe(WORD ppaddress)
|| (txlen<MIN_TXLENGTH)
) {
#ifdef TFE_DEBUG_WARN
if(g_fh) fprintf(g_fh, "WARNING! Should send %u octets: Not allowed, thus ignoring!", txlen);
if(g_fh) fprintf(g_fh, "WARNING! Should send %u octets: Not allowed, thus ignoring!\n", txlen);
#endif
}
else {
@ -949,13 +949,13 @@ void tfe_sideeffects_write_pp(WORD ppaddress, int oddaddress)
case TFE_PP_ADDR_SE_RXEVENT:
#ifdef TFE_DEBUG_WARN
if(g_fh) fprintf(g_fh, "WARNING! Written read-only register TFE_PP_ADDR_SE_RXEVENT: IGNORED");
if(g_fh) fprintf(g_fh, "WARNING! Written read-only register TFE_PP_ADDR_SE_RXEVENT: IGNORED\n");
#endif
break;
case TFE_PP_ADDR_SE_BUSST:
#ifdef TFE_DEBUG_WARN
if(g_fh) fprintf(g_fh, "WARNING! Written read-only register TFE_PP_ADDR_SE_BUSST: IGNORED");
if(g_fh) fprintf(g_fh, "WARNING! Written read-only register TFE_PP_ADDR_SE_BUSST: IGNORED\n");
#endif
break;
@ -966,7 +966,7 @@ void tfe_sideeffects_write_pp(WORD ppaddress, int oddaddress)
#ifdef TFE_DEBUG_WARN
/* check if we had a TXCMD, but not all octets were written */
if (tfe_started_tx && !oddaddress) {
if(g_fh) fprintf(g_fh, "WARNING! Early abort of transmitted frame");
if(g_fh) fprintf(g_fh, "WARNING! Early abort of transmitted frame\n");
}
tfe_started_tx = 1;
#endif
@ -1051,13 +1051,13 @@ void tfe_sideeffects_read_pp(WORD ppaddress)
case TFE_PP_ADDR_TXCMD:
#ifdef TFE_DEBUG_WARN
if(g_fh) fprintf(g_fh, "WARNING! Read write-only register TFE_PP_ADDR_TXCMD: IGNORED");
if(g_fh) fprintf(g_fh, "WARNING! Read write-only register TFE_PP_ADDR_TXCMD: IGNORED\n");
#endif
break;
case TFE_PP_ADDR_TXLENGTH:
#ifdef TFE_DEBUG_WARN
if(g_fh) fprintf(g_fh, "WARNING! Read write-only register TFE_PP_ADDR_TXLENGTH: IGNORED");
if(g_fh) fprintf(g_fh, "WARNING! Read write-only register TFE_PP_ADDR_TXLENGTH: IGNORED\n");
#endif
break;
}
@ -1146,7 +1146,7 @@ BYTE REGPARM1 tfe_read(WORD ioaddress)
case TFE_ADDR_TXLENGTH:
case TFE_ADDR_TXLENGTH+1:
#ifdef TFE_DEBUG_WARN
if(g_fh) fprintf(g_fh, "WARNING! Reading write-only TFE register $%02X!", ioaddress);
if(g_fh) fprintf(g_fh, "WARNING! Reading write-only TFE register $%02X!\n", ioaddress);
#endif
/* @SRT TODO: Verify with reality */
retval = GET_TFE_8(ioaddress);
@ -1157,7 +1157,7 @@ BYTE REGPARM1 tfe_read(WORD ioaddress)
case TFE_ADDR_PP_DATA2:
case TFE_ADDR_PP_DATA2+1:
#ifdef TFE_DEBUG_WARN
if(g_fh) fprintf(g_fh, "WARNING! Reading not supported TFE register $%02X!", ioaddress);
if(g_fh) fprintf(g_fh, "WARNING! Reading not supported TFE register $%02X!\n", ioaddress);
#endif
/* @SRT TODO */
retval = GET_TFE_8(ioaddress);
@ -1229,7 +1229,7 @@ void REGPARM2 tfe_store(WORD ioaddress, BYTE byte)
case TFE_ADDR_INTSTQUEUE:
case TFE_ADDR_INTSTQUEUE+1:
#ifdef TFE_DEBUG_WARN
if(g_fh) fprintf(g_fh, "WARNING! Writing read-only TFE register $%02X!", ioaddress);
if(g_fh) fprintf(g_fh, "WARNING! Writing read-only TFE register $%02X!\n", ioaddress);
#endif
/* @SRT TODO: Verify with reality */
/* do nothing */
@ -1240,7 +1240,7 @@ void REGPARM2 tfe_store(WORD ioaddress, BYTE byte)
case TFE_ADDR_PP_DATA2:
case TFE_ADDR_PP_DATA2+1:
#ifdef TFE_DEBUG_WARN
if(g_fh) fprintf(g_fh, "WARNING! Writing not supported TFE register $%02X!", ioaddress);
if(g_fh) fprintf(g_fh, "WARNING! Writing not supported TFE register $%02X!\n", ioaddress);
#endif
/* do nothing */
return;
@ -1296,7 +1296,7 @@ void REGPARM2 tfe_store(WORD ioaddress, BYTE byte)
#ifdef TFE_DEBUG_WARN
if(g_fh) fprintf(g_fh,
"WARNING! PacketPage register set to odd address $%04X (not allowed!)",
"WARNING! PacketPage register set to odd address $%04X (not allowed!)\n",
tfe_packetpage_ptr );
#endif /* #ifdef TFE_DEBUG_WARN */