SSC: Support for TX IRQ and other SSC updates (#552)

. Support TX IRQ for both TCP and COM modes (fixes #522)
. Support CTS/RTS (fixes #311)
. Fixed reading DIPSW registers
. Fixed TCP mode which was only generating an IRQ for first byte received
. Added UpdateCommandReg() to consolidate all updates to SSC command reg
. Updated reference URLs
This commit is contained in:
TomCh 2018-04-08 17:37:26 +01:00 committed by GitHub
parent 598b20fb52
commit a78f1e04da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 286 additions and 272 deletions

View File

@ -89,7 +89,6 @@ static double g_fMHz = 1.0; // Affected by Config dialog's speed slider bar
int g_nCpuCyclesFeedback = 0; int g_nCpuCyclesFeedback = 0;
DWORD g_dwCyclesThisFrame = 0; DWORD g_dwCyclesThisFrame = 0;
FILE* g_fh = NULL;
bool g_bDisableDirectInput = false; bool g_bDisableDirectInput = false;
bool g_bDisableDirectSound = false; bool g_bDisableDirectSound = false;
bool g_bDisableDirectSoundMockingboard = false; bool g_bDisableDirectSoundMockingboard = false;
@ -301,8 +300,6 @@ static void ContinueExecution(void)
DiskUpdateDriveState(uActualCyclesExecuted); DiskUpdateDriveState(uActualCyclesExecuted);
JoyUpdateButtonLatch(nExecutionPeriodUsec); // Button latch time is independent of CPU clock frequency JoyUpdateButtonLatch(nExecutionPeriodUsec); // Button latch time is independent of CPU clock frequency
sg_SSC.CommUpdate(uActualCyclesExecuted);
PrintUpdate(uActualCyclesExecuted); PrintUpdate(uActualCyclesExecuted);
// //

View File

@ -1814,9 +1814,6 @@ LRESULT CALLBACK FrameWndProc (
case FD_READ: case FD_READ:
sg_SSC.CommTcpSerialReceive(); sg_SSC.CommTcpSerialReceive();
break; break;
case FD_WRITE:
break;
} }
} }
break; break;

View File

