--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/testexecfw/statsrv/device/source/statapi/src/stat_serial.cpp Mon Mar 08 15:03:44 2010 +0800
@@ -0,0 +1,727 @@
+/*
+* Copyright (c) 2005-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:
+*
+*/
+
+
+
+ /**************************************************************************************
+ *
+ * Packetisation transport for STAT -- for packet based network layers
+ *
+ *************************************************************************************/
+
+/**************************************************************************************
+ *
+ * Local Includes
+ *
+ *************************************************************************************/
+#include "assert.h"
+#include "stat.h"
+#include "stat_serial.h"
+#include "MsgWin.h"
+#include "../../../../common/inc/SerialPacketSize.h"
+
+/**************************************************************************************
+ *
+ * Definitions
+ *
+ *************************************************************************************/
+#ifndef LIGHT_MODE
+_LIT(LDD_NAME,"ECOMM");
+#ifdef __WINS__
+_LIT(PDD_NAME,"ECDRV");
+#else
+_LIT(PDD_NAME,"EUART1");
+#endif
+#endif // ifndef LIGHT_MODE
+
+#define KMaxTimeoutRetries (0x0FFFFFFF)
+#define KWriteTimeout 50000000
+
+// Moved this data definitions to the source file where they are
+// less public.
+#define KReadTimeout 30000000
+
+/********************************************************************************
+ *
+ * Macro functions
+ *
+ ********************************************************************************/
+
+/**************************************************************************************
+ *
+ * CStatApiSerial - Construction
+ *
+ *************************************************************************************/
+CStatApiSerial* CStatApiSerial::NewL( TPtrC16 aModule )
+{
+ CStatApiSerial *self = new (ELeave) CStatApiSerial();
+ CleanupStack::PushL(self);
+ self->ConstructL( aModule );
+ CleanupStack::Pop();
+ return self;
+}
+
+CStatApiSerial::CStatApiSerial() : CActive(EPriorityStandard)
+{
+}
+
+CStatApiSerial::~CStatApiSerial()
+{
+ // remove from active scheduler
+ Deque();
+
+ // clean up params
+ if( iRecvBuffer != NULL )
+ delete iRecvBuffer;
+ if( iRecvBufferPtr != NULL )
+ delete iRecvBufferPtr;
+
+#ifndef LIGHT_MODE
+ iCommPort.Close();
+ iCommServer.Close();
+#else // ifndef LIGHT_MODE
+ if( NULL != iCommPort )
+ {
+ CloseSerialPort( iCommPort );
+ iCommPort = NULL;
+ }
+ if( NULL != iCommServer )
+ {
+ CloseSerialServer( iCommServer );
+ iCommServer = NULL;
+ }
+#endif // ifndef LIGHT_MODE
+}
+
+void CStatApiSerial::ConstructL( TPtrC16 aModule )
+{
+ // add to active scheduler
+ CActiveScheduler::Add(this);
+
+ // set parameters
+ asserte( aModule.Length() <= KModuleSize );
+ iModule.Copy( aModule );
+ iRecvBuffer = NULL;
+ iRecvBufferPtr = NULL;
+ iRecvLength = 0;
+ iRWStatus = ENoRW;
+ iSerialStatus = EIdle;
+ iTransport = NULL;
+ iRetries = 0;
+ iCommOldSettingsValid = 0;
+
+#ifdef LIGHT_MODE
+ iCommServer = NULL;
+ iCommPort = NULL;
+#endif // ifdef LIGHT_MODE
+
+ // Initialise the sub-type. We have the iModule text string
+ // and we use it below determine the subtype.
+ iSubType = EInvalid;
+ iMaxPacketSize = KMaxPacketSize;
+
+ // Check the iModule text string to determine our serial
+ // transport sub-type.
+ DetermineSubTypeL();
+ asserte( EInvalid != iSubType );
+}
+
+/**************************************************************************************
+ *
+ * CStatApiSerial - MStatNetwork - Initialise and Release
+ *
+ *************************************************************************************/
+TInt CStatApiSerial::InitialiseL( MNotifyStatTransport *aTransport )
+{
+ TInt r = KErrNone;
+
+ // save the transport interface
+ iTransport = aTransport;
+
+ // set the state
+ SetStatus( EInitialising );
+
+#ifndef LIGHT_MODE
+ // Under WINS we must force a link to the file server so that we're sure we'll be
+ // able to load the device drivers. On a MARM implementation, this code would not
+ // be required because higher level components (EIKON) will automatically have started
+ // the services. NOTE: this is now no longer required since we are an app and so even
+ // on WINS everything else should have started up by now.
+
+ // Load up the physical and the logical device drivers. If they are already loaded
+ // then it won't make any difference.
+ r = User::LoadPhysicalDevice( PDD_NAME );
+ if( (r != KErrNone) && (r != KErrAlreadyExists) ) {
+ User::Leave( r );
+ }
+ r = User::LoadLogicalDevice( LDD_NAME );
+ if( (r != KErrNone) && (r != KErrAlreadyExists) ) {
+ User::Leave( r );
+ }
+
+ // Both WINS and EIKON will have started the comms server process.
+ // (this is only really needed for ARM hardware development racks)
+#ifndef __WINS__
+ r = StartC32();
+ if( (r != KErrNone) && (r != KErrAlreadyExists) )
+ User::Leave( r );
+#endif
+#else // ifndef LIGHT_MODE
+
+ // Do a specific load of the library at this point.
+ r = serialDriverLib.Load(_L("SerialDriver.dll"));
+ if (r != KErrNone)
+ User::Leave( r );
+
+ iCommServer = OpenSerialServerL( );
+
+ if (iCommServer == NULL)
+ User::Leave( KErrNotFound );
+
+#endif // ifndef LIGHT_MODE
+
+ r = OnInitialiseL(r);
+
+ return (r);
+}
+
+/**************************************************************************************
+ *
+ * CStatApiSerial - OnInitialiseL
+ *
+ * Method added to allow for the seperation of InitialiseL into two parts.
+ * The first part is still InitialiseL. The second part is here and
+ * is either called directly or from the RunL callback.
+ *************************************************************************************/
+TInt CStatApiSerial::OnInitialiseL(TInt resultCode)
+{
+ TInt r = resultCode;
+
+ if (r >= 0 )
+ {
+#ifndef LIGHT_MODE
+ // Now connect to the comm server
+
+ User::LeaveIfError( iCommServer.Connect() );
+
+ // Load the CSY module
+ r = iCommServer.LoadCommModule( iModule );
+ User::LeaveIfError( r );
+
+ // check we loaded correctly
+ TInt numPorts;
+ r = iCommServer.NumPorts( numPorts );
+ User::LeaveIfError( r );
+#endif // ifndef LIGHT_MODE
+
+ // set the state
+ SetStatus( EInitialised );
+ }
+
+ return r;
+}
+
+TInt CStatApiSerial::Release(void)
+{
+ // make sure the status is as expected
+ asserte( (iSerialStatus == EInitialising) || (iSerialStatus == EInitialised) || (iSerialStatus == EDisconnected) );
+ SetStatus( EReleasing );
+
+ // disconnect from the comms server
+#ifndef LIGHT_MODE
+ iCommServer.Close();
+#else // ifndef LIGHT_MODE
+ if( NULL != iCommServer )
+ {
+ CloseSerialServer( iCommServer );
+ iCommServer = NULL;
+
+ // Here is an appropriate spot for releasing the library we need for stat-light
+ serialDriverLib.Close();
+
+ }
+#endif // ifndef LIGHT_MODE
+
+ // update state and finish
+ SetStatus( EIdle );
+ return KSTErrSuccess;
+}
+
+/**************************************************************************************
+ *
+ * CStatApiSerial - MStatNetwork - Connect and Close
+ *
+ *************************************************************************************/
+static int atoi( const short *str )
+{
+ int ret = 0;
+ for( int i = 0; str[i] != NULL; i++ ) {
+ ret *= 10;
+ ret += str[i] - '0';
+ }
+ return ret;
+}
+
+void CStatApiSerial::ExtractOptions( TDesC *aRemoteHost, TDes& aPortNumber, TInt& aBaudCap, TBps& aBaudRate )
+{
+ TInt baud;
+ short *delim;
+
+ // get the character array for the remote host (note that this is in unicode)
+ short *opt = (short*)aRemoteHost->Ptr();
+
+ int loop = 0;
+ while(opt[loop] != OPT_DELIMITER)
+ {
+ aPortNumber.Append(opt[loop]);
+ loop++;
+ }
+
+
+ // now search for the next delimiter and NULL it
+ for( delim = &opt[loop+1]; (*delim != NULL) && (*delim != OPT_DELIMITER); delim++ )
+ ;
+
+ // if this is a delim then NULL it
+ if( *delim == OPT_DELIMITER ) {
+ *delim = NULL;
+ }
+
+ // extract the baud -- and set the correct constants for the given baud
+ baud = atoi( &(opt[loop+1]) );
+ switch( baud ) {
+ case 115200:
+ aBaudRate = EBps115200;
+ aBaudCap = KCapsBps115200;
+ break;
+ case 38400:
+ aBaudRate = EBps38400;
+ aBaudCap = KCapsBps38400;
+ break;
+ case 19200:
+ aBaudRate = EBps19200;
+ aBaudCap = KCapsBps19200;
+ break;
+ case 9600:
+ aBaudRate = EBps9600;
+ aBaudCap = KCapsBps9600;
+ break;
+ default:
+ ;
+ break;
+ }
+}
+
+TInt CStatApiSerial::ConnectL( TDesC *aRemoteHost )
+{
+ TBuf<100> portNumber;
+ TInt baudCap;
+ TBps baudRate;
+
+#ifdef LIGHT_MODE
+ static const TInt KMaxPortName = 8;
+ TBool result = EFalse;
+#endif // ifndef LIGHT_MODE
+
+ // verify state
+ asserte( iSerialStatus == EInitialised );
+ SetStatus( EConnecting );
+
+ // I used to verify the address was valid here -- but this has now been moved
+ // to the UI. If it is nonsense then it will just throw an error so it's not
+ // dangerous. Error reporting is now good enough that I can remove this.
+
+ // extract the options from the string
+ ExtractOptions( aRemoteHost, portNumber, baudCap, baudRate );
+
+ // construct the address -- aRemoteHost should provide the COM port number
+
+ TBuf16<KMaxPortName + 4> portName;
+
+ //TInt err = portName.Num( portNumber );
+
+ TLex lNum = TLex(portNumber);
+ TInt lInt;
+
+ TInt err = lNum.Val(lInt);
+
+ if(err == KErrNone)
+ {
+
+ portName.Insert( 0, portNumber);
+ portName.Insert( 0, _L("::") );
+
+ asserte( EInvalid != iSubType );
+ if( SubType() == ESerialCable )
+ {
+ portName.Insert( 0, _L("COMM") );
+ }
+ else if( SubType() == EInfraRed )
+ {
+ portName.Insert( 0, _L("IrCOMM") );
+ }
+ }
+ else
+ {
+ //the port already contains the Type
+ portName.Insert( 0, portNumber);
+
+ }
+
+
+ // open the serial port
+#ifndef LIGHT_MODE
+
+ TInt r = iCommPort.Open( iCommServer, portName, ECommExclusive );
+ User::LeaveIfError( r );
+
+#else // ifndef LIGHT_MODE
+ iCommPort = OpenSerialPortL( iCommServer, portNumber[0]-'0' );
+
+ if( NULL == iCommPort )
+ {
+ User::Leave( KErrCouldNotConnect );
+ }
+#endif // ifndef LIGHT_MODE
+
+#ifndef LIGHT_MODE
+ // save port settings for restoring later
+ iCommPort.Config( iOldPortSettings );
+ iCommOldSettingsValid = 1;
+
+ // check our configuration is supported
+ TCommCaps ourCapabilities;
+ iCommPort.Caps( ourCapabilities );
+ if (((ourCapabilities ().iRate & baudCap) == 0) ||
+ ((ourCapabilities ().iDataBits & KCapsData8) == 0) ||
+ ((ourCapabilities ().iStopBits & KCapsStop1) == 0) ||
+ ((ourCapabilities ().iParity & KCapsParityNone) == 0))
+ {
+ User::Leave( KErrNotSupported );
+ }
+#endif // ifndef LIGHT_MODE
+
+ // set new port settings
+#ifndef LIGHT_MODE
+ iCommPort.Config( iPortSettings );
+#else
+ GetPortConfig (iCommPort, iPortSettings);
+#endif // ifndef LIGHT_MODE
+
+ iPortSettings().iRate = baudRate;
+ iPortSettings().iParity = EParityNone;
+ iPortSettings().iDataBits = EData8;
+ iPortSettings().iStopBits = EStop1;
+ iPortSettings().iFifo = EFifoEnable;
+// iPortSettings().iHandshake = KConfigFreeRTS | KConfigFreeDTR;
+ iPortSettings().iHandshake = KConfigObeyCTS;
+ iPortSettings().iTerminatorCount = 0;
+
+ // cancel any pending reads / writes to be safe and set the config
+#ifndef LIGHT_MODE
+ iCommPort.Cancel();
+#else // ifndef LIGHT_MODE
+ ReadCancel( iCommPort );
+ WriteCancel( iCommPort );
+
+#endif // ifndef LIGHT_MODE
+
+#ifndef LIGHT_MODE
+ r = iCommPort.SetConfig( iPortSettings );
+#else // ifndef LIGHT_MODE
+ TInt r = SetConfig( iCommPort, iPortSettings );
+#endif // ifndef LIGHT_MODE
+
+ if( r != KErrNone )
+ {
+ User::Leave(r);
+ }
+
+ // now turn on DTR and RTS, and set our buffer size
+// commPort.SetSignals (KSignalDTR, 0);
+// commPort.SetSignals (KSignalRTS, 0);
+
+ // set the receive buffer length then check it did it ok
+#ifndef LIGHT_MODE
+ iCommPort.SetReceiveBufferLength( 2*iMaxPacketSize );
+#else // ifndef LIGHT_MODE
+ result = SetReceiveBufferLength( iCommPort, 2*iMaxPacketSize );
+ if( ! result ) {
+ User::Leave(KErrUnknown);
+ }
+#endif // ifndef LIGHT_MODE
+
+ // check buffer size (use a relative check rather than
+ // an absolute check - if we get a bigger buffer than
+ // we asked for then that is no problem)
+ TInt size = 0;
+
+#ifndef LIGHT_MODE
+ size = iCommPort.ReceiveBufferLength();
+#else // ifndef LIGHT_MODE
+ result = ReceiveBufferLength( iCommPort, size );
+ if( ! result ) {
+ User::Leave(KErrUnknown);
+ }
+#endif // ifndef LIGHT_MODE
+
+ if( size < 2*iMaxPacketSize )
+ {
+ User::Leave( KErrTooBig );
+ }
+
+ // allocate enough memory to hold a data read
+ iRecvBuffer = HBufC8::New(iMaxPacketSize);
+ if( !iRecvBuffer ) {
+ User::Leave(KErrNoMemory);
+ }
+ iRecvBufferPtr = new TPtr8( iRecvBuffer->Des() );
+
+ // power up the serial port by doing a null read on the port
+ iRWStatus = EReadPending;
+#ifndef LIGHT_MODE
+ iCommPort.Read( iStatus, iDummyBuffer, 0);
+#else // ifndef LIGHT_MODE
+ Read( iCommPort, iStatus, KReadTimeout, iDummyBuffer, 0 );
+#endif // ifndef LIGHT_MODE
+ SetActive();
+
+ // return asynchronous
+ return KSTErrAsynchronous;
+}
+
+TInt CStatApiSerial::Disconnect(void)
+{
+ // verify the status
+ asserte( (iSerialStatus == EConnected) || (iSerialStatus == EConnecting) );
+ SetStatus( EDisconnecting );
+
+ // clean up the port
+#ifndef LIGHT_MODE
+ TInt sessionHandle = iCommPort.SubSessionHandle();
+ if( sessionHandle )
+ {
+ iCommPort.Cancel();
+ }
+ if( iCommOldSettingsValid )
+ iCommPort.SetConfig( iOldPortSettings );
+ if( sessionHandle )
+ {
+ iCommPort.Close();
+ }
+ sessionHandle = iCommPort.SubSessionHandle();
+ asserte(0 == sessionHandle);
+ iCommOldSettingsValid = 0;
+#else // ifndef LIGHT_MODE
+ if( NULL != iCommPort )
+ {
+ CloseSerialPort( iCommPort );
+ iCommPort = NULL;
+ }
+#endif // ifndef LIGHT_MODE
+
+ // release the data buffer
+ delete iRecvBufferPtr;
+ iRecvBufferPtr = NULL;
+ delete iRecvBuffer;
+ iRecvBuffer = NULL;
+
+ // done
+ SetStatus( EDisconnected );
+
+ return KSTErrSuccess;
+}
+
+/**************************************************************************************
+ *
+ * CStatApiSerial - MStatNetwork - Receive and Send. The ID / Length / Data nonsense
+ * is handled by the packetisation layer. All serial has to do here is send data --
+ * serial is also assuming that the upper layer will keep the data until the response
+ *
+ *************************************************************************************/
+TInt CStatApiSerial::RequestSend( TDesC8 *aData, const TUint aDataLength )
+{
+ // make sure we are in the appropriate state
+ asserte( iSerialStatus == EConnected );
+ asserte( iRWStatus == ENoRW );
+ iRWStatus = EWritePending;
+
+ // do the send
+ asserte( !IsActive() );
+ asserte( (unsigned)aData->Length() == aDataLength );
+#ifndef LIGHT_MODE
+ iCommPort.Write( iStatus, KWriteTimeout, (*aData), aDataLength );
+#else // ifndef LIGHT_MODE
+ Write( iCommPort, iStatus, KWriteTimeout, (*aData), aDataLength );
+#endif // ifndef LIGHT_MODE
+ SetActive();
+ return KSTErrAsynchronous;
+}
+
+TInt CStatApiSerial::RequestReceive( TUint aByteCount )
+{
+ // make sure we are in the appropriate state
+ asserte( iSerialStatus == EConnected );
+ asserte( iRWStatus == ENoRW );
+ iRWStatus = EReadPending;
+
+ // allocate a buffer for the read
+ asserte( aByteCount <= static_cast<TUint>(iMaxPacketSize) );
+ asserte( !IsActive() );
+ iRecvLength = aByteCount;
+ iRecvBufferPtr->SetLength( 0 );
+#ifndef LIGHT_MODE
+ iCommPort.ReadCancel();
+ iCommPort.Read( iStatus, KReadTimeout, *iRecvBufferPtr, aByteCount );
+#else // ifndef LIGHT_MODE
+ ReadCancel( iCommPort );
+ Read( iCommPort, iStatus, KReadTimeout, *iRecvBufferPtr, aByteCount );
+#endif // ifndef LIGHT_MODE
+ SetActive();
+ return KSTErrAsynchronous;
+}
+
+TInt CStatApiSerial::GetPacketSize()
+{
+ // The packet size is configured when we initialise the port.
+ return iMaxPacketSize;
+}
+
+TText8 *CStatApiSerial::Error( void )
+{
+ return NULL;
+}
+
+/**************************************************************************************
+ *
+ * CStatApiSerial - Active Object
+ *
+ *************************************************************************************/
+void CStatApiSerial::RunL( void )
+{
+ // cancels don't require any handling
+ if( iStatus == KErrCancel )
+ return;
+
+ // if timed out then reissue the read
+ if( (iStatus == KErrTimedOut) && (iRWStatus == EReadPending) ) {
+ asserte( iSerialStatus == EConnected );
+ asserte( iRWStatus == EReadPending );
+ iRetries++;
+#ifndef LIGHT_MODE
+ iCommPort.Read( iStatus, KReadTimeout, *iRecvBufferPtr, iRecvLength );
+#else // ifndef LIGHT_MODE
+ Read( iCommPort, iStatus, KReadTimeout, *iRecvBufferPtr, iRecvLength );
+#endif // ifndef LIGHT_MODE
+ SetActive();
+ return;
+ }
+ iRetries = 0;
+
+ // throw an error
+ if( iStatus != KErrNone ) {
+ iRWStatus = ENoRW;
+ iTransport->HandleError( iStatus.Int(), NULL );
+ }
+
+ // if we are in connecting state and have just done the null read then
+ // we are done and have connected
+ if( (iSerialStatus == EConnecting) && (iRWStatus == EReadPending) ) {
+ iRWStatus = ENoRW;
+ SetStatus( EConnected );
+ iTransport->HandleConnect( KErrNone );
+ return;
+ }
+
+
+ // if we are writing then notify of the write
+ if( iRWStatus == EWritePending ) {
+ iRWStatus = ENoRW;
+ iTransport->HandleSend( KErrNone );
+ return;
+ }
+
+ // if we are reading then notify of the read
+ if( iRWStatus == EReadPending ) {
+ TInt length = iRecvLength;
+ iRWStatus = ENoRW;
+ iRecvLength = 0;
+ iTransport->HandleReceive( KErrNone, iRecvBufferPtr, length );
+ return;
+ }
+}
+
+void CStatApiSerial::DoCancel( void )
+{
+ if( (iSerialStatus == EConnected) || (iSerialStatus == EConnecting) )
+ {
+#ifndef LIGHT_MODE
+ iCommPort.Cancel();
+#else // ifndef LIGHT_MODE
+ ReadCancel( iCommPort );
+ WriteCancel( iCommPort );
+#endif // ifndef LIGHT_MODE
+ }
+}
+
+/**************************************************************************************
+ *
+ * CStatApiSerial - Private Functions
+ *
+ *************************************************************************************/
+void CStatApiSerial::SetStatus( TCommStatus aNewStatus )
+{
+ iSerialStatus = aNewStatus;
+}
+
+/**************************************************************************************
+ *
+ * CStatApiSerial - DetermineSubTypeL
+ *
+ *************************************************************************************/
+void CStatApiSerial::DetermineSubTypeL()
+{
+
+
+ const TPtrC subTypes[ENumberOfSubTypes] = {
+ _L(""), // Invalid
+ _L("ECUART"), // Serial cable
+ _L("IrCOMM") // Infra-red
+ };
+
+ const TInt packetSize[ENumberOfSubTypes] = {
+ 0,
+ KMaxPacketSize,
+ KMaxPacketSize
+ };
+
+ TInt count;
+ for( count = 0; ( EInvalid == iSubType ) && ( count < ENumberOfSubTypes ); count++ )
+ {
+ if( 0 == ( iModule.Compare( subTypes[count] ) ) )
+ {
+ iSubType = static_cast<TSerialSubtype>(count);
+ iMaxPacketSize = packetSize[count];
+ }
+ }
+
+ if( EInvalid == iSubType )
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+}