keepalive/flextimer/server/src/flextimersession.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 CFlexTimerSession class.
 *
 */
/*
 * %version: 1 %
 */

// System include files
#include <e32def.h>
#include <e32cmn.h>
#include <hal.h>

// User include files go here:
#include "flextimercommon.h"
#include "flextimersession.h"
#include "mflextimerservice.h"
#include "OstTraceDefinitions.h"
#ifdef OST_TRACE_COMPILER_IN_USE
#include "flextimersessionTraces.h"
#endif

// Constants

// ======== MEMBER FUNCTIONS ========

// --------------------------------------------------------------------------
// Constructor
// --------------------------------------------------------------------------
//
CFlexTimerSession::CFlexTimerSession( MFlexTimerService* aFlexTimerService )
:   iService( aFlexTimerService ),
    iTimerWinSize( 0 ),
    iUseDefaultWin( ETrue )
    {
    OstTrace1( TRACE_INTERNAL,
               CFLEXTIMERSESSION,
               "CFlexTimerSession::CFlexTimerSession; this=%x",
               ( TUint )this );
    }

// --------------------------------------------------------------------------
// Destructor
// --------------------------------------------------------------------------
//
CFlexTimerSession::~CFlexTimerSession()
    {
    OstTrace1( TRACE_INTERNAL,
               CFLEXTIMERSESSIOND,
               "CFlexTimerSession::~CFlexTimerSession; this=%x",
               ( TUint )this );
    }

// --------------------------------------------------------------------------
// Function called from CFlexTimerService::RunL for messages targeted to
// this session
// --------------------------------------------------------------------------
//
void CFlexTimerSession::ServiceL( const RMessage2& aMessage )
    {
    TInt msgType( aMessage.Function() );

    OstTraceExt2( TRACE_INTERNAL,
                  CFLEXTIMERSESSION_MSG,
                  "CFlexTimerSession::ServiceL; this=%x; msgType=%d",
                  ( TInt )this,
                  msgType );

    // Check message type and pass it to correct handler. Handler either 
    // stores the message or completes it immediately.
    switch ( msgType )
        {
        case EFlexTimerServCancelRequest:
            CancelTimer( aMessage );
            break;
        case EFlexTimerServAtRequest:
            NewAtTimer( aMessage );
            break;
        case EFlexTimerServAtUTCRequest:
            NewAtUtcTimer( aMessage );
            break;
        case EFlexTimerServAfterRequest:
            NewAfterTimer( aMessage );
            break;
        case EFlexTimerServAfterTicksRequest:
            NewAfterTicksTimer( aMessage );
            break;
        case EFlexTimerServConfigureRequest:
            ConfigureParameters( aMessage );
            break;
        default:
            OstTrace1(
                    TRACE_INTERNAL,
                    CFLEXTIMERSESSION_ERROR,
                    "CFlexTimerSession::ServiceL: Unknown message; this=%x",
                    ( TUint )this );
            aMessage.Complete( KErrNotSupported );
        }
    }

// --------------------------------------------------------------------------
// Timeout handler for triggering timers
// --------------------------------------------------------------------------
//
void CFlexTimerSession::Timeout() const
    {
    // Check for the validity of pending timeout request
    if ( !iPendingTimeoutMsg.IsNull() )
        {
        OstTraceExt2( TRACE_INTERNAL,
                      CFLEXTIMERSESSION_TIMEOUT,
                      "CFlexTimerSession::Timeout; this=%x; msg=%x",
                      ( TUint )this,
                      ( TUint )iPendingTimeoutMsg.Handle() );
        // Complete message, this sets message pointer to NULL
        iPendingTimeoutMsg.Complete( KErrNone );
        }
    else
        {
        // No valid message pointer, nothing we can do here
        OstTrace1( TRACE_INTERNAL,
                   CFLEXTIMERSESSION_TIMEOUT_ERROR,
                   "CFlexTimerSession::Timeout: No Pending message; this=%x",
                   ( TUint )this );
        }
    }