@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "StdAfx.h" #include "StdAfx.h"
FILE* g_fh = NULL;
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -45,8 +46,6 @@ void LogOutput(LPCTSTR format, ...)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
extern FILE* g_fh; // Filehandle for log file
void LogFileOutput(LPCTSTR format, ...) void LogFileOutput(LPCTSTR format, ...)
{ {
if (!g_fh) if (!g_fh)

View File

@ -8,5 +8,7 @@
#endif #endif
#endif #endif
extern FILE* g_fh; // Filehandle for log file
extern void LogOutput(LPCTSTR format, ...); extern void LogOutput(LPCTSTR format, ...);
extern void LogFileOutput(LPCTSTR format, ...); extern void LogFileOutput(LPCTSTR format, ...);

View File

@ -175,6 +175,7 @@ static void Snapshot_LoadState_v1() // .aws v1.0.0.1, up to (and including) Appl
KeybReset(); KeybReset();
VideoResetState(); VideoResetState();
MB_Reset(); MB_Reset();
sg_SSC.CommReset();
// //
// Apple2 unit // Apple2 unit
@ -497,6 +498,7 @@ static void Snapshot_LoadState_v2(void)
KeybReset(); KeybReset();
VideoResetState(); VideoResetState();
MB_Reset(); MB_Reset();
sg_SSC.CommReset();
#ifdef USE_SPEECH_API #ifdef USE_SPEECH_API
g_Speech.Reset(); g_Speech.Reset();
#endif #endif

View File

@ -26,35 +26,28 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Author: Various * Author: Various
*/ */
// TO DO:
// . Enable & test Tx IRQ
// . DIP switch read values
//
// Refs: // Refs:
// (1) "Super Serial Card (SSC) Memory Locations for Programmers" - Aaron Heiss // [Ref.1] AppleWin\docs\SSC Memory Locations for Programmers.txt
// (2) SSC recv IRQ example: http://www.wright.edu/~john.matthews/ssc.html#lst - John B. Matthews, 5/13/87 // [Ref.2] SSC recv IRQ example: https://sites.google.com/site/drjohnbmatthews/apple2/ssc - John B. Matthews, 5/13/87
// (3) WaitCommEvent, etc: http://mail.python.org/pipermail/python-list/2002-November/131437.html // [Ref.3] SY6551 info: http://users.axess.com/twilight/sock/rs232pak.html
// (4) SY6551 info: http://www.axess.com/twilight/sock/rs232pak.html
// //
// SSC-pg is an abbreviation for pages references to "Super Serial Card, Installation and Operating Manual" by Apple
#include "StdAfx.h" #include "StdAfx.h"
#include "Applewin.h" #include "Applewin.h"
#include "CPU.h" #include "CPU.h"
#include "Disk.h" // DiskIsSpinning()
#include "Frame.h" #include "Frame.h"
#include "Log.h"
#include "Memory.h" #include "Memory.h"
#include "SerialComms.h" #include "SerialComms.h"
#include "YamlHelper.h" #include "YamlHelper.h"
#include "../resource/resource.h" #include "../resource/resource.h"
//#define SUPPORT_MODEM
#define TCP_SERIAL_PORT 1977 #define TCP_SERIAL_PORT 1977
// Default: 19200-8-N-1 // Default: 19200-8-N-1
// Maybe a better default is: 9600-7-N-1 (for HyperTrm)
SSC_DIPSW CSuperSerialCard::m_DIPSWDefault = SSC_DIPSW CSuperSerialCard::m_DIPSWDefault =
{ {
// DIPSW1: // DIPSW1:
@ -65,8 +58,8 @@ SSC_DIPSW CSuperSerialCard::m_DIPSWDefault =
ONESTOPBIT, ONESTOPBIT,
8, // ByteSize 8, // ByteSize
NOPARITY, NOPARITY,
true, // LF false, // SW2-5: LF(0x0A). SSC-24: In Comms mode, SSC automatically discards LF immediately following CR
false, // INT true, // SW2-6: Interrupts. SSC-47: Passes interrupt requests from ACIA to the Apple II. NB. Can't be read from software
}; };
//=========================================================================== //===========================================================================
@ -85,7 +78,6 @@ CSuperSerialCard::CSuperSerialCard() :
m_hCommHandle = INVALID_HANDLE_VALUE; m_hCommHandle = INVALID_HANDLE_VALUE;
m_hCommListenSocket = INVALID_SOCKET; m_hCommListenSocket = INVALID_SOCKET;
m_hCommAcceptSocket = INVALID_SOCKET; m_hCommAcceptSocket = INVALID_SOCKET;
m_dwCommInactivity = 0;
m_hCommThread = NULL; m_hCommThread = NULL;
@ -101,21 +93,32 @@ void CSuperSerialCard::InternalReset()
{ {
GetDIPSW(); GetDIPSW();
m_bTxIrqEnabled = false; // SY6551 datasheet: Hardware reset sets Control register to 0 - the DIPSW settings are not used by h/w to setup this register
m_bRxIrqEnabled = false; m_uControlByte = 0;
m_bWrittenTx = false; // SY6551 datasheet: Hardware reset sets Command register to 0
// . NB. MOS6551 datasheet: Hardware reset: b#00000010 (so ACIA not init'd on IN#2!)
UpdateCommandReg(0);
m_uBaudRate = CBR_19200; // Undefined, as CONTROL.CLK_SOURCE=0=External clock is not supported for SSC - so nominally use 19200
m_uStopBits = ONESTOPBIT;
m_uByteSize = 8;
m_uParity = NOPARITY;
//
m_vuRxCurrBuffer = 0; m_vuRxCurrBuffer = 0;
m_vbTxIrqPending = false; m_vbTxIrqPending = false;
m_vbRxIrqPending = false; m_vbRxIrqPending = false;
m_vbTxEmpty = true;
m_qComSerialBuffer[0].clear(); m_qComSerialBuffer[0].clear();
m_qComSerialBuffer[1].clear(); m_qComSerialBuffer[1].clear();
m_qTcpSerialBuffer.clear(); m_qTcpSerialBuffer.clear();
m_uDTR = DTR_CONTROL_DISABLE; m_uDTR = DTR_CONTROL_DISABLE;
m_uRTS = RTS_CONTROL_DISABLE;
} }
CSuperSerialCard::~CSuperSerialCard() CSuperSerialCard::~CSuperSerialCard()
@ -128,26 +131,12 @@ CSuperSerialCard::~CSuperSerialCard()
// TODO: Serial Comms - UI Property Sheet Page: // TODO: Serial Comms - UI Property Sheet Page:
// . Ability to config the 2x DIPSWs - only takes affect after next Apple2 reset // . Ability to config the 2x DIPSWs - only takes affect after next Apple2 reset
// . 'Default' button that resets DIPSWs to DIPSWDefaults // . 'Default' button that resets DIPSWs to DIPSWDefaults
// . Need to respect IRQ disable dipswitch (cannot be overridden by software) // . Must respect IRQ disable dipswitch (cannot be overridden or read by software)
void CSuperSerialCard::GetDIPSW() void CSuperSerialCard::GetDIPSW()
{ {
// TODO: Read settings from Registry // TODO: Read settings from Registry(?). In the meantime, use the defaults:
// In the meantime, use the defaults:
SetDIPSWDefaults(); SetDIPSWDefaults();
//
m_uBaudRate = m_DIPSWCurrent.uBaudRate;
m_uStopBits = m_DIPSWCurrent.uStopBits;
m_uByteSize = m_DIPSWCurrent.uByteSize;
m_uParity = m_DIPSWCurrent.uParity;
//
m_uControlByte = GenerateControl();
m_uCommandByte = 0x00;
} }
void CSuperSerialCard::SetDIPSWDefaults() void CSuperSerialCard::SetDIPSWDefaults()
@ -166,23 +155,6 @@ void CSuperSerialCard::SetDIPSWDefaults()
m_DIPSWCurrent.bInterrupts = m_DIPSWDefault.bInterrupts; m_DIPSWCurrent.bInterrupts = m_DIPSWDefault.bInterrupts;
} }
BYTE CSuperSerialCard::GenerateControl()
{
const UINT CLK=1; // Internal
UINT bmByteSize = (8 - m_uByteSize); // [8,7,6,5] -> [0,1,2,3]
_ASSERT(bmByteSize <= 3);
UINT StopBit;
if ( ((m_uByteSize == 8) && (m_uParity != NOPARITY)) ||
( m_uStopBits != ONESTOPBIT ) )
StopBit = 1;
else
StopBit = 0;
return (StopBit<<7) | (bmByteSize<<5) | (CLK<<4) | BaudRateToIndex(m_uBaudRate);
}
UINT CSuperSerialCard::BaudRateToIndex(UINT uBaudRate) UINT CSuperSerialCard::BaudRateToIndex(UINT uBaudRate)
{ {
switch (uBaudRate) switch (uBaudRate)
@ -199,7 +171,8 @@ UINT CSuperSerialCard::BaudRateToIndex(UINT uBaudRate)
} }
_ASSERT(0); _ASSERT(0);
return BaudRateToIndex(CBR_9600); LogFileOutput("SSC: BaudRateToIndex(): unsupported rate: %d\n", uBaudRate);
return BaudRateToIndex(CBR_19200); // nominally use 19200
} }
//=========================================================================== //===========================================================================
@ -217,31 +190,29 @@ void CSuperSerialCard::UpdateCommState()
dcb.ByteSize = m_uByteSize; dcb.ByteSize = m_uByteSize;
dcb.Parity = m_uParity; dcb.Parity = m_uParity;
dcb.StopBits = m_uStopBits; dcb.StopBits = m_uStopBits;
dcb.fDtrControl = m_uDTR; dcb.fDtrControl = m_uDTR; // GH#386
dcb.fRtsControl = m_uRTS; // GH#311
SetCommState(m_hCommHandle,&dcb); SetCommState(m_hCommHandle,&dcb);
} }
//=========================================================================== //===========================================================================
BOOL CSuperSerialCard::CheckComm() bool CSuperSerialCard::CheckComm()
{ {
m_dwCommInactivity = 0;
// check for COM or TCP socket handle, and setup if invalid // check for COM or TCP socket handle, and setup if invalid
if (IsActive()) if (IsActive())
return true; return true;
if (m_dwSerialPortItem == m_uTCPChoiceItemIdx) if (m_dwSerialPortItem == m_uTCPChoiceItemIdx)
{ {
// init Winsock 1.1 (for Win95, otherwise could use 2.2)
WSADATA wsaData; WSADATA wsaData;
if (WSAStartup(MAKEWORD(1, 1), &wsaData) == 0) // or (2, 2) for Winsock 2.2 if (WSAStartup(MAKEWORD(2, 2), &wsaData) == 0) // Winsock 2.2
{ {
if (wsaData.wVersion != 0x0101) // or 0x0202 for Winsock 2.2 if (wsaData.wVersion != 0x0202)
{ {
WSACleanup(); WSACleanup();
return FALSE; return false;
} }
// initialized, so try to create a socket // initialized, so try to create a socket
@ -249,7 +220,7 @@ BOOL CSuperSerialCard::CheckComm()
if (m_hCommListenSocket == INVALID_SOCKET) if (m_hCommListenSocket == INVALID_SOCKET)
{ {
WSACleanup(); WSACleanup();
return FALSE; return false;
} }
// have socket so attempt to bind it // have socket so attempt to bind it
@ -261,7 +232,7 @@ BOOL CSuperSerialCard::CheckComm()
{ {
m_hCommListenSocket = INVALID_SOCKET; m_hCommListenSocket = INVALID_SOCKET;
WSACleanup(); WSACleanup();
return FALSE; return false;
} }
// bound, so listen // bound, so listen
@ -269,7 +240,7 @@ BOOL CSuperSerialCard::CheckComm()
{ {
m_hCommListenSocket = INVALID_SOCKET; m_hCommListenSocket = INVALID_SOCKET;
WSACleanup(); WSACleanup();
return FALSE; return false;
} }
// now send async events to our app's message handler // now send async events to our app's message handler
@ -281,7 +252,7 @@ BOOL CSuperSerialCard::CheckComm()
{ {
m_hCommListenSocket = INVALID_SOCKET; m_hCommListenSocket = INVALID_SOCKET;
WSACleanup(); WSACleanup();
return FALSE; return false;
} }
} }
} }
@ -337,7 +308,6 @@ void CSuperSerialCard::CloseComm()
CloseHandle(m_hCommHandle); CloseHandle(m_hCommHandle);
m_hCommHandle = INVALID_HANDLE_VALUE; m_hCommHandle = INVALID_HANDLE_VALUE;
m_dwCommInactivity = 0;
} }
//=========================================================================== //===========================================================================
@ -378,12 +348,14 @@ void CSuperSerialCard::CommTcpSerialAccept()
if ((m_hCommListenSocket != INVALID_SOCKET) && (m_hCommAcceptSocket == INVALID_SOCKET)) if ((m_hCommListenSocket != INVALID_SOCKET) && (m_hCommAcceptSocket == INVALID_SOCKET))
{ {
// Y: accept the connection // Y: accept the connection
m_hCommAcceptSocket = accept(m_hCommListenSocket, NULL, NULL ); m_hCommAcceptSocket = accept(m_hCommListenSocket, NULL, NULL);
} }
} }
//=========================================================================== //===========================================================================
// Called when there's a TCP event via the message pump
// . Because it's via the message pump, then this call is synchronous to CommReceive(), so there's no need for a critical section
void CSuperSerialCard::CommTcpSerialReceive() void CSuperSerialCard::CommTcpSerialReceive()
{ {
if (m_hCommAcceptSocket != INVALID_SOCKET) if (m_hCommAcceptSocket != INVALID_SOCKET)
@ -452,7 +424,7 @@ BYTE __stdcall CSuperSerialCard::SSC_IOWrite(WORD PC, WORD uAddr, BYTE bWrite, B
case 0x6: return IO_Null(PC, uAddr, bWrite, uValue, nExecutedCycles); case 0x6: return IO_Null(PC, uAddr, bWrite, uValue, nExecutedCycles);
case 0x7: return IO_Null(PC, uAddr, bWrite, uValue, nExecutedCycles); case 0x7: return IO_Null(PC, uAddr, bWrite, uValue, nExecutedCycles);
case 0x8: return pSSC->CommTransmit(PC, uAddr, bWrite, uValue, nExecutedCycles); case 0x8: return pSSC->CommTransmit(PC, uAddr, bWrite, uValue, nExecutedCycles);
case 0x9: return pSSC->CommStatus(PC, uAddr, bWrite, uValue, nExecutedCycles); case 0x9: return pSSC->CommProgramReset(PC, uAddr, bWrite, uValue, nExecutedCycles);
case 0xA: return pSSC->CommCommand(PC, uAddr, bWrite, uValue, nExecutedCycles); case 0xA: return pSSC->CommCommand(PC, uAddr, bWrite, uValue, nExecutedCycles);
case 0xB: return pSSC->CommControl(PC, uAddr, bWrite, uValue, nExecutedCycles); case 0xB: return pSSC->CommControl(PC, uAddr, bWrite, uValue, nExecutedCycles);
case 0xC: return IO_Null(PC, uAddr, bWrite, uValue, nExecutedCycles); case 0xC: return IO_Null(PC, uAddr, bWrite, uValue, nExecutedCycles);
@ -466,7 +438,98 @@ BYTE __stdcall CSuperSerialCard::SSC_IOWrite(WORD PC, WORD uAddr, BYTE bWrite, B
//=========================================================================== //===========================================================================
// EG. 0x09 = Enable IRQ, No parity [Ref.2] // 6551 ACIA Command Register ($C08A+s0)
// . EG. 0x09 = "no parity, enable IRQ" - b7:5(No parity), b4 (No echo), b3:1(Enable TX,RX IRQs), b0(DTR: Enable Rx/Tx) [Ref.2]
enum { CMD_PARITY_MASK = 3<<6,
CMD_PARITY_ODD = 0<<6, // Odd parity
CMD_PARITY_EVEN = 1<<6, // Even parity
CMD_PARITY_MARK = 2<<6, // Mark parity
CMD_PARITY_SPACE = 3<<6, // Space parity
CMD_PARITY_ENA = 1<<5,
CMD_ECHO_MODE = 1<<4,
CMD_TX_MASK = 3<<2,
CMD_TX_IRQ_DIS_RTS_HIGH = 0<<2,
CMD_TX_IRQ_ENA_RTS_LOW = 1<<2,
CMD_TX_IRQ_DIS_RTS_LOW = 2<<2,
CMD_TX_IRQ_DIS_RTS_LOW_BRK = 3<<2, // Transmit BRK
CMD_RX_IRQ_DIS = 1<<1, // 1=IRQ interrupt disabled
CMD_DTR = 1<<0, // Data Terminal Ready: 1=Enable Rx/Tx (!DTR low)
};
BYTE __stdcall CSuperSerialCard::CommProgramReset(WORD, WORD, BYTE, BYTE, ULONG)
{
// Command: top-3 parity bits unaffected
UpdateCommandReg( m_uCommandByte & (CMD_PARITY_MASK|CMD_PARITY_ENA) );
// Control: all bits unaffected
// Status: all bits unaffects, except Overrun(bit2) is cleared
return 0;
}
//===========================================================================
void CSuperSerialCard::UpdateCommandReg(BYTE command)
{
m_uCommandByte = command;
if (m_uCommandByte & CMD_PARITY_ENA)
{
switch (m_uCommandByte & CMD_PARITY_MASK)
{
case CMD_PARITY_ODD: m_uParity = ODDPARITY; break;
case CMD_PARITY_EVEN: m_uParity = EVENPARITY; break;
case CMD_PARITY_MARK: m_uParity = MARKPARITY; break;
case CMD_PARITY_SPACE: m_uParity = SPACEPARITY; break;
}
}
else
{
m_uParity = NOPARITY;
}
if (m_uCommandByte & CMD_ECHO_MODE) // Receiver mode echo (0=no echo, 1=echo)
{
_ASSERT(0);
LogFileOutput("SSC: CommCommand(): unsupported Echo mode. Command=0x%02X\n", m_uCommandByte);
}
switch (m_uCommandByte & CMD_TX_MASK) // transmitter interrupt control
{
// Note: the RTS signal must be set 'low' in order to receive any incoming data from the serial device [Ref.1]
case CMD_TX_IRQ_DIS_RTS_HIGH: // set RTS high and transmit no interrupts (transmitter is off [Ref.3])
m_uRTS = RTS_CONTROL_DISABLE;
break;
case CMD_TX_IRQ_ENA_RTS_LOW: // set RTS low and transmit interrupts
m_uRTS = RTS_CONTROL_ENABLE;
break;
case CMD_TX_IRQ_DIS_RTS_LOW: // set RTS low and transmit no interrupts
m_uRTS = RTS_CONTROL_ENABLE;
break;
case CMD_TX_IRQ_DIS_RTS_LOW_BRK: // set RTS low and transmit break signals instead of interrupts
m_uRTS = RTS_CONTROL_ENABLE;
_ASSERT(0);
LogFileOutput("SSC: CommCommand(): unsupported TX mode. Command=0x%02X\n", m_uCommandByte);
break;
}
if (m_DIPSWCurrent.bInterrupts)
{
m_bTxIrqEnabled = (m_uCommandByte & CMD_TX_MASK) == CMD_TX_IRQ_ENA_RTS_LOW;
m_bRxIrqEnabled = (m_uCommandByte & CMD_RX_IRQ_DIS) == 0;
}
else
{
m_bTxIrqEnabled = false;
m_bRxIrqEnabled = false;
}
if (m_bCfgSupportDTR) // GH#386
{
// Data Terminal Ready (DTR) setting (0=set DTR high (indicates 'not ready'))
m_uDTR = (m_uCommandByte & CMD_DTR) ? DTR_CONTROL_ENABLE : DTR_CONTROL_DISABLE;
}
}
BYTE __stdcall CSuperSerialCard::CommCommand(WORD, WORD, BYTE write, BYTE value, ULONG) BYTE __stdcall CSuperSerialCard::CommCommand(WORD, WORD, BYTE write, BYTE value, ULONG)
{ {
@ -475,55 +538,7 @@ BYTE __stdcall CSuperSerialCard::CommCommand(WORD, WORD, BYTE write, BYTE value,
if (write && (value != m_uCommandByte)) if (write && (value != m_uCommandByte))
{ {
m_uCommandByte = value; UpdateCommandReg(value);
// UPDATE THE PARITY
if (m_uCommandByte & 0x20)
{
switch (m_uCommandByte & 0xC0)
{
case 0x00 : m_uParity = ODDPARITY; break;
case 0x40 : m_uParity = EVENPARITY; break;
case 0x80 : m_uParity = MARKPARITY; break;
case 0xC0 : m_uParity = SPACEPARITY; break;
}
}
else
{
m_uParity = NOPARITY;
}
if (m_uCommandByte & 0x10) // Receiver mode echo [0=no echo, 1=echo]
{
}
switch (m_uCommandByte & 0x0C) // transmitter interrupt control
{
// Note: the RTS signal must be set 'low' in order to receive any
// incoming data from the serial device
case 0<<2: // set RTS high and transmit no interrupts
m_bTxIrqEnabled = false;
break;
case 1<<2: // set RTS low and transmit interrupts
m_bTxIrqEnabled = true;
break;
case 2<<2: // set RTS low and transmit no interrupts
m_bTxIrqEnabled = false;
break;
case 3<<2: // set RTS low and transmit break signals instead of interrupts
m_bTxIrqEnabled = false;
break;
}
// interrupt request disable [0=enable receiver interrupts] - NOTE: SSC docs get this wrong!
m_bRxIrqEnabled = ((m_uCommandByte & 0x02) == 0);
if (m_bCfgSupportDTR) // GH#386
{
// Data Terminal Ready (DTR) setting [0=set DTR high (indicates 'not ready')]
m_uDTR = (m_uCommandByte & 0x01) ? DTR_CONTROL_ENABLE : DTR_CONTROL_DISABLE;
}
UpdateCommState(); UpdateCommState();
} }
@ -605,8 +620,6 @@ BYTE __stdcall CSuperSerialCard::CommControl(WORD, WORD, BYTE write, BYTE value,
//=========================================================================== //===========================================================================
static UINT g_uDbgTotalSSCRx = 0;
BYTE __stdcall CSuperSerialCard::CommReceive(WORD, WORD, BYTE, BYTE, ULONG) BYTE __stdcall CSuperSerialCard::CommReceive(WORD, WORD, BYTE, BYTE, ULONG)
{ {
if (!CheckComm()) if (!CheckComm())
@ -616,8 +629,15 @@ BYTE __stdcall CSuperSerialCard::CommReceive(WORD, WORD, BYTE, BYTE, ULONG)
if (!m_qTcpSerialBuffer.empty()) if (!m_qTcpSerialBuffer.empty())
{ {
// NB. See CommTcpSerialReceive() above, for a note explaining why there's no need for a critical section here
result = m_qTcpSerialBuffer.front(); result = m_qTcpSerialBuffer.front();
m_qTcpSerialBuffer.pop_front(); m_qTcpSerialBuffer.pop_front();
if (m_bRxIrqEnabled && !m_qTcpSerialBuffer.empty())
{
CpuIrqAssert(IS_SSC);
m_vbRxIrqPending = true;
}
} }
else if (m_hCommHandle != INVALID_HANDLE_VALUE) // COM else if (m_hCommHandle != INVALID_HANDLE_VALUE) // COM
{ {
@ -646,8 +666,6 @@ BYTE __stdcall CSuperSerialCard::CommReceive(WORD, WORD, BYTE, BYTE, ULONG)
} }
} }
LeaveCriticalSection(&m_CriticalSection); LeaveCriticalSection(&m_CriticalSection);
g_uDbgTotalSSCRx++;
} }
return result; return result;
@ -655,6 +673,17 @@ BYTE __stdcall CSuperSerialCard::CommReceive(WORD, WORD, BYTE, BYTE, ULONG)
//=========================================================================== //===========================================================================
void CSuperSerialCard::TransmitDone(void)
{
m_vbTxEmpty = true; // Transmit done
if (m_bTxIrqEnabled) // GH#522
{
CpuIrqAssert(IS_SSC);
m_vbTxIrqPending = true;
}
}
BYTE __stdcall CSuperSerialCard::CommTransmit(WORD, WORD, BYTE, BYTE value, ULONG) BYTE __stdcall CSuperSerialCard::CommTransmit(WORD, WORD, BYTE, BYTE value, ULONG)
{ {
if (!CheckComm()) if (!CheckComm())
@ -667,22 +696,22 @@ BYTE __stdcall CSuperSerialCard::CommTransmit(WORD, WORD, BYTE, BYTE value, ULON
{ {
data &= ~(1 << m_uByteSize); data &= ~(1 << m_uByteSize);
} }
send(m_hCommAcceptSocket, (const char*)&data, 1, 0); int sent = send(m_hCommAcceptSocket, (const char*)&data, 1, 0);
m_bWrittenTx = true; // Transmit done if (sent == 1)
{
m_vbTxEmpty = false;
// Assume that send() completes immediately
TransmitDone();
}
} }
else if (m_hCommHandle != INVALID_HANDLE_VALUE) else if (m_hCommHandle != INVALID_HANDLE_VALUE)
{ {
DWORD uBytesWritten; DWORD uBytesWritten;
WriteFile(m_hCommHandle, &value, 1, &uBytesWritten, &m_o); WriteFile(m_hCommHandle, &value, 1, &uBytesWritten, &m_o);
m_bWrittenTx = true; // Transmit done m_vbTxEmpty = false;
// NB. Now CommThread() determines when transmit buffer is empty and calls TransmitDone()
} }
// TO DO:
// 1) Use CommThread determine when transmit is complete
// 2) OR do this:
//if (m_bTxIrqEnabled)
// CpuIrqAssert(IS_SSC);
return 0; return 0;
} }
@ -691,24 +720,24 @@ BYTE __stdcall CSuperSerialCard::CommTransmit(WORD, WORD, BYTE, BYTE value, ULON
// 6551 ACIA Status Register ($C089+s0) // 6551 ACIA Status Register ($C089+s0)
// ------------------------------------ // ------------------------------------
// Bit Value Meaning // Bit Value Meaning
// 0 1 Parity error // 7 1 Interrupt (IRQ) true (cleared by reading status reg [Ref.3])
// 1 1 Framing error
// 2 1 Overrun error
// 3 1 Receive register full
// 4 1 Transmit register empty
// 5 0 Data Carrier Detect (DCD) true [0=DCD low (detected), 1=DCD high (not detected)]
// 6 0 Data Set Ready (DSR) true [0=DSR low (ready), 1=DSR high (not ready)] // 6 0 Data Set Ready (DSR) true [0=DSR low (ready), 1=DSR high (not ready)]
// 7 1 Interrupt (IRQ) true (cleared by reading status reg [Ref.4]) // 5 0 Data Carrier Detect (DCD) true [0=DCD low (detected), 1=DCD high (not detected)]
// 4 1 Transmit register empty
// 3 1 Receive register full
// 2 1 Overrun error
// 1 1 Framing error
// 0 1 Parity error
enum { ST_PARITY_ERR = 1<<0, enum { ST_IRQ = 1<<7,
ST_FRAMING_ERR = 1<<1,
ST_OVERRUN_ERR = 1<<2,
ST_RX_FULL = 1<<3,
ST_TX_EMPTY = 1<<4,
ST_DCD = 1<<5,
ST_DSR = 1<<6, ST_DSR = 1<<6,
ST_IRQ = 1<<7 ST_DCD = 1<<5,
}; ST_TX_EMPTY = 1<<4,
ST_RX_FULL = 1<<3,
ST_OVERRUN_ERR = 1<<2,
ST_FRAMING_ERR = 1<<1,
ST_PARITY_ERR = 1<<0,
};
BYTE __stdcall CSuperSerialCard::CommStatus(WORD, WORD, BYTE, BYTE, ULONG) BYTE __stdcall CSuperSerialCard::CommStatus(WORD, WORD, BYTE, BYTE, ULONG)
{ {
@ -724,11 +753,6 @@ BYTE __stdcall CSuperSerialCard::CommStatus(WORD, WORD, BYTE, BYTE, ULONG)
// //
// TO DO - ST_TX_EMPTY:
// . IRQs enabled : set after WaitCommEvent has signaled that TX has completed
// . IRQs disabled : always set it [Currently done]
//
bool bComSerialBufferEmpty = true; // Assume true, so if using TCP then logic below works bool bComSerialBufferEmpty = true; // Assume true, so if using TCP then logic below works
if (m_hCommHandle != INVALID_HANDLE_VALUE) if (m_hCommHandle != INVALID_HANDLE_VALUE)
@ -738,54 +762,67 @@ BYTE __stdcall CSuperSerialCard::CommStatus(WORD, WORD, BYTE, BYTE, ULONG)
bComSerialBufferEmpty = m_qComSerialBuffer[uSSCIdx].empty(); bComSerialBufferEmpty = m_qComSerialBuffer[uSSCIdx].empty();
} }
bool bIRQ = false; BYTE IRQ = 0;
if (m_bTxIrqEnabled && m_bWrittenTx) if (m_bTxIrqEnabled)
{ {
bIRQ = true; IRQ |= m_vbTxIrqPending ? ST_IRQ : 0;
m_vbTxIrqPending = false; // Ensure 2 reads of STATUS reg only return ST_IRQ for first read
} }
if (m_bRxIrqEnabled) if (m_bRxIrqEnabled)
{ {
bIRQ = m_vbRxIrqPending; IRQ |= m_vbRxIrqPending ? ST_IRQ : 0;
m_vbRxIrqPending = false; // Ensure 2 reads of STATUS reg only return ST_IRQ for first read 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
// //
BYTE DCD = 0;
BYTE DSR = 0; BYTE DSR = 0;
BYTE DCD = 0;
if ((m_hCommHandle != INVALID_HANDLE_VALUE) && (m_bCfgSupportDCD || m_bCfgSupportDSR)) // GH#386 if ((m_hCommHandle != INVALID_HANDLE_VALUE) && (m_bCfgSupportDCD || m_bCfgSupportDSR)) // GH#386
{ {
if (m_bCfgSupportDCD)
DCD = (modemStatus & MS_RLSD_ON) ? 0x00 : ST_DCD;
if (m_bCfgSupportDSR) if (m_bCfgSupportDSR)
DSR = (modemStatus & MS_DSR_ON) ? 0x00 : ST_DSR; DSR = (modemStatus & MS_DSR_ON) ? 0x00 : ST_DSR;
if (m_bCfgSupportDCD)
DCD = (modemStatus & MS_RLSD_ON) ? 0x00 : ST_DCD;
} }
BYTE uStatus = ST_TX_EMPTY //
| ((!bComSerialBufferEmpty || !m_qTcpSerialBuffer.empty()) ? ST_RX_FULL : 0x00)
| DCD // Need 0x00 to allow ZLink to start up BYTE TX_EMPTY = m_vbTxEmpty ? ST_TX_EMPTY : 0;
| DSR BYTE RX_FULL = (!bComSerialBufferEmpty || !m_qTcpSerialBuffer.empty()) ? ST_RX_FULL : 0;
| (bIRQ ? ST_IRQ : 0x00);
//
BYTE uStatus =
IRQ
| DSR
| DCD // Need 0x00 to allow ZLink to start up
| TX_EMPTY
| RX_FULL;
if (m_hCommHandle != INVALID_HANDLE_VALUE) if (m_hCommHandle != INVALID_HANDLE_VALUE)
{ {
LeaveCriticalSection(&m_CriticalSection); LeaveCriticalSection(&m_CriticalSection);
} }
CpuIrqDeassert(IS_SSC); CpuIrqDeassert(IS_SSC); // Read status reg always clears IRQ
return uStatus; return uStatus;
} }
//=========================================================================== //===========================================================================
// NB. Some DIPSW settings can't be read:
// SSC-47: Three switches are not connected to the LS365s:
// . SW2-6: passes interrupt requests from ACIA to the Apple II
// . SW1-7 ON and SW2-7 OFF: connects DCD to the DCD input of the ACIA
// . SW1-7 OFF and SW2-7 ON: splices SCTS to the DCD input of the ACIA (when jumper is in TERMINAL position)
BYTE __stdcall CSuperSerialCard::CommDipSw(WORD, WORD addr, BYTE, BYTE, ULONG) BYTE __stdcall CSuperSerialCard::CommDipSw(WORD, WORD addr, BYTE, BYTE, ULONG)
{ {
BYTE sw = 0; BYTE sw = 0;
switch (addr & 0xf) switch (addr & 0xf)
{ {
case 1: // DIPSW1 case 1: // DIPSW1
@ -793,36 +830,51 @@ BYTE __stdcall CSuperSerialCard::CommDipSw(WORD, WORD addr, BYTE, BYTE, ULONG)
break; break;
case 2: // DIPSW2 case 2: // DIPSW2
// Comms mode - SSC manual, pg23/24 // Comms mode: SSC-23
BYTE INT = m_DIPSWCurrent.uStopBits == TWOSTOPBITS ? 1 : 0; // SW2-1 (Stop bits: 1-ON(0); 2-OFF(1)) BYTE SW2_1 = m_DIPSWCurrent.uStopBits == TWOSTOPBITS ? 1 : 0; // SW2-1 (Stop bits: 1-ON(0); 2-OFF(1))
BYTE DSR = 0; // Always zero BYTE SW2_2 = m_DIPSWCurrent.uByteSize == 7 ? 1 : 0; // SW2-2 (Data bits: 8-ON(0); 7-OFF(1))
BYTE DCD = m_DIPSWCurrent.uByteSize == 7 ? 1 : 0; // SW2-2 (Data bits: 8-ON(0); 7-OFF(1))
BYTE TDR = 0; // Always zero
// SW2-3 (Parity: odd-ON(0); even-OFF(1)) // SW2-3 (Parity: odd-ON(0); even-OFF(1))
// SW2-4 (Parity: none-ON(0); SW2-3-OFF(1)) // SW2-4 (Parity: none-ON(0); SW2-3 don't care)
BYTE RDR,OVR; BYTE SW2_3,SW2_4;
switch (m_DIPSWCurrent.uParity) switch (m_DIPSWCurrent.uParity)
{ {
case ODDPARITY: case ODDPARITY:
RDR = 0; OVR = 1; SW2_3 = 0; SW2_4 = 1;
break; break;
case EVENPARITY: case EVENPARITY:
RDR = 1; OVR = 1; SW2_3 = 1; SW2_4 = 1;
break; break;
default: default:
_ASSERT(0); _ASSERT(0);
// fall through...
case NOPARITY: case NOPARITY:
RDR = 0; OVR = 0; SW2_3 = 0; SW2_4 = 0;
break; break;
} }
BYTE FE = m_DIPSWCurrent.bLinefeed ? 1 : 0; // SW2-5 (LF: yes-ON(0); no-OFF(1)) BYTE SW2_5 = m_DIPSWCurrent.bLinefeed ? 0 : 1; // SW2-5 (LF: yes-ON(0); no-OFF(1))
BYTE PE = m_DIPSWCurrent.bInterrupts ? 1 : 0; // SW2-6 (Interrupts: yes-ON(0); no-OFF(1))
sw = (INT<<7) | (DSR<<6) | (DCD<<5) | (TDR<<4) | (RDR<<3) | (OVR<<2) | (FE<<1) | (PE<<0); BYTE CTS = 0; // GH#311
if (CheckComm() && m_hCommHandle != INVALID_HANDLE_VALUE)
{
DWORD modemStatus = 0;
if (GetCommModemStatus(m_hCommHandle, &modemStatus))
CTS = (modemStatus & MS_CTS_ON) ? 0 : 1; // CTS is true when 0
}
// SSC-54:
sw = SW2_1<<7 | // b7 : SW2-1
0<<6 | // b6 : -
SW2_2<<5 | // b5 : SW2-2
0<<4 | // b4 : -
SW2_3<<3 | // b3 : SW2-3
SW2_4<<2 | // b2 : SW2-4
SW2_5<<1 | // b1 : SW2-5
CTS<<0; // b0 : CTS
break; break;
} }
return sw; return sw;
} }
@ -911,35 +963,6 @@ void CSuperSerialCard::CommSetSerialPort(HWND hWindow, DWORD dwNewSerialPortItem
//=========================================================================== //===========================================================================
void CSuperSerialCard::CommUpdate(DWORD totalcycles)
{
if (!IsActive())
return;
if ((m_dwCommInactivity += totalcycles) > 1000000)
{
static DWORD lastcheck = 0;
if ((m_dwCommInactivity > 2000000) || (m_dwCommInactivity-lastcheck > 99950))
{
#ifdef SUPPORT_MODEM
DWORD modemstatus = 0;
GetCommModemStatus(m_hCommHandle,&modemstatus);
if ((modemstatus & MS_RLSD_ON) || DiskIsSpinning())
m_dwCommInactivity = 0;
#else
if (DiskIsSpinning())
m_dwCommInactivity = 0;
#endif
}
//if (m_dwCommInactivity > 2000000)
// CloseComm();
}
}
//===========================================================================
// Had this error when sizeof(m_RecvBuffer)==1 was used // Had this error when sizeof(m_RecvBuffer)==1 was used
// UPDATE: Fixed by using double-buffered queue // UPDATE: Fixed by using double-buffered queue
// //
@ -1016,25 +1039,26 @@ void CSuperSerialCard::CheckCommEvent(DWORD dwEvtMask)
LeaveCriticalSection(&m_CriticalSection); LeaveCriticalSection(&m_CriticalSection);
} }
} }
//else if (dwEvtMask & EV_TXEMPTY) else if (dwEvtMask & EV_TXEMPTY)
//{ {
// if (m_bTxIrqEnabled) TransmitDone();
// { }
// m_vbTxIrqPending = true;
// CpuIrqAssert(IS_SSC);
// }
//}
} }
DWORD WINAPI CSuperSerialCard::CommThread(LPVOID lpParameter) DWORD WINAPI CSuperSerialCard::CommThread(LPVOID lpParameter)
{ {
CSuperSerialCard* pSSC = (CSuperSerialCard*) lpParameter; CSuperSerialCard* pSSC = (CSuperSerialCard*) lpParameter;
char szDbg[100]; char szDbg[100];
// BOOL bRes = SetCommMask(pSSC->m_hCommHandle, EV_TXEMPTY | EV_RXCHAR);
BOOL bRes = SetCommMask(pSSC->m_hCommHandle, EV_RXCHAR); // Just RX BOOL bRes = SetCommMask(pSSC->m_hCommHandle, EV_TXEMPTY | EV_RXCHAR);
// BOOL bRes = SetCommMask(pSSC->m_hCommHandle, EV_RXCHAR); // Just RX
if (!bRes) if (!bRes)
{
sprintf(szDbg, "SSC: CommThread(): SetCommMask() failed\n");
LogOutput("%s", szDbg);
LogFileOutput("%s", szDbg);
return -1; return -1;
}
// //
@ -1060,16 +1084,12 @@ DWORD WINAPI CSuperSerialCard::CommThread(LPVOID lpParameter)
DWORD dwErrors; DWORD dwErrors;
COMSTAT Stat; COMSTAT Stat;
ClearCommError(pSSC->m_hCommHandle, &dwErrors, &Stat); ClearCommError(pSSC->m_hCommHandle, &dwErrors, &Stat);
if (dwErrors) if (dwErrors & CE_RXOVER)
{ sprintf(szDbg, "SSC: CommThread(): LastError=0x%08X, CommError=CE_RXOVER (0x%08X): InQueue=0x%08X\n", dwRet, dwErrors, Stat.cbInQue);
if (dwErrors & CE_RXOVER) else
sprintf(szDbg, "CommThread: Err=CE_RXOVER (0x%08X): InQueue=0x%08X\n", dwErrors, Stat.cbInQue); sprintf(szDbg, "SSC: CommThread(): LastError=0x%08X, CommError=Other (0x%08X): InQueue=0x%08X, OutQueue=0x%08X\n", dwRet, dwErrors, Stat.cbInQue, Stat.cbOutQue);
else LogOutput("%s", szDbg);
sprintf(szDbg, "CommThread: Err=Other (0x%08X): InQueue=0x%08X, OutQueue=0x%08X\n", dwErrors, Stat.cbInQue, Stat.cbOutQue); LogFileOutput("%s", szDbg);
OutputDebugString(szDbg);
if (g_fh)
fprintf(g_fh, "%s", szDbg);
}
return -1; return -1;
} }
@ -1153,8 +1173,9 @@ bool CSuperSerialCard::CommThInit()
if (m_hCommThread == NULL) if (m_hCommThread == NULL)
{ {
DWORD dwThreadId; InitializeCriticalSection(&m_CriticalSection);
DWORD dwThreadId;
m_hCommThread = CreateThread(NULL, // lpThreadAttributes m_hCommThread = CreateThread(NULL, // lpThreadAttributes
0, // dwStackSize 0, // dwStackSize
(LPTHREAD_START_ROUTINE) &CSuperSerialCard::CommThread, (LPTHREAD_START_ROUTINE) &CSuperSerialCard::CommThread,
@ -1163,8 +1184,6 @@ bool CSuperSerialCard::CommThInit()
&dwThreadId); // lpThreadId &dwThreadId); // lpThreadId
SetThreadPriority(m_hCommThread, THREAD_PRIORITY_TIME_CRITICAL); SetThreadPriority(m_hCommThread, THREAD_PRIORITY_TIME_CRITICAL);
InitializeCriticalSection(&m_CriticalSection);
} }
return true; return true;
@ -1325,16 +1344,15 @@ void CSuperSerialCard::SetSnapshot_v1( const DWORD baudrate,
const BYTE stopbits) const BYTE stopbits)
{ {
m_uBaudRate = baudrate; m_uBaudRate = baudrate;
m_uStopBits = stopbits;
m_uByteSize = bytesize; m_uByteSize = bytesize;
m_uCommandByte = commandbyte; // m_dwCommInactivity = comminactivity; // Obsolete
m_dwCommInactivity = comminactivity;
m_uControlByte = controlbyte; m_uControlByte = controlbyte;
m_uParity = parity; // m_uParity = parity; // Redundant: derived from commandbyte in UpdateCommandReg()
// memcpy(m_RecvBuffer, pSS->recvbuffer, uRecvBufferSize); // memcpy(m_RecvBuffer, pSS->recvbuffer, uRecvBufferSize);
// m_vRecvBytes = recvbytes; // m_vRecvBytes = recvbytes;
m_uStopBits = stopbits;
m_uDTR = (m_uCommandByte & 0x01) ? DTR_CONTROL_ENABLE : DTR_CONTROL_DISABLE; UpdateCommandReg(commandbyte);
} }
//=========================================================================== //===========================================================================
@ -1389,15 +1407,15 @@ void CSuperSerialCard::SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
yamlSaveHelper.SaveUint(SS_YAML_KEY_BAUDRATE, m_uBaudRate); yamlSaveHelper.SaveUint(SS_YAML_KEY_BAUDRATE, m_uBaudRate);
yamlSaveHelper.SaveUint(SS_YAML_KEY_STOPBITS, m_uStopBits); yamlSaveHelper.SaveUint(SS_YAML_KEY_STOPBITS, m_uStopBits);
yamlSaveHelper.SaveUint(SS_YAML_KEY_BYTESIZE, m_uByteSize); yamlSaveHelper.SaveUint(SS_YAML_KEY_BYTESIZE, m_uByteSize);
yamlSaveHelper.SaveUint(SS_YAML_KEY_PARITY, m_uParity); yamlSaveHelper.SaveUint(SS_YAML_KEY_PARITY, m_uParity); // Redundant
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_CONTROL, m_uControlByte); yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_CONTROL, m_uControlByte);
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_COMMAND, m_uCommandByte); yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_COMMAND, m_uCommandByte);
yamlSaveHelper.SaveUint(SS_YAML_KEY_INACTIVITY, m_dwCommInactivity); yamlSaveHelper.SaveUint(SS_YAML_KEY_INACTIVITY, 0); // Obsolete
yamlSaveHelper.SaveBool(SS_YAML_KEY_TXIRQENABLED, m_bTxIrqEnabled); yamlSaveHelper.SaveBool(SS_YAML_KEY_TXIRQENABLED, m_bTxIrqEnabled); // Redundant
yamlSaveHelper.SaveBool(SS_YAML_KEY_RXIRQENABLED, m_bRxIrqEnabled); yamlSaveHelper.SaveBool(SS_YAML_KEY_RXIRQENABLED, m_bRxIrqEnabled); // Redundant
yamlSaveHelper.SaveBool(SS_YAML_KEY_TXIRQPENDING, m_vbTxIrqPending); yamlSaveHelper.SaveBool(SS_YAML_KEY_TXIRQPENDING, m_vbTxIrqPending);
yamlSaveHelper.SaveBool(SS_YAML_KEY_RXIRQPENDING, m_vbRxIrqPending); yamlSaveHelper.SaveBool(SS_YAML_KEY_RXIRQPENDING, m_vbRxIrqPending);
yamlSaveHelper.SaveBool(SS_YAML_KEY_WRITTENTX, m_bWrittenTx); yamlSaveHelper.SaveBool(SS_YAML_KEY_WRITTENTX, m_vbTxEmpty);
yamlSaveHelper.SaveString(SS_YAML_KEY_SERIALPORTNAME, GetSerialPortName()); yamlSaveHelper.SaveString(SS_YAML_KEY_SERIALPORTNAME, GetSerialPortName());
} }
@ -1431,17 +1449,17 @@ bool CSuperSerialCard::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, U
m_uBaudRate = yamlLoadHelper.LoadUint(SS_YAML_KEY_BAUDRATE); m_uBaudRate = yamlLoadHelper.LoadUint(SS_YAML_KEY_BAUDRATE);
m_uStopBits = yamlLoadHelper.LoadUint(SS_YAML_KEY_STOPBITS); m_uStopBits = yamlLoadHelper.LoadUint(SS_YAML_KEY_STOPBITS);
m_uByteSize = yamlLoadHelper.LoadUint(SS_YAML_KEY_BYTESIZE); m_uByteSize = yamlLoadHelper.LoadUint(SS_YAML_KEY_BYTESIZE);
m_uParity = yamlLoadHelper.LoadUint(SS_YAML_KEY_PARITY); yamlLoadHelper.LoadUint(SS_YAML_KEY_PARITY); // Redundant: derived from uCommandByte in UpdateCommandReg()
m_uControlByte = yamlLoadHelper.LoadUint(SS_YAML_KEY_CONTROL); m_uControlByte = yamlLoadHelper.LoadUint(SS_YAML_KEY_CONTROL);
m_uCommandByte = yamlLoadHelper.LoadUint(SS_YAML_KEY_COMMAND); UINT uCommandByte = yamlLoadHelper.LoadUint(SS_YAML_KEY_COMMAND);
m_dwCommInactivity = yamlLoadHelper.LoadUint(SS_YAML_KEY_INACTIVITY); yamlLoadHelper.LoadUint(SS_YAML_KEY_INACTIVITY); // Obsolete (so just consume)
m_bTxIrqEnabled = yamlLoadHelper.LoadBool(SS_YAML_KEY_TXIRQENABLED); yamlLoadHelper.LoadBool(SS_YAML_KEY_TXIRQENABLED); // Redundant: derived from uCommandByte in UpdateCommandReg()
m_bRxIrqEnabled = yamlLoadHelper.LoadBool(SS_YAML_KEY_RXIRQENABLED); yamlLoadHelper.LoadBool(SS_YAML_KEY_RXIRQENABLED); // Redundant: derived from uCommandByte in UpdateCommandReg()
m_vbTxIrqPending = yamlLoadHelper.LoadBool(SS_YAML_KEY_TXIRQPENDING); m_vbTxIrqPending = yamlLoadHelper.LoadBool(SS_YAML_KEY_TXIRQPENDING);
m_vbRxIrqPending = yamlLoadHelper.LoadBool(SS_YAML_KEY_RXIRQPENDING); m_vbRxIrqPending = yamlLoadHelper.LoadBool(SS_YAML_KEY_RXIRQPENDING);
m_bWrittenTx = yamlLoadHelper.LoadBool(SS_YAML_KEY_WRITTENTX); m_vbTxEmpty = yamlLoadHelper.LoadBool(SS_YAML_KEY_WRITTENTX);
m_uDTR = (m_uCommandByte & 0x01) ? DTR_CONTROL_ENABLE : DTR_CONTROL_DISABLE; UpdateCommandReg(uCommandByte);
std::string serialPortName = yamlLoadHelper.LoadString(SS_YAML_KEY_SERIALPORTNAME); std::string serialPortName = yamlLoadHelper.LoadString(SS_YAML_KEY_SERIALPORTNAME);
SetSerialPortName(serialPortName.c_str()); SetSerialPortName(serialPortName.c_str());

