keepalive/flextimer/client/src/rflextimer.cpp
author hgs
Mon, 24 May 2010 20:51:35 +0300
changeset 32 5c4486441ae6
permissions -rw-r--r--
201021

/*
 * Copyright (c) 2010 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:  Implementation of RFlexTimer class
 *
 */

/*
 * %version: 1 %
 */
#include "rflextimer.h"
#include "flextimercommon.h"
#include "OstTraceDefinitions.h"
#ifdef OST_TRACE_COMPILER_IN_USE
#include "rflextimerTraces.h"
#endif


_LIT( KFlexTimerSemaphoreName, "FlexTimerSemaphore" );

// Semaphore count value initialization to 1. The 1st to call Wait() will
// pass the semaphore. Other processes attempting entry will wait until the
// 1st one has called Signal() on the semaphore.
const TInt KPassFirstWaitEntry = 1;

// ======== MEMBER FUNCTIONS ========
// ---------------------------------------------------------------------------
// Constructs the object.
// ---------------------------------------------------------------------------
//
EXPORT_C RFlexTimer::RFlexTimer()
    {
    OstTrace1( TRACE_NORMAL, RFLEXTIMER_RFLEXTIMER,
               "RFlexTimer::RFlexTimer;this=%x", this );
    
    }

// ---------------------------------------------------------------------------
// Destructs the object.
// ---------------------------------------------------------------------------
//
EXPORT_C RFlexTimer::~RFlexTimer()
    {
    OstTrace1( TRACE_NORMAL, DUP1_RFLEXTIMER_RFLEXTIMER,
               "RFlexTimer::~RFlexTimer;this=%x", ( TUint )this );
    
    Close();
    }

// ---------------------------------------------------------------------------
// Connects to the server and create a session.
// ---------------------------------------------------------------------------
//
EXPORT_C TInt RFlexTimer::Connect()
    {
    OstTrace1( TRACE_NORMAL, RFLEXTIMER_CONNECT,
               "RFlexTimer::Connect;this=%x", ( TUint )this );
    
    // Not opened handle-number
    const TInt kHandleNotOpened( 0 );
    
    // Starts the server, if it does not already exist in the system.
    TInt ret = StartServer();

    if ( ret == KErrNone )
        { // No session, create it

        // Handle() is zero when initialized RHandleBase. Close() also zeroes 
        // the handle. If CreateSession() fails, Handle() is still zero.
        // If session is created ok, the Handle() contains the (non zero)
        // handle-number. 
        //
        // Handle() can be used for checking is the handle opened or not.
        //
        if ( Handle() == kHandleNotOpened )
            {
            // Creates the session for this client.
            ret = CreateSession( KFlexTimerServerName,
                                 Version(),
                                 KFlexTimerServerMessageSlots );
            }
        else
            { // Session already exists - panic.

            OstTrace1( 
                TRACE_NORMAL, 
                DUP1_RFLEXTIMER_CONNECT,
                "RFlexTimer::Connect already connected - PANIC;this=%x", 
                ( TUint )this );
        
            User::Panic( KRFlexTimerPanicCat, EFlexTimerAlreadyConnected );
            }
        }
    return ret;
    }

// ---------------------------------------------------------------------------
// Cancels any outstanding request to the server.
// ---------------------------------------------------------------------------
//
EXPORT_C void RFlexTimer::Cancel()
    {
    OstTrace1( TRACE_NORMAL, RFLEXTIMER_CANCEL,
               "RFlexTimer::Cancel;this=%x", ( TUint )this );
    
    SendReceive( EFlexTimerServCancelRequest );
    }

// ---------------------------------------------------------------------------
// Fire timer at latest on the given interval. 32-bit interval.
// ---------------------------------------------------------------------------
//
EXPORT_C void RFlexTimer::After( TRequestStatus& aStatus,
                                 TTimeIntervalMicroSeconds32 aInterval )
    {
    OstTraceExt3( TRACE_NORMAL, RFLEXTIMER_AFTER32,
                  "RFlexTimer::After32;this=%x;aStatus=%x;aInterval=%d",
                  ( TUint )this, ( TUint )&( aStatus ), aInterval.Int() );
    
    const TTimeIntervalMicroSeconds32 ZERO_INTERVAL32(0);
    __ASSERT_ALWAYS(aInterval >= ZERO_INTERVAL32,
                    User::Panic(KRFlexTimerPanicCat,
                                EFlexTimerAfterIntervalLessThanZero));
    
    TIpcArgs args( aInterval.Int(), 0 );
    //asynchronous request for timer creation and timeout request.    
    SendReceive( EFlexTimerServAfterRequest, args, aStatus );
    }

