hti/HtiServicePlugins/HtiStifTfServicePlugin/src/HtiStifTfIf.cpp
branchRCL_3
changeset 59 8ad140f3dd41
parent 0 a03f92240627
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hti/HtiServicePlugins/HtiStifTfServicePlugin/src/HtiStifTfIf.cpp	Wed Oct 13 16:17:58 2010 +0300
@@ -0,0 +1,2092 @@
+/*
+* Copyright (c) 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:  Implements the functions to control STIF Test Framework
+*                through the STIF TF interface.
+*
+*/
+
+
+
+// INCLUDE FILES
+#include <badesca.h>
+#include <bautils.h>
+#include <charconv.h>
+#include <e32cons.h>
+#include <HtiLogging.h>
+#include "HtiStifTfIf.h"
+
+// EXTERNAL DATA STRUCTURES
+
+// EXTERNAL FUNCTION PROTOTYPES
+
+// CONSTANTS
+
+// MACROS
+
+// LOCAL CONSTANTS AND MACROS
+const static TUid KStifTfServiceUid = { 0x10210CC3 };
+
+enum TStifTfCommands
+    {
+    ECmdOpen            = 0x01,
+    ECmdClose           = 0x02,
+    ECmdLoadModule      = 0x03,
+    ECmdUnloadModule    = 0x04,
+    ECmdListCases       = 0x05,
+    ECmdStartCase       = 0x06,
+    ECmdCancelCase      = 0x07,
+    ECmdPauseCase       = 0x08,
+    ECmdResumeCase      = 0x09,
+    ECmdAddCaseFile     = 0x0A,
+    ECmdRemoveCaseFile  = 0x0B,
+    ECmdCaseMsg         = 0x0C,
+    ECmdSetDevId        = 0x0D,
+    ECmdTestCompleted   = 0x0E,
+    ECmdAtsMessage      = 0x0F,
+    ECmdSetAttribute    = 0x10
+    };
+
+_LIT8( KParameterDelimiter, "|" );
+
+// NOTE: Max length for error description is defined
+// in HtiDispatcherInterface.h (currently 118).
+_LIT8( KErrorStifTfNotOpen, "ERROR: STIF TF is not open" );
+_LIT8( KErrorOpen, "ERROR: Failed to open STIF TF" );
+_LIT8( KErrorAlreadyOpen, "ERROR: STIF TF is already open" );
+_LIT8( KErrorClose, "ERROR: Failed to close STIF TF" );
+_LIT8( KErrorUnknownCmd, "ERROR: Unknown STIF TF command" );
+_LIT8( KErrorNoCmd, "ERROR: No command given" );
+_LIT8( KErrorParameterMissing, "ERROR: Mandatory parameter missing" );
+_LIT8( KErrorParameterTooLong, "ERROR: Parameter too long" );
+_LIT8( KErrorTooManyParameters, "ERROR: Too many parameters" );
+_LIT8( KErrorNoMemory, "ERROR: Memory allocation failure" );
+_LIT8( KErrorLoadModule, "ERROR: Load Module failed" );
+_LIT8( KErrorUnloadModule, "ERROR: Unload Module failed" );
+_LIT8( KErrorInvalidCaseNumber, "ERROR: Invalid test case number parameter" );
+_LIT8( KErrorModuleNotLoaded, "ERROR: Given test module is not loaded" );
+_LIT8( KErrorGetTestCases, "ERROR: Failed to get test cases from module" );
+_LIT8( KErrorGetTestCaseInfos, "ERROR: Failed to get test case infos" );
+_LIT8( KErrorStartTestCase, "ERROR: Failed to start test case" );
+_LIT8( KErrorCancelTestCase, "ERROR: Failed to cancel test case" );
+_LIT8( KErrorPauseTestCase, "ERROR: Failed to pause test case" );
+_LIT8( KErrorResumeTestCase, "ERROR: Failed to resume test case" );
+_LIT8( KErrorInvalidDeviceId, "ERROR: Invalid device ID parameter" );
+_LIT8( KErrorAddCaseFile, "ERROR: Add Case File failed" );
+_LIT8( KErrorRemoveCaseFile, "ERROR: Remove Case File failed" );
+_LIT8( KErrorFileServer, "ERROR: Failed to connect to file server" );
+_LIT8( KErrorCaseFileNotFound, "ERROR: Given test case file was not found" );
+_LIT8( KErrorIniFileNotFound, "ERROR: Given ini-file was not found" );
+_LIT8( KErrorCaseMessage, "ERROR: Test case message sending failed" );
+_LIT8( KErrorCharConv, "ERROR: Character conversion failed" );
+_LIT8( KErrorInvalidAttributeId, "ERROR: Invalid attribute id parameter" );
+_LIT8( KErrorSetAttribute, "ERROR: Failed to set attribute" );
+_LIT8( KErrorUnknown, "ERROR: Unspecified error occured" );
+
+// MODULE DATA STRUCTURES
+
+// LOCAL FUNCTION PROTOTYPES
+
+// FORWARD DECLARATIONS
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::CHtiStifTfIf
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CHtiStifTfIf::CHtiStifTfIf():iIsBusy( EFalse ),
+                             iMessage( NULL ),
+                             iErrorCode( 0 ),
+                             iStifTfOpen( EFalse ),
+                             iDevId( KDefaultDevId ),
+                             iConsole( NULL )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::ConstructL( CHtiStifTfServicePlugin* aPlugin )
+    {
+    iCommandId = 0;
+    iParameters = new (ELeave) CDesC8ArrayFlat( 5 );
+    iPlugin = aPlugin;
+    }
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CHtiStifTfIf* CHtiStifTfIf::NewL( CHtiStifTfServicePlugin* aPlugin )
+    {
+    CHtiStifTfIf* self = new( ELeave ) CHtiStifTfIf;
+    CleanupStack::PushL( self );
+    self->ConstructL( aPlugin );
+    CleanupStack::Pop();
+    return self;
+    }
+
+
+// Destructor
+CHtiStifTfIf::~CHtiStifTfIf()
+    {
+    if ( iParameters )
+        {
+        iParameters->Reset();
+        }
+    delete iParameters;
+    iLoadedInfos.ResetAndDestroy();
+    iLoadedInfos.Close();
+    delete iMessage;
+    if ( iStifTfOpen ) Close();
+    iPlugin = NULL;  // Not owned, so not deleted.
+    iConsole = NULL; // Not owned, so not deleted.
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::ProcessMessageL
+// Interpretes the message and calls appropriate command handling method.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::ProcessMessageL( const TDesC8& aMessage,
+    THtiMessagePriority /*aPriority*/)
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::ProcessMessageL" );
+    HTI_LOG_FORMAT( "Message length = %d", aMessage.Length() );
+
+    if ( iIsBusy )
+        {
+        HTI_LOG_TEXT( "Plugin is busy - leaving" );
+        User::Leave( KErrInUse );
+        }
+
+    iIsBusy = ETrue;
+
+    if ( aMessage.Length() < 1 )
+        {
+        User::LeaveIfError(
+            SendErrorResponseMsg( KErrArgument, KErrorNoCmd ) );
+        return;
+        }
+
+    iCommandId = aMessage[0];
+    HTI_LOG_FORMAT( "Command = %d", iCommandId );
+
+    TRAPD( err, ParseParametersL( aMessage ) );
+
+    if ( err == KErrNoMemory )
+        {
+        User::LeaveIfError( SendErrorResponseMsg( err, KErrorNoMemory ) );
+        return;
+        }
+
+    else if ( err )
+        {
+        User::LeaveIfError(
+            SendErrorResponseMsg( KErrGeneral, KErrorUnknown ) );
+        return;
+        }
+
+    // If STIF TF is not open, any other command than OPEN returns KErrNotReady
+    if ( !iStifTfOpen )
+        {
+        if ( iCommandId == ECmdOpen )
+            {
+            HandleOpenCmdL();
+            return;
+            }
+        else
+            {
+            User::LeaveIfError(
+                SendErrorResponseMsg( KErrNotReady, KErrorStifTfNotOpen ) );
+            return;
+            }
+        }
+
+
+    // Go through the rest of the commands
+    if ( iCommandId == ECmdLoadModule )
+        {
+        HandleLoadModuleCmdL();
+        }
+
+    else if ( iCommandId == ECmdUnloadModule )
+        {
+        HandleUnloadModuleCmdL();
+        }
+
+    else if ( iCommandId == ECmdListCases )
+        {
+        HandleListCasesCmdL();
+        }
+
+    else if ( iCommandId == ECmdStartCase )
+        {
+        HandleStartCaseCmdL();
+        }
+
+    else if ( iCommandId == ECmdCancelCase )
+        {
+        HandleCancelCaseCmdL();
+        }
+
+    else if ( iCommandId == ECmdPauseCase )
+        {
+        HandlePauseCaseCmdL();
+        }
+
+    else if ( iCommandId == ECmdResumeCase )
+        {
+        HandleResumeCaseCmdL();
+        }
+
+    else if ( iCommandId == ECmdAddCaseFile )
+        {
+        HandleAddCaseFileCmdL();
+        }
+
+    else if ( iCommandId == ECmdRemoveCaseFile )
+        {
+        HandleRemoveCaseFileCmdL();
+        }
+
+    else if ( iCommandId == ECmdCaseMsg )
+        {
+        HandleCaseMsgCmdL();
+        }
+
+    else if ( iCommandId == ECmdSetDevId )
+        {
+        HandleSetDevIdCmdL();
+        }
+
+    else if ( iCommandId == ECmdSetAttribute )
+        {
+        HandleSetAttributeCmdL();
+        }
+
+    else if ( iCommandId == ECmdClose )
+        {
+        HandleCloseCmdL();
+        }
+
+    else if ( iCommandId == ECmdOpen )
+        {
+        User::LeaveIfError(
+            SendErrorResponseMsg( KErrArgument, KErrorAlreadyOpen ) );
+        }
+
+    else
+        {
+        User::LeaveIfError(
+            SendErrorResponseMsg( KErrArgument, KErrorUnknownCmd ) );
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::ProcessMessageL" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::HandleOpenCmdL
+// Handles opening of the STIF Test Framework.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::HandleOpenCmdL()
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::HandleOpenCmdL" );
+
+    TInt err = KErrNone;
+
+    // OPEN command has 1 optional parameter (test framework ini-file)
+    if ( iParameters->Count() == 0 )
+        {
+        err = Open();
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorOpen );
+            return;
+            }
+
+        iStifTfOpen = ETrue;
+        SendResponseMsg( _L8( "OK" ) );
+        }
+
+    else if ( iParameters->Count() == 1 )
+        {
+        TBuf<KMaxFileName> iniFilePath;
+        if ( (*iParameters)[0].Length() > iniFilePath.MaxLength() )
+            {
+            SendErrorResponseMsg( KErrArgument, KErrorParameterTooLong );
+            return;
+            }
+
+        iniFilePath.Copy( (*iParameters)[0] );
+
+        RFs fsSession;
+        err = fsSession.Connect();
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorFileServer );
+            return;
+            }
+
+        if ( !( BaflUtils::FileExists( fsSession, iniFilePath ) ) )
+            {
+            SendErrorResponseMsg( KErrNotFound, KErrorIniFileNotFound );
+            fsSession.Close();
+            return;
+            }
+
+        fsSession.Close();
+
+        err = Open( iniFilePath );
+
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorOpen );
+            return;
+            }
+
+        // Load the test case infos of all currently loaded test
+        // modules (modules listed in the given ini-file).
+        TRAP( err, LoadTestCaseInfosL() );
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorGetTestCaseInfos );
+            return;
+            }
+
+        iStifTfOpen = ETrue;
+        SendResponseMsg( _L8( "OK" ) );
+        }
+
+    else
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorTooManyParameters );
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::HandleOpenCmdL" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::HandleCloseCmdL
+// Closes the STIF Test Framework.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::HandleCloseCmdL()
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::HandleCloseCmdL" );
+
+    TInt err = KErrNone;
+
+    // CLOSE command has no parameters
+    if ( iParameters->Count() == 0 )
+        {
+        err = Close();
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorClose );
+            return;
+            }
+
+        iStifTfOpen = EFalse;
+        iLoadedInfos.ResetAndDestroy(); // empty the cache of test case infos
+        SendResponseMsg( _L8( "OK" ) );
+        }
+
+    else
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorTooManyParameters );
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::HandleCloseCmdL" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::HandleLoadModuleCmdL
+// Loads a STIF TF test module (optionally with ini-file).
+// Also calls the LoadTestCaseInfosL helper method to load the test case info
+// objects from the test module.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::HandleLoadModuleCmdL()
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::HandleLoadModuleCmdL" );
+
+    TInt err = KErrNone;
+
+    TBuf<KMaxFileName> moduleName;
+    TBuf<KMaxFileName> iniFilePath;
+
+    // LOAD_MODULE command has 1 mandatory parameter (module name)
+    // and 1 optional parameter (ini-file path).
+    if ( iParameters->Count() == 0 )
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorParameterMissing );
+        return;
+        }
+
+    else if ( iParameters->Count() == 1 )
+        {
+        if ( (*iParameters)[0].Length() > moduleName.MaxLength() )
+            {
+            SendErrorResponseMsg( KErrArgument, KErrorParameterTooLong );
+            return;
+            }
+        moduleName.Copy( (*iParameters)[0] );
+        err = AddTestModule( moduleName );
+        }
+
+    else if ( iParameters->Count() == 2 )
+        {
+        if ( (*iParameters)[0].Length() > moduleName.MaxLength() ||
+             (*iParameters)[1].Length() > iniFilePath.MaxLength() )
+            {
+            SendErrorResponseMsg( KErrArgument, KErrorParameterTooLong );
+            return;
+            }
+
+        moduleName.Copy( (*iParameters)[0] );
+        iniFilePath.Copy( (*iParameters)[1] );
+
+        RFs fsSession;
+        err = fsSession.Connect();
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorFileServer );
+            return;
+            }
+
+        if ( !( BaflUtils::FileExists( fsSession, iniFilePath ) ) )
+            {
+            SendErrorResponseMsg( KErrNotFound, KErrorIniFileNotFound );
+            fsSession.Close();
+            return;
+            }
+
+        fsSession.Close();
+
+        err = AddTestModule( moduleName, iniFilePath );
+        }
+
+    else
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorTooManyParameters );
+        return;
+        }
+
+    if ( err )
+        {
+        HTI_LOG_FORMAT( "LoadModule: Error %d", err );
+        SendErrorResponseMsg( err, KErrorLoadModule );
+        }
+
+    else
+        {
+        TRAP( err, LoadTestCaseInfosL( moduleName ) );
+
+        if ( err )
+            {
+            HTI_LOG_FORMAT(
+                "LoadModule - Error from LoadTestCaseInfosL %d", err );
+            RemoveTestModule( moduleName );
+            SendErrorResponseMsg( err, KErrorGetTestCases );
+            return;
+            }
+
+        // Sends the name of the loaded module as a response.
+        SendResponseMsg( (*iParameters)[0] );
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::HandleLoadModuleCmdL" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::HandleUnloadModuleCmdL
+// Unloads a STIF TF test module.
+// Also removes and deletes the corresponding CHtiTestModuleCaseInfos object
+// from iLoadedInfos pointer array.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::HandleUnloadModuleCmdL()
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::HandleUnloadModuleCmdL" );
+
+    TInt err = KErrNone;
+
+    TBuf<KMaxFileName> moduleName;
+
+    // UNLOAD_MODULE command has always 1 parameter (module name).
+    if ( iParameters->Count() == 0 )
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorParameterMissing );
+        return;
+        }
+
+    if ( iParameters->Count() == 1 )
+        {
+        if ( (*iParameters)[0].Length() > moduleName.MaxLength() )
+            {
+            SendErrorResponseMsg( KErrArgument, KErrorParameterTooLong );
+            return;
+            }
+        moduleName.Copy( (*iParameters)[0] );
+        err = RemoveTestModule( moduleName );
+        }
+
+    else
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorTooManyParameters );
+        return;
+        }
+
+    if ( err )
+        {
+        HTI_LOG_FORMAT( "UnloadModule: Error %d", err );
+        SendErrorResponseMsg( err, KErrorUnloadModule );
+        }
+
+    else
+        {
+        // Remove the test case infos of the unloaded module.
+        TInt moduleIndex = IndexByModuleName( moduleName );
+        if ( moduleIndex != KErrNotFound )
+            {
+            CHtiTestModuleCaseInfos* module = iLoadedInfos[moduleIndex];
+            iLoadedInfos.Remove( moduleIndex );
+            delete module;
+            }
+
+        // Sends the name of the unloaded module as a response.
+        SendResponseMsg( (*iParameters)[0] );
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::HandleUnloadModuleCmdL" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::HandleListCasesCmdL
+// Creates a list of titles of the test cases inside the given test module.
+// Output is a string of test case titles separated with the | character.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::HandleListCasesCmdL()
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::HandleListCasesCmdL" );
+
+    TInt err = KErrNone;
+
+    TBuf<KMaxFileName> moduleName;
+    TBuf8<128> buf8;  // temporary buffer for case titles
+
+    CHtiTestModuleCaseInfos* module = NULL;
+    CTestInfo* caseInfo = NULL;
+
+    // LIST_CASES command has 1 optional parameter (module name).
+
+    // If no parameter given all cases of all currently loaded
+    // modules are listed.
+    if ( iParameters->Count() == 0 )
+        {
+        /*
+        // (Re)load case infos from all loaded modules
+        TRAP( err, LoadTestCaseInfosL() );
+
+        if ( err )
+            {
+            HTI_LOG_FORMAT(
+                "ListCases - Error from LoadTestCaseInfosL %d", err );
+            SendErrorResponseMsg( err, KErrorGetTestCaseInfos );
+            }
+        */
+        CBufFlat* caseListBuf = NULL;
+        TRAP( err, caseListBuf = CBufFlat::NewL( 128 ) );
+        if ( err )
+            {
+            SendErrorResponseMsg( KErrNoMemory, KErrorNoMemory );
+            return;
+            }
+
+        // Loop all loaded test modules
+        TInt pos = 0;
+        for ( TInt i = 0; i < iLoadedInfos.Count(); i++ )
+            {
+            module = NULL;
+            module = iLoadedInfos[i];
+            HTI_LOG_FORMAT( "Listing cases from module %S",
+                module->iModuleName );
+
+            // Loop all case infos in this module
+            for ( TInt j = 0; j < module->iTestInfos.Count(); j++ )
+                {
+                caseInfo = NULL;
+                caseInfo = module->iTestInfos[j];
+
+                if ( !( i == 0 && j == 0 ) )
+                    {
+                    buf8.Append( KParameterDelimiter );
+                    }
+
+                buf8.Append( caseInfo->TestCaseTitle() );
+
+                TRAP( err, caseListBuf->ExpandL( pos, buf8.Length() ) );
+                if ( err )
+                    {
+                    SendErrorResponseMsg( KErrNoMemory, KErrorNoMemory );
+                    delete caseListBuf;
+                    return;
+                    }
+                caseListBuf->Write( pos, buf8, buf8.Length() );
+                pos += buf8.Length();
+                buf8.Zero();
+                }
+            }
+
+        if ( caseListBuf->Size() > 0 )
+            {
+            TPtr8 ptr = caseListBuf->Ptr( 0 );
+            SendResponseMsg( ptr );
+            }
+
+        else
+            {
+            SendResponseMsg( buf8 );
+            }
+
+        delete caseListBuf;
+        }
+
+    else if ( iParameters->Count() == 1 )
+        {
+        if ( (*iParameters)[0].Length() > moduleName.MaxLength() )
+            {
+            SendErrorResponseMsg( KErrArgument, KErrorParameterTooLong );
+            return;
+            }
+
+        moduleName.Copy( (*iParameters)[0] );
+        TInt moduleIndex = IndexByModuleName( moduleName );
+
+        if ( moduleIndex == KErrNotFound )
+            {
+            HTI_LOG_TEXT( "Module is not loaded" );
+            SendErrorResponseMsg( KErrNotFound, KErrorModuleNotLoaded );
+            return;
+            }
+        /*
+        // (Re)load the case infos of given module
+        TRAP( err, LoadTestCaseInfosL( moduleName ) );
+        if ( err )
+            {
+            HTI_LOG_FORMAT(
+                "ListCases - Error from LoadTestCaseInfosL %d", err );
+            SendErrorResponseMsg( err, KErrorGetTestCaseInfos );
+            return;
+            }
+        */
+        module = iLoadedInfos[moduleIndex];
+        CBufFlat* caseListBuf = NULL;
+
+        TRAP( err, caseListBuf = CBufFlat::NewL( 128 ) );
+
+        if ( err )
+            {
+            SendErrorResponseMsg( KErrNoMemory, KErrorNoMemory );
+            return;
+            }
+
+        TInt pos = 0;
+        for ( TInt i = 0; i < module->iTestInfos.Count(); i++ )
+            {
+            caseInfo = NULL;
+            caseInfo = module->iTestInfos[i];
+            buf8.Copy( caseInfo->TestCaseTitle() );
+            if ( !( i == module->iTestInfos.Count() - 1 ) )
+                {
+                buf8.Append( KParameterDelimiter );
+                }
+            TRAP( err, caseListBuf->ExpandL( pos, buf8.Length() ) );
+            if ( err )
+                {
+                SendErrorResponseMsg( KErrNoMemory, KErrorNoMemory );
+                delete caseListBuf;
+                return;
+                }
+            caseListBuf->Write( pos, buf8, buf8.Length() );
+            pos += buf8.Length();
+            buf8.Zero();
+            }
+
+        if ( module->iTestInfos.Count() > 0 )
+            {
+            TPtr8 ptr = caseListBuf->Ptr( 0 );
+            SendResponseMsg( ptr );
+            }
+
+        else
+            {
+            SendResponseMsg( buf8 );
+            }
+
+        delete caseListBuf;
+        }
+
+    else
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorTooManyParameters );
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::HandleListCasesCmdL" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::HandleStartCaseCmdL
+// Starts one test case based on test module name and test case index number.
+// STIF TF gives an ID to the started case and that ID is sent as a response
+// message.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::HandleStartCaseCmdL()
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::HandleStartCaseCmdL" );
+
+    TInt err = KErrNone;
+    TInt caseNumber = -1;
+
+    // START_CASE command has 1 or 2 parameters.
+    // If only one parameter given, it's the index of test case to start. The
+    // index refers to the list of test cases of all currently loaded modules.
+    // If two parameters given, then the first one is the module name and
+    // second is the test case index number inside the given module,
+
+    if ( iParameters->Count() == 0 )
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorParameterMissing );
+        return;
+        }
+
+    else if ( iParameters->Count() == 1 )
+        {
+        TLex8 lex( (*iParameters)[0] );
+        err = lex.Val( caseNumber );
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorInvalidCaseNumber );
+            return;
+            }
+
+        CTestInfo* caseInfo = NULL;
+        TRAP( err, caseInfo = GetCaseInfoL( caseNumber ) );
+
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorInvalidCaseNumber );
+            return;
+            }
+
+        TInt caseId = -1;
+
+        err = StartTestCase( caseId, *caseInfo );
+
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorStartTestCase );
+            return;
+            }
+
+        TBuf8<32> msg;
+        msg.AppendNum( caseId );
+        SendResponseMsg( msg );
+        }
+
+    else if ( iParameters->Count() == 2 )
+        {
+        TBuf<KMaxFileName> moduleName;
+        if ( (*iParameters)[0].Length() > moduleName.MaxLength() )
+            {
+            SendErrorResponseMsg( KErrArgument, KErrorParameterTooLong );
+            return;
+            }
+
+        moduleName.Copy( (*iParameters)[0] );
+        TLex8 lex( (*iParameters)[1] );
+        err = lex.Val( caseNumber );
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorInvalidCaseNumber );
+            return;
+            }
+
+        TInt moduleIndex = IndexByModuleName( moduleName );
+
+        if ( moduleIndex == KErrNotFound )
+            {
+            // We don't have case infos of given module loaded - try to
+            // load them.
+            TRAP( err, LoadTestCaseInfosL( moduleName ) );
+            if ( err )
+                {
+                HTI_LOG_FORMAT(
+                    "StartCase - Error from LoadTestCaseInfosL %d", err );
+                SendErrorResponseMsg( err, KErrorModuleNotLoaded );
+                return;
+                }
+            // Now there should be the module added - get its index
+            moduleIndex = IndexByModuleName( moduleName );
+            }
+
+        CHtiTestModuleCaseInfos* module = iLoadedInfos[moduleIndex];
+
+        if ( caseNumber < 0 ||
+             caseNumber >= module->iTestInfos.Count() ||
+             module->iTestInfos.Count() == 0 )
+            {
+            SendErrorResponseMsg( KErrArgument, KErrorInvalidCaseNumber );
+            return;
+            }
+
+        CTestInfo* caseInfo = module->iTestInfos[caseNumber];
+        TInt caseId = -1;
+
+        err = StartTestCase( caseId, *caseInfo );
+
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorStartTestCase );
+            return;
+            }
+
+        TBuf8<32> msg;
+        msg.AppendNum( caseId );
+        SendResponseMsg( msg );
+        }
+
+    else
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorTooManyParameters );
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::HandleStartCaseCmdL" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::HandleCancelCaseCmdL
+// Cancels test case execution based on test case ID.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::HandleCancelCaseCmdL()
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::HandleCancelCaseCmdL" );
+
+    TInt err = KErrNone;
+
+    // CANCEL_CASE command always has 1 parameter (test case id).
+    if ( iParameters->Count() == 0 )
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorParameterMissing );
+        return;
+        }
+
+    else if ( iParameters->Count() == 1 )
+        {
+        TInt caseId = -1;
+        TLex8 lex( (*iParameters)[0] );
+        err = lex.Val( caseId );
+
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorInvalidCaseNumber );
+            return;
+            }
+
+        err = CancelTestCase( caseId );
+
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorCancelTestCase );
+            }
+
+        else
+            {
+            SendResponseMsg( _L8( "OK" ) );
+            }
+        }
+
+    else
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorTooManyParameters );
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::HandleCancelCaseCmdL" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::HandlePauseCaseCmdL
+// Pauses test case execution based on test case ID.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::HandlePauseCaseCmdL()
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::HandlePauseCaseCmdL" );
+
+    TInt err = KErrNone;
+
+    // PAUSE_CASE command always has 1 parameter (test case id).
+    if ( iParameters->Count() == 0 )
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorParameterMissing );
+        return;
+        }
+
+    else if ( iParameters->Count() == 1 )
+        {
+        TInt caseId = -1;
+        TLex8 lex( (*iParameters)[0] );
+        err = lex.Val( caseId );
+
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorInvalidCaseNumber );
+            return;
+            }
+
+        err = PauseTestCase( caseId );
+
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorPauseTestCase );
+            }
+
+        else
+            {
+            SendResponseMsg( _L8( "OK" ) );
+            }
+        }
+
+    else
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorTooManyParameters );
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::HandlePauseCaseCmdL" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::HandleResumeCaseCmdL
+// Resumes execution of a paused test case based on test case ID.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::HandleResumeCaseCmdL()
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::HandleResumeCaseCmdL" );
+
+    TInt err = KErrNone;
+
+    // RESUME_CASE command always has 1 parameter (test case id).
+    if ( iParameters->Count() == 0 )
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorParameterMissing );
+        return;
+        }
+
+    else if ( iParameters->Count() == 1 )
+        {
+        TInt caseId = -1;
+        TLex8 lex( (*iParameters)[0] );
+        err = lex.Val( caseId );
+
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorInvalidCaseNumber );
+            return;
+            }
+
+        err = ResumeTestCase( caseId );
+
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorResumeTestCase );
+            }
+
+        else
+            {
+            SendResponseMsg( _L8( "OK" ) );
+            }
+        }
+
+    else
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorTooManyParameters );
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::HandleResumeCaseCmdL" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::HandleAddCaseFileCmdL
+// Adds a test case file to an earlier loaded test module.
+// Checks that the module is loaded and that the given test case file exists.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::HandleAddCaseFileCmdL()
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::HandleAddCaseFileCmdL" );
+
+    TInt err = KErrNone;
+
+    TBuf<KMaxFileName> moduleName;
+    TBuf<KMaxFileName> caseFilePath;
+
+    // ADD_CASE_FILE command always has 2 mandatory parameters (module name
+    // and test case file path).
+    if ( iParameters->Count() == 0 || iParameters->Count() == 1 )
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorParameterMissing );
+        return;
+        }
+
+    else if ( iParameters->Count() == 2 )
+        {
+        if ( (*iParameters)[0].Length() > moduleName.MaxLength() ||
+             (*iParameters)[1].Length() > caseFilePath.MaxLength() )
+            {
+            SendErrorResponseMsg( KErrArgument, KErrorParameterTooLong );
+            return;
+            }
+
+        moduleName.Copy( (*iParameters)[0] );
+        caseFilePath.Copy( (*iParameters)[1] );
+
+        RFs fsSession;
+        err = fsSession.Connect();
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorFileServer );
+            return;
+            }
+
+        if ( !( BaflUtils::FileExists( fsSession, caseFilePath ) ) )
+            {
+            SendErrorResponseMsg( KErrNotFound, KErrorCaseFileNotFound );
+            fsSession.Close();
+            return;
+            }
+
+        fsSession.Close();
+
+        err = AddTestCaseFile( moduleName, caseFilePath );
+
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorAddCaseFile );
+            return;
+            }
+
+        // Test case file has been added - update test case infos
+        TRAP( err, LoadTestCaseInfosL( moduleName ) );
+
+        if ( err )
+            {
+            HTI_LOG_FORMAT(
+                "AddCaseFile - Error from LoadTestCaseInfosL %d", err );
+            SendErrorResponseMsg( err, KErrorGetTestCases );
+            return;
+            }
+
+        SendResponseMsg( _L8( "OK" ) );
+        }
+
+    else
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorTooManyParameters );
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::HandleAddCaseFileCmdL" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::HandleRemoveCaseFileCmdL
+// Removes a test case file from test module.
+// Checks that the module is loaded and that the given test case file exists.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::HandleRemoveCaseFileCmdL()
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::HandleRemoveCaseFileCmdL" );
+
+    TInt err = KErrNone;
+
+    TBuf<KMaxFileName> moduleName;
+    TBuf<KMaxFileName> caseFilePath;
+
+    // REMOVE_CASE_FILE command always has 2 mandatory parameters (module name
+    // and test case file path).
+    if ( iParameters->Count() == 0 || iParameters->Count() == 1 )
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorParameterMissing );
+        return;
+        }
+
+    else if ( iParameters->Count() == 2 )
+        {
+        if ( (*iParameters)[0].Length() > moduleName.MaxLength() ||
+             (*iParameters)[1].Length() > caseFilePath.MaxLength() )
+            {
+            SendErrorResponseMsg( KErrArgument, KErrorParameterTooLong );
+            return;
+            }
+
+        moduleName.Copy( (*iParameters)[0] );
+        caseFilePath.Copy( (*iParameters)[1] );
+
+        RFs fsSession;
+        err = fsSession.Connect();
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorFileServer );
+            return;
+            }
+
+        if ( !( BaflUtils::FileExists( fsSession, caseFilePath ) ) )
+            {
+            SendErrorResponseMsg( KErrNotFound, KErrorCaseFileNotFound );
+            fsSession.Close();
+            return;
+            }
+
+        fsSession.Close();
+
+        err = RemoveTestCaseFile( moduleName, caseFilePath );
+
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorRemoveCaseFile );
+            return;
+            }
+
+        // Test case file has been removed - update test case infos
+        TRAP( err, LoadTestCaseInfosL( moduleName ) );
+
+        if ( err )
+            {
+            HTI_LOG_FORMAT(
+                "RemoveCaseFile - Error from LoadTestCaseInfosL %d", err );
+            SendErrorResponseMsg( err, KErrorGetTestCases );
+            return;
+            }
+
+        SendResponseMsg( _L8( "OK" ) );
+        }
+
+    else
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorTooManyParameters );
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::HandleRemoveCaseFileCmdL" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::HandleCaseMsgCmdL
+// Sends a message to STIF Test Framework.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::HandleCaseMsgCmdL()
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::HandleCaseMsgCmdL" );
+
+    TInt err = KErrNone;
+
+    // CASE_MESSAGE command always has 1 parameter (the message).
+    if ( iParameters->Count() == 0 )
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorParameterMissing );
+        return;
+        }
+
+    else if ( iParameters->Count() == 1 )
+        {
+        HBufC* msg = HBufC::New( (*iParameters)[0].Length() );
+        if ( msg == NULL )
+            {
+            SendErrorResponseMsg( KErrNoMemory, KErrorNoMemory );
+            return;
+            }
+        msg->Des().Copy( (*iParameters)[0] );
+        HTI_LOG_TEXT( "Sending case message:" );
+        HTI_LOG_DES( *msg );
+        err = AtsReceive( *msg );
+        delete msg;
+
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorCaseMessage );
+            }
+
+        else
+            {
+            SendResponseMsg( _L8( "OK" ) );
+            }
+        }
+
+    else
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorTooManyParameters );
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::HandleCaseMsgCmdL" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::HandleSetDevIdCmdL
+// Sets device ID. If successfull sends the set ID back as response message.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::HandleSetDevIdCmdL()
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::HandleSetDevIdCmdL" );
+
+    TInt err = KErrNone;
+
+    // SET_DEVICEID command always has 1 parameter (device id).
+    if ( iParameters->Count() == 0 )
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorParameterMissing );
+        return;
+        }
+
+    else if ( iParameters->Count() == 1 )
+        {
+        TUint16 deviceId = KDefaultDevId;
+        TLex8 lex( (*iParameters)[0] );
+        err = lex.Val( deviceId, EDecimal );
+
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorInvalidDeviceId );
+            return;
+            }
+
+        iDevId = deviceId;
+
+        // On success sends the set device id as response.
+        TBuf8<32> msg;
+        msg.AppendNum( (TInt)iDevId );
+        SendResponseMsg( msg );
+        }
+
+    else
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorTooManyParameters );
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::HandleSetDevIdCmdL" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::HandleSetAttributeCmdL
+// Sets attributes for test framework.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::HandleSetAttributeCmdL()
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::HandleSetAttributeCmdL" );
+
+    TInt err = KErrNone;
+
+    // SET_ATTRIBUTE command always has 2 paramters (attribute id and value)
+    if ( iParameters->Count() < 2 )
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorParameterMissing );
+        }
+
+    else if ( iParameters->Count() == 2 )
+        {
+        TInt attributeId = -1;
+        TLex8 lex( (*iParameters)[0] );
+        err = lex.Val( attributeId );
+
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorInvalidAttributeId );
+            return;
+            }
+
+        TBuf<256> value;
+        if ( (*iParameters)[1].Length() > value.MaxLength() )
+            {
+            SendErrorResponseMsg( KErrArgument, KErrorParameterTooLong );
+            return;
+            }
+        value.Copy( (*iParameters)[1] );
+
+        err = SetAttribute( (TAttribute)attributeId, value );
+
+        if ( err )
+            {
+            SendErrorResponseMsg( err, KErrorSetAttribute );
+            }
+
+        else
+            {
+            SendResponseMsg( _L8( "OK" ) );
+            }
+        }
+
+    else
+        {
+        SendErrorResponseMsg( KErrArgument, KErrorTooManyParameters );
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::HandleSetAttributeCmdL" );
+    }
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::TestCompleted
+// This method is called by the STIF TF when a test case execution completes.
+// The test case result is send out as a formatted string.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::TestCompleted( TInt aTestId,
+                                  TInt aTestExecutionResult,
+                                  TTestResult& aTestResult )
+    {
+    // Note that the STIF TF is not aware whether the service is busy processing,
+    // sending, or waiting to send a previous message. So if this method
+    // is called by the STIF TF while the service is busy, the currently
+    // pending message will be overridden by the message sent from this method.
+
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::TestCompleted" );
+
+    iIsBusy = ETrue;  // Will be set to EFalse when response have been sent
+
+    // The maximum length of TResultDes is 128, so a buffer of 256
+    // should be enough for the whole "Test Completed" message.
+    TBuf8<256> buf8;
+
+    // Add first the test id
+    buf8.AppendFormat( _L8( "%d" ), aTestId );
+    buf8.Append( KParameterDelimiter );
+
+    // Add the test result - if it's 0 case has passed
+    buf8.AppendFormat( _L8( "%d" ), aTestResult.iResult );
+    buf8.Append( KParameterDelimiter );
+
+    // Add the test execution result
+    buf8.AppendFormat( _L8( "%d" ), aTestExecutionResult );
+    buf8.Append( KParameterDelimiter );
+
+    // Finally add the description (if there's any)
+    if ( aTestResult.iResultDes.Length() > 0 )
+        {
+        buf8.Append( aTestResult.iResultDes );
+        }
+
+    // and send it
+    SendResponseMsg( buf8, ECmdTestCompleted );
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::TestCompleted" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::AtsSend
+// This method is called by the STIF TF when it needs to send a message to ATS
+// (or some other PC-side component listening for messages)
+// The message is converted to 8-bit representation before sending.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::AtsSend( const TDesC& aMessage )
+    {
+    // Note that the STIF TF is not aware whether the service is busy processing,
+    // sending, or waiting to send a previous message. So if this method
+    // is called by the STIF TF while the service is busy, the currently
+    // pending message will be overridden by the message sent from this method.
+
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::AtsSend" );
+    HTI_LOG_TEXT( "Message: " );
+    HTI_LOG_DES( aMessage );
+
+    iIsBusy = ETrue;  // Will be set to EFalse when response have been sent
+
+    TInt err = KErrNone;
+
+    CCnvCharacterSetConverter* converter = NULL;
+    TRAP( err, converter = CCnvCharacterSetConverter::NewL() );
+
+    if ( err )
+        {
+        SendErrorResponseMsg( err, KErrorCharConv );
+        return;
+        }
+
+    RFs fsSession;
+    err = fsSession.Connect();
+    if ( err )
+        {
+        SendErrorResponseMsg( err, KErrorFileServer );
+        delete converter;
+        return;
+        }
+
+    CCnvCharacterSetConverter::TAvailability availability =
+        CCnvCharacterSetConverter::ENotAvailable;
+
+    TRAP( err, availability = converter->PrepareToConvertToOrFromL(
+        KCharacterSetIdentifierAscii, fsSession ) );
+
+    if ( err || availability == CCnvCharacterSetConverter::ENotAvailable )
+        {
+        SendErrorResponseMsg( err, KErrorCharConv );
+        fsSession.Close();
+        delete converter;
+        return;
+        }
+
+    fsSession.Close();
+
+    HBufC8* asciiBuffer = NULL;
+    TRAP( err, asciiBuffer = HBufC8::NewL( aMessage.Length() ) );
+
+    if ( err )
+        {
+        SendErrorResponseMsg( err, KErrorNoMemory );
+        delete converter;
+        return;
+        }
+
+    TPtr8 ptr8 = asciiBuffer->Des();
+    ptr8.Zero();
+
+    err = converter->ConvertFromUnicode( ptr8, aMessage );
+
+    if ( err )
+        {
+        SendErrorResponseMsg( err, KErrorCharConv );
+        }
+
+    else
+        {
+        TPtr8 converted = asciiBuffer->Des();
+        HTI_LOG_TEXT( "Converted message: " );
+        HTI_LOG_DES( converted );
+        SendResponseMsg( converted, ECmdAtsMessage );
+        }
+
+    delete converter;
+    delete asciiBuffer;
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::AtsSend" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::Print
+// This method is called by the STIF TF when a test case prints.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::Print( TInt /*aTestId*/,
+                          TTestProgress& aProgress )
+    {
+    if ( iConsole )
+        {
+        iConsole->Printf( _L("%S: %S\n"),
+                         &aProgress.iDescription,
+                         &aProgress.iText );
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::LoadTestCaseInfosL
+// A helper method that loads the test case info objects from all currently
+// loaded test modules. Creates and inserts new CHtiTestModuleCaseInfos objects
+// to iLoadedInfos pointer array. Leaves on failure.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::LoadTestCaseInfosL()
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::LoadTestCaseInfosL()" );
+
+    RPointerArray<CTestInfo> allTestInfos;
+    CleanupClosePushL( allTestInfos );
+
+    HTI_LOG_TEXT( "Getting test cases" );
+    // Ignoring possible errors
+    GetTestCases( allTestInfos );
+    HTI_LOG_FORMAT( "Got %d cases", allTestInfos.Count() );
+
+    // Clear all old test case infos from iLoadedInfos
+    iLoadedInfos.ResetAndDestroy();
+
+    // Loop through all test case infos and add them to the correct modules
+    // to iLoadedInfos
+    for ( TInt i = 0; i < allTestInfos.Count(); i++ )
+        {
+        CHtiTestModuleCaseInfos* currentModule = NULL;
+        CTestInfo* caseInfo = NULL;
+
+        caseInfo = allTestInfos[i];
+
+        // Get or create the CHtiTestModuleCaseInfos where this case belongs.
+        TInt moduleIndex = IndexByModuleName( caseInfo->ModuleName() );
+
+        if ( moduleIndex == KErrNotFound )
+            {
+            HTI_LOG_TEXT( "Module not found - adding it" );
+            currentModule = CHtiTestModuleCaseInfos::NewLC(
+                caseInfo->ModuleName() );
+            User::LeaveIfError( iLoadedInfos.Append( currentModule ) );
+            CleanupStack::Pop(); // currentModule
+            }
+
+        else
+            {
+            HTI_LOG_TEXT( "Module found - getting it" );
+            currentModule = iLoadedInfos[moduleIndex];
+            }
+
+        // Add the case info to the CHtiTestModuleCaseInfos object
+        currentModule->iTestInfos.Append( caseInfo );
+        }
+
+    HTI_LOG_FORMAT( "Case infos of %d modules added", iLoadedInfos.Count() );
+    allTestInfos.Reset();
+    CleanupStack::PopAndDestroy(); // allTestInfos
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::LoadTestCaseInfosL()" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::LoadTestCaseInfosL
+// A helper method that loads the test case info objects from the given test
+// module. Creates and inserts a new CHtiTestModuleCaseInfos object to
+// iLoadedInfos pointer array. Leaves on failure.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::LoadTestCaseInfosL( TDesC& aModuleName )
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::LoadTestCaseInfosL( moduleName )" );
+
+    // Check if test case infos of this module already loaded
+    TInt index = IndexByModuleName( aModuleName );
+    if ( index != KErrNotFound )
+        {
+        // If infos already loaded, delete and load again
+        HTI_LOG_TEXT( "Already loaded - updating" );
+        CHtiTestModuleCaseInfos* module = iLoadedInfos[index];
+        iLoadedInfos.Remove( index );
+        delete module;
+        }
+
+    CHtiTestModuleCaseInfos* newModule =
+            CHtiTestModuleCaseInfos::NewLC( aModuleName );
+
+    HTI_LOG_TEXT( "Getting test cases" );
+
+    // If the module is not loaded STIF TF seems to behave so that
+    // GetTestCases method does not return error but it returns
+    // zero test cases.
+    // At least in some cases if the module is loaded but it does not have
+    // any test cases, GetTestCases returns KErrNotFound.
+    // So possible errors or zero test case situations from GetTestCases
+    // are ignored here - if there's an error then the module will just
+    // have 0 test case infos.
+    GetTestCases( newModule->iTestInfos, aModuleName );
+
+    HTI_LOG_FORMAT( "Got %d cases", newModule->iTestInfos.Count() );
+
+    User::LeaveIfError( iLoadedInfos.Append( newModule ) );
+    CleanupStack::Pop(); // newModule
+
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::LoadTestCaseInfosL( moduleName )" );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::ParseParametersL
+// A helper method for parsing the parameters from the given command message.
+// Parameters must be separated with a character defined by the
+// KParameterDelimiter. Parsed parameters are stored to iParameters array.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::ParseParametersL( const TDesC8& aCommand )
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::ParseParametersL" );
+
+    // Clear the parameter array
+    iParameters->Reset();
+
+    // Then loop all the parameters.
+    TInt sectionStart = 0;
+    TInt sectionEnd = 0;
+    while ( true )
+        {
+        sectionStart = sectionEnd + 1;
+        if ( sectionStart >= aCommand.Length() )
+            {
+            HTI_LOG_FORMAT( "Parameters %d", iParameters->Count() );
+            HTI_LOG_FUNC_OUT( "CHtiStifTfIf::ParseParametersL" );
+            return;
+            }
+
+        sectionEnd = aCommand.Mid( sectionStart ).Find( KParameterDelimiter )
+            + sectionStart;
+
+        if ( sectionEnd >= sectionStart )
+            {
+            iParameters->AppendL(
+                aCommand.Mid( sectionStart, sectionEnd - sectionStart ) );
+            HTI_LOG_DES( aCommand.Mid( sectionStart, sectionEnd - sectionStart ) );
+            }
+        else
+            {
+            iParameters->AppendL( aCommand.Mid( sectionStart ) );
+            HTI_LOG_DES( aCommand.Mid( sectionStart ) );
+            HTI_LOG_FORMAT( "Parameters %d", iParameters->Count() );
+            HTI_LOG_FUNC_OUT( "CHtiStifTfIf::ParseParametersL" );
+            return;  // End of parameters.
+            }
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::SetDispatcher
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::SetDispatcher( MHtiDispatcher* aDispatcher )
+    {
+    iDispatcher = aDispatcher;
+    iConsole = iDispatcher->GetConsole();
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::NotifyMemoryChange
+// Called when HTI Framework has dispatched a message forward and the amount
+// of free memory in the message queue has changed.
+// -----------------------------------------------------------------------------
+//
+void CHtiStifTfIf::NotifyMemoryChange( TInt aAvailableMemory )
+    {
+    if ( iIsBusy && iMessage )
+        {
+        if ( aAvailableMemory >= iMessage->Size() )
+            {
+
+            if ( iErrorCode == 0 )
+                {
+                TInt err = iDispatcher->DispatchOutgoingMessage(
+                    iMessage, KStifTfServiceUid );
+
+                if ( err == KErrNone )
+                    {
+                    // Ownership of iMessage has been transferred
+                    iMessage = NULL;
+                    iIsBusy = EFalse;
+                    iDispatcher->RemoveMemoryObserver(
+                            ( MHtiMemoryObserver* ) iPlugin );
+                    }
+
+                else if ( err == KErrNoMemory )
+                    {
+                    // Just keep retrying.
+                    }
+
+                else // Give up on sending
+                    {
+                    delete iMessage;
+                    iMessage = NULL;
+                    iIsBusy = EFalse;
+                    iDispatcher->RemoveMemoryObserver(
+                            ( MHtiMemoryObserver* ) iPlugin );
+                    }
+
+                }
+
+            else
+                {
+                TInt err = iDispatcher->DispatchOutgoingErrorMessage(
+                    iErrorCode, *iMessage, KStifTfServiceUid );
+
+                // If it was success or some other error than KErrNoMemory
+                // we are done sending or trying to send this message.
+                if ( err != KErrNoMemory )
+                    {
+                    delete iMessage;
+                    iMessage = NULL;
+                    iIsBusy = EFalse;
+                    iDispatcher->RemoveMemoryObserver(
+                            ( MHtiMemoryObserver* ) iPlugin );
+                    }
+
+                else
+                    {
+                    // Just keep retrying.
+                    }
+                }
+            }
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::SendResponseMsg
+// Sends a message out to the message dispatcher.
+// -----------------------------------------------------------------------------
+//
+TInt CHtiStifTfIf::SendResponseMsg( const TDesC8& aMsg,
+                        const TUint8 aCommandId )
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::SendResponseMsg" );
+
+    iErrorCode = 0;
+
+    if ( iDispatcher == NULL )
+        {
+        iIsBusy = EFalse;
+        return KErrGeneral;
+        }
+
+    iDispatcher->RemoveMemoryObserver( ( MHtiMemoryObserver* ) iPlugin );
+
+    delete iMessage;
+    iMessage = NULL;
+    iMessage = HBufC8::New( aMsg.Length() + 1 );
+
+
+    if ( iMessage == NULL )
+        {
+        iIsBusy = EFalse;
+        return KErrNoMemory;
+        }
+
+    TPtr8 ptr8 = iMessage->Des();
+    if ( aCommandId != 0 )
+        {
+        ptr8.Append( aCommandId );
+        }
+    else
+        {
+        ptr8.Append( iCommandId );
+        }
+
+    ptr8.Append( aMsg );
+
+    TInt err = KErrNone;
+
+    err = iDispatcher->DispatchOutgoingMessage( iMessage, KStifTfServiceUid );
+
+    if ( err == KErrNoMemory )
+        {
+        HTI_LOG_TEXT( "Message queue memory full - waiting" );
+        iIsBusy = ETrue; // Should already be true, but just in case
+        iDispatcher->AddMemoryObserver( ( MHtiMemoryObserver* ) iPlugin );
+        // For the caller of this method all is OK, sending is just delayed
+        err = KErrNone;
+        }
+
+    else if ( err == KErrNone )
+        {
+        HTI_LOG_TEXT( "Message sent to dispatcher" );
+        iMessage = NULL; // Ownership of iMessage has been transferred
+        iIsBusy = EFalse;
+        }
+
+    else // give up on sending
+        {
+        HTI_LOG_FORMAT( "Other dispatcher error %d", err );
+        delete iMessage;
+        iMessage = NULL;
+        iIsBusy = EFalse;
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::SendResponseMsg" );
+    return err;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::SendErrorResponseMsg
+// Sends an error message out to the message dispatcher.
+// -----------------------------------------------------------------------------
+//
+TInt CHtiStifTfIf::SendErrorResponseMsg( TInt aErrorCode,
+                        const TDesC8& aErrorDescription,
+                        const TUint8 aCommandId )
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::SendErrorResponseMsg" );
+
+    iErrorCode = aErrorCode;
+
+    if ( iDispatcher == NULL )
+        {
+        iIsBusy = EFalse;
+        return KErrGeneral;
+        }
+
+    iDispatcher->RemoveMemoryObserver( ( MHtiMemoryObserver* ) iPlugin );
+
+    delete iMessage;
+    iMessage = NULL;
+    iMessage = HBufC8::New( aErrorDescription.Length() + 1 );
+
+    if ( iMessage == NULL )
+        {
+        iIsBusy = EFalse;
+        return KErrNoMemory;
+        }
+
+    TPtr8 ptr8 = iMessage->Des();
+    if ( aCommandId != 0 )
+        {
+        ptr8.Append( aCommandId );
+        }
+    else
+        {
+        ptr8.Append( iCommandId );
+        }
+
+    ptr8.Append( aErrorDescription );
+
+    TInt err = KErrNone;
+
+    err = iDispatcher->DispatchOutgoingErrorMessage(
+        aErrorCode, *iMessage, KStifTfServiceUid );
+
+    if ( err == KErrNoMemory )
+        {
+        HTI_LOG_TEXT( "Message queue memory full - waiting" );
+        iIsBusy = ETrue; // Should already be true, but just in case
+        iDispatcher->AddMemoryObserver( ( MHtiMemoryObserver* ) iPlugin );
+        // For the caller of this method all is OK, sending is just delayed
+        err = KErrNone;
+        }
+
+    else if ( err == KErrNone )
+        {
+        HTI_LOG_TEXT( "Error message sent to dispatcher" );
+        delete iMessage;
+        iMessage = NULL;
+        iIsBusy = EFalse;
+        }
+
+    else // give up on sending
+        {
+        HTI_LOG_FORMAT( "Other dispatcher error %d", err );
+        delete iMessage;
+        iMessage = NULL;
+        iIsBusy = EFalse;
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::SendErrorResponseMsg" );
+    return err;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::IndexByModuleName
+// A helper method to search for a CHtiTestModuleCaseInfos object from the
+// iLoadedInfos array based on the module name.
+// -----------------------------------------------------------------------------
+//
+TInt CHtiStifTfIf::IndexByModuleName( const TDesC& aModuleName )
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::IndexByModuleName" );
+
+    CHtiTestModuleCaseInfos* module;
+    for ( TInt i = 0; i < iLoadedInfos.Count(); i++ )
+        {
+        module = NULL;
+        module = iLoadedInfos[i];
+        if ( module->iModuleName->Compare( aModuleName ) == 0 )
+            {
+            HTI_LOG_FORMAT( "Module found from index %d", i );
+            HTI_LOG_FUNC_OUT( "CHtiStifTfIf::IndexByModuleName" );
+            return i;
+            }
+        }
+    HTI_LOG_TEXT( "Module not found" );
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::IndexByModuleName" );
+    return KErrNotFound;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiStifTfIf::GetCaseInfoL
+// A helper method to get the correct CTestInfo object based on the index
+// number, referring to list of case infos of all loaded test modules.
+// -----------------------------------------------------------------------------
+//
+CTestInfo* CHtiStifTfIf::GetCaseInfoL( TInt aCaseIndex )
+    {
+    HTI_LOG_FUNC_IN( "CHtiStifTfIf::GetCaseInfoL" );
+
+    if ( aCaseIndex < 0 )
+        {
+        User::Leave( KErrArgument );
+        }
+
+    TInt index = -1;
+    TInt caseCount = 0;
+    CHtiTestModuleCaseInfos* module = NULL;
+    for ( TInt i = 0; i < iLoadedInfos.Count(); i++ )
+        {
+        module = NULL;
+        module = iLoadedInfos[i];
+        caseCount += module->iTestInfos.Count();
+        HTI_LOG_FORMAT( "Case count = %d", caseCount );
+        if ( aCaseIndex < caseCount )
+            {
+            // This is the right module
+            // Get the case index inside this module
+            index = module->iTestInfos.Count() - ( caseCount - aCaseIndex );
+            }
+        if ( index >= 0 ) break; // Case found - break out of loop
+        }
+
+    if ( index < 0 )
+        {
+        HTI_LOG_TEXT( "Given index was too big - case not found" );
+        User::Leave( KErrNotFound );
+        }
+
+    // Following should never be true - this is for testing.
+    if ( index > module->iTestInfos.Count() )
+        {
+        HTI_LOG_TEXT( "**Calculated index > test info count of module**" );
+        User::Leave( KErrGeneral );
+        }
+
+    HTI_LOG_FORMAT( "Case found from index %d", index );
+    HTI_LOG_FUNC_OUT( "CHtiStifTfIf::GetCaseInfoL" );
+    return module->iTestInfos[index];
+    }
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+
+// -----------------------------------------------------------------------------
+// CHtiTestModuleCaseInfos::NewL
+// -----------------------------------------------------------------------------
+//
+CHtiTestModuleCaseInfos* CHtiTestModuleCaseInfos::NewL(
+                                                const TDesC& aModuleName )
+    {
+    CHtiTestModuleCaseInfos* self = NewLC( aModuleName );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiTestModuleCaseInfos::NewLC
+// -----------------------------------------------------------------------------
+//
+CHtiTestModuleCaseInfos* CHtiTestModuleCaseInfos::NewLC(
+                                                const TDesC& aModuleName )
+    {
+    CHtiTestModuleCaseInfos* self = new (ELeave) CHtiTestModuleCaseInfos;
+    CleanupStack::PushL( self );
+    self->ConstructL( aModuleName );
+    return self;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiTestModuleCaseInfos::ConstructL
+// 2nd phase constructor.
+// -----------------------------------------------------------------------------
+//
+void CHtiTestModuleCaseInfos::ConstructL( const TDesC& aModuleName )
+    {
+    iModuleName = aModuleName.AllocL();
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiTestModuleCaseInfos::CHtiTestModuleCaseInfos
+// C++ default constructor
+// -----------------------------------------------------------------------------
+//
+CHtiTestModuleCaseInfos::CHtiTestModuleCaseInfos()
+    {
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiTestModuleCaseInfos::~CHtiTestModuleCaseInfos
+// Destructor.
+// -----------------------------------------------------------------------------
+//
+CHtiTestModuleCaseInfos::~CHtiTestModuleCaseInfos()
+    {
+    delete iModuleName;
+    iTestInfos.ResetAndDestroy();
+    iTestInfos.Close();
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiTestModuleCaseInfos::Compare
+// Compares the order of two CHtiTestModuleCaseInfos objects using module name
+// as the ordering key.
+// -----------------------------------------------------------------------------
+//
+TInt CHtiTestModuleCaseInfos::Compare( const CHtiTestModuleCaseInfos& aFirst,
+        const CHtiTestModuleCaseInfos& aSecond )
+    {
+    return ( aFirst.iModuleName )->Compare( *aSecond.iModuleName );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CHtiTestModuleCaseInfos::Match
+// Checks the equality of two CHtiTestModuleCaseInfos objects.
+// Objects are considered to be equal if their module name is equal.
+// -----------------------------------------------------------------------------
+//
+TBool CHtiTestModuleCaseInfos::Match( const CHtiTestModuleCaseInfos& aFirst,
+        const CHtiTestModuleCaseInfos& aSecond )
+    {
+    if ( ( aFirst.iModuleName )->Compare( *aSecond.iModuleName ) == 0 )
+        {
+        return true;
+        }
+
+    return false;
+    }
+
+
+//  End of File