diff -r 000000000000 -r 3e07fef1e154 testexecfw/statsrv/device/source/statapi/src/stat_engine.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testexecfw/statsrv/device/source/statapi/src/stat_engine.cpp Mon Mar 08 15:03:44 2010 +0800 @@ -0,0 +1,428 @@ +/* +* 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: +* +*/ + + + + /******************************************************************************** + * + * System Includes + * + ********************************************************************************/ +#include +#include + +/******************************************************************************** + * + * Local Includes + * + ********************************************************************************/ +#include "assert.h" +#include "stat.h" +#include "stat_engine.h" + +/******************************************************************************** + * + * Macro functions + * + ********************************************************************************/ + +/******************************************************************************** + * + * Definitions + * + ********************************************************************************/ +const TUint KSyncMax = 5; + +/******************************************************************************** + * + * CStatEngine -- construction + * + ********************************************************************************/ +CStatEngine *CStatEngine::NewL( MNotifyStatController *aController, RFs *const aSession, MNotifyLogMessage *const aMsg ) +{ + CStatEngine *self = new (ELeave) CStatEngine(); + CleanupStack::PushL( self ); + self->ConstructL( aController, aSession, aMsg ); + CleanupStack::Pop(); + return self; +} + +void CStatEngine::ConstructL( MNotifyStatController *aController, RFs *const aSession, MNotifyLogMessage *const aMsg ) +{ + // check params + asserte( aController != NULL ); + + // setup all params + iController = aController; + iEngineStatus = EIdle; + iRemoteHost = NULL; + iResyncCount = 0; + iFs = aSession; + iMsg = aMsg; + iCommandDecoder = CStatApiCommandDecoder::NewL( iFs, iMsg ); +} + +CStatEngine::CStatEngine() : iDataSupplier( NULL ), iMsg( NULL ), iFs( NULL ), iDeleteLastFile(EFalse) +{ +} + +CStatEngine::~CStatEngine() +{ + // clean up all params + if( iRemoteHost != NULL ) { + delete iRemoteHost; + } + delete iCommandDecoder; + + if(iDataSupplier) + { + iDataSupplier->Delete( ); + iDataSupplier = NULL; + } +} + +/******************************************************************************** + * + * CStatEngine -- MStatEngine implementation + * + ********************************************************************************/ +void CStatEngine::StartEngine( MStatApiTransport *aStatTransport, + TStatConnectType aConnectType, TDesC *aRemoteHost ) +{ + TInt exception, ret = KErrNone; + iTransport = aStatTransport; + + // save the remote host address string + iRemoteHost = new TPtrC( *aRemoteHost ); + + // create the message log + + // start the initialisation procedure the ugly second line means that if an + // exception is thrown the ret will have the exception, otherwise it will have + // the return code. Exceptions are always -ve and return values are always +ve + // so the two number spaces don't overlap (as zero means success in both). + iMsg->Msg( _L("ENGINE: Calling InitialiseL, %d (%S)."), aConnectType, aRemoteHost ); + SetState( EInitialising ); + TRAP( exception, (ret = iTransport->InitialiseL()) ); + ret = ((exception == KErrNone) ? ret : exception); + HandleStateChange( KOpInitialise, ret ); +} + +// the controller calls stop whenever he (yes the controller is male) wants the engine +// to arrange itself and the transport into a state where he can safetly shut it down. It +// can be called at any time -- i.e. when the engine is in any state. +void CStatEngine::StopEngine( void ) +{ + TInt exception, ret = KErrNone; + + switch( iEngineStatus ) { + + case EIdle: + ; + break; + + case EConnecting: + case EConnected: + case EReceivePending: + case ESendPending: + iMsg->Msg( _L("ENGINE: Calling Disconnect.") ); + SetState( EDisconnecting ); + TRAP( exception, (ret = iTransport->Disconnect()) ); + ret = ((exception == KErrNone) ? ret : exception); + HandleStateChange( KOpDisconnect, ret ); + break; + + case EDisconnecting: + case EDisconnected: + case EReleasing: + // nothing I can really do -- there is already a disconnect call + // pending -- just return and wait for notification -- or force + // disconnect by just deleting the object + break; + + case EInitialising: + case EInitialised: + ; + break; + case ELast: + ; + break; + } +} + +/******************************************************************************** + * + * CStatEngine - Higher level transport handling code. All errors and startup + * shutdown issues are handled by the MNotifyStatEngine implementation. + * + ********************************************************************************/ +void CStatEngine::OnConnect( void ) +{ + iMsg->Msg( _L("ENGINE: Waiting for next command.") ); + SetState( EReceivePending ); + TInt err = iTransport->RequestReceive(); + asserte( err == KSTErrAsynchronous ); +} + +void CStatEngine::OnRecvCommand( TUint aCommand, MDataConsumer *const aDataConsumer ) +{ + TInt err = KErrNone; + TInt dataLength = 0; + + if (aCommand == 'B') + iDeleteLastFile = EFalse; + else if (aCommand == 'S' || aCommand == 'X') + iDeleteLastFile = ETrue; + + // Clean up the old data supplier. + // If we are getting a command then it is safe to assume + // that everyone has finished with the old data supplier as + // they are valid only for the context of the current + // command. + if(iDataSupplier) + { + iDataSupplier->Delete( ); + iDataSupplier = NULL; + } + + // if this is a resync command then we have already done all we need to do so + // just return and wait for the next command. If we reach the maximum of + // resync commands disconnect and reset. + if( aCommand == RESYNC_ID ) { + iResyncCount++; + if( iResyncCount > KSyncMax ) { + iMsg->Msg( _L("ENGINE: Resync limit reached, calling Disconnect().") ); + SetState( EDisconnecting ); + err = iTransport->Disconnect(); + iMsg->Msg( _L("ENGINE: Synchronous response from Disconnect(%d)."), err ); + HandleStateChange( KOpDisconnect, err ); + } + SetState( ESendPending ); + return; + } + iResyncCount = 0; + + if(aCommand == REFRESH_ID) + { + SetState( EDisconnecting ); + err = iTransport->Disconnect(); + HandleStateChange( KOpDisconnect, err ); + SetState( ESendPending ); + + return; + } + + // otherwise execute the command + err = iCommandDecoder->ExecuteCommand( aCommand, aDataConsumer, &iDataSupplier ); + + if( err == KErrNone ) + { + if(iDataSupplier) + { + err = iDataSupplier->GetTotalSize( dataLength ); + } + } + + // if there was an error then the result code is FAILED_ID + if( err != KErrNone ) + { + aCommand = FAILED_ID; + } + + // now send the response and return + iMsg->Msg( _L("ENGINE: Sending reply (%c, %d)."), (char)aCommand, dataLength ); + SetState( ESendPending ); + err = iTransport->RequestSend( aCommand, iDataSupplier ); + asserte( err == KSTErrAsynchronous ); + + return; +} + +/******************************************************************************** + * + * CStatEngine -- MNotifyStatEngine implementation -- this is the lower level + * which maintains the startup / shutdown protocol with the transport to keep + * them happy and deal with the asynchronous behaviour. + * + ********************************************************************************/ +void CStatEngine::HandleStateChange( TStateOp aOperation, TInt aResult ) +{ + TPtrC opname[] = { _L("ENGINE: - response (%d)."), + _L("ENGINE: InitialiseL - response (%d)."), + _L("ENGINE: ConnectL - response (%d)."), + _L("ENGINE: Disconnect - response (%d)."), + _L("ENGINE: Release - response (%d).") }; + + iMsg->Msg( opname[aOperation], aResult ); + while( (aResult != KSTErrAsynchronous) ) { + if( aResult != KSTErrSuccess ) + iController->HandleError( aResult, NULL ); + HandleSingleStateChange( &aOperation, &aResult ); + iMsg->Msg( opname[aOperation], aResult ); + } +} + +void CStatEngine::HandleSingleStateChange( TStateOp *aOperation, TInt *aResult ) +{ + TStateOp thisOperation = *aOperation; + TInt exception, ret = KErrNone, thisResult = *aResult; + + // should never get in here with a result of async + asserte( *aResult != KSTErrAsynchronous ); + + // set the operation to none by default and asynchronous which will break out of the above loop + *aOperation = KOpNone; + *aResult = KSTErrAsynchronous; + + // handle each operation + switch( thisOperation ) { + + // if initialise failed then call release, otherwise call connect + case KOpInitialise: + if( thisResult == KSTErrSuccess ) { + SetState( EInitialised ); + *aOperation = KOpConnect; + SetState( EConnecting ); + TRAP( exception, (ret = iTransport->ConnectL(iRemoteHost)) ); + *aResult = ((exception == KErrNone) ? ret : exception); + } else { + *aOperation = KOpRelease; + SetState( EReleasing ); + *aResult = iTransport->Release(); + } + break; + + // if connect failed call disconnect, otherwise call the internal OnConnect function + case KOpConnect: + if( thisResult != KSTErrSuccess ) { + SetState( EDisconnecting ); + *aOperation = KOpDisconnect; + *aResult = iTransport->Disconnect(); + } else { + SetState( EConnected ); + OnConnect(); + } + break; + + // call release after disconnect regardless of result + case KOpDisconnect: + *aOperation = KOpRelease; + SetState( EReleasing ); + *aResult = iTransport->Release(); + break; + + // exit after release + case KOpRelease: + SetState( EIdle ); + break; + + case KOpNone: + ; + break; + } +} + +void CStatEngine::HandleInitialise( TInt aResult ) +{ + HandleStateChange( KOpInitialise, aResult ); +} + +void CStatEngine::HandleConnect( TInt aResult ) +{ + HandleStateChange( KOpConnect, aResult ); +} + +void CStatEngine::HandleDisconnect( TInt aResult ) +{ + HandleStateChange( KOpDisconnect, aResult ); +} + +void CStatEngine::HandleRelease( TInt aResult ) +{ + HandleStateChange( KOpRelease, aResult ); +} + +void CStatEngine::HandleSend( TInt aResult ) +{ + TInt err; + + // we must either be sending an ack or a response + asserte( iEngineStatus == ESendPending ); + + if (iDeleteLastFile) + { + iCommandDecoder->DeleteLastFile(); + iDeleteLastFile = EFalse; + } + // now that the reply has been sent wait for the next command + iMsg->Msg( _L("ENGINE: Reply sent (%d)."), aResult ); + iMsg->Msg( _L("ENGINE: Waiting for next command.") ); + asserte( iEngineStatus == ESendPending ); + SetState( EReceivePending ); + err = iTransport->RequestReceive(); + asserte( err == KSTErrAsynchronous ); +} + +void CStatEngine::HandleReceive( TInt aResult, const TUint aCommand, + MDataConsumer *const aDataConsumer ) +{ + // log the receipt + TInt dataLength = 0; + + if(aDataConsumer) + { + aDataConsumer->GetTotalSize( dataLength ); + } + iMsg->Msg( _L("ENGINE: Command Received (%d, %c, %d)."), aResult, (char)(aCommand), dataLength ); + + // verify that the engine state is as expected + asserte( iEngineStatus == EReceivePending ); + + // process the command + iMsg->Msg( _L("ENGINE: Processing command (%c)."), (char)(aCommand) ); + OnRecvCommand( aCommand, aDataConsumer ); +} + +void CStatEngine::HandleError( TInt aError, void* aErrorData ) +{ + // log the error + iMsg->Msg( _L("ENGINE: Error encountered (%d)."), aError ); + + // call the upper layers so that the UI can notify the user that an error has + // occured. + iController->HandleError( aError, aErrorData ); + + // on an error the engine takes the responsibility of closing itself down -- and + // then informing the controller than it can clean up the objects. + SetState( EDisconnecting ); + TInt err = iTransport->Disconnect(); + HandleStateChange( KOpDisconnect, err ); +} + +void CStatEngine::HandleInfo( const TDesC *aInfo ) +{ + iController->HandleInfo( aInfo ); +} + +void CStatEngine::SetState( TCommStatus aNewStatus ) +{ + // change the internal status and notify the controller of the change + iEngineStatus = aNewStatus; + asserte( iController != NULL ); + iController->HandleStatusChange( iEngineStatus ); +} +