// ---------------------------------------------------------------------------
// Fire timer at latest on the given interval. 64-bit interval.
// ---------------------------------------------------------------------------
//
EXPORT_C void RFlexTimer::After( TRequestStatus& aStatus,
                                 TTimeIntervalMicroSeconds aInterval )
    {
    OstTraceExt3( TRACE_NORMAL, RFLEXTIMER_AFTER64,
                  "RFlexTimer::After64;this=%x;aStatus=%x;aInterval=%lld",
                  ( TUint )this, ( TUint )&( aStatus ), aInterval.Int64() );
    
    const TTimeIntervalMicroSeconds ZERO_INTERVAL(0);
    __ASSERT_ALWAYS(aInterval >= ZERO_INTERVAL,
                    User::Panic(KRFlexTimerPanicCat,
                                EFlexTimerAfterIntervalLessThanZero));
    
    TIpcArgs args( I64LOW(aInterval.Int64()), I64HIGH(aInterval.Int64()) );
    //asynchronous request for timer creation and timeout request.    
    SendReceive( EFlexTimerServAfterRequest, args, aStatus );
    }

// ---------------------------------------------------------------------------
// Fire timer at latest after the given number of ticks.
// ---------------------------------------------------------------------------
//
EXPORT_C void RFlexTimer::AfterTicks( TRequestStatus& aStatus, TInt aTicks )
    {
    OstTraceExt3( TRACE_NORMAL, RFLEXTIMER_AFTERTICKS,
                  "RFlexTimer::AfterTicks;this=%x;aStatus=%d;aTicks=%d",
                  ( TUint )this, ( TUint )&( aStatus ), aTicks );
    
    __ASSERT_ALWAYS(aTicks >= 0,
                    User::Panic(KRFlexTimerPanicCat,
                                EFlexTimerAfterTicksIntervalLessThanZero));

    TIpcArgs args( aTicks );
    //asynchronous request for timer creation and timeout request.    
    SendReceive( EFlexTimerServAfterTicksRequest, args, aStatus );
    }

// ---------------------------------------------------------------------------
// Fire timer between at latest by the given time value.
// ---------------------------------------------------------------------------
//
EXPORT_C void RFlexTimer::At( TRequestStatus& aStatus, const TTime& aTime )
    {
    OstTraceExt3( TRACE_NORMAL, RFLEXTIMER_AT,
                  "RFlexTimer::At;this=%x;aStatus=%d;aTime=%lld",
                  ( TUint )this, ( TUint )&( aStatus ), aTime.Int64() );
    
    TTime nowTime;
    nowTime.HomeTime();
    
    __ASSERT_ALWAYS(aTime >= nowTime,
                    User::Panic(KRFlexTimerPanicCat,
                                EFlexTimerAtIntervalLessThanZero));
    
    TIpcArgs args( I64LOW(aTime.Int64()), I64HIGH(aTime.Int64()) );
    //asynchronous request for timer creation and timeout request.    
    SendReceive( EFlexTimerServAtRequest, args, aStatus );
    }

// ---------------------------------------------------------------------------
// Fire timer between at latest by the given time value.
// ---------------------------------------------------------------------------
//
EXPORT_C void RFlexTimer::AtUTC( TRequestStatus& aStatus, const TTime& aTime )
    {
    OstTraceExt3( TRACE_NORMAL, RFLEXTIMER_ATUTC,
                  "RFlexTimer::AtUTC;this=%x;aStatus=%d;aTime=%lld",
                  ( TUint )this, ( TUint )&( aStatus ), aTime.Int64() );
    
    TTime nowTime;
    nowTime.UniversalTime();
    
    __ASSERT_ALWAYS(aTime >= nowTime,
                    User::Panic(KRFlexTimerPanicCat,
                                EFlexTimerAtUTCIntervalLessThanZero));
    
    TIpcArgs args( I64LOW(aTime.Int64()), I64HIGH(aTime.Int64()) );
    //asynchronous request for timer creation and timeout request.    
    SendReceive( EFlexTimerServAtUTCRequest, args, aStatus );
    }

// ---------------------------------------------------------------------------
// Sets the window size in which alignment is possible for the timer.
// This is a synchronous command. 32-bit function version.
// ---------------------------------------------------------------------------
//
EXPORT_C TInt RFlexTimer::Configure( TTimeIntervalMicroSeconds32 aWindowSize )
    {
    OstTraceExt2( TRACE_NORMAL, RFLEXTIMER_CONFIGURE,
                  "RFlexTimer::Configure32;this=%x;aWindowSize=%d",
                  ( TUint )this, aWindowSize.Int() );
    
    const TTimeIntervalMicroSeconds32 ZERO_INTERVAL32(0);
    __ASSERT_ALWAYS(aWindowSize >= ZERO_INTERVAL32,
                    User::Panic(KRFlexTimerPanicCat,
                                EFlexTimerWindowLessThanZero));
    
    TInt64 transfer = MAKE_TINT64( 0, aWindowSize.Int() );
        
    // Regardless of the user function, the window size is always transmitted
    // as a 64-bit integer.
    TIpcArgs args( EConfigureRequestWindowSize, 
                   I64LOW(transfer), I64HIGH(transfer) );

    return SendReceive( EFlexTimerServConfigureRequest, args );
    }

