examples/Base/IPC/Async/Fibonacci3/Fibonacci3.cpp

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 

Generated by  doxygen 1.6.2