multimediacommscontroller/mmccshared/src/mcctimermanager.cpp
changeset 0 1bce908db942
equal deleted inserted replaced
-1:000000000000 0:1bce908db942
       
     1 /*
       
     2 * Copyright (c) 2006-2008 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 #include "mcctimermanager.h"
       
    21 #include "mcccontrollerlogs.h"
       
    22 
       
    23 
       
    24 // Granularity for timer entry array iEntries
       
    25 const TInt KArrayGranularity( 8 );
       
    26 
       
    27 // 30min is the longest time we wait using RTimer::After() and millisecond
       
    28 // precision (absolute max would be ~35min). Anything longer goes for
       
    29 // RTimer::At() and one second precision.
       
    30 const TInt KMaxSeconds( 30 * 60 );
       
    31 
       
    32 // One second as microseconds
       
    33 const TInt KOneSecondAsMicros( 1000000 );
       
    34 
       
    35 // Minimum time interval for waiting with system timers (8 ms)
       
    36 // (max +-50% error with smallest delays (timer resolution in hw = ~15ms)
       
    37 const TInt KMinMicroseconds( 8000 );
       
    38 
       
    39 // -----------------------------------------------------------------------------
       
    40 // CMccTimerManager::NewL
       
    41 // -----------------------------------------------------------------------------
       
    42 //
       
    43 CMccTimerManager* CMccTimerManager::NewL()
       
    44 	{
       
    45 	CMccTimerManager* self = CMccTimerManager::NewLC();
       
    46 	CleanupStack::Pop( self );
       
    47 	return self;
       
    48 	}
       
    49 
       
    50 // -----------------------------------------------------------------------------
       
    51 // CMccTimerManager::NewLC
       
    52 // -----------------------------------------------------------------------------
       
    53 //
       
    54 CMccTimerManager* CMccTimerManager::NewLC()
       
    55 	{
       
    56 	CMccTimerManager* self = new( ELeave ) CMccTimerManager;
       
    57 	CleanupStack::PushL( self );
       
    58 	self->ConstructL();
       
    59 	return self;
       
    60 	}
       
    61 
       
    62 // -----------------------------------------------------------------------------
       
    63 // CMccTimerManager::~CMccTimerManager
       
    64 // -----------------------------------------------------------------------------
       
    65 //
       
    66 CMccTimerManager::~CMccTimerManager()
       
    67 	{
       
    68 	Cancel();
       
    69 	iTimer.Close();
       
    70 	iEntries.Reset();
       
    71 	}
       
    72 
       
    73 // -----------------------------------------------------------------------------
       
    74 // CMccTimerManager::DoCancel
       
    75 // -----------------------------------------------------------------------------
       
    76 //
       
    77 void CMccTimerManager::DoCancel()
       
    78 	{
       
    79 	iTimer.Cancel();
       
    80 	}
       
    81 
       
    82 // -----------------------------------------------------------------------------
       
    83 // CMccTimerManager::RunL
       
    84 // -----------------------------------------------------------------------------
       
    85 //
       
    86 void CMccTimerManager::RunL()
       
    87 	{
       
    88     __CONTROLLER("CMccTimerManager::RunL, Entry")
       
    89     
       
    90     if ( iEntries.Count() > 0 )
       
    91         {
       
    92     	// The first entry is the active one (which has expired)
       
    93     	// Make a copy so that we can delete the instance from the array
       
    94     	TEntry entry = iEntries[ 0 ];
       
    95     	iEntries.Delete( 0 );
       
    96 
       
    97     	// Schedule the next timer entry for execution (if any)
       
    98     	ActivateFirstEntry();
       
    99 
       
   100     	// Notify the observer, leave errors are ignored in RunError	
       
   101     	entry.iObserver->TimerExpiredL( entry.iId, entry.iObserverParam );
       
   102         }
       
   103 	
       
   104 	__CONTROLLER("CMccTimerManager::RunL, Exit")
       
   105 	}
       
   106 
       
   107 // -----------------------------------------------------------------------------
       
   108 // CMccTimerManager::RunError
       
   109 // -----------------------------------------------------------------------------
       
   110 //
       
   111 TInt CMccTimerManager::RunError( TInt aError )
       
   112     {
       
   113     __CONTROLLER_INT1("CMccTimerManager::RunError, error:", aError)
       
   114     
       
   115     if ( aError != KErrNoMemory )
       
   116         {
       
   117         aError = KErrNone;
       
   118         }
       
   119         
       
   120     return aError;
       
   121     }
       
   122     
       
   123 // -----------------------------------------------------------------------------
       
   124 // CMccTimerManager::StartL
       
   125 // -----------------------------------------------------------------------------
       
   126 //
       
   127 TMccTimerId CMccTimerManager::StartL( MMccExpirationHandler* aObserver,
       
   128 								TUint aMilliseconds )
       
   129 	{
       
   130 	return StartL( aObserver, aMilliseconds, NULL );
       
   131 	}
       
   132 
       
   133 // -----------------------------------------------------------------------------
       
   134 // CMccTimerManager::StartL
       
   135 // -----------------------------------------------------------------------------
       
   136 //
       
   137 TMccTimerId CMccTimerManager::StartL( MMccExpirationHandler* aObserver,
       
   138 								TUint aMilliseconds,
       
   139 								TAny* aTimerParam )
       
   140 	{
       
   141     __CONTROLLER_INT1( "CMccTimerManager::StartL aMilliseconds: ", aMilliseconds )
       
   142     
       
   143 	// Do not accept a NULL observer
       
   144 	if( !aObserver )
       
   145 		{
       
   146 		User::Leave( KErrArgument );
       
   147 		}
       
   148 
       
   149 	// Get new unique timer id
       
   150 	TMccTimerId newTimerId = NewTimerId();
       
   151 
       
   152 	// Define a new entry with the new id
       
   153 	TEntry newEntry;
       
   154 	newEntry.iId = newTimerId;
       
   155 	newEntry.iObserver = aObserver;
       
   156 	newEntry.iObserverParam = aTimerParam;
       
   157 
       
   158 	// Calculate a timestamp for the delay (aMilliseoncds from current time)
       
   159 	TInt64 microSeconds( aMilliseconds );
       
   160 	microSeconds *= 1000;
       
   161 	newEntry.iTimeStamp.HomeTime();
       
   162 	newEntry.iTimeStamp += TTimeIntervalMicroSeconds( microSeconds );
       
   163 
       
   164 	// Find an insertion point from the array
       
   165 	// Sort entries in timestamp order ("nearest" timestamp first)
       
   166 	TInt entryPos;
       
   167 	TInt count = iEntries.Count();
       
   168 	for( entryPos = 0; entryPos < count; entryPos++ )
       
   169 		{
       
   170 		if( iEntries[ entryPos ].iTimeStamp > newEntry.iTimeStamp )
       
   171 			{
       
   172 			break;
       
   173 			}
       
   174 		}
       
   175 
       
   176 	// Insert the new entry to the array
       
   177 	iEntries.InsertL( entryPos, newEntry );
       
   178 
       
   179 	// If the entry ended being the first entry, cancel any previous entries
       
   180 	// and schedule this one to the system timer instead.
       
   181 	if( entryPos == 0 )
       
   182 		{
       
   183 		ActivateFirstEntry();
       
   184 		}
       
   185 
       
   186     __CONTROLLER("CMccTimerManager::StartL, Exit")
       
   187 	return newEntry.iId;
       
   188 	}
       
   189 
       
   190 // -----------------------------------------------------------------------------
       
   191 // CMccTimerManager::Stop
       
   192 // -----------------------------------------------------------------------------
       
   193 //
       
   194 TInt CMccTimerManager::Stop( TMccTimerId aTimerId )
       
   195 	{
       
   196     __CONTROLLER("CMccTimerManager::Stop, Entry")
       
   197 	__CONTROLLER_INT1("timer", aTimerId )
       
   198 	
       
   199 	// Find the timer entry to be stopped
       
   200 	TInt entryIndex = FindEntry( aTimerId );
       
   201 	if( entryIndex == KErrNotFound )
       
   202 		{
       
   203         __CONTROLLER("CMccTimerManager::Stop - timer not active, Exit")
       
   204 		return KErrNotFound;
       
   205 		}
       
   206 
       
   207 	// Delete the timer entry from our array
       
   208 	iEntries.Delete( entryIndex );
       
   209 
       
   210 	// Cancel system timer if this entry was the active one
       
   211 	if( entryIndex == 0 )
       
   212 		{
       
   213 		// Schedule the next timer entry for execution (if any)
       
   214 		ActivateFirstEntry();
       
   215 		}
       
   216 
       
   217     __CONTROLLER("CMccTimerManager::Stop, Exit")
       
   218 	return KErrNone;
       
   219 	}
       
   220 
       
   221 // -----------------------------------------------------------------------------
       
   222 // CMccTimerManager::IsRunning
       
   223 // -----------------------------------------------------------------------------
       
   224 //
       
   225 TBool CMccTimerManager::IsRunning( TMccTimerId aTimerId ) const
       
   226 	{
       
   227 
       
   228 	TInt entryIndex = FindEntry( aTimerId );
       
   229 	if( entryIndex != KErrNotFound )
       
   230 		{
       
   231 		return ETrue;
       
   232 		}
       
   233 	return EFalse;
       
   234 	}
       
   235 
       
   236 // -----------------------------------------------------------------------------
       
   237 // CMccTimerManager::NewTimerId
       
   238 // -----------------------------------------------------------------------------
       
   239 //
       
   240 TMccTimerId CMccTimerManager::NewTimerId()
       
   241 	{
       
   242 	// Note that a rolling unsigned 32bit integer id counter
       
   243 	// is not strictly unique - however, it is not possible
       
   244 	// to have a timer with id 1 and id 2^32-1 at the same time
       
   245 	// due to time and memory constraints.
       
   246 	iTimerIdCounter++;
       
   247 	if( iTimerIdCounter == KNoSuchTimer )
       
   248 		{
       
   249 		iTimerIdCounter++;
       
   250 		}
       
   251 	return iTimerIdCounter;
       
   252 	}
       
   253 
       
   254 // -----------------------------------------------------------------------------
       
   255 // CMccTimerManager::FindEntry
       
   256 // -----------------------------------------------------------------------------
       
   257 //
       
   258 TInt CMccTimerManager::FindEntry( TMccTimerId aTimerId ) const
       
   259 	{
       
   260 	// Search for an entry with a matching id
       
   261 	// (entries are sorted by timestamp, not by id)
       
   262 	TInt count = iEntries.Count();
       
   263 	for( TInt i = 0; i < count; i++ )
       
   264 		{
       
   265 		if( iEntries[ i ].iId == aTimerId )
       
   266 			{
       
   267 			return i;
       
   268 			}
       
   269 		}
       
   270 
       
   271 	return KErrNotFound;
       
   272 	}
       
   273 
       
   274 // -----------------------------------------------------------------------------
       
   275 // CMccTimerManager::ActivateFirstEntry
       
   276 // -----------------------------------------------------------------------------
       
   277 //
       
   278 void CMccTimerManager::ActivateFirstEntry()
       
   279 	{
       
   280 	Cancel();
       
   281 	if( iEntries.Count() > 0 )
       
   282 		{
       
   283 		// Calculate required interval from current time
       
   284 		TTime now;
       
   285 		now.HomeTime();
       
   286 		TTime timeStamp = iEntries[ 0 ].iTimeStamp;
       
   287 		TInt64 interval( timeStamp.MicroSecondsFrom( now ).Int64() );
       
   288 		TInt64 intervalSeconds = interval / KOneSecondAsMicros;
       
   289 
       
   290 		// Check that the interval is long enough, otherwise complete
       
   291 		// immediately
       
   292 		if( interval > KMinMicroseconds )
       
   293 			{
       
   294 			// If interval is greater than ~33minutes (32bits), we have to use
       
   295 			// RTimer::At() instead of RTimer::After()
       
   296 			// At(), however, uses a precision of one second as compared
       
   297 			// to 1/64th (1/10th in emulator) precision of After()
       
   298 			if( intervalSeconds < KMaxSeconds )
       
   299 				{
       
   300 				iTimer.After( iStatus,
       
   301 						TTimeIntervalMicroSeconds32( I64INT( interval ) ) );
       
   302 				}
       
   303 			else
       
   304 				{
       
   305 				iTimer.At( iStatus, iEntries[ 0 ].iTimeStamp );
       
   306 				}
       
   307 			}
       
   308 		else
       
   309 			{
       
   310 			// Complete immediately
       
   311 			TRequestStatus* status = &iStatus;
       
   312 			User::RequestComplete( status, KErrNone );
       
   313 			}
       
   314 		SetActive();
       
   315 		}
       
   316 	}
       
   317 
       
   318 // -----------------------------------------------------------------------------
       
   319 // CMccTimerManager::CMccTimerManager
       
   320 // -----------------------------------------------------------------------------
       
   321 //
       
   322 CMccTimerManager::CMccTimerManager()
       
   323 	: CActive( CActive::EPriorityStandard ),
       
   324 	  iEntries( KArrayGranularity ),
       
   325 	  iTimerIdCounter( KNoSuchTimer )
       
   326 	{
       
   327 	CActiveScheduler::Add( this );
       
   328 	}
       
   329 
       
   330 // -----------------------------------------------------------------------------
       
   331 // CMccTimerManager::ConstructL
       
   332 // -----------------------------------------------------------------------------
       
   333 //
       
   334 void CMccTimerManager::ConstructL()
       
   335 	{
       
   336 	User::LeaveIfError( iTimer.CreateLocal() );
       
   337 	}
       
   338 
       
   339 // -----------------------------------------------------------------------------
       
   340 // CMccTimerManager::TEntry::TEntry
       
   341 // -----------------------------------------------------------------------------
       
   342 //
       
   343 CMccTimerManager::TEntry::TEntry()
       
   344 	: iId( KNoSuchTimer ), iTimeStamp(),
       
   345 	  iObserver( NULL ), iObserverParam( NULL )
       
   346 	{
       
   347 	}