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:
parent
598b20fb52
commit
a78f1e04da
7 changed files with 286 additions and 272 deletions
|
@ -89,7 +89,6 @@ static double g_fMHz = 1.0; // Affected by Config dialog's speed slider bar
|
|||
int g_nCpuCyclesFeedback = 0;
|
||||
DWORD g_dwCyclesThisFrame = 0;
|
||||
|
||||
FILE* g_fh = NULL;
|
||||
bool g_bDisableDirectInput = false;
|
||||
bool g_bDisableDirectSound = false;
|
||||
bool g_bDisableDirectSoundMockingboard = false;
|
||||
|
@ -301,8 +300,6 @@ static void ContinueExecution(void)
|
|||
|
||||
DiskUpdateDriveState(uActualCyclesExecuted);
|
||||
JoyUpdateButtonLatch(nExecutionPeriodUsec); // Button latch time is independent of CPU clock frequency
|
||||
|
||||
sg_SSC.CommUpdate(uActualCyclesExecuted);
|
||||
PrintUpdate(uActualCyclesExecuted);
|
||||
|
||||
//
|
||||
|
|
|
@ -1814,9 +1814,6 @@ LRESULT CALLBACK FrameWndProc (
|
|||
case FD_READ:
|
||||
sg_SSC.CommTcpSerialReceive();
|
||||
break;
|
||||
|
||||
case FD_WRITE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
|
||||
#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, ...)
|
||||
{
|
||||
if (!g_fh)
|
||||
|
|
|
@ -8,5 +8,7 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
extern FILE* g_fh; // Filehandle for log file
|
||||
|
||||
extern void LogOutput(LPCTSTR format, ...);
|
||||
extern void LogFileOutput(LPCTSTR format, ...);
|
||||
|
|
|
@ -175,6 +175,7 @@ static void Snapshot_LoadState_v1() // .aws v1.0.0.1, up to (and including) Appl
|
|||
KeybReset();
|
||||
VideoResetState();
|
||||
MB_Reset();
|
||||
sg_SSC.CommReset();
|
||||
|
||||
//
|
||||
// Apple2 unit
|
||||
|
@ -497,6 +498,7 @@ static void Snapshot_LoadState_v2(void)
|
|||
KeybReset();
|
||||
VideoResetState();
|
||||
MB_Reset();
|
||||
sg_SSC.CommReset();
|
||||
#ifdef USE_SPEECH_API
|
||||
g_Speech.Reset();
|
||||
#endif
|
||||
|
|
|
@ -26,35 +26,28 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||
* Author: Various
|
||||
*/
|
||||
|
||||
// TO DO:
|
||||
// . Enable & test Tx IRQ
|
||||
// . DIP switch read values
|
||||
//
|
||||
|
||||
// Refs:
|
||||
// (1) "Super Serial Card (SSC) Memory Locations for Programmers" - Aaron Heiss
|
||||
// (2) SSC recv IRQ example: http://www.wright.edu/~john.matthews/ssc.html#lst - John B. Matthews, 5/13/87
|
||||
// (3) WaitCommEvent, etc: http://mail.python.org/pipermail/python-list/2002-November/131437.html
|
||||
// (4) SY6551 info: http://www.axess.com/twilight/sock/rs232pak.html
|
||||
// [Ref.1] AppleWin\docs\SSC Memory Locations for Programmers.txt
|
||||
// [Ref.2] SSC recv IRQ example: https://sites.google.com/site/drjohnbmatthews/apple2/ssc - John B. Matthews, 5/13/87
|
||||
// [Ref.3] SY6551 info: http://users.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 "Applewin.h"
|
||||
#include "CPU.h"
|
||||
#include "Disk.h" // DiskIsSpinning()
|
||||
#include "Frame.h"
|
||||
#include "Log.h"
|
||||
#include "Memory.h"
|
||||
#include "SerialComms.h"
|
||||
#include "YamlHelper.h"
|
||||
|
||||
#include "../resource/resource.h"
|
||||
|
||||
//#define SUPPORT_MODEM
|
||||
#define TCP_SERIAL_PORT 1977
|
||||
|
||||
// Default: 19200-8-N-1
|
||||
// Maybe a better default is: 9600-7-N-1 (for HyperTrm)
|
||||
SSC_DIPSW CSuperSerialCard::m_DIPSWDefault =
|
||||
{
|
||||
// DIPSW1:
|
||||
|
@ -65,8 +58,8 @@ SSC_DIPSW CSuperSerialCard::m_DIPSWDefault =
|
|||
ONESTOPBIT,
|
||||
8, // ByteSize
|
||||
NOPARITY,
|
||||
true, // LF
|
||||
false, // INT
|
||||
false, // SW2-5: LF(0x0A). SSC-24: In Comms mode, SSC automatically discards LF immediately following CR
|
||||
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_hCommListenSocket = INVALID_SOCKET;
|
||||
m_hCommAcceptSocket = INVALID_SOCKET;
|
||||
m_dwCommInactivity = 0;
|
||||
|
||||
m_hCommThread = NULL;
|
||||
|
||||
|
@ -101,21 +93,32 @@ void CSuperSerialCard::InternalReset()
|
|||
{
|
||||
GetDIPSW();
|
||||
|
||||
m_bTxIrqEnabled = false;
|
||||
m_bRxIrqEnabled = false;
|
||||
// SY6551 datasheet: Hardware reset sets Control register to 0 - the DIPSW settings are not used by h/w to setup this register
|
||||
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_vbTxIrqPending = false;
|
||||
m_vbRxIrqPending = false;
|
||||
m_vbTxEmpty = true;
|
||||
|
||||
m_qComSerialBuffer[0].clear();
|
||||
m_qComSerialBuffer[1].clear();
|
||||
m_qTcpSerialBuffer.clear();
|
||||
|
||||
m_uDTR = DTR_CONTROL_DISABLE;
|
||||
m_uRTS = RTS_CONTROL_DISABLE;
|
||||
}
|
||||
|
||||
CSuperSerialCard::~CSuperSerialCard()
|
||||
|
@ -128,26 +131,12 @@ CSuperSerialCard::~CSuperSerialCard()
|
|||
// TODO: Serial Comms - UI Property Sheet Page:
|
||||
// . Ability to config the 2x DIPSWs - only takes affect after next Apple2 reset
|
||||
// . '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()
|
||||
{
|
||||
// TODO: Read settings from Registry
|
||||
// In the meantime, use the defaults:
|
||||
// TODO: Read settings from Registry(?). In the meantime, use the defaults:
|
||||
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()
|
||||
|
@ -166,23 +155,6 @@ void CSuperSerialCard::SetDIPSWDefaults()
|
|||
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)
|
||||
{
|
||||
switch (uBaudRate)
|
||||
|
@ -199,7 +171,8 @@ UINT CSuperSerialCard::BaudRateToIndex(UINT uBaudRate)
|
|||
}
|
||||
|
||||
_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.Parity = m_uParity;
|
||||
dcb.StopBits = m_uStopBits;
|
||||
dcb.fDtrControl = m_uDTR;
|
||||
dcb.fDtrControl = m_uDTR; // GH#386
|
||||
dcb.fRtsControl = m_uRTS; // GH#311
|
||||
|
||||
SetCommState(m_hCommHandle,&dcb);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
||||
BOOL CSuperSerialCard::CheckComm()
|
||||
bool CSuperSerialCard::CheckComm()
|
||||
{
|
||||
m_dwCommInactivity = 0;
|
||||
|
||||
// check for COM or TCP socket handle, and setup if invalid
|
||||
if (IsActive())
|
||||
return true;
|
||||
|
||||
if (m_dwSerialPortItem == m_uTCPChoiceItemIdx)
|
||||
{
|
||||
// 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 (WSAStartup(MAKEWORD(2, 2), &wsaData) == 0) // Winsock 2.2
|
||||
{
|
||||
if (wsaData.wVersion != 0x0101) // or 0x0202 for Winsock 2.2
|
||||
if (wsaData.wVersion != 0x0202)
|
||||
{
|
||||
WSACleanup();
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// initialized, so try to create a socket
|
||||
|
@ -249,7 +220,7 @@ BOOL CSuperSerialCard::CheckComm()
|
|||
if (m_hCommListenSocket == INVALID_SOCKET)
|
||||
{
|
||||
WSACleanup();
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// have socket so attempt to bind it
|
||||
|
@ -261,7 +232,7 @@ BOOL CSuperSerialCard::CheckComm()
|
|||
{
|
||||
m_hCommListenSocket = INVALID_SOCKET;
|
||||
WSACleanup();
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// bound, so listen
|
||||
|
@ -269,7 +240,7 @@ BOOL CSuperSerialCard::CheckComm()
|
|||
{
|
||||
m_hCommListenSocket = INVALID_SOCKET;
|
||||
WSACleanup();
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// now send async events to our app's message handler
|
||||
|
@ -281,7 +252,7 @@ BOOL CSuperSerialCard::CheckComm()
|
|||
{
|
||||
m_hCommListenSocket = INVALID_SOCKET;
|
||||
WSACleanup();
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -337,7 +308,6 @@ void CSuperSerialCard::CloseComm()
|
|||
CloseHandle(m_hCommHandle);
|
||||
|
||||
m_hCommHandle = INVALID_HANDLE_VALUE;
|
||||
m_dwCommInactivity = 0;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -378,12 +348,14 @@ void CSuperSerialCard::CommTcpSerialAccept()
|
|||
if ((m_hCommListenSocket != INVALID_SOCKET) && (m_hCommAcceptSocket == INVALID_SOCKET))
|
||||
{
|
||||
// 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()
|
||||
{
|
||||
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 0x7: return IO_Null(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 0xB: return pSSC->CommControl(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)
|
||||
{
|
||||
|
@ -475,55 +538,7 @@ BYTE __stdcall CSuperSerialCard::CommCommand(WORD, WORD, BYTE write, BYTE value,
|
|||
|
||||
if (write && (value != m_uCommandByte))
|
||||
{
|
||||
m_uCommandByte = 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;
|
||||
}
|
||||
|
||||
UpdateCommandReg(value);
|
||||
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)
|
||||
{
|
||||
if (!CheckComm())
|
||||
|
@ -616,8 +629,15 @@ BYTE __stdcall CSuperSerialCard::CommReceive(WORD, WORD, BYTE, BYTE, ULONG)
|
|||
|
||||
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();
|
||||
m_qTcpSerialBuffer.pop_front();
|
||||
|
||||
if (m_bRxIrqEnabled && !m_qTcpSerialBuffer.empty())
|
||||
{
|
||||
CpuIrqAssert(IS_SSC);
|
||||
m_vbRxIrqPending = true;
|
||||
}
|
||||
}
|
||||
else if (m_hCommHandle != INVALID_HANDLE_VALUE) // COM
|
||||
{
|
||||
|
@ -646,8 +666,6 @@ BYTE __stdcall CSuperSerialCard::CommReceive(WORD, WORD, BYTE, BYTE, ULONG)
|
|||
}
|
||||
}
|
||||
LeaveCriticalSection(&m_CriticalSection);
|
||||
|
||||
g_uDbgTotalSSCRx++;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (!CheckComm())
|
||||
|
@ -667,22 +696,22 @@ BYTE __stdcall CSuperSerialCard::CommTransmit(WORD, WORD, BYTE, BYTE value, ULON
|
|||
{
|
||||
data &= ~(1 << m_uByteSize);
|
||||
}
|
||||
send(m_hCommAcceptSocket, (const char*)&data, 1, 0);
|
||||
m_bWrittenTx = true; // Transmit done
|
||||
int sent = send(m_hCommAcceptSocket, (const char*)&data, 1, 0);
|
||||
if (sent == 1)
|
||||
{
|
||||
m_vbTxEmpty = false;
|
||||
// Assume that send() completes immediately
|
||||
TransmitDone();
|
||||
}
|
||||
}
|
||||
else if (m_hCommHandle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD uBytesWritten;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -691,24 +720,24 @@ BYTE __stdcall CSuperSerialCard::CommTransmit(WORD, WORD, BYTE, BYTE value, ULON
|
|||
// 6551 ACIA Status Register ($C089+s0)
|
||||
// ------------------------------------
|
||||
// Bit Value Meaning
|
||||
// 0 1 Parity error
|
||||
// 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)]
|
||||
// 7 1 Interrupt (IRQ) true (cleared by reading status reg [Ref.3])
|
||||
// 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,
|
||||
ST_FRAMING_ERR = 1<<1,
|
||||
ST_OVERRUN_ERR = 1<<2,
|
||||
ST_RX_FULL = 1<<3,
|
||||
ST_TX_EMPTY = 1<<4,
|
||||
ST_DCD = 1<<5,
|
||||
enum { ST_IRQ = 1<<7,
|
||||
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)
|
||||
{
|
||||
|
@ -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
|
||||
|
||||
if (m_hCommHandle != INVALID_HANDLE_VALUE)
|
||||
|
@ -738,54 +762,67 @@ BYTE __stdcall CSuperSerialCard::CommStatus(WORD, WORD, BYTE, BYTE, ULONG)
|
|||
bComSerialBufferEmpty = m_qComSerialBuffer[uSSCIdx].empty();
|
||||
}
|
||||
|
||||
bool bIRQ = false;
|
||||
if (m_bTxIrqEnabled && m_bWrittenTx)
|
||||
BYTE IRQ = 0;
|
||||
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)
|
||||
{
|
||||
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_bWrittenTx = false; // Read status reg always clears IRQ
|
||||
|
||||
//
|
||||
|
||||
BYTE DCD = 0;
|
||||
BYTE DSR = 0;
|
||||
BYTE DCD = 0;
|
||||
|
||||
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)
|
||||
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
|
||||
| DSR
|
||||
| (bIRQ ? ST_IRQ : 0x00);
|
||||
//
|
||||
|
||||
BYTE TX_EMPTY = m_vbTxEmpty ? ST_TX_EMPTY : 0;
|
||||
BYTE RX_FULL = (!bComSerialBufferEmpty || !m_qTcpSerialBuffer.empty()) ? ST_RX_FULL : 0;
|
||||
|
||||
//
|
||||
|
||||
BYTE uStatus =
|
||||
IRQ
|
||||
| DSR
|
||||
| DCD // Need 0x00 to allow ZLink to start up
|
||||
| TX_EMPTY
|
||||
| RX_FULL;
|
||||
|
||||
if (m_hCommHandle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
LeaveCriticalSection(&m_CriticalSection);
|
||||
}
|
||||
|
||||
CpuIrqDeassert(IS_SSC);
|
||||
CpuIrqDeassert(IS_SSC); // Read status reg always clears IRQ
|
||||
|
||||
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 sw = 0;
|
||||
|
||||
switch (addr & 0xf)
|
||||
{
|
||||
case 1: // DIPSW1
|
||||
|
@ -793,36 +830,51 @@ BYTE __stdcall CSuperSerialCard::CommDipSw(WORD, WORD addr, BYTE, BYTE, ULONG)
|
|||
break;
|
||||
|
||||
case 2: // DIPSW2
|
||||
// Comms mode - SSC manual, pg23/24
|
||||
BYTE INT = m_DIPSWCurrent.uStopBits == TWOSTOPBITS ? 1 : 0; // SW2-1 (Stop bits: 1-ON(0); 2-OFF(1))
|
||||
BYTE DSR = 0; // Always zero
|
||||
BYTE DCD = m_DIPSWCurrent.uByteSize == 7 ? 1 : 0; // SW2-2 (Data bits: 8-ON(0); 7-OFF(1))
|
||||
BYTE TDR = 0; // Always zero
|
||||
// Comms mode: SSC-23
|
||||
BYTE SW2_1 = m_DIPSWCurrent.uStopBits == TWOSTOPBITS ? 1 : 0; // SW2-1 (Stop bits: 1-ON(0); 2-OFF(1))
|
||||
BYTE SW2_2 = m_DIPSWCurrent.uByteSize == 7 ? 1 : 0; // SW2-2 (Data bits: 8-ON(0); 7-OFF(1))
|
||||
|
||||
// SW2-3 (Parity: odd-ON(0); even-OFF(1))
|
||||
// SW2-4 (Parity: none-ON(0); SW2-3-OFF(1))
|
||||
BYTE RDR,OVR;
|
||||
// SW2-4 (Parity: none-ON(0); SW2-3 don't care)
|
||||
BYTE SW2_3,SW2_4;
|
||||
switch (m_DIPSWCurrent.uParity)
|
||||
{
|
||||
case ODDPARITY:
|
||||
RDR = 0; OVR = 1;
|
||||
SW2_3 = 0; SW2_4 = 1;
|
||||
break;
|
||||
case EVENPARITY:
|
||||
RDR = 1; OVR = 1;
|
||||
SW2_3 = 1; SW2_4 = 1;
|
||||
break;
|
||||
default:
|
||||
_ASSERT(0);
|
||||
// fall through...
|
||||
case NOPARITY:
|
||||
RDR = 0; OVR = 0;
|
||||
SW2_3 = 0; SW2_4 = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
BYTE FE = m_DIPSWCurrent.bLinefeed ? 1 : 0; // 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))
|
||||
BYTE SW2_5 = m_DIPSWCurrent.bLinefeed ? 0 : 1; // SW2-5 (LF: 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;
|
||||
}
|
||||
|
||||
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
|
||||
// UPDATE: Fixed by using double-buffered queue
|
||||
//
|
||||
|
@ -1016,25 +1039,26 @@ void CSuperSerialCard::CheckCommEvent(DWORD dwEvtMask)
|
|||
LeaveCriticalSection(&m_CriticalSection);
|
||||
}
|
||||
}
|
||||
//else if (dwEvtMask & EV_TXEMPTY)
|
||||
//{
|
||||
// if (m_bTxIrqEnabled)
|
||||
// {
|
||||
// m_vbTxIrqPending = true;
|
||||
// CpuIrqAssert(IS_SSC);
|
||||
// }
|
||||
//}
|
||||
else if (dwEvtMask & EV_TXEMPTY)
|
||||
{
|
||||
TransmitDone();
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI CSuperSerialCard::CommThread(LPVOID lpParameter)
|
||||
{
|
||||
CSuperSerialCard* pSSC = (CSuperSerialCard*) lpParameter;
|
||||
|
||||
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)
|
||||
{
|
||||
sprintf(szDbg, "SSC: CommThread(): SetCommMask() failed\n");
|
||||
LogOutput("%s", szDbg);
|
||||
LogFileOutput("%s", szDbg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
|
@ -1060,16 +1084,12 @@ DWORD WINAPI CSuperSerialCard::CommThread(LPVOID lpParameter)
|
|||
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, "%s", szDbg);
|
||||
}
|
||||
if (dwErrors & CE_RXOVER)
|
||||
sprintf(szDbg, "SSC: CommThread(): LastError=0x%08X, CommError=CE_RXOVER (0x%08X): InQueue=0x%08X\n", dwRet, dwErrors, Stat.cbInQue);
|
||||
else
|
||||
sprintf(szDbg, "SSC: CommThread(): LastError=0x%08X, CommError=Other (0x%08X): InQueue=0x%08X, OutQueue=0x%08X\n", dwRet, dwErrors, Stat.cbInQue, Stat.cbOutQue);
|
||||
LogOutput("%s", szDbg);
|
||||
LogFileOutput("%s", szDbg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -1153,8 +1173,9 @@ bool CSuperSerialCard::CommThInit()
|
|||
|
||||
if (m_hCommThread == NULL)
|
||||
{
|
||||
DWORD dwThreadId;
|
||||
InitializeCriticalSection(&m_CriticalSection);
|
||||
|
||||
DWORD dwThreadId;
|
||||
m_hCommThread = CreateThread(NULL, // lpThreadAttributes
|
||||
0, // dwStackSize
|
||||
(LPTHREAD_START_ROUTINE) &CSuperSerialCard::CommThread,
|
||||
|
@ -1163,8 +1184,6 @@ bool CSuperSerialCard::CommThInit()
|
|||
&dwThreadId); // lpThreadId
|
||||
|
||||
SetThreadPriority(m_hCommThread, THREAD_PRIORITY_TIME_CRITICAL);
|
||||
|
||||
InitializeCriticalSection(&m_CriticalSection);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1325,16 +1344,15 @@ void CSuperSerialCard::SetSnapshot_v1( const DWORD baudrate,
|
|||
const BYTE stopbits)
|
||||
{
|
||||
m_uBaudRate = baudrate;
|
||||
m_uStopBits = stopbits;
|
||||
m_uByteSize = bytesize;
|
||||
m_uCommandByte = commandbyte;
|
||||
m_dwCommInactivity = comminactivity;
|
||||
// m_dwCommInactivity = comminactivity; // Obsolete
|
||||
m_uControlByte = controlbyte;
|
||||
m_uParity = parity;
|
||||
// m_uParity = parity; // Redundant: derived from commandbyte in UpdateCommandReg()
|
||||
// memcpy(m_RecvBuffer, pSS->recvbuffer, uRecvBufferSize);
|
||||
// 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_STOPBITS, m_uStopBits);
|
||||
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_COMMAND, m_uCommandByte);
|
||||
yamlSaveHelper.SaveUint(SS_YAML_KEY_INACTIVITY, m_dwCommInactivity);
|
||||
yamlSaveHelper.SaveBool(SS_YAML_KEY_TXIRQENABLED, m_bTxIrqEnabled);
|
||||
yamlSaveHelper.SaveBool(SS_YAML_KEY_RXIRQENABLED, m_bRxIrqEnabled);
|
||||
yamlSaveHelper.SaveUint(SS_YAML_KEY_INACTIVITY, 0); // Obsolete
|
||||
yamlSaveHelper.SaveBool(SS_YAML_KEY_TXIRQENABLED, m_bTxIrqEnabled); // Redundant
|
||||
yamlSaveHelper.SaveBool(SS_YAML_KEY_RXIRQENABLED, m_bRxIrqEnabled); // Redundant
|
||||
yamlSaveHelper.SaveBool(SS_YAML_KEY_TXIRQPENDING, m_vbTxIrqPending);
|
||||
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());
|
||||
}
|
||||
|
||||
|
@ -1431,17 +1449,17 @@ bool CSuperSerialCard::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, U
|
|||
m_uBaudRate = yamlLoadHelper.LoadUint(SS_YAML_KEY_BAUDRATE);
|
||||
m_uStopBits = yamlLoadHelper.LoadUint(SS_YAML_KEY_STOPBITS);
|
||||
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_uCommandByte = yamlLoadHelper.LoadUint(SS_YAML_KEY_COMMAND);
|
||||
m_dwCommInactivity = yamlLoadHelper.LoadUint(SS_YAML_KEY_INACTIVITY);
|
||||
m_bTxIrqEnabled = yamlLoadHelper.LoadBool(SS_YAML_KEY_TXIRQENABLED);
|
||||
m_bRxIrqEnabled = yamlLoadHelper.LoadBool(SS_YAML_KEY_RXIRQENABLED);
|
||||
UINT uCommandByte = yamlLoadHelper.LoadUint(SS_YAML_KEY_COMMAND);
|
||||
yamlLoadHelper.LoadUint(SS_YAML_KEY_INACTIVITY); // Obsolete (so just consume)
|
||||
yamlLoadHelper.LoadBool(SS_YAML_KEY_TXIRQENABLED); // Redundant: derived from uCommandByte in UpdateCommandReg()
|
||||
yamlLoadHelper.LoadBool(SS_YAML_KEY_RXIRQENABLED); // Redundant: derived from uCommandByte in UpdateCommandReg()
|
||||
m_vbTxIrqPending = yamlLoadHelper.LoadBool(SS_YAML_KEY_TXIRQPENDING);
|
||||
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);
|
||||
SetSerialPortName(serialPortName.c_str());
|
||||
|
|
|
@ -16,7 +16,7 @@ typedef struct
|
|||
UINT uByteSize;
|
||||
UINT uParity;
|
||||
bool bLinefeed;
|
||||
bool bInterrupts;
|
||||
bool bInterrupts; // NB. Can't be read from s/w
|
||||
} SSC_DIPSW;
|
||||
|
||||
#define TEXT_SERIAL_COM TEXT("COM")
|
||||
|
@ -32,7 +32,6 @@ public:
|
|||
void CommReset();
|
||||
void CommDestroy();
|
||||
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);
|
||||
std::string GetSnapshotCardName(void);
|
||||
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 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 CommProgramReset(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles);
|
||||
|
||||
void InternalReset();
|
||||
void UpdateCommandReg(BYTE command);
|
||||
void GetDIPSW();
|
||||
void SetDIPSWDefaults();
|
||||
BYTE GenerateControl();
|
||||
UINT BaudRateToIndex(UINT uBaudRate);
|
||||
void UpdateCommState();
|
||||
BOOL CheckComm();
|
||||
void TransmitDone(void);
|
||||
bool CheckComm();
|
||||
void CloseComm();
|
||||
void CheckCommEvent(DWORD dwEvtMask);
|
||||
static DWORD WINAPI CommThread(LPVOID lpParameter);
|
||||
|
@ -97,10 +98,7 @@ private:
|
|||
static SSC_DIPSW m_DIPSWDefault;
|
||||
SSC_DIPSW m_DIPSWCurrent;
|
||||
|
||||
// Derived from DIPSW1
|
||||
UINT m_uBaudRate;
|
||||
|
||||
// Derived from DIPSW2
|
||||
UINT m_uStopBits;
|
||||
UINT m_uByteSize;
|
||||
UINT m_uParity;
|
||||
|
@ -114,24 +112,22 @@ private:
|
|||
HANDLE m_hCommHandle;
|
||||
SOCKET m_hCommListenSocket;
|
||||
SOCKET m_hCommAcceptSocket;
|
||||
DWORD m_dwCommInactivity;
|
||||
|
||||
//
|
||||
|
||||
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
|
||||
std::deque<BYTE> m_qTcpSerialBuffer;
|
||||
std::deque<BYTE> m_qTcpSerialBuffer;
|
||||
|
||||
//
|
||||
|
||||
bool m_bTxIrqEnabled;
|
||||
bool m_bRxIrqEnabled;
|
||||
|
||||
volatile bool m_vbTxIrqPending;
|
||||
volatile bool m_vbRxIrqPending;
|
||||
|
||||
bool m_bWrittenTx;
|
||||
volatile bool m_vbTxIrqPending;
|
||||
volatile bool m_vbRxIrqPending;
|
||||
volatile bool m_vbTxEmpty;
|
||||
|
||||
//
|
||||
|
||||
|
@ -146,6 +142,9 @@ private:
|
|||
// Modem
|
||||
bool m_bCfgSupportDCD;
|
||||
bool m_bCfgSupportDSR;
|
||||
UINT m_uDTR;
|
||||
bool m_bCfgSupportDTR;
|
||||
UINT m_uDTR;
|
||||
// Modem (end)
|
||||
|
||||
UINT m_uRTS;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue