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

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

Generated by  doxygen 1.6.2