// --------------------------------------------------------------------------
// Function for aborting At-timer
// --------------------------------------------------------------------------
//
void CFlexTimerSession::Abort( TInt aReason ) const
    {
    // Check for the validity of pending timeout request
    if ( !iPendingTimeoutMsg.IsNull() )
        {
        OstTraceExt2( TRACE_INTERNAL,
                      CFLEXTIMERSESSION_ABORT,
                      "CFlexTimerSession::Abort; this=%x; msg=%x",
                      ( TUint )this,
                      ( TUint )iPendingTimeoutMsg.Handle() );
        // Complete message, this sets message pointer to NULL
        iPendingTimeoutMsg.Complete( aReason );
        }
    else
        {
        // No valid message pointer, nothing we can do here
        OstTrace1(
                TRACE_INTERNAL,
                CFLEXTIMERSESSION_ABORT_ERROR,
                "CFlexTimerSession::Abort: No Pending message; this=%x",
                ( TUint )this );

        }
    }

// --------------------------------------------------------------------------
// Handler function for starting At() -timer
// --------------------------------------------------------------------------
//
void CFlexTimerSession::NewAtTimer( const RMessage2& aMessage )
    {

    // Check that we do not have a pending timer request
    if ( !iPendingTimeoutMsg.IsNull() )
        {
        OstTraceExt2( TRACE_INTERNAL,
                      CFLEXTIMERSESSION_ATPANIC,
                      "CFlexTimerSession::NewAtTimer: Already pending; "
                      "this=%x; msg=%x",
                      ( TUint )this,
                      ( TUint )iPendingTimeoutMsg.Handle() );

        aMessage.Panic( KRFlexTimerPanicCat,
                        EFlexTimerServerErrorPendingTimer );
        return;
        }

    // Get interval from current time to the requested timestamp
    TTime refTime;
    refTime.HomeTime();
    TTimeIntervalMicroSeconds interval;
    GetIntervalToMsgTime( aMessage, refTime, interval );

    OstTraceExt2( TRACE_INTERNAL,
                  CFLEXTIMERSESSION_ATTIMER,
                  "CFlexTimerSession::NewAtTimer; this=%x; interval=%lld",
                  ( TUint )this,
                  interval.Int64() );

    // Add the timer to engine
    DoAddTimer( aMessage, interval, ETrue );

    }

// --------------------------------------------------------------------------
// Handler function for starting AtUTC() -timer
// --------------------------------------------------------------------------
//
void CFlexTimerSession::NewAtUtcTimer( const RMessage2& aMessage )
    {

    // Check that we do not have a pending timer request
    if ( !iPendingTimeoutMsg.IsNull() )
        {
        OstTraceExt2( TRACE_INTERNAL,
                      CFLEXTIMERSESSION_ATUTCPANIC,
                      "CFlexTimerSession::NewAtUtcTimer: Already pending; "
                      "this=%x; msg=%x",
                      ( TUint )this,
                      ( TUint )iPendingTimeoutMsg.Handle() );

        aMessage.Panic( KRFlexTimerPanicCat,
                        EFlexTimerServerErrorPendingTimer );
        return;
        }

    TTime refTime;
    refTime.UniversalTime();
    TTimeIntervalMicroSeconds interval;
    GetIntervalToMsgTime( aMessage, refTime, interval );
    
    OstTraceExt2( 
            TRACE_INTERNAL,
            CFLEXTIMERSESSION_ATUTCTIMER,
            "CFlexTimerSession::NewAtUtcTimer; this=%x; interval=%lld",
            ( TUint )this,
            interval.Int64() );

    // Add the timer to engine
    DoAddTimer( aMessage, interval, ETrue );

    }

// --------------------------------------------------------------------------
// Handler function for starting After()-timer
// --------------------------------------------------------------------------
//
void CFlexTimerSession::NewAfterTimer( const RMessage2& aMessage )
    {

    // Check that we do not have a pending timer request
    if ( !iPendingTimeoutMsg.IsNull() )
        {
        OstTraceExt2( TRACE_INTERNAL,
                      CFLEXTIMERSESSION_AFTERPANIC,
                      "CFlexTimerSession::NewAfterTimer: Already pending; "
                      "this=%x; msg=%x",
                      ( TUint )this,
                      ( TUint )iPendingTimeoutMsg.Handle() );

        aMessage.Panic( KRFlexTimerPanicCat,
                        EFlexTimerServerErrorPendingTimer );
        return;
        }

    TInt64 timeStamp = MAKE_TINT64( aMessage.Int1(), aMessage.Int0() );
    TTimeIntervalMicroSeconds interval( timeStamp );

    OstTraceExt2(
            TRACE_INTERNAL,
            CFLEXTIMERSESSION_AFTERTIMER,
            "CFlexTimerSession::NewAfterTimer; this=%x; interval=%llu",
            ( TUint )this,
            interval.Int64() );

    // Add the timer to engine, request cancellation if the secure time
    // is not available
    DoAddTimer( aMessage, interval, EFalse );
    }

