diff -r 000000000000 -r 83f4b4db085c toolsandutils/wintunnel/src_beech/d_cdrv.cpp --- /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 +#include +#pragma warning( default : 4201 ) // nonstandard extension used : nameless struct/union +#include +#include +#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 + +//#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 (iNumOutChars0) + { +// 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 iniFileName; + iniFileName.Copy(EmulatorDataPath()); + iniFileName.Append(_L8("DComm.ini")); + LPCSTR pszIniFle = (LPCSTR)iniFileName.PtrZ(); + + //-- get com port mapping string + TBuf8 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 (iiHandshake & 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; iiHandshake=%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); + }