--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/toolsandutils/wintunnel/src_beech/d_cdrv.cpp Tue Feb 02 01:39:43 2010 +0200
@@ -0,0 +1,1890 @@
+// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Modified serial pdd that supports IP tunneling data from the emulator to socket.
+// Beech specific version.
+//
+//
+
+/**
+ @file
+*/
+
+#if defined(_UNICODE)
+#if !defined(UNICODE)
+#define UNICODE
+#endif
+#endif
+#define _WIN32_WINDOWS 0x0410 // Need NT4 / 98 or higher for the timer
+#define WIN32_LEAN_AND_MEAN
+#pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union
+#include <windows.h>
+#include <winsock2.h>
+#pragma warning( default : 4201 ) // nonstandard extension used : nameless struct/union
+#include <k32std.h>
+#include <e32wins.h>
+#include "uansi.h"
+#include "d_comm.h"
+
+//#include "iostream.h"
+
+// Dumps everything written to the serial port to temp files.
+//#define _LOG_OUTPUT
+
+
+//----------------------------------------------------------------
+// logging macros. Just define WINTUN_PDD_LOGGING to enable debug trace
+// require MSVCRTD.LIB
+#include <crtdbg.h>
+
+//#define WINTUN_PDD_LOGGING
+
+#ifdef WINTUN_PDD_LOGGING
+
+ #pragma warning( disable : 4127 )
+
+ #define _Log(a) _RPT0(_CRT_WARN,a)
+ #define _Log2(a,b) _RPT1(_CRT_WARN,a,b)
+ #define _Log3(a,b,c) _RPT2(_CRT_WARN,a,b,c)
+ #define _Log4(a,b,c,d) _RPT3(_CRT_WARN,a,b,c,d)
+
+#else
+ #define _Log(a)
+ #define _Log2(a,b)
+ #define _Log3(a,b,c)
+ #define _Log4(a,b,c,d)
+
+#endif
+
+const TInt KReadBufSize = 1024;
+const TInt KWriteBufSize = 16;
+//const TInt KWinNTReadBufSize = 1024;
+const TInt KWinNTReadBufSize = 1500;
+const TInt KWinNTWriteBufSize = KWriteBufSize;
+static DWORD dummyLen=0;
+
+enum TDCommWinsFault
+ {
+ EWindowsUnexpectedError,
+ EUnknownCommand,
+ EBadIOLen,
+ EEofOnSerial,
+ EWriteEarlyCompletion,
+ ELineErrorNotReported,
+ };
+
+class DDriverComm : public DPhysicalDevice
+ {
+public:
+ DDriverComm();
+ virtual TInt Install();
+ virtual TInt Remove();
+ virtual void GetCaps(TDes8 &aDes) const;
+ virtual CBase *CreateL(TInt aUnit,const TDesC *anInfo,const TVersion &aVer);
+ };
+
+class DCommWins : public DComm
+ {
+public:
+ enum TDriverCommand {ESetBreak,EClearBreak,ETransmit,
+ EGetSignals,ESetSignals,EConfigure,
+ EStop,EStopNoDrain,EStart,EDie,EInvalidCommand};
+public:
+ DCommWins();
+ ~DCommWins();
+ virtual TInt Start();
+ virtual void Stop(TStopMode aMode);
+ virtual void Break(TBool aState);
+ virtual void EnableTransmit();
+ virtual TUint Signals() const;
+ virtual void SetSignals(TUint aSetMask,TUint aClearMask);
+ virtual TInt Validate(const TCommConfigV01 &aConfig) const;
+ virtual void Configure(TCommConfigV01 &aConfig);
+ virtual void DoConfigure();
+ virtual void CheckConfig(TCommConfigV01& aConfig);
+ virtual void Caps(TDes8 &aCaps) const;
+ virtual void EnableInterrupts();
+ virtual void DisableInterrupts();
+ TInt CompleteSlowOpen(DThread *aThread,TRequestStatus *aReqStat);
+ void EnterCritical();
+ void LeaveCritical();
+ TInt DoCreate(TInt aUnit,const TDesC *anInfo);
+ void WaitForEvent();
+ void DriverCommand(TDriverCommand aCommand);
+ void DoTransmit(TInt aByteCount);
+ void DoReceive(TInt aByteCount);
+ void RunCommThread(TDriverCommand aCommand);
+ inline void SignalDriverThread();
+ TInt DoTransmitIsr(TInt anOffset);
+ void DoReceiveIsr(TUint aCharAndMask);
+ void DoStateIsr();
+
+ void SetTimer(const TUint aTimeOut);
+ void CancelTimer();
+
+
+private:
+ TBool iWritePending;
+ TBool iReadPending;
+
+ TBool iStopping;
+ // TBool iReading;
+ TBool iRunning;
+ TDriverCommand iCommand;
+ TCommConfigV01 *iConfig;
+ TUint iSignals;
+ TUint8 iInBuf[KReadBufSize];
+ DWORD iNumInChars;
+ TUint8 iOutBuf[KWriteBufSize];
+ DWORD iNumOutChars;
+ HANDLE iThread;
+ HANDLE iCommThreadSem;
+ HANDLE iDriverThreadSem;
+ HANDLE iCommPort;
+ HANDLE iWaitableTimer;
+ LARGE_INTEGER iTimeOut;
+ DWORD iThreadID;
+ DWORD iSignalStatus;
+ OVERLAPPED iReadOverLapped;
+ OVERLAPPED iWriteOverLapped;
+ OVERLAPPED iSignalOverLapped;
+#if defined (_DEBUG)
+ TInt iUnit;
+ HANDLE iLogFile;
+#endif
+#if defined (_LOG_OUTPUT)
+ HANDLE iWritesHandle;
+ HANDLE iReadsHandle;
+#endif
+ CRITICAL_SECTION iCriticalSection;
+ TInt iIntRefCount;
+ TBool iSkipTransmitIsrNextTime;
+
+ SOCKET iSocket;
+
+
+ /** @return ETrue if we use socket instead of a real COM port */
+ TBool inline UseSocket(void) const
+ {return (iSocket != INVALID_SOCKET) && (iSocket != NULL); }
+
+ TInt QueSocketRead();
+
+ TBool GetComPortMapping(LPCSTR aFileName, TInt aPortNum, TDes8& aPortMapStr);
+
+ };
+
+void Panic(TDCommWinsFault aFault)
+//
+// Panic the driver
+//
+ {
+
+ Plat::Panic(_L("DCommWins"),aFault);
+ }
+
+
+TInt MapWinError(TInt aErrCode)
+{
+ switch (aErrCode)
+ {
+ case ERROR_INVALID_USER_BUFFER:
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_INSUFFICIENT_BUFFER:
+ return(KErrNoMemory);
+ case ERROR_ACCESS_DENIED:
+ return(KErrAccessDenied);
+ case ERROR_NOT_SUPPORTED:
+ return(KErrNotSupported);
+ default:
+ return(KErrGeneral);
+ }
+}
+
+TInt MapWinError()
+//
+// Make an E32 error from the dodgy old thing windows tells us
+//
+{
+ DWORD winErr=GetLastError();
+ return MapWinError(winErr);
+}
+
+TUint commThread(DCommWins *comm)
+//
+// Comm thread entry point
+//
+ {
+
+ comm->WaitForEvent();
+ return 0;
+ }
+
+//VOID WINAPI ReadComplete(DWORD anErr,DWORD numBytes,LPOVERLAPPED anOverLapped)
+//
+// Windows read completion routine
+//
+// {
+//
+// if (numBytes>KReadBufSize)
+// Panic(EBadIOLen);
+// if (anErr==ERROR_HANDLE_EOF)
+// Panic(EEofOnSerial);
+// ((DCommWins *)(anOverLapped->hEvent))->DoReceive(numBytes);
+// }
+
+VOID WINAPI WriteCompletion(DCommWins *aDrv, DWORD anErr,DWORD numBytes)
+//
+// Windows read completion routine
+//
+ {
+
+ if (numBytes>KWriteBufSize+1) // May have written an Xon
+ Panic(EBadIOLen);
+ if (anErr==ERROR_HANDLE_EOF)
+ Panic(EEofOnSerial);
+ aDrv->DoTransmit(numBytes);
+ }
+
+BOOL WINAPI EscapeCommFunctionP(HANDLE hFile,DWORD dwFunc, BOOL bUseSocket)
+//
+// Protected Set/Clear modem control signals: protects against this operation being cancelled by another thread
+//
+ {
+ if(bUseSocket)
+ return TRUE;
+
+ DWORD err,res,res1;
+ COMSTAT s;
+ BOOL result;
+
+ result=FALSE;
+ do
+ {
+ ClearCommError(hFile,&err,&s);
+ if((res1=EscapeCommFunction(hFile,dwFunc))==FALSE)
+ res=GetLastError();
+ else
+ {
+ result=TRUE;
+ break;
+ }
+ }
+ while((res1==FALSE) && (res==ERROR_OPERATION_ABORTED));
+ return(result);
+ }
+
+BOOL WINAPI GetCommModemStatusP(HANDLE hFile,LPDWORD lpModemStat, BOOL bUseSocket)
+//
+// Protected read modem control signals: protects against this operation being cancelled by another thread
+//
+ {
+ if(bUseSocket)
+ return TRUE;
+
+ DWORD err,res,res1;
+ COMSTAT s;
+ BOOL result;
+
+ result=FALSE;
+ do
+ {
+ ClearCommError(hFile,&err,&s);
+ if((res1=GetCommModemStatus(hFile,lpModemStat))==FALSE)
+ res=GetLastError();
+ else
+ {
+ result=TRUE;
+ break;
+ }
+ }
+ while((res1==FALSE) && (res==ERROR_OPERATION_ABORTED));
+ return(result);
+ }
+
+BOOL WINAPI GetCommStateP(HANDLE hFile,LPDCB lpDCB, BOOL bUseSocket)
+//
+// Retrieves the current control settings for a specified communications device: protected against
+// this operation being cancelled by another thread
+//
+ {
+ if(bUseSocket)
+ return TRUE;
+
+ DWORD err,res,res1;
+ COMSTAT s;
+ BOOL result;
+
+ result=FALSE;
+ do
+ {
+ ClearCommError(hFile,&err,&s);
+ if((res1=GetCommState(hFile,lpDCB))==FALSE)
+ res=GetLastError();
+ else
+ {
+ result=TRUE;
+ break;
+ }
+ }
+ while((res1==FALSE) && (res==ERROR_OPERATION_ABORTED));
+ return(result);
+ }
+
+BOOL WINAPI SetCommStateP(HANDLE hFile,LPDCB lpDCB, BOOL bUseSocket)
+//
+// Configures a communications device according to the specifications in a device-control block: protected against
+// this operation being cancelled by another thread
+//
+ {
+ if(bUseSocket)
+ return TRUE;
+
+ DWORD err,res,res1;
+ COMSTAT s;
+ BOOL result;
+
+ result=FALSE;
+ do
+ {
+ ClearCommError(hFile,&err,&s);
+ if((res1=SetCommState(hFile,lpDCB))==FALSE)
+ res=GetLastError();
+ else
+ {
+ result=TRUE;
+ break;
+ }
+ }
+ while((res1==FALSE) && (res==ERROR_OPERATION_ABORTED));
+ return(result);
+ }
+
+BOOL WINAPI SetCommMaskP(HANDLE hFile,DWORD dwEvtMask, BOOL bUseSocket)
+//
+// Specifies a set of events to be monitored for a communications device: protected against
+// this operation being cancelled by another thread
+//
+ {
+ if(bUseSocket)
+ return TRUE;
+
+ DWORD err,res,res1;
+ COMSTAT s;
+ BOOL result;
+
+ result=FALSE;
+ do
+ {
+ ClearCommError(hFile,&err,&s);
+ if((res1=SetCommMask(hFile,dwEvtMask))==FALSE)
+ res=GetLastError();
+ else
+ {
+ result=TRUE;
+ break;
+ }
+ }
+ while((res1==FALSE) && (res==ERROR_OPERATION_ABORTED));
+ return(result);
+ }
+
+BOOL WINAPI WriteFileP(HANDLE hFile,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped)
+//
+// Writes data to device pointed by hFile: protected against
+// this operation being cancelled by another thread
+//
+ {
+ DWORD err,res,res1;
+ COMSTAT s;
+ BOOL result;
+
+ result=FALSE;
+ do
+ {
+ ClearCommError(hFile,&err,&s);
+ if((res1=WriteFile(hFile,lpBuffer,nNumberOfBytesToWrite,lpNumberOfBytesWritten,lpOverlapped))==FALSE)
+ res=GetLastError();
+ else
+ {
+ result=TRUE;
+ break;
+ }
+ }
+ while((res1==FALSE) && (res==ERROR_OPERATION_ABORTED));
+ return(result);
+ }
+
+BOOL WINAPI ReadFileP(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped)
+//
+// Writes data to device pointed by hFile: protected against
+// this operation being cancelled by another thread
+//
+ {
+ DWORD err,res,res1;
+ COMSTAT s;
+ BOOL result;
+
+ result=FALSE;
+ do
+ {
+ ClearCommError(hFile,&err,&s);
+ if((res1=ReadFile(hFile,lpBuffer,nNumberOfBytesToRead,lpNumberOfBytesRead,lpOverlapped))==FALSE)
+ res=GetLastError();
+ else
+ {
+ result=TRUE;
+ break;
+ }
+ }
+ while((res1==FALSE) && (res==ERROR_OPERATION_ABORTED));
+ return(result);
+ }
+
+DDriverComm::DDriverComm()
+//
+// Constructor
+//
+ {
+
+#if defined (__COM_ONE_ONLY__)
+ iUnitsMask=0x1; // Support units 0
+#elif defined (__COM_TWO_ONLY__)
+ iUnitsMask=0x2; // Support units 1
+#else
+ iUnitsMask=0x3ff; // Support units 0 to 9
+#endif
+
+ iVersion=TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber);
+ }
+
+TInt DDriverComm::Install()
+//
+// Install the device driver.
+//
+ {
+#if defined (__COM_ONE_ONLY__)
+ TPtrC buf=_L("Comm.Wins1");
+ return(SetName(&buf));
+#elif defined (__COM_TWO_ONLY__)
+ TPtrC buf=_L("Comm.Wins2");
+ return(SetName(&buf));
+#else
+ TPtrC buf=_L("Comm.Wins");
+ return(SetName(&buf));
+#endif
+ }
+
+TInt DDriverComm::Remove()
+//
+// Remove the device driver.
+//
+ {
+ return(KErrNone);
+ }
+
+void GetWinsCommsCaps(TDes8 &aCaps)
+ {
+
+ TCommCaps2 capsBuf;
+ TCommCapsV02 &c=capsBuf();
+//
+// All rates except 50,2000, 3600 and special
+//
+ c.iRate=KCapsBps75|KCapsBps110|KCapsBps134|KCapsBps150|KCapsBps300|KCapsBps600|KCapsBps1200|KCapsBps1800|KCapsBps2400|KCapsBps4800|KCapsBps7200|KCapsBps9600|KCapsBps19200|KCapsBps38400|KCapsBps57600|KCapsBps115200;
+
+ c.iDataBits=0xf; // All data sizes
+ c.iStopBits=0x3; // 1 and 2 stop bits
+ c.iParity=0x7; // None, Even and Odd
+ c.iHandshake=0x1ff; // All handshakes
+ c.iSignals=0x3f; // All signals
+ c.iSIR=0;//No Ir
+ c.iNotificationCaps=KNotifySignalsChangeSupported|KNotifyDataAvailableSupported;
+ c.iRoleCaps=0;
+ c.iFlowControlCaps=0;
+ aCaps.FillZ(aCaps.MaxLength());
+ aCaps=capsBuf.Left(Min(capsBuf.Length(),aCaps.MaxLength()));
+ }
+
+void DDriverComm::GetCaps(TDes8 &aDes) const
+//
+// Return the drivers capabilities.
+//
+ {
+
+ GetWinsCommsCaps(aDes);
+ }
+
+CBase *DDriverComm::CreateL(TInt aUnit,const TDesC *anInfo,const TVersion &aVer)
+//
+// Create a channel on the device.
+//
+ {
+
+ if (!User::QueryVersionSupported(iVersion,aVer))
+ User::Leave(KErrNotSupported);
+ DCommWins *pD=new(ELeave) DCommWins;
+ TInt ret=pD->DoCreate(aUnit,anInfo);
+ if (ret!=KErrNone)
+ {
+ delete pD;
+ User::Leave(ret);
+ }
+ return(pD);
+ }
+
+
+
+void DCommWins::DoTransmit(TInt aByteCount)
+//
+// Called from write completion routine
+//
+ {
+
+ if(aByteCount==0)
+ {
+ DWORD err,res;
+ COMSTAT s;
+ if (!UseSocket() && ClearCommError(iCommPort,&err,&s)==FALSE)
+ res=GetLastError();
+ }
+ __ASSERT_ALWAYS(iNumOutChars-aByteCount<=KWriteBufSize,Panic(EWriteEarlyCompletion));
+#if defined (_LOG_WRITES)
+ TBuf<0x40> buf;
+ DWORD dummy;
+ buf.Format(_L("write complete %d\r\n"),aByteCount);
+ WriteFile(iLogFile,buf.PtrZ(),buf.Length(),&dummy,NULL);
+#endif
+//
+ iNumOutChars-=aByteCount;
+ if (iCommand==EStop)
+ return;
+ if (iSkipTransmitIsrNextTime)
+ {
+ iSkipTransmitIsrNextTime=EFalse;
+ }
+ else
+ {
+ while (iNumOutChars<KWriteBufSize)
+ {
+ iSkipTransmitIsrNextTime=!DoTransmitIsr(iNumOutChars);
+ if (iSkipTransmitIsrNextTime)
+ break;
+ iNumOutChars++;
+ }
+ }
+ if(iNumOutChars>0)
+ {
+// WriteFileEx(iCommPort,iOutBuf,iNumOutChars,&iWriteOverLapped,WriteComplete);
+ WriteFile(iCommPort,iOutBuf,iNumOutChars, &dummyLen, &iWriteOverLapped);
+ iWritePending=ETrue;
+
+#if defined (_LOG_OUTPUT)
+ DWORD dummy;
+ WriteFile(iWritesHandle,iOutBuf,iNumOutChars,&dummy,NULL);
+#endif
+#if defined (_LOG_WRITES)
+ buf.Format(_L("Writing %d\r\n"),iNumOutChars);
+ WriteFile(iLogFile,buf.PtrZ(),buf.Length(),&dummy,NULL);
+#endif
+
+ }
+ else
+ iWritePending=EFalse;
+ }
+
+/*
+For reference only:
+Returned from 2nd param to ClearCommError (err below)
+#define CE_RXOVER 0x0001 // Receive Queue overflow
+#define CE_OVERRUN 0x0002 // Receive Overrun Error
+#define CE_RXPARITY 0x0004 // Receive Parity Error
+#define CE_FRAME 0x0008 // Receive Framing error
+#define CE_BREAK 0x0010 // Break Detected
+#define CE_TXFULL 0x0100 // TX Queue is full
+#define CE_PTO 0x0200 // LPTx Timeout
+#define CE_IOE 0x0400 // LPTx I/O Error
+#define CE_DNS 0x0800 // LPTx Device not selected
+#define CE_OOP 0x1000 // LPTx Out-Of-Paper
+#define CE_MODE 0x8000 // Requested mode unsupported
+
+#define IE_BADID (-1) // Invalid or unsupported id
+#define IE_OPEN (-2) // Device Already Open
+#define IE_NOPEN (-3) // Device Not Open
+#define IE_MEMORY (-4) // Unable to allocate queues
+#define IE_DEFAULT (-5) // Error in default parameters
+#define IE_HARDWARE (-10) // Hardware Not Present
+#define IE_BYTESIZE (-11) // Illegal Byte Size
+#define IE_BAUDRATE (-12) // Unsupported BaudRate
+*/
+
+//void DCommWins::DoReceive(TInt aByteCount)
+//
+// Called from read completion routine
+//
+// {
+// if(aByteCount==0)
+// {
+// DWORD err=0,res;
+// COMSTAT s;
+// if (iCommPort && ClearCommError(iCommPort,&err,&s)==FALSE)
+// res=GetLastError();
+// if(err)
+// {
+// Panic(ELineErrorNotReported);
+// }
+// }
+// TInt i=0;
+//
+// while(i<aByteCount)
+// {
+// DoReceiveIsr(iInBuf[i]);
+// i++;
+// }
+//#if defined (_LOG_OUTPUT)
+// DWORD dummy;
+// WriteFile(iReadsHandle,iInBuf,aByteCount,&dummy,NULL);
+//#endif
+// if(iStopping)
+// {
+// iStopping=EFalse;
+// return;
+// }
+//
+// if (!ReadFileEx(iCommPort,iInBuf,KReadBufSize,&iReadOverLapped,ReadComplete))
+// {
+// TInt r=GetLastError();
+// Panic(EWindowsUnexpectedError);
+// }
+// }
+
+void DCommWins::RunCommThread(TDriverCommand aCommand)
+//
+// Wake up the comms thread
+//
+ {
+ _Log2("# DCommWins::RunCommThread, command=%d\n", aCommand);
+
+ __ASSERT_DEBUG(aCommand!=EInvalidCommand,Panic(EUnknownCommand));
+ iCommand=aCommand;
+//
+// Are we about to go re-entrant?
+//
+ if(GetCurrentThreadId()==iThreadID)
+ {
+ DriverCommand(aCommand);
+ WaitForSingleObject(iDriverThreadSem,INFINITE);
+ }
+ else
+ {
+ Sleep(0); // Possible deadlock solution - see MSDN Knowledge Base Article Q173260
+
+ if (ReleaseSemaphore(iCommThreadSem,1,NULL)==FALSE)
+ {
+ DWORD ret=GetLastError();
+ ret=ret;
+ Panic(EWindowsUnexpectedError);
+ }
+ WaitForSingleObject(iDriverThreadSem,INFINITE);
+ }
+ }
+
+inline void DCommWins::SignalDriverThread()
+//
+// Wake up the comms thread
+//
+ {
+ _Log("# DCommWins::SignalDriverThread(), release iDriverThreadSem\n");
+ Sleep(0); // Possible deadlock solution - see MSDN Knowledge Base Article Q173260
+ if (ReleaseSemaphore(iDriverThreadSem,1,NULL)==FALSE)
+ {
+ DWORD ret=GetLastError();
+ ret=ret;
+ Panic(EWindowsUnexpectedError);
+ }
+ }
+
+
+
+//
+#pragma warning( disable : 4705 ) // statement has no effect
+DCommWins::DCommWins()
+//
+// Constructor
+//
+ {
+// iRunning=EFalse;
+// iCommand=ESetBreak;
+// iSignals=0;
+// iInBuf=0;
+// iOutBuf=0;
+// iThread=NULL;
+// iCommThreadSem=NULL;
+// iCommPort=NULL;
+// iThreadID=0;
+ iWritePending = EFalse;
+ iReadPending = EFalse;
+
+ Mem::FillZ(&iReadOverLapped,sizeof(OVERLAPPED));
+ Mem::FillZ(&iWriteOverLapped,sizeof(OVERLAPPED));
+ __DECLARE_NAME(_S("DCommWins"));
+#ifdef _DEBUG_DEVCOMM
+ iTxIntCount = 0;
+ iRxIntCount = 0;
+ iTxErrCount = 0;
+ iRxErrCount = 0;
+#endif
+ iIntRefCount = 0;
+ iSocket = INVALID_SOCKET;
+
+ _Log("# ------------------------------------------------\n");
+ _Log("# DCommWins::DCommWins()\n");
+
+ }
+#pragma warning( default : 4705 )
+
+/**
+* Read serial port mapping from ini file (dComm.ini usually)
+*
+* @param aFileName ini full file path descriptor
+* @param aPortNum serial port number (e.g. 0 for COMM::0)
+* @param aPortMapStr descriptor for returned port mapping (e.g. "10.35.2.53:110)
+*
+* @return ETrue if the parameter found and everything is OK.
+*/
+TBool DCommWins::GetComPortMapping(LPCSTR aFileName, TInt aPortNum, TDes8& aPortMapStr)
+{
+ TBool bRes = ETrue;
+ TInt fileSize;
+ LPVOID pFileData=NULL;
+
+ //-- open dcomm.ini file
+ HANDLE hFile=CreateFileA(aFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (!hFile || hFile == INVALID_HANDLE_VALUE)
+ {//-- can't open file, maybe it is just not present
+ bRes = EFalse;
+ goto CleanUp;
+ }
+
+ //-- get file size
+ fileSize = GetFileSize(hFile, NULL);
+ if (fileSize == INVALID_FILE_SIZE || !fileSize)
+ {//-- something is wrong with file size
+ bRes = EFalse;
+ goto CleanUp;
+ }
+
+ //-- allocate data for buffer
+ // fileSize+1 to ensure zero-termination of file, since Windows98 might use
+ // a dirty page of memory. VirtualAlloc initializes memory to zero
+ pFileData = VirtualAlloc(NULL, fileSize+1, MEM_COMMIT, PAGE_READWRITE);
+ if(! pFileData)
+ {//-- something is wrong with memory allocation
+ bRes = EFalse;
+ goto CleanUp;
+ }
+
+ //-- read whole file into buffer
+ DWORD bytesRead;
+
+ if (! ReadFile(hFile, pFileData, fileSize, &bytesRead, NULL))
+ bRes = EFalse;
+ else
+ {//-- parse file line by line looking for the appropriate port
+ LPSTR linePtr=(LPSTR)pFileData;
+ _LIT8(KCommToken, "COMM::");
+ bRes = EFalse;
+
+
+ while(linePtr && *linePtr)
+ {
+ //-- skip spaces at the beginning of the current line
+ while (*linePtr && (*linePtr == '\r' || *linePtr == '\n' || *linePtr == ' ' || *linePtr =='\t'))
+ {
+ ++linePtr;
+ --bytesRead;
+ }
+
+ //-- find the end of the line
+ TPtrC8 line((unsigned char*)linePtr, bytesRead);
+ TInt len;
+ for (len = 0; len < line.Length() && (line[len] != '\r' && line[len] != '\n'); ++len)
+ ;
+
+ line.Set(line.Left(len));
+ bytesRead -= line.Length();
+ linePtr += line.Length();
+
+ //-- parse the line
+ TLex8 lex(line);
+ TPtrC8 commname (lex.NextToken());
+ if(commname.Length() <= KCommToken().Size())
+ continue; // not enough chars
+ if(commname[0] == '#')
+ continue; // comment line
+
+ if (commname.Left(KCommToken().Size()).CompareF(KCommToken) != 0)
+ continue; // unreconised option. Should log?!?
+
+ //-- extract comm port number
+ TLex8 numLex(commname.Mid(KCommToken().Size()));
+ TInt commNum;
+ if(numLex.Val(commNum) != KErrNone || commNum != aPortNum)
+ continue;
+
+ //-- extract comm port mapping substring
+ lex.SkipSpace();
+ aPortMapStr.Copy(lex.Remainder());
+ aPortMapStr.PtrZ();
+ bRes = ETrue;
+
+ break;
+ }//while(linePtr && *linePtr)
+ }
+
+
+ CleanUp:
+
+ CloseHandle(hFile);
+ VirtualFree(pFileData, 0, MEM_RELEASE);
+
+ return bRes;
+}
+
+
+TInt DCommWins::DoCreate(TInt aUnit,const TDesC * /*anInfo*/)
+//
+// Create the comms driver.
+//
+ {
+ _Log("# DCommWins::DoCreate()\n");
+
+ InitializeCriticalSection(&iCriticalSection);
+
+#if defined (__COM_ONE_ONLY__)
+ if (aUnit!=0)
+ return KErrNotSupported;
+#elif defined (__COM_TWO_ONLY__)
+ if (aUnit!=1)
+ return KErrNotSupported;
+#endif
+
+ //-- get full path for the DComm.ini configuration file
+ TBuf8<MAX_PATH> iniFileName;
+ iniFileName.Copy(EmulatorDataPath());
+ iniFileName.Append(_L8("DComm.ini"));
+ LPCSTR pszIniFle = (LPCSTR)iniFileName.PtrZ();
+
+ //-- get com port mapping string
+ TBuf8<MAX_PATH> strPortMapping;
+ TBool bFound = GetComPortMapping(pszIniFle, aUnit, strPortMapping);
+
+ if(bFound)
+ {//-- comm port mapping string is found in cofiguration file, we are dealing with sockets now
+
+ //-- try to locate port number after colon
+ TInt nColonPos = strPortMapping.Locate(':');
+ if(nColonPos != KErrNotFound)
+ {// Found a ':' ... must be a TCP name & port no.
+ TPtrC8 hostAddr(strPortMapping.Left(nColonPos));
+
+ ((char*)strPortMapping.Ptr())[nColonPos] = 0; // replace : with a null term
+
+ TLex8 portLex (strPortMapping.Mid(nColonPos + 1));
+ TInt port = 0;
+ portLex.Val(port);
+
+
+ //-- initialize socket
+
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+ wVersionRequested = MAKEWORD(2, 0);
+ err = WSAStartup(wVersionRequested, &wsaData);
+ if (err != 0)
+ return MapWinError(WSAGetLastError());
+
+ iSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, WSA_FLAG_OVERLAPPED);
+ if(iSocket == INVALID_SOCKET)
+ return MapWinError(WSAGetLastError());
+
+ _Log2("# DCommWins: created socket id: %d\n", iSocket );
+
+ sockaddr_in sin;
+
+ char* devname = (char*)(strPortMapping.Ptr());
+ u_long nRemoteAddr = inet_addr(devname);
+
+ if (nRemoteAddr != INADDR_NONE)
+ {
+ sin.sin_addr.s_addr = nRemoteAddr;
+ }
+ else
+ {
+ struct hostent FAR * hostaddr = gethostbyname (devname);
+ if(hostaddr == NULL)
+ return MapWinError(WSAGetLastError());
+
+ sin.sin_addr.s_addr = *((u_long*)hostaddr->h_addr_list[0]);
+ }
+
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(TUint16(port));
+
+ err = WSAConnect(iSocket, (sockaddr*)&sin, sizeof(sin), 0, 0, 0, 0);
+ if(err)
+ return MapWinError(WSAGetLastError());
+
+ _Log2("# DCommWins: socket connected to the port: %d\n", port);
+
+ iCommPort = (void*)iSocket;
+
+ }
+ }
+
+
+ //-----------------------------------------
+
+ if(! UseSocket())
+ {//-- use PC serial port as usual
+ //-- open Windows serial port
+ TBuf8<0x10> n;
+ n.Format(_L8("\\\\.\\COM%d"),aUnit+1);
+ iCommPort=CreateFileA((LPCSTR)n.PtrZ(),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);
+ if (iCommPort==INVALID_HANDLE_VALUE)
+ {
+ // Reused code from MapWinError() rather than adding an extra case
+ // to MapWinError() because mapping KErrNotSupported to the returned
+ // FILE_NOT_FOUND is non-intuitive and special to this case only
+ DWORD winErr=GetLastError();
+ switch (winErr)
+ {
+ case ERROR_INVALID_USER_BUFFER:
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_INSUFFICIENT_BUFFER:
+ return(KErrNoMemory);
+ case ERROR_ACCESS_DENIED:
+ return(KErrAccessDenied);
+ case ERROR_FILE_NOT_FOUND: // Reflects value returned by
+ return(KErrNotSupported); // corresponding MARM Pdd
+ case ERROR_NOT_SUPPORTED:
+ return(KErrNotSupported);
+ default:
+ return(KErrGeneral);
+ }
+ }
+
+ DCB dcb;
+ if (!GetCommStateP(iCommPort,&dcb,UseSocket()))
+ return MapWinError();
+
+ dcb.fDtrControl=DTR_CONTROL_DISABLE;
+ dcb.fRtsControl=RTS_CONTROL_DISABLE;
+ dcb.fAbortOnError=TRUE; // Tell me about your parity problems luvvy
+ dcb.fParity=TRUE;
+ dcb.fBinary=TRUE;
+ dcb.fOutxCtsFlow=FALSE;
+ dcb.fOutxDsrFlow=FALSE;
+ dcb.fDsrSensitivity=FALSE;
+ dcb.fTXContinueOnXoff=TRUE;
+ dcb.fOutX=FALSE;
+ dcb.fInX=FALSE;
+ dcb.fErrorChar=FALSE;
+ dcb.fNull=FALSE;
+ //
+ // dcb.ByteSize; // number of bits/byte, 4-8
+ // dcb.Parity; // 0-4=no,odd,even,mark,space
+ // dcb.StopBits; // 0,1,2 = 1, 1.5, 2
+ // dcb.XonChar; // Tx and Rx XON character
+ // dcb.XoffChar; // Tx and Rx XOFF character
+ // dcb.ErrorChar; // error replacement character
+ // dcb.EofChar; // end of input character
+ // dcb.EvtChar;
+ //
+ if (!SetCommStateP(iCommPort,&dcb, UseSocket()))
+ return MapWinError();
+
+ EscapeCommFunctionP(iCommPort,0,UseSocket());
+
+ //
+ // Could add EV_RXCHAR|EV_RXFLAG|EV_TXEMPTY to the following
+ // mask too and get all chars through the call to WaitForAnyObject
+ // rather then the completion routine followed by a manual read
+ //
+ if (!SetCommMaskP(iCommPort,EV_CTS|EV_ERR|EV_DSR|EV_RLSD|EV_RXCHAR,UseSocket()))
+ return MapWinError();
+
+ if(!SetupComm(iCommPort,KWinNTReadBufSize,KWinNTWriteBufSize))
+ return MapWinError();
+
+ //
+ // The serial port seems to open with the error condition set
+ //
+
+ DWORD err,res;
+ COMSTAT s;
+ if (ClearCommError(iCommPort,&err,&s)==FALSE)
+ res=GetLastError();
+ }//if(! UseSocket())
+
+ if ((iCommThreadSem=CreateSemaphoreA(NULL,0,0x7fffffff,NULL))==NULL)
+ return MapWinError();
+
+ if ((iDriverThreadSem=CreateSemaphoreA(NULL,0,0x7fffffff,NULL))==NULL)
+ return MapWinError();
+
+ if ((iWaitableTimer=CreateWaitableTimer(NULL, FALSE, NULL))==NULL)
+ return MapWinError();
+
+ if ((iThread=CreateThread(NULL,0x4000,(LPTHREAD_START_ROUTINE)commThread,(void *)this,CREATE_SUSPENDED,&iThreadID))==NULL)
+ return MapWinError();
+
+
+
+#if defined (_LOG_WRITES)
+ TBuf8<0x40> logName;
+ logName.Format(_L8("C:\\tmp\\log%d.tmp"),iUnit);
+ DWORD fileErr;
+ if((iLogFile=CreateFileA((char *)logName.PtrZ(),GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL))==INVALID_HANDLE_VALUE)
+ fileErr=GetLastError();
+#endif
+#if defined (_LOG_OUTPUT)
+ TBuf8<0x40> fileName;
+ DWORD fileErr;
+ fileName.Format(_L8("C:\\tmp\\Writes%d.tmp"),iUnit);
+ if((iWritesHandle=CreateFileA((char *)fileName.PtrZ(),GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL))==INVALID_HANDLE_VALUE)
+ fileErr=GetLastError();
+ fileName.Format(_L8("C:\\tmp\\Reads%d.tmp"),iUnit);
+ if((iReadsHandle=CreateFileA((char *)fileName.PtrZ(),GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL))==INVALID_HANDLE_VALUE)
+ fileErr=GetLastError();
+#endif
+
+ SetThreadPriority(iThread,THREAD_PRIORITY_HIGHEST);
+ return(KErrNone);
+ }
+
+DCommWins::~DCommWins()
+//
+// Destruct
+//
+ {
+ if (iThread)
+ {
+ if (! iRunning)
+ {
+ __ASSERT_ALWAYS(
+ ResumeThread(iThread) != 0xffffffff,
+ User::Panic(_L("Wins comm error"), 0));
+ }
+
+ iRunning=ETrue;
+ RunCommThread(EDie);
+ }
+
+ if(UseSocket())
+ {
+ closesocket(iSocket);
+ WSACleanup();
+ iCommPort = (HANDLE) NULL;
+ iSocket = NULL;
+ }
+
+ if (iCommPort)
+ CloseHandle(iCommPort);
+
+ if (iDriverThreadSem)
+ CloseHandle(iDriverThreadSem);
+
+ if (iCommThreadSem)
+ CloseHandle(iCommThreadSem);
+
+ if (iWaitableTimer)
+ CloseHandle(iWaitableTimer);
+
+ if (iReadOverLapped.hEvent)
+ CloseHandle(iReadOverLapped.hEvent);
+
+ if (iWriteOverLapped.hEvent)
+ CloseHandle(iWriteOverLapped.hEvent);
+
+ if (iSignalOverLapped.hEvent)
+ CloseHandle(iSignalOverLapped.hEvent);
+
+ if (iThread)
+ CloseHandle(iThread);
+
+ DeleteCriticalSection(&iCriticalSection);
+ }
+
+TInt DCommWins::Start()
+//
+// Start receiving characters
+//
+ {
+
+ __ASSERT_ALWAYS(ResumeThread(iThread)!=0xffffffff,User::Panic(_L("Wins comm error"),0));
+// if (ResumeThread(iThread)==0xffffffff)
+// return(MapWinError());
+ iRunning=ETrue;
+ RunCommThread(EStart);
+ return(KErrNone);
+ }
+
+void DCommWins::Stop(TStopMode aMode)
+//
+// Stop receiving characters
+//
+ {
+
+ iSkipTransmitIsrNextTime=EFalse;
+ RunCommThread((aMode==EStopEmergency) ? EStopNoDrain : EStop);
+ SuspendThread(iThread);
+ iRunning=EFalse;
+ iNumInChars=iNumOutChars=0;
+ }
+
+void DCommWins::Break(TBool aState)
+//
+// Assert a break signal
+//
+ {
+
+ if (aState)
+ RunCommThread(ESetBreak);
+ else
+ RunCommThread(EClearBreak);
+ }
+
+void DCommWins::EnableTransmit()
+//
+// Start transmitting characters
+//
+ {
+ RunCommThread(ETransmit);
+ }
+
+
+TUint DCommWins::Signals() const
+//
+// Return the current signals state
+//
+ {
+ if(UseSocket())
+ {
+ return MS_CTS_ON|MS_DSR_ON|KSignalCTS|KSignalDSR;
+ }
+
+ ULONG signals=0;
+ GetCommModemStatusP(iCommPort,&signals, UseSocket());
+ TUint status=0;
+ if (signals&MS_CTS_ON)
+ status|=KSignalCTS;
+ if (signals&MS_DSR_ON)
+ status|=KSignalDSR;
+ if (signals&MS_RING_ON)
+ status|=KSignalRNG;
+ if (signals&MS_RLSD_ON)
+ status|=KSignalDCD;
+ CONST_CAST(DCommWins*,this)->iSkipTransmitIsrNextTime=EFalse;
+ return(status|iSignals);
+ }
+
+void DCommWins::SetSignals(TUint aSetMask,TUint aClearMask)
+//
+// Set the state of the output signals
+//
+ {
+
+ if (aSetMask&KSignalRTS)
+ {
+ iSignals|=KSignalRTS;
+ EscapeCommFunctionP(iCommPort,SETRTS, UseSocket());
+ }
+ if (aSetMask&KSignalDTR)
+ {
+ iSignals|=KSignalDTR;
+ EscapeCommFunctionP(iCommPort,SETDTR, UseSocket());
+ }
+ if (aClearMask&KSignalRTS)
+ {
+ iSignals&=(~KSignalRTS);
+ EscapeCommFunctionP(iCommPort,CLRRTS, UseSocket());
+ }
+ if (aClearMask&KSignalDTR)
+ {
+ iSignals&=(~KSignalDTR);
+ EscapeCommFunctionP(iCommPort,CLRDTR, UseSocket());
+ }
+
+ _Log2("#~DCommWins::SetSignals, iSignals has become=0x%x\n", iSignals);
+ }
+
+void DCommWins::CheckConfig(TCommConfigV01& /*aConfig*/)
+ {
+ // Do nothing
+ }
+
+
+TInt DCommWins::CompleteSlowOpen(DThread *aThread,TRequestStatus *aReqStat)
+ {
+ // Should never be called
+ aThread->RequestComplete(aReqStat,KErrNone);
+ return(KErrNone);
+ }
+
+TInt DCommWins::Validate(const TCommConfigV01 &aConfig) const
+//
+// Confirm that aConfig is a valid configuration.
+//
+ {
+
+ if (aConfig.iSIREnable==ESIREnable)
+ return KErrNotSupported;
+
+ if (aConfig.iRate&KCapsBpsSpecial)
+ return(KErrNotSupported);
+ switch (aConfig.iRate)
+ {
+ case EBps50:
+ case EBps2000:
+ case EBps3600:
+ return(KErrNotSupported);
+ };
+ return(KErrNone);
+ }
+
+void DCommWins::Configure(TCommConfigV01 &aConfig)
+//
+// Ask comm thread to set up the serial port
+//
+ {
+
+ iConfig=&aConfig;
+ if (iRunning)
+ {
+ RunCommThread(EConfigure);
+ }
+ else
+ {
+// iCommand=EConfigure;
+ DoConfigure();
+ }
+ }
+
+void DCommWins::DoConfigure()
+//
+// Set up the serial port
+//
+ {
+
+
+
+ DCB dcb;
+ if (!GetCommStateP(iCommPort,&dcb, UseSocket()))
+ return;
+
+ if(iRunning)
+ {
+ SetCommMaskP(iCommPort,EV_CTS|EV_ERR|EV_DSR|EV_RLSD|EV_RXCHAR, UseSocket());
+ WaitForSingleObject(iSignalOverLapped.hEvent, INFINITE);
+ }
+
+//
+// Need only worry about the framing and speed.
+//
+ switch (iConfig->iRate)
+ {
+ case EBps75:
+ dcb.BaudRate=75;
+ break;
+ case EBps110:
+ dcb.BaudRate=110;
+ break;
+ case EBps134:
+ dcb.BaudRate=134;
+ break;
+ case EBps150:
+ dcb.BaudRate=150;
+ break;
+ case EBps300:
+ dcb.BaudRate=300;
+ break;
+ case EBps600:
+ dcb.BaudRate=600;
+ break;
+ case EBps1200:
+ dcb.BaudRate=1200;
+ break;
+ case EBps1800:
+ dcb.BaudRate=1800;
+ break;
+ case EBps2400:
+ dcb.BaudRate=2400;
+ break;
+ case EBps4800:
+ dcb.BaudRate=4800;
+ break;
+ case EBps7200:
+ dcb.BaudRate=7200;
+ break;
+ case EBps9600:
+ dcb.BaudRate=9600;
+ break;
+ case EBps19200:
+ dcb.BaudRate=19200;
+ break;
+ case EBps38400:
+ dcb.BaudRate=38400;
+ break;
+ case EBps57600:
+ dcb.BaudRate=57600;
+ break;
+ case EBps115200:
+ dcb.BaudRate=115200;
+ break;
+ }
+
+ switch(iConfig->iDataBits)
+ {
+ case EData5:
+ dcb.ByteSize=5;
+ break;
+ case EData6:
+ dcb.ByteSize=6;
+ break;
+ case EData7:
+ dcb.ByteSize=7;
+ break;
+ case EData8:
+ dcb.ByteSize=8;
+ break;
+ }
+
+ switch(iConfig->iStopBits)
+ {
+ case EStop1:
+ dcb.StopBits=ONESTOPBIT;
+ break;
+ case EStop2:
+ dcb.StopBits=TWOSTOPBITS;
+ break;
+ }
+
+ switch (iConfig->iParity)
+ {
+ case EParityNone:
+ dcb.Parity=NOPARITY;
+ break;
+ case EParityEven:
+ dcb.Parity=EVENPARITY;
+ break;
+ case EParityOdd:
+ dcb.Parity=ODDPARITY;
+ break;
+ }
+
+ // make sure that SetCommState won't change the state of the Modem signals
+ TUint prov=iSignals&KSignalRTS;
+ if(prov)
+ dcb.fRtsControl=RTS_CONTROL_ENABLE;
+ else
+ dcb.fRtsControl=RTS_CONTROL_DISABLE;
+
+ prov=iSignals&KSignalDTR;
+ if(prov)
+ dcb.fDtrControl=DTR_CONTROL_ENABLE;
+ else
+ dcb.fDtrControl=DTR_CONTROL_DISABLE;
+
+ TInt error_r=KErrNone;
+ if(!SetCommStateP(iCommPort,&dcb, UseSocket()))
+ error_r=GetLastError();
+// SetSignals(iSignals, ~iSignals); // For NT 4 -> redundant (see above comments on preserving Modem control signals)
+//
+// Clear any error we may have caused
+//
+ DWORD err,res;
+ COMSTAT s;
+ if (ClearCommError(iCommPort,&err,&s)==FALSE)
+ res=GetLastError();
+
+ if(iRunning)
+ {
+ if(!WaitCommEvent(iCommPort,&iSignalStatus,&iSignalOverLapped))
+ {
+ TInt i=50;
+ while(--i)
+ {
+ if(WaitCommEvent(iCommPort,&iSignalStatus,&iSignalOverLapped))
+ break;
+ }
+ }
+ }
+ }
+
+void DCommWins::Caps(TDes8 &aCaps) const
+//
+// Return the current capabilities
+//
+ {
+
+ GetWinsCommsCaps(aCaps);
+ }
+
+void DCommWins::EnableInterrupts()
+//
+// Wake the comms thread up
+//
+ {
+ LeaveCritical();
+// if (ResumeThread(iThread)==0xFFFFFFFF)
+// {
+// DWORD err=GetLastError();
+// Panic(EWindowsUnexpectedError);
+// }
+ iSkipTransmitIsrNextTime=EFalse;
+ }
+
+void DCommWins::DisableInterrupts()
+//
+// Suspend the thread (assuming we're not it...)
+//
+ {
+ EnterCritical();
+// if(GetCurrentThreadId()!=iThreadID)
+// if (SuspendThread(iThread)==0xFFFFFFFF)
+// {
+// DWORD err=GetLastError();
+// Panic(EWindowsUnexpectedError);
+// }
+ }
+
+/**
+ Associate event with our socket
+*/
+TInt DCommWins::QueSocketRead()
+ {
+ if(WSAEventSelect(iSocket, iReadOverLapped.hEvent, FD_READ))
+ {// Some error?!?
+ DWORD res = WSAGetLastError();
+ return res;
+ }
+ return KErrNone;
+
+ }
+
+
+void DCommWins::WaitForEvent()
+//
+// Comm port thread - wait for serial port and semaphore
+//
+ {
+
+ HANDLE objects[5];
+
+
+ iReadOverLapped.hEvent=CreateEventA(NULL,FALSE,FALSE,NULL);
+ iWriteOverLapped.hEvent=CreateEventA(NULL,FALSE,FALSE,NULL);
+ iSignalOverLapped.hEvent=CreateEventA(NULL,FALSE,FALSE,NULL);
+ objects[0]=iSignalOverLapped.hEvent; // iCommPort;
+ objects[1]=iCommThreadSem;
+ objects[2]=iWriteOverLapped.hEvent;
+ objects[3]=iReadOverLapped.hEvent;
+ objects[4]=iWaitableTimer;
+
+ FOREVER
+ {
+ DWORD waitTimeout = INFINITE; // Default timeout
+ if(iReadPending) // If we have a queued read event, we need to check periodically if it can be carried out.
+ {
+ waitTimeout = 150;
+ }
+
+ // Once an event is signalled and WaitFor.. returns, it is reset by WaitFor.. just before it returns.
+ // This means that once a read on the socket is signalled. we absolutely must read from it (eventually).
+ // Otherwise, the read event remains reset and no further reads are signalled, even if data arrives.
+ // This means that if we cannot read immediately,we MUST queue the read, and carry it out sometimes in the future.
+ DWORD ret=WaitForMultipleObjectsEx(5,objects,FALSE,waitTimeout,TRUE);
+
+ // If the wait for an event has timed out, AND we have a queued read, try to carry out the read.
+ // If we have not timed out, carry out the operation as usual:
+ // it cannot be a read, but it may be something which enables us to read later.
+ if(ret == WAIT_TIMEOUT && iReadPending)
+ {
+ ret = WAIT_OBJECT_0 + 3; // Fall through to the read.
+ }
+
+ switch (ret)
+ {
+ case WAIT_OBJECT_0:
+ ASSERT(iCommPort);
+ EnterCritical();
+ DWORD commErrors;
+ COMSTAT cstat;
+//
+// iCommPort has completed other than read/write - could be either error or line status change
+//
+ if ((iSignalStatus&EV_ERR) || (iSignalStatus&EV_RXCHAR))
+ {
+ ClearCommError(iCommPort,&commErrors,&cstat);
+ if (cstat.cbInQue)
+ {
+//
+// Drain the input buffer
+//
+ while (cstat.cbInQue>0)
+ {
+ _Log2("#~ WAIT_OBJECT_0 cstat.cbInQue=%d\n",cstat.cbInQue);//
+
+ TInt min = Min((TInt)cstat.cbInQue, (TInt)KReadBufSize);
+ TInt i;
+ ReadFile(iCommPort,iInBuf,min,(LPDWORD)&i,&iReadOverLapped);
+ WaitForSingleObject(iReadOverLapped.hEvent,INFINITE);
+ GetOverlappedResult(iCommPort, &iReadOverLapped, (LPDWORD)&i, FALSE);
+ __ASSERT_ALWAYS(i==min,Panic(EBadIOLen));
+
+ cstat.cbInQue-=min;
+ i=0;
+ while (i<min)
+ {
+
+ if(i==(min-1) && !cstat.cbInQue)
+ {
+ //
+ // Mark the final byte with the parity error
+ //
+
+
+ TInt temp=0;
+ if (commErrors&CE_RXPARITY)
+ temp|=KReceiveIsrParityError;
+ if (commErrors&CE_FRAME)
+ temp|=KReceiveIsrFrameError;
+ if (commErrors&CE_OVERRUN)
+ temp|=KReceiveIsrOverrunError;
+ DoReceiveIsr(iInBuf[i++]|temp);
+ }
+ else
+ DoReceiveIsr(iInBuf[i++]);
+ }
+ }
+
+
+ }
+ }
+ if (iSignalStatus&(EV_DSR|EV_CTS|EV_RLSD))
+ DoStateIsr();
+ iSignalStatus=0;
+ WaitCommEvent(iCommPort,&iSignalStatus,&iSignalOverLapped);
+ LeaveCritical();
+ break;
+ case WAIT_OBJECT_0+1:
+//
+// iCommThreadSemaphore has been signalled
+//
+ DriverCommand(iCommand);
+ break;
+ case WAIT_OBJECT_0+2:
+ //
+ // Write completion
+ //
+ {
+ DWORD len=iWriteOverLapped.InternalHigh;
+// GetOverlappedResult(iCommPort, &iWriteOverLapped, &len, FALSE);
+
+ EnterCritical();
+ WriteCompletion(this, 0, len);
+ LeaveCritical();
+ break;
+ }
+
+ case WAIT_OBJECT_0+3:
+ //
+ // Read completion
+ //
+ {
+ ASSERT(iSocket);
+ EnterCritical();
+ if(iConfig->iHandshake & KConfigFreeRTS || iSignals & KSignalRTS)
+ {// Only read when RTS is freed or asserted
+
+ int num = recv(iSocket, (char*)iInBuf, 16, 0); // Only read 16 bytes at a go, to give LDD plenty of chance to flow off
+
+ if(num == 0 || (num == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) || num < 0)
+ {
+ DoReceiveIsr(KReceiveIsrFrameError);
+ num = 0;
+ }
+
+ for(int i = 0; i<num; ++i)
+ {
+ DoReceiveIsr(iInBuf[i]);
+ }
+ // We'll automatically be re-signalled if there's more data waiting
+
+ iSignalStatus=0;
+ // if(QueSocketRead() != KErrNone)
+ // {
+ // DoReceiveIsr(KReceiveIsrFrameError);
+ // iNumInChars = 0;
+ // }
+
+ iReadPending = EFalse; // Make sure read is not queued
+ }
+ else // We cannot read at this time.
+ {
+ // We have skipped the read, and the read event is reset at this point.
+ iReadPending = ETrue; // Queue the read event
+ _Log3("#~ ReadCompletion FC, iSignals=0x%x, iConfig->iHandshake=%d\n", iSignals, iConfig->iHandshake);
+ }
+ LeaveCritical();
+ break;
+ }
+
+
+ case WAIT_OBJECT_0+4:
+ //
+ // Timer completion
+ //
+ {
+ Comm().TurnaroundStartDfcImplementation();
+ break;
+ }
+
+ case WAIT_IO_COMPLETION:
+//
+// A read or write completion routine has been queued - why would we care?
+// Do nothing?
+ _Log("#~ WAIT_IO_COMPLETION\n");//
+
+ break;
+
+ case WAIT_TIMEOUT: // Ignore the timeout.
+ // Just in case we timed out and no read is queued.
+ // This is impossible, because we can time out only when a read is queued,
+ // so we'll try to read rather than end up here.
+ // This code is just in case there are further modifications to the event handling code.
+ break;
+
+ default:
+ MapWinError();
+ Panic(EWindowsUnexpectedError);
+ }
+ }
+ }
+
+void DCommWins::DriverCommand(TDriverCommand aCommand)
+//
+// Do a driver command - executed when the semaphore has been signalled in the comm port thread
+//
+ {
+ switch (aCommand)
+ {
+ case ESetBreak:
+ if(!UseSocket()) SetCommBreak(iCommPort);
+ break;
+ case EClearBreak:
+ if(!UseSocket()) ClearCommBreak(iCommPort);
+ break;
+ case ETransmit:
+ // Only Transmit one character to get the driver transmit cycle going
+ // otherwise we can empty the buffer and get double starts and re-write death
+ if (!iWritePending)
+ {
+ if(DoTransmitIsr(iNumOutChars))
+ iNumOutChars++;
+#if defined (_LOG_OUTPUT)
+ DWORD dummy;
+ WriteFile(iWritesHandle,iOutBuf,iNumOutChars,&dummy,NULL);
+#endif
+ if (iNumOutChars>0)
+ {
+ iWritePending=ETrue;
+// WriteFileEx(iCommPort,iOutBuf,iNumOutChars,&iWriteOverLapped,WriteComplete);
+ WriteFile(iCommPort,iOutBuf,iNumOutChars, NULL, &iWriteOverLapped);
+
+#if defined (_LOG_WRITES)
+ TBuf<0x40> buf;
+ DWORD dummy;
+ buf.Format(_L("writing %d\r\n"),iNumOutChars);
+ WriteFile(iLogFile,buf.PtrZ(),buf.Length(),&dummy,NULL);
+#endif
+
+ }
+ }
+ break;
+ case EStart:
+
+ if(UseSocket())
+ {
+ if(QueSocketRead() != KErrNone)
+ {// Couldn't que initial read :-(
+ __DEBUGGER();
+ }
+ }
+ else
+ {
+ DWORD err,res;
+ COMSTAT s;
+ if (iCommPort && ClearCommError(iCommPort,&err,&s)==FALSE)
+ res=GetLastError();
+ PurgeComm(iCommPort ,PURGE_RXCLEAR);
+ iSignalStatus=0;
+ WaitCommEvent(iCommPort,&iSignalStatus,&iSignalOverLapped);
+ }
+
+ // if (ReadFileEx(iCommPort,iInBuf,1,&iReadOverLapped,ReadComplete)==FALSE)
+ // DWORD res=GetLastError();
+ break;
+ case EStop:
+ if(!UseSocket() && iNumOutChars)
+ {
+#if defined (_LOG_OUTPUT)
+ DWORD dummy;
+ WriteFile(iWritesHandle,iOutBuf,iNumOutChars,&dummy,NULL);
+#endif
+ // Flush last write
+ if(iWritePending)
+ {
+ WaitForSingleObject(iWriteOverLapped.hEvent, INFINITE);
+ FlushFileBuffers(iCommPort);
+ iWritePending=EFalse;
+ }
+ }
+ // Fall through
+ case EStopNoDrain:
+ if(UseSocket())
+ {
+ CancelIo(iCommPort); // cancels read & write (see below)
+ }
+ // Cancel any pending writes
+ if(iWritePending)
+ {
+ if(!UseSocket())
+ {
+ PurgeComm(iCommPort, PURGE_TXABORT|PURGE_TXCLEAR);
+ WaitForSingleObject(iWriteOverLapped.hEvent, INFINITE);
+ }
+ iWritePending=EFalse;
+ }
+
+ iStopping=ETrue;
+ if(iRunning)
+ {
+ if(!UseSocket())
+ {
+ SetCommMask(iCommPort,EV_CTS|EV_ERR|EV_DSR|EV_RLSD|EV_RXCHAR);
+ WaitForSingleObject(iSignalOverLapped.hEvent, INFINITE);
+ }
+ }
+ break;
+ case EDie:
+ SignalDriverThread();
+ ExitThread(1);
+ break;
+ case EConfigure:
+ DoConfigure();
+ break;
+ default:
+ // Panic(EUnknownCommand);
+ break;
+ }
+ iCommand=EInvalidCommand;
+ SignalDriverThread();
+ }
+
+TInt DCommWins::DoTransmitIsr(TInt anOffset)
+//
+// Call the transmit Isr in the LDD to get the next character
+//
+ {
+
+ TInt ret;
+ ret=Comm().TransmitIsr();
+ iOutBuf[anOffset]=(*(char *)&ret);
+#ifdef _DEBUG_DEVCOMM
+ iTxIntCount += (ret!=KTransmitIrqEmpty);
+#endif
+ return(ret!=KTransmitIrqEmpty);
+ }
+
+void DCommWins::DoReceiveIsr(TUint anCharAndMask)
+//
+// Call the Isr in the LDD to process this character
+//
+ {
+#ifdef _DEBUG_DEVCOMM
+ iRxIntCount++;
+ if (anCharAndMask & ~0xff)
+ iRxErrCount++;
+#endif
+ Comm().ReceiveIsr(anCharAndMask);
+ }
+
+void DCommWins::DoStateIsr()
+//
+// Call the Isr in the device to handle a line status change.
+//
+ {
+ Comm().StateIsr(Signals());
+ }
+
+void DCommWins::EnterCritical()
+//
+// Call the Isr in the device to handle a line status change.
+//
+ {
+ EnterCriticalSection(&iCriticalSection);
+ iIntRefCount++;
+ }
+
+void DCommWins::LeaveCritical()
+//
+// Call the Isr in the device to handle a line status change.
+//
+ {
+ --iIntRefCount;
+ LeaveCriticalSection(&iCriticalSection);
+ }
+
+void DCommWins::SetTimer(const TUint aTimeOut)
+ {
+ TInt timeout = aTimeOut;
+ timeout *= 10; // to 100ns units
+ timeout = -timeout; // make relative to current time
+ iTimeOut.QuadPart = timeout;
+ SetWaitableTimer(iWaitableTimer, &iTimeOut, 0, NULL, NULL, 0);
+ }
+
+void DCommWins::CancelTimer()
+ {
+ CancelWaitableTimer(iWaitableTimer);
+ }
+
+EXPORT_C DPhysicalDevice *CreatePhysicalDevice()
+//
+// Create a new physical device driver
+//
+ {
+
+ return(new DDriverComm);
+ }
+
+GLDEF_C TInt E32Dll(TDllReason /*aReason*/)
+//
+// DLL entry point
+//
+ {
+
+ return(KErrNone);
+ }