View File

@ -16,7 +16,7 @@ typedef struct
UINT uByteSize; UINT uByteSize;
UINT uParity; UINT uParity;
bool bLinefeed; bool bLinefeed;
bool bInterrupts; bool bInterrupts; // NB. Can't be read from s/w
} SSC_DIPSW; } SSC_DIPSW;
#define TEXT_SERIAL_COM TEXT("COM") #define TEXT_SERIAL_COM TEXT("COM")
@ -32,7 +32,6 @@ public:
void CommReset(); void CommReset();
void CommDestroy(); void CommDestroy();
void CommSetSerialPort(HWND hWindow, DWORD dwNewSerialPortItem); void CommSetSerialPort(HWND hWindow, DWORD dwNewSerialPortItem);
void CommUpdate(DWORD);
void SetSnapshot_v1(const DWORD baudrate, const BYTE bytesize, const BYTE commandbyte, const DWORD comminactivity, const BYTE controlbyte, const BYTE parity, const BYTE stopbits); void SetSnapshot_v1(const DWORD baudrate, const BYTE bytesize, const BYTE commandbyte, const DWORD comminactivity, const BYTE controlbyte, const BYTE parity, const BYTE stopbits);
std::string GetSnapshotCardName(void); std::string GetSnapshotCardName(void);
void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper); void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
@ -62,14 +61,16 @@ private:
BYTE __stdcall CommReceive(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles); BYTE __stdcall CommReceive(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles);
BYTE __stdcall CommStatus(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles); BYTE __stdcall CommStatus(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles);
BYTE __stdcall CommTransmit(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles); BYTE __stdcall CommTransmit(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles);
BYTE __stdcall CommProgramReset(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles);
void InternalReset(); void InternalReset();
void UpdateCommandReg(BYTE command);
void GetDIPSW(); void GetDIPSW();
void SetDIPSWDefaults(); void SetDIPSWDefaults();
BYTE GenerateControl();
UINT BaudRateToIndex(UINT uBaudRate); UINT BaudRateToIndex(UINT uBaudRate);
void UpdateCommState(); void UpdateCommState();
BOOL CheckComm(); void TransmitDone(void);
bool CheckComm();
void CloseComm(); void CloseComm();
void CheckCommEvent(DWORD dwEvtMask); void CheckCommEvent(DWORD dwEvtMask);
static DWORD WINAPI CommThread(LPVOID lpParameter); static DWORD WINAPI CommThread(LPVOID lpParameter);
@ -97,10 +98,7 @@ private:
static SSC_DIPSW m_DIPSWDefault; static SSC_DIPSW m_DIPSWDefault;
SSC_DIPSW m_DIPSWCurrent; SSC_DIPSW m_DIPSWCurrent;
// Derived from DIPSW1
UINT m_uBaudRate; UINT m_uBaudRate;
// Derived from DIPSW2
UINT m_uStopBits; UINT m_uStopBits;
UINT m_uByteSize; UINT m_uByteSize;
UINT m_uParity; UINT m_uParity;
@ -114,24 +112,22 @@ private:
HANDLE m_hCommHandle; HANDLE m_hCommHandle;
SOCKET m_hCommListenSocket; SOCKET m_hCommListenSocket;
SOCKET m_hCommAcceptSocket; SOCKET m_hCommAcceptSocket;
DWORD m_dwCommInactivity;
// //
CRITICAL_SECTION m_CriticalSection; // To guard /g_vRecvBytes/ CRITICAL_SECTION m_CriticalSection; // To guard /g_vRecvBytes/
std::deque<BYTE> m_qComSerialBuffer[2]; std::deque<BYTE> m_qComSerialBuffer[2];
volatile UINT m_vuRxCurrBuffer; // Written to on COM recv. SSC reads from other one volatile UINT m_vuRxCurrBuffer; // Written to on COM recv. SSC reads from other one
std::deque<BYTE> m_qTcpSerialBuffer; std::deque<BYTE> m_qTcpSerialBuffer;
// //
bool m_bTxIrqEnabled; bool m_bTxIrqEnabled;
bool m_bRxIrqEnabled; bool m_bRxIrqEnabled;
volatile bool m_vbTxIrqPending; volatile bool m_vbTxIrqPending;
volatile bool m_vbRxIrqPending; volatile bool m_vbRxIrqPending;
volatile bool m_vbTxEmpty;
bool m_bWrittenTx;
// //
@ -146,6 +142,9 @@ private:
// Modem // Modem
bool m_bCfgSupportDCD; bool m_bCfgSupportDCD;
bool m_bCfgSupportDSR; bool m_bCfgSupportDSR;
UINT m_uDTR;
bool m_bCfgSupportDTR; bool m_bCfgSupportDTR;
UINT m_uDTR;
// Modem (end)
UINT m_uRTS;
}; };