diff --git a/AppleWin/source/SerialComms.cpp b/AppleWin/source/SerialComms.cpp index fd0a1682..5282ee7f 100644 --- a/AppleWin/source/SerialComms.cpp +++ b/AppleWin/source/SerialComms.cpp @@ -21,14 +21,28 @@ along with AppleWin; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* Description: Serial port emulation: not SSC, but similar (same?) regs +/* Description: Super Serial Card emulation * * 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 +// + #include "StdAfx.h" #pragma hdrstop +//#define SUPPORT_MODEM + static DWORD baudrate = CBR_19200; static BYTE bytesize = 8; static BYTE commandbyte = 0x00; @@ -36,238 +50,669 @@ static HANDLE commhandle = INVALID_HANDLE_VALUE; static DWORD comminactivity = 0; static BYTE controlbyte = 0x1F; static BYTE parity = NOPARITY; -static BYTE recvbuffer[9]; -static DWORD recvbytes = 0; DWORD serialport = 0; static BYTE stopbits = ONESTOPBIT; -static void UpdateCommState (); +// + +static CRITICAL_SECTION g_CriticalSection; // To guard /g_vRecvBytes/ +static BYTE g_RecvBuffer[uRecvBufferSize]; // NB: More work required if >1 is used +static volatile DWORD g_vRecvBytes = 0; + +// + +static bool g_bTxIrqEnabled = false; +static bool g_bRxIrqEnabled = false; + +static bool g_bWrittenTx = false; + +// + +static volatile bool g_vbCommIRQ = false; +static HANDLE g_hCommThread = NULL; + +enum {COMMEVT_WAIT=0, COMMEVT_ACK, COMMEVT_TERM, COMMEVT_MAX}; +static HANDLE g_hCommEvent[COMMEVT_MAX] = {NULL}; +static OVERLAPPED o; //=========================================================================== -static BOOL CheckComm () { - comminactivity = 0; - if ((commhandle == INVALID_HANDLE_VALUE) && serialport) { - TCHAR portname[8]; - wsprintf(portname, - TEXT("COM%u"), - serialport); - commhandle = CreateFile(portname, - GENERIC_READ | GENERIC_WRITE, - 0, - (LPSECURITY_ATTRIBUTES)NULL, - OPEN_EXISTING, - 0, - NULL); - if (commhandle != INVALID_HANDLE_VALUE) { - UpdateCommState(); - COMMTIMEOUTS ct; - ZeroMemory(&ct,sizeof(COMMTIMEOUTS)); - ct.ReadIntervalTimeout = MAXDWORD; - SetCommTimeouts(commhandle,&ct); - } - } - return (commhandle != INVALID_HANDLE_VALUE); + +static void UpdateCommState () +{ + if (commhandle == INVALID_HANDLE_VALUE) + return; + + DCB dcb; + ZeroMemory(&dcb,sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + GetCommState(commhandle,&dcb); + dcb.BaudRate = baudrate; + dcb.ByteSize = bytesize; + dcb.Parity = parity; + dcb.StopBits = stopbits; + + SetCommState(commhandle,&dcb); } //=========================================================================== -static void CheckReceive () { - if (recvbytes || (commhandle == INVALID_HANDLE_VALUE)) - return; - ReadFile(commhandle,recvbuffer,8,&recvbytes,NULL); + +static BOOL CheckComm () +{ + comminactivity = 0; + + if ((commhandle == INVALID_HANDLE_VALUE) && serialport) + { + TCHAR portname[8]; + wsprintf(portname, TEXT("COM%u"), serialport); + + commhandle = 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 (commhandle != INVALID_HANDLE_VALUE) + { + UpdateCommState(); + COMMTIMEOUTS ct; + ZeroMemory(&ct,sizeof(COMMTIMEOUTS)); + ct.ReadIntervalTimeout = MAXDWORD; + SetCommTimeouts(commhandle,&ct); + CommThInit(); + } + else + { + DWORD uError = GetLastError(); + } + } + + return (commhandle != INVALID_HANDLE_VALUE); } //=========================================================================== -static void CloseComm () { - if (commhandle != INVALID_HANDLE_VALUE) - CloseHandle(commhandle); - commhandle = INVALID_HANDLE_VALUE; - comminactivity = 0; + +static void CloseComm () +{ + CommThUninit(); // Kill CommThread before closing COM handle + + if (commhandle != INVALID_HANDLE_VALUE) + CloseHandle(commhandle); + + commhandle = INVALID_HANDLE_VALUE; + comminactivity = 0; } //=========================================================================== -static void UpdateCommState () { - if (commhandle == INVALID_HANDLE_VALUE) - return; - DCB dcb; - ZeroMemory(&dcb,sizeof(DCB)); - dcb.DCBlength = sizeof(DCB); - GetCommState(commhandle,&dcb); - dcb.BaudRate = baudrate; - dcb.ByteSize = bytesize; - dcb.Parity = parity; - dcb.StopBits = stopbits; - SetCommState(commhandle,&dcb); + +// EG. 0x09 = Enable IRQ, No parity [Ref.2] + +BYTE __stdcall CommCommand (WORD, BYTE, BYTE write, BYTE value, ULONG) +{ + if (!CheckComm()) + return 0; + + if (write && (value != commandbyte)) + { + commandbyte = value; + + // UPDATE THE PARITY + if (commandbyte & 0x20) + { + switch (commandbyte & 0xC0) + { + case 0x00 : parity = ODDPARITY; break; + case 0x40 : parity = EVENPARITY; break; + case 0x80 : parity = MARKPARITY; break; + case 0xC0 : parity = SPACEPARITY; break; + } + } + else + { + parity = NOPARITY; + } + + if (commandbyte & 0x10) // Receiver mode echo [0=no echo, 1=echo] + { + } + + switch (commandbyte & 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 + g_bTxIrqEnabled = false; + break; + case 1<<2: // set RTS low and transmit interrupts + g_bTxIrqEnabled = true; + break; + case 2<<2: // set RTS low and transmit no interrupts + g_bTxIrqEnabled = false; + break; + case 3<<2: // set RTS low and transmit break signals instead of interrupts + g_bTxIrqEnabled = false; + break; + } + + // interrupt request disable [0=enable receiver interrupts] + g_bRxIrqEnabled = ((commandbyte & 0x02) == 0); + + if (commandbyte & 0x01) // Data Terminal Ready (DTR) setting [0=set DTR high (indicates 'not ready')] + { + // Note that, although the DTR is generally not used in the SSC (it may actually not + // be connected!), it must be set to 'low' in order for the 6551 to function correctly. + } + + UpdateCommState(); + } + + return commandbyte; } //=========================================================================== -BYTE __stdcall CommCommand (WORD, BYTE, BYTE write, BYTE value, ULONG) { - if (!CheckComm()) - return 0; - if (write && (value != commandbyte)) { - commandbyte = value; - // UPDATE THE PARITY - if (commandbyte & 0x20) - switch (commandbyte & 0xC0) { - case 0x00 : parity = ODDPARITY; break; - case 0x40 : parity = EVENPARITY; break; - case 0x80 : parity = MARKPARITY; break; - case 0xC0 : parity = SPACEPARITY; break; - } - else - parity = NOPARITY; +BYTE __stdcall CommControl (WORD, BYTE, BYTE write, BYTE value, ULONG) +{ + if (!CheckComm()) + return 0; - UpdateCommState(); - } - return commandbyte; -} + if (write && (value != controlbyte)) + { + controlbyte = value; -//=========================================================================== -BYTE __stdcall CommControl (WORD, BYTE, BYTE write, BYTE value, ULONG) { - if (!CheckComm()) - return 0; - if (write && (value != controlbyte)) { - controlbyte = value; + // UPDATE THE BAUD RATE + switch (controlbyte & 0x0F) + { + // Note that 1 MHz Apples (everything other than the Apple IIgs and //c + // Plus running in "fast" mode) cannot handle 19.2 kbps, and even 9600 + // bps on these machines requires either some highly optimised code or + // a decent buffer in the device being accessed. The faster Apples + // have no difficulty with this speed, however. - // UPDATE THE BAUD RATE - switch (controlbyte & 0x0F) { - case 0x00: // fall through - case 0x01: // fall through - case 0x02: // fall through - case 0x03: // fall through - case 0x04: // fall through - case 0x05: baudrate = CBR_110; break; - case 0x06: baudrate = CBR_300; break; - case 0x07: baudrate = CBR_600; break; - case 0x08: baudrate = CBR_1200; break; - case 0x09: // fall through - case 0x0A: baudrate = CBR_2400; break; - case 0x0B: // fall through - case 0x0C: baudrate = CBR_4800; break; - case 0x0D: // fall through - case 0x0E: baudrate = CBR_9600; break; - case 0x0F: baudrate = CBR_19200; break; - } + case 0x00: // fall through [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: baudrate = CBR_110; break; // [150 bps] + case 0x06: baudrate = CBR_300; break; + case 0x07: baudrate = CBR_600; break; + case 0x08: baudrate = CBR_1200; break; + case 0x09: // fall through [1800 bps] + case 0x0A: baudrate = CBR_2400; break; + case 0x0B: // fall through [3600 bps] + case 0x0C: baudrate = CBR_4800; break; + case 0x0D: // fall through [7200 bps] + case 0x0E: baudrate = CBR_9600; break; + case 0x0F: baudrate = CBR_19200; break; + } - // UPDATE THE BYTE SIZE - switch (controlbyte & 0x60) { - case 0x00: bytesize = 8; break; - case 0x20: bytesize = 7; break; - case 0x40: bytesize = 6; break; - case 0x60: bytesize = 5; break; - } + if (controlbyte & 0x10) + { + // receiver clock source [0= external, 1= internal] + } - // UPDATE THE NUMBER OF STOP BITS - if (controlbyte & 0x80) { - if ((bytesize == 8) && (parity == NOPARITY)) - stopbits = ONESTOPBIT; - else if ((bytesize == 5) && (parity == NOPARITY)) - stopbits = ONE5STOPBITS; - else - stopbits = TWOSTOPBITS; - } - else - stopbits = ONESTOPBIT; + // UPDATE THE BYTE SIZE + switch (controlbyte & 0x60) + { + case 0x00: bytesize = 8; break; + case 0x20: bytesize = 7; break; + case 0x40: bytesize = 6; break; + case 0x60: bytesize = 5; break; + } + + // UPDATE THE NUMBER OF STOP BITS + if (controlbyte & 0x80) + { + if ((bytesize == 8) && (parity == NOPARITY)) + stopbits = ONESTOPBIT; + else if ((bytesize == 5) && (parity == NOPARITY)) + stopbits = ONE5STOPBITS; + else + stopbits = TWOSTOPBITS; + } + else + { + stopbits = ONESTOPBIT; + } + + UpdateCommState(); + } - UpdateCommState(); - } return controlbyte; } //=========================================================================== -void CommDestroy () { - if ((baudrate != CBR_19200) || - (bytesize != 8) || - (parity != NOPARITY) || - (stopbits != ONESTOPBIT)) { - CommReset(); - CheckComm(); - } - CloseComm(); + +BYTE __stdcall CommReceive (WORD, BYTE, BYTE, BYTE, ULONG) +{ + if (!CheckComm()) + return 0; + + BYTE result = 0; + if (g_vRecvBytes) + { + // Don't need critical section in here as CommThread is waiting for ACK + + result = g_RecvBuffer[0]; + --g_vRecvBytes; + + if (g_vbCommIRQ && !g_vRecvBytes) + { + // Read last byte, so get CommThread to call WaitCommEvent() again + OutputDebugString("CommRecv: SetEvent - ACK\n"); + SetEvent(g_hCommEvent[COMMEVT_ACK]); + } + } + + return result; } //=========================================================================== -BYTE __stdcall CommDipSw (WORD, BYTE, BYTE, BYTE, ULONG) { - // note: determine what values a real SSC returns - return 0; + +BYTE __stdcall CommTransmit (WORD, BYTE, BYTE, BYTE value, ULONG) +{ + if (!CheckComm()) + return 0; + + DWORD uBytesWritten; + WriteFile(commhandle, &value, 1, &uBytesWritten, &o); + + g_bWrittenTx = true; // Transmit done + + // TO DO: + // 1) Use CommThread determine when transmit is complete + // 2) OR do this: + //if (g_bTxIrqEnabled) + // CpuIrqAssert(IS_SSC); + + return 0; } //=========================================================================== -void CommSetSerialPort (HWND window, DWORD newserialport) { - if (commhandle == INVALID_HANDLE_VALUE) - serialport = newserialport; - else - MessageBox(window, - TEXT("You cannot change the serial port while it is ") - TEXT("in use."), - TEXT("Configuration"), - MB_ICONEXCLAMATION | MB_SETFOREGROUND); + +// 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)] +// 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]) + +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, + ST_DSR = 1<<6, + ST_IRQ = 1<<7 + }; + +BYTE __stdcall CommStatus (WORD, BYTE, BYTE, BYTE, ULONG) +{ + if (!CheckComm()) + return ST_DSR | ST_DCD | ST_TX_EMPTY; + +#ifdef SUPPORT_MODEM + DWORD modemstatus = 0; + GetCommModemStatus(commhandle,&modemstatus); // Returns 0x30 = MS_DSR_ON|MS_CTS_ON +#endif + + // + + // TO DO - ST_TX_EMPTY: + // . IRQs enabled : set after WaitCommEvent has signaled that TX has completed + // . IRQs disabled : always set it [Currently done] + // + + // So that /g_vRecvBytes/ doesn't change midway (from 0 to 1): + // . bIRQ=false, but uStatus.ST_RX_FULL=1 + EnterCriticalSection(&g_CriticalSection); + + bool bIRQ = false; + if (g_bTxIrqEnabled && g_bWrittenTx) + { + bIRQ = true; + } + if (g_bRxIrqEnabled && g_vRecvBytes) + { + bIRQ = true; + } + + g_bWrittenTx = false; // Read status reg always clears IRQ + + // + + BYTE uStatus = ST_TX_EMPTY + | (g_vRecvBytes ? 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) +#endif + | (bIRQ ? ST_IRQ : 0x00); + + LeaveCriticalSection(&g_CriticalSection); + + CpuIrqDeassert(IS_SSC); + + return uStatus; } //=========================================================================== -void CommUpdate (DWORD totalcycles) { - if (commhandle == INVALID_HANDLE_VALUE) - return; - if ((comminactivity += totalcycles) > 1000000) { - static DWORD lastcheck = 0; - if ((comminactivity > 2000000) || (comminactivity-lastcheck > 99950)) { - DWORD modemstatus = 0; - GetCommModemStatus(commhandle,&modemstatus); - if ((modemstatus & MS_RLSD_ON) || DiskIsSpinning()) - comminactivity = 0; - } - if (comminactivity > 2000000) - CloseComm(); - } + +BYTE __stdcall CommDipSw (WORD, BYTE addr, BYTE, BYTE, ULONG) +{ + // TO DO: determine what values a real SSC returns + BYTE sw = 0; + return sw; } //=========================================================================== -BYTE __stdcall CommReceive (WORD, BYTE, BYTE, BYTE, ULONG) { - if (!CheckComm()) - return 0; - if (!recvbytes) - CheckReceive(); - BYTE result = 0; - if (recvbytes) { - result = recvbuffer[0]; - if (--recvbytes) - MoveMemory(recvbuffer,recvbuffer+1,recvbytes); - } - return result; + +void CommReset () +{ + CloseComm(); + + baudrate = CBR_19200; + bytesize = 8; + commandbyte = 0x00; + controlbyte = 0x1F; + parity = NOPARITY; + g_vRecvBytes = 0; + stopbits = ONESTOPBIT; } //=========================================================================== -void CommReset () { - CloseComm(); - baudrate = CBR_19200; - bytesize = 8; - commandbyte = 0x00; - controlbyte = 0x1F; - parity = NOPARITY; - recvbytes = 0; - stopbits = ONESTOPBIT; + +void CommDestroy () +{ + if ((baudrate != CBR_19200) || + (bytesize != 8) || + (parity != NOPARITY) || + (stopbits != ONESTOPBIT)) + { + CommReset(); + } + + CloseComm(); } //=========================================================================== -BYTE __stdcall CommStatus (WORD, BYTE, BYTE, BYTE, ULONG) { - if (!CheckComm()) - return 0x70; - if (!recvbytes) - CheckReceive(); - DWORD modemstatus = 0; - GetCommModemStatus(commhandle,&modemstatus); - return 0x10 | (recvbytes ? 0x08 : 0x00) - | ((modemstatus & MS_RLSD_ON) ? 0x00 : 0x20) - | ((modemstatus & MS_DSR_ON) ? 0x00 : 0x40); + +void CommSetSerialPort (HWND window, DWORD newserialport) +{ + if (commhandle == INVALID_HANDLE_VALUE) + { + serialport = newserialport; + } + else + { + MessageBox(window, + TEXT("You cannot change the serial port while it is ") + TEXT("in use."), + TEXT("Configuration"), + MB_ICONEXCLAMATION | MB_SETFOREGROUND); + } } //=========================================================================== -BYTE __stdcall CommTransmit (WORD, BYTE, BYTE, BYTE value, ULONG) { - if (!CheckComm()) - return 0; - DWORD byteswritten; - WriteFile(commhandle,&value,1,&byteswritten,NULL); - return 0; + +void CommUpdate (DWORD totalcycles) +{ + if (commhandle == INVALID_HANDLE_VALUE) + return; + + if ((comminactivity += totalcycles) > 1000000) + { + static DWORD lastcheck = 0; + + if ((comminactivity > 2000000) || (comminactivity-lastcheck > 99950)) + { +#ifdef SUPPORT_MODEM + DWORD modemstatus = 0; + GetCommModemStatus(commhandle,&modemstatus); + if ((modemstatus & MS_RLSD_ON) || DiskIsSpinning()) + comminactivity = 0; +#else + if (DiskIsSpinning()) + comminactivity = 0; +#endif + } + + //if (comminactivity > 2000000) + // CloseComm(); + } +} + +//=========================================================================== + +static void CheckCommEvent(DWORD dwEvtMask) +{ + if (dwEvtMask & EV_RXCHAR) + { + EnterCriticalSection(&g_CriticalSection); + ReadFile(commhandle, g_RecvBuffer, 1, (DWORD*)&g_vRecvBytes, &o); + LeaveCriticalSection(&g_CriticalSection); + + if (g_bRxIrqEnabled && g_vRecvBytes) + { + g_vbCommIRQ = true; + CpuIrqAssert(IS_SSC); + } + } + //else if (dwEvtMask & EV_TXEMPTY) + //{ + // if (g_bTxIrqEnabled) + // { + // g_vbCommIRQ = true; + // CpuIrqAssert(IS_SSC); + // } + //} +} + +static DWORD WINAPI CommThread(LPVOID lpParameter) +{ + char szDbg[100]; +// BOOL bRes = SetCommMask(commhandle, EV_TXEMPTY | EV_RXCHAR); + BOOL bRes = SetCommMask(commhandle, EV_RXCHAR); // Just RX + if (!bRes) + return -1; + + // + + const UINT nNumEvents = 2; +#if 1 + HANDLE hCommEvent_Wait[nNumEvents] = {g_hCommEvent[COMMEVT_WAIT], g_hCommEvent[COMMEVT_TERM]}; + HANDLE hCommEvent_Ack[nNumEvents] = {g_hCommEvent[COMMEVT_ACK], g_hCommEvent[COMMEVT_TERM]}; +#else + HANDLE hCommEvent_Wait[nNumEvents]; + HANDLE hCommEvent_Ack[nNumEvents]; + + hCommEvent_Wait[0] = g_hCommEvent[COMMEVT_WAIT]; + hCommEvent_Wait[1] = g_hCommEvent[COMMEVT_TERM]; + + hCommEvent_Ack[0] = g_hCommEvent[COMMEVT_ACK]; + hCommEvent_Ack[1] = g_hCommEvent[COMMEVT_TERM]; +#endif + + while(1) + { + DWORD dwEvtMask = 0; + DWORD dwWaitResult; + + bRes = WaitCommEvent(commhandle, &dwEvtMask, &o); // Will return immediately (probably with ERROR_IO_PENDING) + _ASSERT(!bRes); + if (!bRes) + { + DWORD dwRet = GetLastError(); + _ASSERT(dwRet == ERROR_IO_PENDING); + if (dwRet != ERROR_IO_PENDING) + return -1; + + // + // Wait for comm event + // + + while(1) + { + OutputDebugString("CommThread: Wait1\n"); + dwWaitResult = WaitForMultipleObjects( + nNumEvents, // number of handles in array + hCommEvent_Wait, // array of event handles + FALSE, // wait until any one is signaled + INFINITE); + + // On very 1st wait *only*: get a false signal (when not running via debugger) + if ((dwWaitResult == WAIT_OBJECT_0) && (dwEvtMask == 0)) + continue; + + if ((dwWaitResult >= WAIT_OBJECT_0) && (dwWaitResult <= WAIT_OBJECT_0+nNumEvents-1)) + break; + } + + dwWaitResult -= WAIT_OBJECT_0; // Determine event # that signaled + sprintf(szDbg, "CommThread: GotEvent1: %d\n", dwWaitResult); OutputDebugString(szDbg); + + if (dwWaitResult == (nNumEvents-1)) + break; // Termination event + } + + // Comm event + CheckCommEvent(dwEvtMask); + + if (g_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 + + g_vbCommIRQ = false; + } + } + + return 0; +} + +bool CommThInit() +{ + _ASSERT(g_hCommThread == NULL); + _ASSERT(commhandle); + + if ((g_hCommEvent[0] == NULL) && (g_hCommEvent[1] == NULL) && (g_hCommEvent[2] == NULL)) + { + // Create an event object for use by WaitCommEvent + + o.hEvent = CreateEvent( + NULL, // default security attributes + FALSE, // auto reset event (bManualReset) + FALSE, // not signaled (bInitialState) + NULL // no name + ); + + // Initialize the rest of the OVERLAPPED structure to zero + o.Internal = 0; + o.InternalHigh = 0; + o.Offset = 0; + o.OffsetHigh = 0; + + // + + g_hCommEvent[COMMEVT_WAIT] = o.hEvent; + g_hCommEvent[COMMEVT_ACK] = CreateEvent(NULL, // lpEventAttributes + FALSE, // bManualReset (FALSE = auto-reset) + FALSE, // bInitialState (FALSE = non-signaled) + NULL); // lpName + g_hCommEvent[COMMEVT_TERM] = CreateEvent(NULL, // lpEventAttributes + FALSE, // bManualReset (FALSE = auto-reset) + FALSE, // bInitialState (FALSE = non-signaled) + NULL); // lpName + + if ((g_hCommEvent[0] == NULL) || (g_hCommEvent[1] == NULL) || (g_hCommEvent[2] == NULL)) + { + if(g_fh) fprintf(g_fh, "Comm: CreateEvent failed\n"); + return false; + } + } + + // + + if (g_hCommThread == NULL) + { + DWORD dwThreadId; + + g_hCommThread = CreateThread(NULL, // lpThreadAttributes + 0, // dwStackSize + CommThread, + NULL, // lpParameter + 0, // dwCreationFlags : 0 = Run immediately + &dwThreadId); // lpThreadId + + InitializeCriticalSection(&g_CriticalSection); + } + + return true; +} + +void CommThUninit() +{ + if (g_hCommThread) + { + SetEvent(g_hCommEvent[COMMEVT_TERM]); // Signal to thread that it should exit + + do + { + DWORD dwExitCode; + if(GetExitCodeThread(g_hCommThread, &dwExitCode)) + { + if(dwExitCode == STILL_ACTIVE) + Sleep(10); + else + break; + } + } + while(1); + + CloseHandle(g_hCommThread); + g_hCommThread = NULL; + + DeleteCriticalSection(&g_CriticalSection); + } + + // + + for (UINT i=0; icomminactivity = comminactivity; pSS->controlbyte = controlbyte; pSS->parity = parity; - memcpy(pSS->recvbuffer, recvbuffer, 9); - pSS->recvbytes = recvbytes; + memcpy(pSS->recvbuffer, g_RecvBuffer, uRecvBufferSize); + pSS->recvbytes = g_vRecvBytes; pSS->stopbits = stopbits; return 0; } @@ -294,8 +739,8 @@ DWORD CommSetSnapshot(SS_IO_Comms* pSS) comminactivity = pSS->comminactivity; controlbyte = pSS->controlbyte; parity = pSS->parity; - memcpy(recvbuffer, pSS->recvbuffer, 9); - recvbytes = pSS->recvbytes; + memcpy(g_RecvBuffer, pSS->recvbuffer, uRecvBufferSize); + g_vRecvBytes = pSS->recvbytes; stopbits = pSS->stopbits; return 0; } diff --git a/AppleWin/source/SerialComms.h b/AppleWin/source/SerialComms.h index fbb3e190..7b70711f 100644 --- a/AppleWin/source/SerialComms.h +++ b/AppleWin/source/SerialComms.h @@ -6,6 +6,8 @@ void CommDestroy (); void CommReset (); void CommSetSerialPort (HWND,DWORD); void CommUpdate (DWORD); +bool CommThInit(); +void CommThUninit(); DWORD CommGetSnapshot(SS_IO_Comms* pSS); DWORD CommSetSnapshot(SS_IO_Comms* pSS);