You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
781 lines
19 KiB
781 lines
19 KiB
/*--------------------------------------------------------------
|
|
*
|
|
* FILE: SK_COMM.C
|
|
*
|
|
* PURPOSE: The file contains the Functions responsible for
|
|
* managing the COMM ports
|
|
*
|
|
* CREATION: June 1994
|
|
*
|
|
* COPYRIGHT: Black Diamond Software (C) 1994
|
|
*
|
|
* AUTHOR: Ronald Moak
|
|
*
|
|
* NOTES:
|
|
*
|
|
* This file, and all others associated with it contains trade secrets
|
|
* and information that is proprietary to Black Diamond Software.
|
|
* It may not be copied copied or distributed to any person or firm
|
|
* without the express written permission of Black Diamond Software.
|
|
* This permission is available only in the form of a Software Source
|
|
* License Agreement.
|
|
*
|
|
* $Header: %Z% %F% %H% %T% %I%
|
|
*
|
|
*--- Includes ---------------------------------------------------------*/
|
|
|
|
//#define WINVER 0x0300
|
|
|
|
// added to be compatible with new windows.h (12/91) and wintric.h
|
|
#define USECOMM
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <process.h>
|
|
|
|
#include "windows.h"
|
|
//#include "winstric.h" // added for win 3.1 compatibility 1/92
|
|
|
|
#include "gide.h" // Serial Keys Function Proto
|
|
#include "initgide.h" // Serial Keys Function Proto
|
|
#include "w95trace.h"
|
|
#include "sk_defs.h"
|
|
#include "sk_comm.h"
|
|
#include "drivers.h"
|
|
#include "sk_ex.h"
|
|
|
|
#define COMMTERMINATE 0xFFFFFFFF // this 'character' indicates a request to terminate
|
|
|
|
// Local Function ProtoTypes --------------------------------
|
|
|
|
static BOOL OpenComm();
|
|
static void __cdecl ProcessComm(VOID *notUsed);
|
|
static int ReadComm();
|
|
|
|
|
|
// Local Variables ---------------------------------------------------
|
|
|
|
static DCB s_dcbCommNew; // New DCB for comm port
|
|
static DCB s_dcbCommOld; // Origional DCB for comm port
|
|
|
|
static OVERLAPPED s_oRead; // Overlapped structure for reading.
|
|
|
|
static HANDLE s_hFileComm;
|
|
|
|
static HANDLE s_hThreadComm = NULL;
|
|
|
|
static HDESK s_hdeskUser = NULL;
|
|
|
|
static DWORD s_NullTimer;
|
|
static int s_NullCount=0;
|
|
|
|
static HANDLE s_ahEvents[2] = {NULL, NULL};
|
|
|
|
#define iEventComm 0
|
|
#define iEventExit 1
|
|
|
|
|
|
/*---------------------------------------------------------------
|
|
*
|
|
* Global Functions -
|
|
*
|
|
*---------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------
|
|
*
|
|
* FUNCTION void InitComm()
|
|
*
|
|
* TYPE Global
|
|
*
|
|
* PURPOSE
|
|
*
|
|
* INPUTS None
|
|
*
|
|
* RETURNS None
|
|
*
|
|
*---------------------------------------------------------------*/
|
|
BOOL InitComm()
|
|
{
|
|
BOOL fOk = TRUE;
|
|
|
|
DBPRINTF(TEXT("InitComm()\r\n"));
|
|
|
|
// Create Event for Overlap File Read
|
|
s_ahEvents[iEventComm] = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
fOk = (NULL != s_ahEvents[iEventComm]);
|
|
if (fOk)
|
|
{
|
|
s_ahEvents[iEventExit] = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
fOk = (NULL != s_ahEvents[iEventExit]);
|
|
}
|
|
|
|
if (!fOk)
|
|
{
|
|
TerminateComm();
|
|
}
|
|
|
|
return(fOk);
|
|
}
|
|
|
|
/*---------------------------------------------------------------
|
|
*
|
|
* FUNCTION void TerminateComm()
|
|
*
|
|
* TYPE Global
|
|
*
|
|
* PURPOSE The function is called for the final shutdown of
|
|
* the comm port.
|
|
*
|
|
* INPUTS None
|
|
*
|
|
* RETURNS TRUE - Start Successful
|
|
* FALSE - Start Failed
|
|
*
|
|
*---------------------------------------------------------------*/
|
|
void TerminateComm()
|
|
{
|
|
BOOL fOk;
|
|
int i;
|
|
|
|
DBPRINTF(TEXT("TerminateComm()\r\n"));
|
|
|
|
StopComm();
|
|
|
|
for (i = 0; i < ARRAY_SIZE(s_ahEvents); ++i)
|
|
{
|
|
if (NULL != s_ahEvents[i])
|
|
{
|
|
fOk = CloseHandle(s_ahEvents[i]);
|
|
DBPRINTF_IF(fOk, TEXT("Unable to Close Event\r\n"));
|
|
s_ahEvents[i] = NULL;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------
|
|
*
|
|
* FUNCTION BOOL StartComm()
|
|
*
|
|
* TYPE Global
|
|
*
|
|
* PURPOSE The function is call to start the thread to
|
|
* read and process data coming from the comm port.
|
|
* It will create a thread and an event. This function
|
|
* assumes that the comm port is already opened.
|
|
*
|
|
* INPUTS None
|
|
*
|
|
* RETURNS TRUE - Start Successful
|
|
* FALSE - Start Failed
|
|
*
|
|
*---------------------------------------------------------------*/
|
|
BOOL StartComm()
|
|
{
|
|
BOOL fOk = TRUE;
|
|
DWORD Id;
|
|
|
|
DBPRINTF(TEXT("StartComm()\r\n"));
|
|
|
|
// ----------------------------------------------------------
|
|
// Note: Comm Threads are started and stopped whenever
|
|
// the com port is changed. The User logs in or out
|
|
// or the comm configuration is changed.
|
|
// ----------------------------------------------------------
|
|
|
|
if (NULL == s_hFileComm && // no port currently in use
|
|
(skNewKey.dwFlags & SERKF_AVAILABLE) &&
|
|
(skNewKey.dwFlags & SERKF_SERIALKEYSON))
|
|
{
|
|
if (NULL != s_hThreadComm)
|
|
{
|
|
// This is an unexpected situation. We have the comm thread
|
|
// running with no open comm port. The thread must be hung.
|
|
// Let's close the open handle and forget about it.
|
|
|
|
DBPRINTF(TEXT("StartComm() unexpected (NULL != s_hThreadComm)\r\n"));
|
|
WaitForSingleObject(s_hThreadComm, 5 * 1000);
|
|
|
|
if (NULL != s_hThreadComm)
|
|
{
|
|
DBPRINTF(TEXT("StartComm() s_hThreadComm abandoned\r\n"));
|
|
CloseHandle(s_hThreadComm);
|
|
s_hThreadComm = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
// skNewKey is used by OpenComm. We're setting skCurKey to default
|
|
// values in case OpenComm fails.
|
|
|
|
skCurKey.iBaudRate = 300; // No - Reset To Default Values
|
|
skCurKey.iPortState= 0;
|
|
skCurKey.dwFlags = 0;
|
|
lstrcpy(skCurKey.lpszActivePort, TEXT("COM1"));
|
|
lstrcpy(skCurKey.lpszPort, TEXT("COM1"));
|
|
|
|
if (!OpenComm()) // Did Comm Open Ok?
|
|
{
|
|
skNewKey.iBaudRate = 300; // No - Reset To Default Values
|
|
skNewKey.iPortState= 0;
|
|
skNewKey.dwFlags = 0;
|
|
lstrcpy(skNewKey.lpszActivePort, TEXT("COM1"));
|
|
lstrcpy(skNewKey.lpszPort, TEXT("COM1"));
|
|
fOk = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// ensure we start with clean events
|
|
|
|
ResetEvent(s_ahEvents[iEventComm]);
|
|
ResetEvent(s_ahEvents[iEventExit]);
|
|
|
|
memset(&s_oRead, 0, sizeof(OVERLAPPED)); // Init Struct
|
|
s_oRead.hEvent = s_ahEvents[iEventComm]; // Store Event
|
|
|
|
// Create thread to handle Processing Comm Port
|
|
s_hThreadComm = (HANDLE)CreateThread( // Start Service Thread
|
|
0, 0,
|
|
(LPTHREAD_START_ROUTINE) ProcessComm,
|
|
0, 0,&Id); // argument to thread
|
|
|
|
if (NULL == s_hThreadComm)// Is Thread Handle Valid?
|
|
{
|
|
// Close out the Comm Port
|
|
SetCommState(s_hFileComm, &s_dcbCommOld); // Restore Comm State
|
|
CloseHandle(s_hFileComm);
|
|
s_hFileComm = NULL;
|
|
skCurKey.iPortState = 0;
|
|
|
|
fOk = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Comm Thread Successfully Started Set The Current Values
|
|
skCurKey.iBaudRate = skNewKey.iBaudRate;
|
|
skCurKey.iPortState = 2;
|
|
skCurKey.dwFlags = SERKF_SERIALKEYSON
|
|
| SERKF_AVAILABLE
|
|
| SERKF_ACTIVE;
|
|
|
|
lstrcpy(skCurKey.lpszActivePort, skNewKey.lpszActivePort);
|
|
lstrcpy(skCurKey.lpszPort, skNewKey.lpszActivePort);
|
|
|
|
DBPRINTF(TEXT("---- Comm Started\r\n"));
|
|
}
|
|
}
|
|
}
|
|
return(fOk);
|
|
}
|
|
|
|
/*---------------------------------------------------------------
|
|
*
|
|
* FUNCTION void SuspendComm()
|
|
*
|
|
* TYPE Global
|
|
*
|
|
* PURPOSE The function is called to Pause the thread
|
|
* reading and processing data coming from the comm port.
|
|
*
|
|
* INPUTS None
|
|
*
|
|
* RETURNS None
|
|
*
|
|
*---------------------------------------------------------------*/
|
|
void SuspendComm()
|
|
{
|
|
DBPRINTF(TEXT("SuspendComm()\r\n"));
|
|
|
|
if (NULL != s_hThreadComm)
|
|
{
|
|
SuspendThread(s_hThreadComm);
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------
|
|
*
|
|
* FUNCTION void ResumeComm()
|
|
*
|
|
* TYPE Global
|
|
*
|
|
* PURPOSE The function is called to resume the Paused thread.
|
|
*
|
|
* INPUTS None
|
|
*
|
|
* RETURNS None
|
|
*
|
|
*---------------------------------------------------------------*/
|
|
void ResumeComm()
|
|
{
|
|
if (s_hThreadComm != NULL)
|
|
ResumeThread(s_hThreadComm);
|
|
}
|
|
|
|
/*---------------------------------------------------------------
|
|
*
|
|
* FUNCTION void StopComm()
|
|
*
|
|
* TYPE Global
|
|
*
|
|
* PURPOSE The function is called to stop the thread
|
|
* reading and processing data coming from the comm port.
|
|
*
|
|
* INPUTS None
|
|
*
|
|
* RETURNS TRUE - Start Successful
|
|
* FALSE - Start Failed
|
|
*
|
|
*---------------------------------------------------------------*/
|
|
void StopComm()
|
|
{
|
|
DBPRINTF(TEXT("StopComm()\r\n"));
|
|
|
|
if (NULL != s_hFileComm)
|
|
{
|
|
skCurKey.dwFlags = SERKF_AVAILABLE;
|
|
|
|
SetEvent(s_ahEvents[iEventExit]);
|
|
|
|
if (NULL != s_hThreadComm)
|
|
{
|
|
DWORD dwRet;
|
|
BOOL fOk;
|
|
|
|
dwRet = WaitForSingleObject(s_hThreadComm, 5 * 1000);
|
|
DBPRINTF_IF(WAIT_OBJECT_0 == dwRet, TEXT("StopComm() Comm Thread may be hung.\r\n"));
|
|
CloseHandle(s_hThreadComm);
|
|
s_hThreadComm = NULL;
|
|
|
|
SetCommState(s_hFileComm, &s_dcbCommOld); // Restore Comm State
|
|
fOk = CloseHandle(s_hFileComm); // Close the Comm Port
|
|
DBPRINTF_IF(fOk, TEXT("Unable to Close Comm File\r\n"));
|
|
s_hFileComm = NULL;
|
|
|
|
skCurKey.iPortState = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------
|
|
*
|
|
* FUNCTION void SetCommBaud(int Baud)
|
|
*
|
|
* TYPE Global
|
|
*
|
|
* PURPOSE
|
|
*
|
|
*
|
|
* INPUTS None
|
|
*
|
|
* RETURNS TRUE - Start Successful
|
|
* FALSE - Start Failed
|
|
*
|
|
*---------------------------------------------------------------*/
|
|
void SetCommBaud(int Baud)
|
|
{
|
|
DBPRINTF(TEXT("SetCommBaud(%d)\r\n"), Baud);
|
|
|
|
switch (Baud) // Check for Valid Baud Rates
|
|
{
|
|
case 300:
|
|
case 600:
|
|
case 1200:
|
|
case 2400:
|
|
case 4800:
|
|
case 9600:
|
|
case 19200:
|
|
case 110:
|
|
case 14400:
|
|
case 38400:
|
|
case 56000:
|
|
case 57600:
|
|
case 115200:
|
|
break; // Baud Ok
|
|
|
|
default:
|
|
return; // Baud Invalid
|
|
}
|
|
|
|
skNewKey.iBaudRate = Baud; // Save Baud
|
|
|
|
if (NULL != s_hFileComm) // Is Comm Port Open?
|
|
{
|
|
s_dcbCommNew.BaudRate = skNewKey.iBaudRate; // Set new DCB Params
|
|
if (SetCommState(s_hFileComm, &s_dcbCommNew)) // State Change Ok?
|
|
{
|
|
skCurKey.iBaudRate = skNewKey.iBaudRate; // Save New Baud Rate
|
|
} else
|
|
{
|
|
DBPRINTF(TEXT("SetCommState(%d) FAILED!\r\n"), Baud);
|
|
// failed to set baud rate; try to revert it
|
|
s_dcbCommNew.BaudRate = skCurKey.iBaudRate; // reset DCB Params
|
|
if (!SetCommState(s_hFileComm, &s_dcbCommNew))
|
|
DBPRINTF(TEXT("SetCommState(%d) FAILED!\r\n"), skCurKey.iBaudRate);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------
|
|
*
|
|
* Local Functions
|
|
*
|
|
/*---------------------------------------------------------------
|
|
|
|
|
|
/*---------------------------------------------------------------
|
|
*
|
|
* FUNCTION void _CRTAPI1 ProcessComm()
|
|
*
|
|
* TYPE Local
|
|
*
|
|
* PURPOSE The function is the thread the cycles thru reading
|
|
* processing data coming from the comm port.
|
|
*
|
|
* INPUTS None
|
|
*
|
|
* RETURNS None
|
|
*
|
|
*---------------------------------------------------------------*/
|
|
static void __cdecl ProcessComm(VOID *notUsed)
|
|
{
|
|
int c;
|
|
HWINSTA hwinstaSave;
|
|
HWINSTA hwinstaUser;
|
|
HDESK hdeskSave;
|
|
DWORD dwThreadId;
|
|
BOOL fCont;
|
|
|
|
//------------------------------------------------------
|
|
//
|
|
// Note:
|
|
// The following code set the input focus to the current
|
|
// desktop. It is needed to insure that keyboard and mouse
|
|
// events will be passed to the current desktop.
|
|
//
|
|
//------------------------------------------------------
|
|
|
|
hwinstaSave = GetProcessWindowStation();
|
|
dwThreadId = GetCurrentThreadId();
|
|
hdeskSave = GetThreadDesktop(dwThreadId);
|
|
|
|
hwinstaUser = OpenWindowStation(TEXT("WinSta0"), FALSE, MAXIMUM_ALLOWED);
|
|
SetProcessWindowStation(hwinstaUser);
|
|
|
|
|
|
serialKeysStartUpInit(); // Initialize the Serial Keys
|
|
fCont = TRUE;
|
|
|
|
while (fCont)
|
|
{
|
|
c = ReadComm(); // Read Char from Com Port
|
|
switch (c)
|
|
{
|
|
case 0:
|
|
// Is Character a Null
|
|
|
|
// Is Null Timer > 30 Seconds
|
|
if ((GetTickCount() - s_NullTimer) > 30000)
|
|
{
|
|
s_NullTimer = GetTickCount(); // Yes - Reset Timer
|
|
s_NullCount = 1; // Reset Null Count
|
|
} else {
|
|
|
|
s_NullCount++; // No - Inc Null Count
|
|
if (s_NullCount == 3) // Have we had 3 Null in 30 Sec.?
|
|
{
|
|
// the user is requesting us to reset
|
|
SetCommBaud(300);
|
|
|
|
// DeskSwitch should be unnessary, but if it gets out of sync,
|
|
// this is where we resync
|
|
|
|
s_NullCount = 0; // Reset Null Counter
|
|
}
|
|
}
|
|
break;
|
|
|
|
case COMMTERMINATE:
|
|
fCont = FALSE;
|
|
break;
|
|
|
|
default:
|
|
DeskSwitchToInput();
|
|
serialKeysBegin((UCHAR)c); // Process Char
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
SetThreadDesktop(hdeskSave);
|
|
SetProcessWindowStation(hwinstaSave);
|
|
CloseDesktop(s_hdeskUser);
|
|
s_hdeskUser = NULL;
|
|
CloseWindowStation(hwinstaUser);
|
|
|
|
ExitThread(0); // Close Thread
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------
|
|
*
|
|
* BOOL IsCommPortName()
|
|
*
|
|
* Determines whether a given filename is a valid COM port name.
|
|
* Used by OpenComm so that it doesn't open a remote file or named
|
|
* pipe instead.
|
|
*
|
|
*---------------------------------------------------------------*/
|
|
static BOOL IsCommPortName( LPCTSTR pszFilename )
|
|
{
|
|
// Ensure that filename has form:
|
|
// COMn[n]\0
|
|
LPCTSTR pScan = pszFilename;
|
|
|
|
// Must start with COMn, where COM can be any case,
|
|
// and n is any 0..9 digit.
|
|
if( *pScan != 'C' && *pScan != 'c' )
|
|
return FALSE;
|
|
pScan++;
|
|
if( *pScan != 'O' && *pScan != 'o' )
|
|
return FALSE;
|
|
pScan++;
|
|
if( *pScan != 'M' && *pScan != 'm' )
|
|
return FALSE;
|
|
pScan++;
|
|
|
|
if( *pScan < '0' || *pScan > '9' )
|
|
return FALSE;
|
|
pScan++;
|
|
|
|
/*
|
|
// TODO: are COM54 really allowed?
|
|
// Optional second digit
|
|
if( *pScan >= '0' && *pScan <= '9' )
|
|
pScan++;
|
|
*/
|
|
|
|
// Manditory terminating nul
|
|
if( *pScan != '\0' )
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*---------------------------------------------------------------
|
|
*
|
|
* FUNCTION BOOL OpenComm()
|
|
*
|
|
* TYPE Local
|
|
*
|
|
* PURPOSE This Function opens the comm port and sets the new
|
|
* sets the Device Control Block.
|
|
*
|
|
* INPUTS None
|
|
*
|
|
* RETURNS TRUE - Open Ok / FALSE - Open Failed
|
|
*
|
|
*---------------------------------------------------------------*/
|
|
static BOOL OpenComm()
|
|
{
|
|
BOOL fOk = FALSE;
|
|
COMMTIMEOUTS ctmo;
|
|
|
|
// Check that the path we're given looks like a COM port.
|
|
// (Not, eg, a remote file or named pipe.)
|
|
if( ! IsCommPortName( skNewKey.lpszActivePort ) )
|
|
{
|
|
DBPRINTF(TEXT("- Not a COMn port\r\n"));
|
|
s_hFileComm = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
// The Security flags ensure that if we are duped into opening
|
|
// a named pipe, we'll do so anonymously, so that we can't be
|
|
// impersonated.
|
|
s_hFileComm = CreateFile(
|
|
skNewKey.lpszActivePort,// FileName (Com Port)
|
|
GENERIC_READ , // Access Mode
|
|
0, // Share Mode
|
|
NULL, // Address of Security Descriptor
|
|
OPEN_EXISTING, // How to Create
|
|
FILE_ATTRIBUTE_NORMAL // File Attributes
|
|
| FILE_FLAG_OVERLAPPED // Set for Async File Reads
|
|
| SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS, // see above comment
|
|
NULL); // Templet File.
|
|
|
|
if (INVALID_HANDLE_VALUE == s_hFileComm) // File Ok?
|
|
{
|
|
DBPRINTF(TEXT("- Invalid File\r\n"));
|
|
|
|
s_hFileComm = NULL;
|
|
}
|
|
else
|
|
{
|
|
BOOL fRet;
|
|
COMMPROP cmmp;
|
|
|
|
SetupComm(
|
|
s_hFileComm,
|
|
1024, // size of input buffer
|
|
1024); // size of output buffer
|
|
|
|
memset(&s_dcbCommOld, 0, sizeof(s_dcbCommOld));
|
|
s_dcbCommOld.DCBlength = sizeof(s_dcbCommOld);
|
|
|
|
GetCommState(s_hFileComm, &s_dcbCommOld); // Save Old DCB for restore
|
|
s_dcbCommNew = s_dcbCommOld; // Copy to New
|
|
|
|
// set XoffLim and XonLim based on actual buffer size
|
|
|
|
fRet = GetCommProperties(s_hFileComm, &cmmp);
|
|
if (fRet)
|
|
{
|
|
s_dcbCommNew.XoffLim = (WORD)(cmmp.dwCurrentRxQueue / 4);
|
|
s_dcbCommNew.XonLim = (WORD)(cmmp.dwCurrentRxQueue / 4);
|
|
}
|
|
|
|
s_dcbCommNew.BaudRate = skNewKey.iBaudRate; // Set new DCB Params
|
|
s_dcbCommNew.ByteSize = 8;
|
|
s_dcbCommNew.Parity = NOPARITY;
|
|
s_dcbCommNew.StopBits = ONESTOPBIT;
|
|
s_dcbCommNew.fOutX = FALSE; // XOn/XOff used during transmission
|
|
s_dcbCommNew.fInX = TRUE; // XOn/XOff used during reception
|
|
s_dcbCommNew.fNull = FALSE; // tell windows not to strip nulls
|
|
s_dcbCommNew.fBinary = TRUE;
|
|
|
|
s_dcbCommNew.fOutxCtsFlow = FALSE;
|
|
s_dcbCommNew.fOutxDsrFlow = FALSE;
|
|
s_dcbCommNew.fDtrControl = DTR_CONTROL_ENABLE;
|
|
s_dcbCommNew.fDsrSensitivity = FALSE;
|
|
s_dcbCommNew.fErrorChar = TRUE;
|
|
s_dcbCommNew.fRtsControl = RTS_CONTROL_DISABLE;
|
|
s_dcbCommNew.fAbortOnError = FALSE;
|
|
s_dcbCommNew.XonChar = (char)0x11;
|
|
s_dcbCommNew.XoffChar = (char)0x13;
|
|
s_dcbCommNew.ErrorChar = '\0';
|
|
|
|
fOk = SetCommState(s_hFileComm, &s_dcbCommNew);
|
|
|
|
memset(&ctmo, 0, sizeof(ctmo));
|
|
SetCommTimeouts(s_hFileComm, &ctmo);
|
|
}
|
|
|
|
if (!fOk && NULL != s_hFileComm)
|
|
{
|
|
CloseHandle(s_hFileComm);
|
|
s_hFileComm = NULL;
|
|
}
|
|
|
|
return(fOk);
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------
|
|
*
|
|
* FUNCTION int ReadComm()
|
|
*
|
|
* TYPE Local
|
|
*
|
|
* PURPOSE This Function reads a character from the comm port.
|
|
* If no character is present it wait on the HEV_COMM
|
|
* Event untill a character is present
|
|
*
|
|
* INPUTS None
|
|
*
|
|
* RETURNS int - Character read (-1 = Error Read)
|
|
*
|
|
*---------------------------------------------------------------*/
|
|
static int ReadComm()
|
|
{
|
|
int nRet;
|
|
DWORD cbRead = 0;
|
|
DWORD lastError, ComError;
|
|
DWORD dwRetWait;
|
|
BOOL fOk;
|
|
BOOL fExit;
|
|
|
|
BOOL fExitLoop = FALSE; // Boolean Flag to exit loop.
|
|
UCHAR uchBuff;
|
|
COMSTAT ComStat;
|
|
|
|
fExit = (WAIT_OBJECT_0 == WaitForSingleObject(s_ahEvents[iEventExit], 0));
|
|
|
|
if (!fExit)
|
|
{
|
|
fOk = ReadFile(s_hFileComm, &uchBuff, 1, &cbRead, &s_oRead);
|
|
|
|
if (!fOk) // Was there a Read Error?
|
|
{
|
|
lastError = GetLastError(); // This var can be useful for debugging
|
|
switch (lastError)
|
|
{
|
|
// If Error = IO_PENDING, wait til
|
|
// the event hadle signals success,
|
|
case ERROR_IO_PENDING:
|
|
dwRetWait = WaitForMultipleObjects(
|
|
ARRAY_SIZE(s_ahEvents), s_ahEvents, FALSE, INFINITE);
|
|
|
|
switch (dwRetWait - WAIT_OBJECT_0)
|
|
{
|
|
case iEventComm:
|
|
// this is the expected event
|
|
GetOverlappedResult(s_hFileComm, &s_oRead, &cbRead, FALSE);
|
|
|
|
if (cbRead < 1) // Did we read bytes;
|
|
{
|
|
// There was some error, return null
|
|
nRet = 0;
|
|
}
|
|
else
|
|
{
|
|
nRet = uchBuff;
|
|
}
|
|
break;
|
|
|
|
case iEventExit:
|
|
fExit = TRUE;
|
|
// fall through
|
|
|
|
default:
|
|
// this indicates and error and we exit to prevent loop
|
|
nRet = COMMTERMINATE;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
fOk = ClearCommError(s_hFileComm, &ComError,&ComStat);
|
|
if (fOk)
|
|
{
|
|
nRet = 0; // return a null
|
|
}
|
|
else
|
|
{
|
|
nRet = COMMTERMINATE; // terminate
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (cbRead < 1) // Did we read bytes;
|
|
{
|
|
// There was some error, return null
|
|
nRet = 0;
|
|
}
|
|
else
|
|
{
|
|
nRet = uchBuff;
|
|
}
|
|
|
|
}
|
|
}
|
|
if (fExit)
|
|
{
|
|
ResetEvent(s_ahEvents[iEventExit]);
|
|
nRet = COMMTERMINATE;
|
|
}
|
|
return(nRet);
|
|
}
|