// --------------------------------------------------------------------------
// Handler function for starting AfterTicks()-timer
// --------------------------------------------------------------------------
//
void CFlexTimerSession::NewAfterTicksTimer( const RMessage2& aMessage )
    {

    // Check that we do not have a pending timer request
    if ( !iPendingTimeoutMsg.IsNull() )
        {
        OstTraceExt2(
                TRACE_INTERNAL,
                CFLEXTIMERSESSION_AFTERTICKSPANIC,
                "CFlexTimerSession::NewAfterTicksTimer: Already pending; "
                "this=%x; msg=%x",
                ( TUint )this,
                ( TUint )iPendingTimeoutMsg.Handle() );

        aMessage.Panic( KRFlexTimerPanicCat,
                        EFlexTimerServerErrorPendingTimer );
        return;
        }

    // Get the tick period from HAL and convert ticks to microseconds
    TInt tickUs;
    HAL::Get( HAL::ESystemTickPeriod, tickUs );

    TTimeIntervalMicroSeconds interval =
            static_cast<TInt64> ( aMessage.Int0() ) * tickUs;

    OstTraceExt2(
            TRACE_INTERNAL,
            CFLEXTIMERSESSION_AFTERTICKSTIMER,
            "CFlexTimerSession::NewAfterTicksTimer; this=%x; interval=%llu",
            ( TUint )this,
            interval.Int64() );

    // Add the timer to engine
    DoAddTimer( aMessage, interval, EFalse );
    }

// --------------------------------------------------------------------------
// Handler function for cancelling running timer
// --------------------------------------------------------------------------
//
void CFlexTimerSession::CancelTimer( const RMessage2& aMessage )
    {
    TInt ret;
    // Check that we have a pending timer request
    if ( iPendingTimeoutMsg.IsNull() )
        {
        OstTrace1(
                TRACE_INTERNAL,
                CFLEXTIMERSESSION_CANCELERROR,
                "CFlexTimerSession::CancelTimer: no pending msg; this=%x",
                ( TUint )this );
        ret = KErrNotFound;
        }
    else
        {
        ret = iService->CancelTimer( this );
        OstTraceExt2( TRACE_INTERNAL,
                      CFLEXTIMERSESSION_CANCEL,
                      "CFlexTimerSession::CancelTimer; this=%x; ret=%d",
                      ( TUint )this,
                      ret );

        // Complete pending message, this sets message pointer to NULL
        iPendingTimeoutMsg.Complete( KErrCancel );
        }

    // Complete cancel message
    aMessage.Complete( ret );
    }

// --------------------------------------------------------------------------
// Handler function for configuring timer parameters
// --------------------------------------------------------------------------
//
void CFlexTimerSession::ConfigureParameters( const RMessage2& aMessage )
    {
    TInt ret( KErrNone );

    // Configuration is not allowed when there is a pending message
    if ( !iPendingTimeoutMsg.IsNull() )
        {
        OstTrace1( TRACE_INTERNAL,
                   CFLEXTIMERSESSION_CONFIGERROR,
                   "CFlexTimerSession::ConfigureParameters: Timer pending; "
                   "this=%x",
                   ( TUint )this );
        ret = KErrInUse;
        }
    else
        {
        TInt paramType( aMessage.Int0() );
        OstTraceExt2( TRACE_INTERNAL,
                      CFLEXTIMERSESSION_CONFIG,
                      "CFlexTimerSession::ConfigureParameters; this=%x; "
                      "paramType=%d",
                      ( TUint )this,
                      paramType );

        switch ( paramType )
            {
            case EConfigureRequestWindowSize:
                {
                TInt winLo = aMessage.Int1();
                TInt winHi = aMessage.Int2();

                iTimerWinSize = MAKE_TINT64( winHi, winLo );
                iUseDefaultWin = EFalse;

                OstTraceExt1( TRACE_INTERNAL,
                              CFLEXTIMERSESSION_CONFIGWIN,
                              "CFlexTimerSession::ConfigureParameters; "
                              "iTimerWinSize=%lld",
                              iTimerWinSize.Int64() );
                
                if ( iTimerWinSize.Int64() < 0 ||
                    iTimerWinSize.Int64() > KFlexTimerMaxTimerLength )
                    {
                    aMessage.Panic( KRFlexTimerPanicCat,
                        EFlexTimerServerIllegalTimerValue );
                    // Return after panicing the client -- completing the
                    // message afterwards panics the server with USER 70.
                    return;
                    }
                break;
                }
            default:
                OstTrace0( TRACE_INTERNAL,
                           CFLEXTIMERSESSION_CONFIGUNKNOWN,
                           "CFlexTimerSession::ConfigureParameters: "
                           "ERROR - Invalid parameter type" );
                ret = KErrNotSupported;
                break;
            }
        }
    aMessage.Complete( ret );
    }

