multimediacommscontroller/mmccshared/src/mcctimermanager.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmccshared/src/mcctimermanager.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,347 @@
+/*
+* Copyright (c) 2006-2008 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:  
+*
+*/
+
+
+
+#include "mcctimermanager.h"
+#include "mcccontrollerlogs.h"
+
+
+// Granularity for timer entry array iEntries
+const TInt KArrayGranularity( 8 );
+
+// 30min is the longest time we wait using RTimer::After() and millisecond
+// precision (absolute max would be ~35min). Anything longer goes for
+// RTimer::At() and one second precision.
+const TInt KMaxSeconds( 30 * 60 );
+
+// One second as microseconds
+const TInt KOneSecondAsMicros( 1000000 );
+
+// Minimum time interval for waiting with system timers (8 ms)
+// (max +-50% error with smallest delays (timer resolution in hw = ~15ms)
+const TInt KMinMicroseconds( 8000 );
+
+// -----------------------------------------------------------------------------
+// CMccTimerManager::NewL
+// -----------------------------------------------------------------------------
+//
+CMccTimerManager* CMccTimerManager::NewL()
+	{
+	CMccTimerManager* self = CMccTimerManager::NewLC();
+	CleanupStack::Pop( self );
+	return self;
+	}
+
+// -----------------------------------------------------------------------------
+// CMccTimerManager::NewLC
+// -----------------------------------------------------------------------------
+//
+CMccTimerManager* CMccTimerManager::NewLC()
+	{
+	CMccTimerManager* self = new( ELeave ) CMccTimerManager;
+	CleanupStack::PushL( self );
+	self->ConstructL();
+	return self;
+	}
+
+// -----------------------------------------------------------------------------
+// CMccTimerManager::~CMccTimerManager
+// -----------------------------------------------------------------------------
+//
+CMccTimerManager::~CMccTimerManager()
+	{
+	Cancel();
+	iTimer.Close();
+	iEntries.Reset();
+	}
+
+// -----------------------------------------------------------------------------
+// CMccTimerManager::DoCancel
+// -----------------------------------------------------------------------------
+//
+void CMccTimerManager::DoCancel()
+	{
+	iTimer.Cancel();
+	}
+
+// -----------------------------------------------------------------------------
+// CMccTimerManager::RunL
+// -----------------------------------------------------------------------------
+//
+void CMccTimerManager::RunL()
+	{
+    __CONTROLLER("CMccTimerManager::RunL, Entry")
+    
+    if ( iEntries.Count() > 0 )
+        {
+    	// The first entry is the active one (which has expired)
+    	// Make a copy so that we can delete the instance from the array
+    	TEntry entry = iEntries[ 0 ];
+    	iEntries.Delete( 0 );
+
+    	// Schedule the next timer entry for execution (if any)
+    	ActivateFirstEntry();
+
+    	// Notify the observer, leave errors are ignored in RunError	
+    	entry.iObserver->TimerExpiredL( entry.iId, entry.iObserverParam );
+        }
+	
+	__CONTROLLER("CMccTimerManager::RunL, Exit")
+	}
+
+// -----------------------------------------------------------------------------
+// CMccTimerManager::RunError
+// -----------------------------------------------------------------------------
+//
+TInt CMccTimerManager::RunError( TInt aError )
+    {
+    __CONTROLLER_INT1("CMccTimerManager::RunError, error:", aError)
+    
+    if ( aError != KErrNoMemory )
+        {
+        aError = KErrNone;
+        }
+        
+    return aError;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccTimerManager::StartL
+// -----------------------------------------------------------------------------
+//
+TMccTimerId CMccTimerManager::StartL( MMccExpirationHandler* aObserver,
+								TUint aMilliseconds )
+	{
+	return StartL( aObserver, aMilliseconds, NULL );
+	}
+
+// -----------------------------------------------------------------------------
+// CMccTimerManager::StartL
+// -----------------------------------------------------------------------------
+//
+TMccTimerId CMccTimerManager::StartL( MMccExpirationHandler* aObserver,
+								TUint aMilliseconds,
+								TAny* aTimerParam )
+	{
+    __CONTROLLER_INT1( "CMccTimerManager::StartL aMilliseconds: ", aMilliseconds )
+    
+	// Do not accept a NULL observer
+	if( !aObserver )
+		{
+		User::Leave( KErrArgument );
+		}
+
+	// Get new unique timer id
+	TMccTimerId newTimerId = NewTimerId();
+
+	// Define a new entry with the new id
+	TEntry newEntry;
+	newEntry.iId = newTimerId;
+	newEntry.iObserver = aObserver;
+	newEntry.iObserverParam = aTimerParam;
+
+	// Calculate a timestamp for the delay (aMilliseoncds from current time)
+	TInt64 microSeconds( aMilliseconds );
+	microSeconds *= 1000;
+	newEntry.iTimeStamp.HomeTime();
+	newEntry.iTimeStamp += TTimeIntervalMicroSeconds( microSeconds );
+
+	// Find an insertion point from the array
+	// Sort entries in timestamp order ("nearest" timestamp first)
+	TInt entryPos;
+	TInt count = iEntries.Count();
+	for( entryPos = 0; entryPos < count; entryPos++ )
+		{
+		if( iEntries[ entryPos ].iTimeStamp > newEntry.iTimeStamp )
+			{
+			break;
+			}
+		}
+
+	// Insert the new entry to the array
+	iEntries.InsertL( entryPos, newEntry );
+
+	// If the entry ended being the first entry, cancel any previous entries
+	// and schedule this one to the system timer instead.
+	if( entryPos == 0 )
+		{
+		ActivateFirstEntry();
+		}
+
+    __CONTROLLER("CMccTimerManager::StartL, Exit")
+	return newEntry.iId;
+	}
+
+// -----------------------------------------------------------------------------
+// CMccTimerManager::Stop
+// -----------------------------------------------------------------------------
+//
+TInt CMccTimerManager::Stop( TMccTimerId aTimerId )
+	{
+    __CONTROLLER("CMccTimerManager::Stop, Entry")
+	__CONTROLLER_INT1("timer", aTimerId )
+	
+	// Find the timer entry to be stopped
+	TInt entryIndex = FindEntry( aTimerId );
+	if( entryIndex == KErrNotFound )
+		{
+        __CONTROLLER("CMccTimerManager::Stop - timer not active, Exit")
+		return KErrNotFound;
+		}
+
+	// Delete the timer entry from our array
+	iEntries.Delete( entryIndex );
+
+	// Cancel system timer if this entry was the active one
+	if( entryIndex == 0 )
+		{
+		// Schedule the next timer entry for execution (if any)
+		ActivateFirstEntry();
+		}
+
+    __CONTROLLER("CMccTimerManager::Stop, Exit")
+	return KErrNone;
+	}
+
+// -----------------------------------------------------------------------------
+// CMccTimerManager::IsRunning
+// -----------------------------------------------------------------------------
+//
+TBool CMccTimerManager::IsRunning( TMccTimerId aTimerId ) const
+	{
+
+	TInt entryIndex = FindEntry( aTimerId );
+	if( entryIndex != KErrNotFound )
+		{
+		return ETrue;
+		}
+	return EFalse;
+	}
+
+// -----------------------------------------------------------------------------
+// CMccTimerManager::NewTimerId
+// -----------------------------------------------------------------------------
+//
+TMccTimerId CMccTimerManager::NewTimerId()
+	{
+	// Note that a rolling unsigned 32bit integer id counter
+	// is not strictly unique - however, it is not possible
+	// to have a timer with id 1 and id 2^32-1 at the same time
+	// due to time and memory constraints.
+	iTimerIdCounter++;
+	if( iTimerIdCounter == KNoSuchTimer )
+		{
+		iTimerIdCounter++;
+		}
+	return iTimerIdCounter;
+	}
+
+// -----------------------------------------------------------------------------
+// CMccTimerManager::FindEntry
+// -----------------------------------------------------------------------------
+//
+TInt CMccTimerManager::FindEntry( TMccTimerId aTimerId ) const
+	{
+	// Search for an entry with a matching id
+	// (entries are sorted by timestamp, not by id)
+	TInt count = iEntries.Count();
+	for( TInt i = 0; i < count; i++ )
+		{
+		if( iEntries[ i ].iId == aTimerId )
+			{
+			return i;
+			}
+		}
+
+	return KErrNotFound;
+	}
+
+// -----------------------------------------------------------------------------
+// CMccTimerManager::ActivateFirstEntry
+// -----------------------------------------------------------------------------
+//
+void CMccTimerManager::ActivateFirstEntry()
+	{
+	Cancel();
+	if( iEntries.Count() > 0 )
+		{
+		// Calculate required interval from current time
+		TTime now;
+		now.HomeTime();
+		TTime timeStamp = iEntries[ 0 ].iTimeStamp;
+		TInt64 interval( timeStamp.MicroSecondsFrom( now ).Int64() );
+		TInt64 intervalSeconds = interval / KOneSecondAsMicros;
+
+		// Check that the interval is long enough, otherwise complete
+		// immediately
+		if( interval > KMinMicroseconds )
+			{
+			// If interval is greater than ~33minutes (32bits), we have to use
+			// RTimer::At() instead of RTimer::After()
+			// At(), however, uses a precision of one second as compared
+			// to 1/64th (1/10th in emulator) precision of After()
+			if( intervalSeconds < KMaxSeconds )
+				{
+				iTimer.After( iStatus,
+						TTimeIntervalMicroSeconds32( I64INT( interval ) ) );
+				}
+			else
+				{
+				iTimer.At( iStatus, iEntries[ 0 ].iTimeStamp );
+				}
+			}
+		else
+			{
+			// Complete immediately
+			TRequestStatus* status = &iStatus;
+			User::RequestComplete( status, KErrNone );
+			}
+		SetActive();
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CMccTimerManager::CMccTimerManager
+// -----------------------------------------------------------------------------
+//
+CMccTimerManager::CMccTimerManager()
+	: CActive( CActive::EPriorityStandard ),
+	  iEntries( KArrayGranularity ),
+	  iTimerIdCounter( KNoSuchTimer )
+	{
+	CActiveScheduler::Add( this );
+	}
+
+// -----------------------------------------------------------------------------
+// CMccTimerManager::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CMccTimerManager::ConstructL()
+	{
+	User::LeaveIfError( iTimer.CreateLocal() );
+	}
+
+// -----------------------------------------------------------------------------
+// CMccTimerManager::TEntry::TEntry
+// -----------------------------------------------------------------------------
+//
+CMccTimerManager::TEntry::TEntry()
+	: iId( KNoSuchTimer ), iTimeStamp(),
+	  iObserver( NULL ), iObserverParam( NULL )
+	{
+	}