00001 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). 00002 // All rights reserved. 00003 // This component and the accompanying materials are made available 00004 // under the terms of "Eclipse Public License v1.0" 00005 // which accompanies this distribution, and is available 00006 // at the URL "http://www.eclipse.org/legal/epl-v10.html". 00007 // 00008 // Initial Contributors: 00009 // Nokia Corporation - initial contribution. 00010 // 00011 // Contributors: 00012 // 00013 // Description: 00014 // Example wraps a console in an active object and performs the 00015 // Fibonacci calculation as a background active object. 00016 // The technique used is similar to, but not identical, to that used by CIdle, where 00017 // the background active object is repeatedly called provided the other (higher priority) 00018 // active objects are not ready to run. 00019 // Fibonacci Active Objects example 00020 // 00021 00022 #include <e32cons.h> 00023 #include <e32base.h> 00024 #include <e32std.h> 00025 00027 //nclude <e32hal.h> 00028 00029 00030 LOCAL_D CConsoleBase* console; 00031 00032 _LIT(KTxtMainInstructions,"\n\nPress 'F' to start\n 'ESC' to exit\n 'C' to cancel, anytime\n"); 00033 00035 // 00036 // -----> CActiveConsole (definition) 00037 // 00038 // An abstract class which provides the facility to issue key requests. 00039 // 00041 class CActiveConsole : public CActive 00042 { 00043 public: 00044 // Construction 00045 CActiveConsole(CConsoleBase* aConsole); 00046 void ConstructL(); 00047 00048 // Destruction 00049 ~CActiveConsole(); 00050 00051 // Issue request 00052 void RequestCharacter(); 00053 00054 // Cancel request. 00055 // Defined as pure virtual by CActive; 00056 // implementation provided by this class. 00057 void DoCancel(); 00058 00059 // Service completed request. 00060 // Defined as pure virtual by CActive; 00061 // implementation provided by this class, 00062 void RunL(); 00063 00064 // Called from RunL() - an implementation must be provided 00065 // by derived classes to handle the completed request 00066 virtual void ProcessKeyPress(TChar aChar) = 0; 00067 00068 protected: 00069 // Data members defined by this class 00070 CConsoleBase* iConsole; // A console for reading from 00071 }; 00072 00073 00075 // 00076 // -----> CExampleScheduler (definition) 00077 // 00079 class CActiveConsole; 00080 00081 class CExampleScheduler : public CActiveScheduler 00082 { 00083 public: 00084 void Error (TInt aError) const; 00085 void WaitForAnyRequest(); 00086 void SetActiveObject(CActiveConsole* aActiveConsole); 00087 private: 00088 // data members defined for this class 00089 CActiveConsole* iActiveConsole; 00090 }; 00091 00092 00093 00095 // 00096 // -----> CFibonacciEngine (definition) 00097 // 00098 // This class provides the fibonacci calculation engine 00099 // 00101 00102 class CFibonacciEngine : public CBase 00103 { 00104 public: 00105 CFibonacciEngine() ; 00106 void StartCalculate (TInt aTerms) ; 00107 void StepCalculate () ; 00108 00109 TUint iResult ; 00110 00111 enum TEngineState {eInactive, eCalculating, eCompleted} ; 00112 TEngineState iState ; 00113 00114 private: 00115 TUint iCurrentTotal ; 00116 TUint iPreviousTotal ; 00117 TInt iTermsLeftToDo ; 00118 } ; 00119 00120 00122 // 00123 // -----> CFibonacciApplication (definition) 00124 // 00125 // This class encapsulates the fibonacci thread that runs the fibonacci engine 00126 // 00128 00129 class CFibonacciApplication : public CActive 00130 { 00131 public: 00132 CFibonacciApplication(CConsoleBase* aConsole, CFibonacciEngine* aFibonacciEngine) ; 00133 ~CFibonacciApplication() ; 00134 00135 void CalculateFibonacci(TInt aIterations) ; 00136 00137 private: 00138 void DoCancel() ; 00139 void RunL() ; 00140 00141 private: 00142 CConsoleBase* iConsole ; 00143 CFibonacciEngine* iFibonacciEngine ; 00144 } ; 00145 00146 00148 // 00149 // -----> CFibonacciKeyHandler (definition) 00150 // 00151 // This class encapsulates the fibonacci keyboard handler 00152 // 00154 00155 class CFibonacciKeyHandler : public CActiveConsole 00156 { 00157 public: 00158 CFibonacciKeyHandler( CConsoleBase* aConsole, 00159 CFibonacciApplication* aApplication) ; 00160 void ConstructL(); 00161 00162 // Static construction 00163 static CFibonacciKeyHandler* NewLC(CConsoleBase* aConsole, CFibonacciApplication* aHandler) ; 00164 00165 // service request 00166 void ProcessKeyPress(TChar aChar) ; 00167 00168 private: 00169 CConsoleBase* iConsole ; 00170 CFibonacciApplication* iApplication ; 00171 }; 00172 00173 00175 // 00176 // -----> CActiveConsole (implementation) 00177 // 00179 CActiveConsole::CActiveConsole( CConsoleBase* aConsole) 00180 : CActive(CActive::EPriorityUserInput) 00181 // Construct high-priority active object 00182 { 00183 iConsole = aConsole; 00184 __DECLARE_NAME(_S("CActiveConsole")); 00185 00186 } 00187 00188 void CActiveConsole::ConstructL() 00189 { 00190 // Add to active scheduler 00191 CActiveScheduler::Add(this); 00192 } 00193 00194 CActiveConsole::~CActiveConsole() 00195 { 00196 // Make sure we're cancelled 00197 Cancel(); 00198 } 00199 00200 void CActiveConsole::DoCancel() 00201 { 00202 iConsole->ReadCancel(); 00203 } 00204 00205 void CActiveConsole::RunL() 00206 { 00207 // Handle completed request 00208 ProcessKeyPress(TChar(iConsole->KeyCode())); 00209 } 00210 00211 void CActiveConsole::RequestCharacter() 00212 { 00213 // A request is issued to the CConsoleBase to accept a 00214 // character from the keyboard. 00215 iConsole->Read(iStatus); 00216 SetActive(); 00217 } 00218 00219 00221 // 00222 // -----> CExampleScheduler (implementation) 00223 // 00225 void CExampleScheduler::Error(TInt aError) const 00226 { 00227 _LIT(KTxtSchedulerError,"CExampleScheduler - error"); 00228 User::Panic(KTxtSchedulerError,aError); 00229 } 00230 00231 00232 void CExampleScheduler::WaitForAnyRequest() 00233 { 00234 if (!(iActiveConsole->IsActive())) 00235 iActiveConsole->RequestCharacter(); 00236 CActiveScheduler::WaitForAnyRequest(); 00237 } 00238 00239 void CExampleScheduler::SetActiveObject(CActiveConsole* aActiveConsole) 00240 { 00241 iActiveConsole = aActiveConsole; 00242 } 00243 00244 00245 00247 // CFibonacciKeyHandler support routine 00248 // uses up arrow & down arrow to change number, Enter to select 00250 00251 TInt GetValueFromKeyboard (TInt aInitial, TInt aStep, TInt lowerLimit, TInt upperLimit, const TDesC& aPrompt, CConsoleBase* aConsole) 00252 { 00253 TChar input ; 00254 TInt value = aInitial ; 00255 00256 aConsole->Printf(aPrompt) ; 00257 do 00258 { 00259 aConsole->SetPos(0); 00260 _LIT(KFormat1,"%d "); 00261 aConsole->Printf(KFormat1, value); 00262 input = aConsole->Getch() ; 00263 if (input == EKeyUpArrow && value < upperLimit) value = value + aStep ; 00264 if (input == EKeyDownArrow && value > lowerLimit) value = value - aStep ; 00265 } 00266 while (input != EKeyEnter) ; 00267 00268 return value ; 00269 } 00270 00271 00273 // 00274 // -----> CFibonacciKeyHandler (implementation) 00275 // 00277 00278 CFibonacciKeyHandler::CFibonacciKeyHandler(CConsoleBase* aConsole, CFibonacciApplication* aApplication) 00279 : CActiveConsole(aConsole) 00280 // construct zero-priority active object 00281 { 00282 iConsole = aConsole ; 00283 iApplication = aApplication ; 00284 00285 __DECLARE_NAME(_S("CFibonacciApplication")); 00286 // Add to active scheduler 00287 CActiveScheduler::Add(this); 00288 // Make this the active object 00289 ((CExampleScheduler*)(CActiveScheduler::Current()))->SetActiveObject(this); 00290 } 00291 00292 00293 void CFibonacciKeyHandler::ProcessKeyPress(TChar aChar) 00294 { 00295 // if key is ESC, cancel any outstanding request & stop the scheduler 00296 if (aChar == EKeyEscape) 00297 { 00298 CActiveScheduler::Stop(); 00299 return; 00300 } 00301 00302 // If key is "f" or "F", issue a Fibonacci request if none is in progress 00303 if (aChar == 'f' || aChar == 'F') 00304 { 00305 if (!(iApplication->IsActive())) 00306 { 00307 _LIT(KTxtReturnTermNumber,"\nENTER selects num\nUP arrow increases num\nDOWN arrow decreases num\n\n"); 00308 TInt iterations = GetValueFromKeyboard(5,1,2,46, KTxtReturnTermNumber, iConsole) ; 00309 iApplication->CalculateFibonacci(iterations); 00310 } 00311 else 00312 { 00313 _LIT(KTxtAlreadyInProgress,"[Already in progress]"); 00314 iConsole->Printf(KTxtAlreadyInProgress); 00315 } 00316 return; 00317 } 00318 00319 // If key is "c" or "C", cancel any outstanding request 00320 if (aChar == 'c' || aChar == 'C') 00321 { 00322 _LIT(KTxtCancelFibonacci,"\nCancelling Fibonacci.... \n"); 00323 iConsole->Printf(KTxtCancelFibonacci); 00324 iApplication->Cancel(); 00325 iConsole->Printf(KTxtMainInstructions); 00326 return; 00327 } 00328 00329 _LIT(KTxtNotRecognised,"\nUnwanted key pressed"); 00330 iConsole->Printf(KTxtNotRecognised); 00331 iConsole->Printf(KTxtMainInstructions); 00332 } 00333 00334 00336 // 00337 // -----> CFibonacciApplication (implementation) 00338 // 00340 00341 CFibonacciApplication::CFibonacciApplication(CConsoleBase* aConsole, CFibonacciEngine* aFibonacciEngine) 00342 // 00343 // Constructor 00344 // 00345 : CActive(EPriorityStandard) 00346 { 00347 iConsole = aConsole ; 00348 iFibonacciEngine = aFibonacciEngine ; 00349 CActiveScheduler::Add(this); 00350 __DECLARE_NAME(_S("CFibonacciApplication")); 00351 }; 00352 00353 00354 // destructor 00355 CFibonacciApplication::~CFibonacciApplication() 00356 { 00357 // cancel any requests and tell server 00358 Cancel() ; 00359 } 00360 00361 00362 void CFibonacciApplication::DoCancel() 00363 { 00364 // cancel the active object request 00365 iFibonacciEngine->iState = CFibonacciEngine::eInactive ; 00366 } 00367 00368 00369 00370 // initiate a request 00371 void CFibonacciApplication::CalculateFibonacci(TInt aIterations) 00372 { 00373 // initialize engine 00374 // no neeed to set iStatus to KRequestPending, as request completes below 00375 iFibonacciEngine->StartCalculate(aIterations) ; 00376 00377 // schedule the request 00378 SetActive() ; 00379 00380 // send signal that this request has completed 00381 TRequestStatus* status = &iStatus ; 00382 User::RequestComplete(status, KErrNone) ; 00383 } 00384 00385 00386 00387 void CFibonacciApplication::RunL() 00388 // implements a simple state engine: {eInactive, eCalculating, eCompleted} 00389 { 00390 if (iFibonacciEngine->iState == CFibonacciEngine::eInactive ) 00391 { 00392 _LIT(KTxtEngineNotInitialized,"Engine not initialized"); 00393 User::Panic(KTxtEngineNotInitialized, KErrNotReady) ; 00394 } 00395 else if (iFibonacciEngine->iState == CFibonacciEngine::eCalculating ) 00396 { 00397 // unnecessary - just provides feedback on progression of the calculation 00398 _LIT(KTxtDot,"."); 00399 iConsole->Printf(KTxtDot) ; 00400 00401 // no neeed to set iStatus to KRequestPending, as request completes below 00402 00403 // request next step 00404 iFibonacciEngine->StepCalculate() ; 00405 00406 // schedule request 00407 SetActive() ; 00408 00409 // send signal that this request has completed 00410 TRequestStatus* status = &iStatus ; 00411 User::RequestComplete(status, KErrNone) ; 00412 } 00413 else if (iFibonacciEngine->iState == CFibonacciEngine::eCompleted ) 00414 { 00415 // finished calculation: print result and reset state engine 00416 _LIT(KFormat2,"\n Result : %u \n"); //not used 00417 iConsole->Printf(KFormat2, iFibonacciEngine->iResult) ; 00418 iConsole->Printf(KTxtMainInstructions) ; 00419 iFibonacciEngine->iState = CFibonacciEngine::eInactive ; 00420 } 00421 } 00422 00423 00424 00426 // 00427 // -----> CFibonacciEngine (implementation) 00428 // 00430 CFibonacciEngine::CFibonacciEngine() 00431 { 00432 iState = eInactive ; 00433 } 00434 00435 00436 void CFibonacciEngine::StartCalculate (TInt aTerms) 00437 { 00438 // initialise all internal variables to initial state 00439 iCurrentTotal = 1 ; 00440 iPreviousTotal = 0 ; 00441 iResult = 0 ; 00442 iTermsLeftToDo = aTerms + 1 ; // first step completed in variable initialization 00443 iState = eCalculating ; 00444 } 00445 00446 00447 00448 void CFibonacciEngine::StepCalculate () 00449 { 00450 00451 // if full calculation not yet complete, but in progress (i.e. not cancelled) 00452 if (--iTermsLeftToDo > 0 && iState == eCalculating) 00453 { 00454 // calculate next number in series 00455 TInt newTotal = iCurrentTotal + iPreviousTotal ; 00456 00457 // update internal variables 00458 iPreviousTotal = iCurrentTotal ; 00459 iCurrentTotal = newTotal ; 00460 00461 // introduce a delay to make us a long-running service 00462 User::After(1000000) ; 00463 00464 // not necessary, but allows running total to be used during the calculation 00465 // (say for putting values into a chart or graph) 00466 iResult = iCurrentTotal ; 00467 } 00468 else if (iTermsLeftToDo <= 0) 00469 { 00470 // flag that calculation has finished and ensure final result is available 00471 iState = eCompleted ; 00472 iResult = iCurrentTotal ; 00473 } 00474 } 00475 00476 00477 00479 // This section deals with initialisation and ensuring we have a console active 00481 00482 void doExampleL () ; 00483 00484 void SetupConsoleL(); 00485 00486 GLDEF_C TInt E32Main() // main function called by E32 00487 { 00488 CTrapCleanup* cleanup=CTrapCleanup::New(); // get clean-up stack 00489 TRAPD(error,SetupConsoleL()); // more initialization, then do example 00490 _LIT(KTxtFibonacciExampleError,"Fibonacci example error"); 00491 __ASSERT_ALWAYS(!error,User::Panic(KTxtFibonacciExampleError,error)); 00492 delete cleanup; // destroy clean-up stack 00493 return 0; // and return 00494 } 00495 00496 void SetupConsoleL() // initialize and call example code under cleanup stack 00497 { 00498 _LIT(KTxtFibActObjBackground,"Background Active Object"); 00499 console=Console::NewL(KTxtFibActObjBackground, TSize(KConsFullScreen,KConsFullScreen)); 00500 CleanupStack::PushL(console); 00501 console->Printf(KTxtMainInstructions) ; 00502 TRAPD(error, doExampleL()); // perform example function 00503 if (error) 00504 { 00505 _LIT(KFormat3,"failed: leave code=%d"); 00506 console->Printf(KFormat3, error); 00507 } 00508 _LIT(KTxtPressAnyKey,"[Press any key to exit]"); 00509 console->Printf(KTxtPressAnyKey); 00510 console->Getch(); // get and ignore character 00511 CleanupStack::PopAndDestroy(); // close console 00512 } 00513 00514 00516 // 00517 // Do the example 00518 // 00520 void doExampleL() 00521 { 00522 // Construct and install the active scheduler; push onto the cleanup stack 00523 CExampleScheduler* exampleScheduler = new (ELeave) CExampleScheduler; 00524 CleanupStack::PushL(exampleScheduler); 00525 00526 // Install as the active scheduler 00527 CActiveScheduler::Install(exampleScheduler); 00528 00529 // Create CFibonacciEngine active object; push onto the cleanup stack 00530 CFibonacciEngine* fibEngine = new (ELeave) CFibonacciEngine ; 00531 CleanupStack::PushL(fibEngine); 00532 00533 // Create CFibonacciApplication handler active object; push onto the cleanup stack 00534 CFibonacciApplication* fibApplication = new CFibonacciApplication(console, fibEngine); 00535 CleanupStack::PushL(fibApplication); 00536 00537 // Create CFibonacciKeyHandler active object; push onto the cleanup stack 00538 CFibonacciKeyHandler* fibKeyHandler = new CFibonacciKeyHandler(console, fibApplication); 00539 CleanupStack::PushL(fibKeyHandler); 00540 00541 // issue initial request 00542 fibKeyHandler->RequestCharacter() ; 00543 00544 // Main part of the program: 00545 // wait loop that cycles until ActiveScheduler::Stop called 00546 CActiveScheduler::Start(); 00547 00548 // Remove items from the cleanup stack and destroy them 00549 CleanupStack::PopAndDestroy(4); 00550 } 00551 00552
Copyright ©2010 Nokia Corporation and/or its subsidiary(-ies).
All rights
reserved. Unless otherwise stated, these materials are provided under the terms of the Eclipse Public License
v1.0.