// ---------------------------------------------------------------------------
// Sets the window size in which alignment is possible for the timer.
// This is a synchronous command. 64-bit function version.
// ---------------------------------------------------------------------------
//
EXPORT_C TInt RFlexTimer::Configure( TTimeIntervalMicroSeconds aWindowSize )
    {
    OstTraceExt2( TRACE_NORMAL, DUP1_RFLEXTIMER_CONFIGURE,
                  "RFlexTimer::Configure64;this=%x;aWindowSize=%lld",
                  ( TUint )this, aWindowSize.Int64() );
    
    const TTimeIntervalMicroSeconds ZERO_INTERVAL64(0);
    __ASSERT_ALWAYS(aWindowSize >= ZERO_INTERVAL64,
                    User::Panic(KRFlexTimerPanicCat,
                                EFlexTimerWindowLessThanZero));
    
    // Regardless of the user function, the window size is always transmitted
    // as a 64-bit integer.
    TIpcArgs args( EConfigureRequestWindowSize,
                   I64LOW(aWindowSize.Int64()),
                   I64HIGH(aWindowSize.Int64()) );

    return SendReceive( EFlexTimerServConfigureRequest, args  );
    }

// ---------------------------------------------------------------------------
// Gets the version number.
// ---------------------------------------------------------------------------
//
TVersion RFlexTimer::Version() const
    {
    return ( TVersion( KFlexTimerServMajorVersionNumber,
                       KFlexTimerServMinorVersionNumber,
                       KFlexTimerServBuildVersionNumber ) );
    }

// ---------------------------------------------------------------------------
// Connects to the server. If server does not exist, it is created.
// ---------------------------------------------------------------------------
//
TInt RFlexTimer::StartServer()
    {
    OstTrace1( TRACE_NORMAL, RFLEXTIMER_STARTSERVER,
               "RFlexTimer::StartServer;this=%x", ( TUint )this );
    
    TFindServer findServer( KFlexTimerServerName );
    TFullName serverName;

    // See if the server is already started. 
    TInt ret = findServer.Next( serverName );
    
    if ( ret != KErrNone )
        {
        //Server was not found so create one.
        RProcess serverProcess;
        TBuf<1> serverParameters;

        // Semaphore to guard the opening of the server process.
        RSemaphore semaphore;

        // Prevent two clients from  creating the serverProcess at the same
        // time.
        if ( ( ret = semaphore.CreateGlobal( 
                KFlexTimerSemaphoreName, KPassFirstWaitEntry ) ) != KErrNone )
            {
            ret = semaphore.OpenGlobal( KFlexTimerSemaphoreName );
            }

        if ( ret == KErrNone )
            {
            semaphore.Wait();

            // See again if the server is already started. This doublechecking
            // is necessary, since two or processes may have resolved the
            // first findserver before any server was created.

            // TFindServer sets its content only when instantiated.
            // Just using findServer.Next() does not work in here.
            TFindServer findServerAgain( KFlexTimerServerName );
            if ( findServerAgain.Next( serverName ) != KErrNone )
                {
                // Load the executable for the server.
                ret = serverProcess.Create( KFlexTimerServerExe,
                                            serverParameters,
                                            EOwnerThread );

                if ( ret == KErrNone )
                    {
                    // Server has been created successfully. It is initially 
                    // in suspended state. Now resume the server process.
                    serverProcess.Resume();

                    // Wait until the server process has been started.
                    TRequestStatus status;
                    serverProcess.Rendezvous( status );
                    User::WaitForRequest( status );

                    // Check if server has panicked during initialization.
                    ret = serverProcess.ExitType();
                    if ( ret == EExitPanic )
                        {
                        OstTrace1( TRACE_NORMAL, DUP1_RFLEXTIMER_STARTSERVER,
                                "RFlexTimer::StartServer;this=%x; "
                                "ERROR: Server paniced",
                                ( TUint )this );

                        ret = KErrServerTerminated;
                        }
                    else
                        {
                        ret = status.Int();
                        }

                    // The server process stands on its own. This handle can
                    // be closed. 
                    serverProcess.Close();
                    }
                else
                    {
                    OstTrace1( TRACE_NORMAL, DUP2_RFLEXTIMER_STARTSERVER,
                            "RFlexTimer::StartServer;this=%x; "
                            "ERROR: Server creation failed",
                            ( TUint )this );
                    }
                }
            
            semaphore.Signal();
            semaphore.Close();
            }
        }

    return ret;
    }