// --------------------------------------------------------------------------
// Function for adding timer to engine and handling its return value
// --------------------------------------------------------------------------
//
void CFlexTimerSession::DoAddTimer( const RMessage2& aMessage,
                                    TTimeIntervalMicroSeconds& aWinEnd,
                                    TBool aRequestAbort )
    {
    OstTraceExt4( TRACE_INTERNAL,
               CFLEXTIMERSESSION_ADDTIMER,
               "CFlexTimerSession::DoAddTimer; this=%x; msg=%x; aWinEnd=%llu;"
               " aRequestAbort=%d",
               ( TUint )this,
               ( TUint )aMessage.Handle(),
               aWinEnd.Int64(),
               aRequestAbort );  
    
    // Check that the timer has valid values.
    if ( aWinEnd.Int64() < 0 || aWinEnd.Int64() > KFlexTimerMaxTimerLength)
        {
        OstTraceExt4( TRACE_INTERNAL, 
                      CFLEXTIMERSESSION_DOADDTIMER, 
                      "CFlexTimerSession::DoAddTimer;Invalid parameters "
                      "- panicing client;this=%x;aMessage=%x;aWinEnd=%llu;"
                      "aRequestAbort=%d", 
                      ( TUint )this, 
                      ( TUint )aMessage.Handle(), 
                      aWinEnd.Int64(),
                      aRequestAbort );
        aMessage.Panic( KRFlexTimerPanicCat,
                        EFlexTimerServerIllegalTimerValue );
        return;
        }
    
    TTimeIntervalMicroSeconds winStart;
    TTimeIntervalMicroSeconds window = iTimerWinSize;
    
    if ( iUseDefaultWin )
        {
        window = static_cast<TInt64> ( static_cast<TReal64> ( aWinEnd.Int64() )
            * KDefaultWindowMultiplier );
        }

    winStart = aWinEnd.Int64() - window.Int64();

    // Store pending message. Not completed until timer expires.
    // Note that in case of zero or negative timer value, message can
    // be completed through Timeout() even before AddTimer returns. This
    // implementation saves some checks and timer stopping/starting in engine.
    iPendingTimeoutMsg = aMessage;

    // Add timer to engine
    TInt ret = iService->AddTimer( winStart, aWinEnd, aRequestAbort, this );

    if ( KErrNone != ret )
        {
        // Failed, pass error code to client side
        OstTraceExt2( TRACE_INTERNAL,
                   CFLEXTIMERSESSION_ADDERROR,
                   "CFlexTimerSession::DoAddTimer: Error; this=%x, ret=%d",
                   ( TUint )this,
                   ret );
        // Complete pending message, this sets message pointer to NULL
        iPendingTimeoutMsg.Complete( ret );
        }
    }

// --------------------------------------------------------------------------
// From CSession2
// Function for handling unintentional termination of the client
// --------------------------------------------------------------------------
//
void CFlexTimerSession::Disconnect( const RMessage2 &aMessage )
    {
    // The client of this session has died.
    
    // Remove timer from engine.
    iService->CancelTimer( this );

    // Disconnect() must end with a call to the base class implementation, 
    // which will delete the session object and complete the disconnect 
    // message.
    CSession2::Disconnect( aMessage );
    }