Adaptation/GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703.dita
changeset 15 307f4279f433
equal deleted inserted replaced
14:578be2adaf3e 15:307f4279f433
       
     1 <?xml version="1.0" encoding="utf-8"?>
       
     2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
       
     3 <!-- This component and the accompanying materials are made available under the terms of the License 
       
     4 "Eclipse Public License v1.0" which accompanies this distribution, 
       
     5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
       
     6 <!-- Initial Contributors:
       
     7     Nokia Corporation - initial contribution.
       
     8 Contributors: 
       
     9 -->
       
    10 <!DOCTYPE concept
       
    11   PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
       
    12 <concept id="GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703" xml:lang="en"><title>Power Controller DPowerController Implementation Tutorial</title><shortdesc>This topic describes how to implement the <codeph>DPowerController</codeph> class to provide the main power controller functionality in a base
       
    13 port.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
       
    14 <p><xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita"><apiname>DPowerController</apiname></xref> is defined as: </p>
       
    15 <codeblock id="GUID-95318C39-B205-557C-B1F3-75C1441E464A" xml:space="preserve">class DPowerController : public DBase
       
    16     {
       
    17 public:
       
    18     IMPORT_C DPowerController();
       
    19     IMPORT_C void Register();
       
    20     IMPORT_C void WakeupEvent();
       
    21 
       
    22 #ifndef __X86__
       
    23     IMPORT_C TInt RegisterResourceController(DBase* aController, TInt aClientId);
       
    24 private:
       
    25     struct SResourceControllerData
       
    26         {
       
    27         DBase* iResourceController;
       
    28         TInt   iClientId;
       
    29         } iResourceControllerData;
       
    30 #endif
       
    31 
       
    32 public:
       
    33     volatile TPowerState    iTargetState;
       
    34 public:
       
    35     virtual void CpuIdle() = 0;
       
    36     virtual void EnableWakeupEvents() = 0;
       
    37     virtual void DisableWakeupEvents() = 0;
       
    38     virtual void AbsoluteTimerExpired() = 0;
       
    39     virtual void PowerDown(TTimeK aWakeupTime) = 0;
       
    40     };
       
    41       </codeblock>
       
    42 <p>The first three functions are exported from the kernel, <filepath>EKERN.EXE</filepath>, while the other five pure virtual functions
       
    43 are implemented by your base port. You do not need to export any other
       
    44 functions. </p>
       
    45 <ul>
       
    46 <li id="GUID-2EEFEFF3-FCAF-526C-A11B-790A2A47AA9C"><p> <xref href="GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703.dita#GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703/GUID-BCCDBA09-415D-5779-BCE5-CDEB2E1EF7D8">Initialising the power controller</xref>, </p> </li>
       
    47 <li id="GUID-CBB1EE9C-CD27-5417-973C-3BBED74715D6"><p> <xref href="GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703.dita#GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703/GUID-DCD91EBA-CB0E-5EA9-84E0-8F8FED6FC91E">DPowerController::RegisterResourceController()</xref>, </p> </li>
       
    48 <li id="GUID-4E2D396D-E6FA-5658-830F-9F82D4A63AD1"><p> <xref href="GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703.dita#GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703/GUID-5A0CAD08-AA12-56EE-B0A3-75548D1896C9">DPowerController::EnableWakeupEvents()</xref>, </p> </li>
       
    49 <li id="GUID-DB82BCE3-702A-51EB-ADE0-9434D59CD553"><p> <xref href="GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703.dita#GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703/GUID-51D37A0C-AD46-52D5-A31C-CB3A8046CE84">DPowerController::AbsoluteTimerExpired()</xref>, </p> </li>
       
    50 <li id="GUID-77CCBFFE-037D-5B86-BF14-1BE87D38B47A"><p> <xref href="GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703.dita#GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703/GUID-1F77C71C-D226-58BB-ABAE-43F958CC0C61">DPowerController::PowerDown()</xref>, </p> </li>
       
    51 <li id="GUID-8657D772-2338-588D-B074-832B06144D8B"><p> <xref href="GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703.dita#GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703/GUID-E2A072D0-A67F-5E6D-81ED-CFD77B6ED4F1">CpuIdle()</xref>. </p> </li>
       
    52 </ul>
       
    53 <section id="GUID-BCCDBA09-415D-5779-BCE5-CDEB2E1EF7D8"><title>Initialising
       
    54 the power controller</title> <p>Typically, you implement your derived
       
    55 class in a power management kernel extension, which has the opportunity
       
    56 to perform initialisation before the system itself is fully initialised.
       
    57 This is done via the extension's DLL entry point. You use the <xref href="GUID-7964FC46-4641-3BDD-92C9-50FA22C3321A.dita"><apiname>DECLARE_STANDARD_EXTENSION()</apiname></xref> macro as a wrapper around
       
    58 your initialisation code. There are at least three things to do here: </p> <ul>
       
    59 <li id="GUID-25C66F1B-6B2F-5B3B-A827-410263EE22A4"><p>create an instance
       
    60 of your power controller object </p> </li>
       
    61 <li id="GUID-369A09EC-74D3-529A-AC05-0EFE0C4ABBF7"><p>register your
       
    62 power controller object with the Symbian platform power manager, by
       
    63 calling <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-F66D72D0-AA27-3BAF-8915-C6E8CC4E7CCF"><apiname>DPowerController::Register()</apiname></xref>. Your power
       
    64 controller cannot be used by the Symbian platform power manager until
       
    65 it has been registered. </p> </li>
       
    66 <li id="GUID-E4C7D934-AAB9-511B-93A4-125D5A5B248D"><p>if you intend
       
    67 to use a battery monitor, then you would create it and register it
       
    68 as the HAL handler to deal with <xref href="GUID-66A851A0-2A0C-3624-AEC1-22F6629FABF7.dita#GUID-66A851A0-2A0C-3624-AEC1-22F6629FABF7/GUID-227B4DCD-5D74-3AB7-8E09-64A04D88F094"><apiname>THalFunctionGroup::EHALGroupPower</apiname></xref> calls. See <xref href="GUID-65CDCA83-C726-5173-8E46-B8981D1D7B02.dita">Battery Monitor Implementation Tutorialc</xref> and <xref href="GUID-54042C84-6216-5930-9CBF-BAF635CECD4D.dita">Power HAL Handler
       
    69 Tutorial</xref> for more detail. </p> </li>
       
    70 </ul> <p>For example: </p> <codeblock id="GUID-1A909C4C-DCAF-54E3-B482-16918E33BF4F" xml:space="preserve">DECLARE_STANDARD_EXTENSION()
       
    71     {
       
    72     TInt r=KErrNoMemory;
       
    73 
       
    74     // Create the power controller object, and register it.
       
    75     DPowerController* pC = new DYourPowerController;
       
    76     if !(pC)
       
    77         {
       
    78         return (r);
       
    79         }
       
    80         pC-&gt;Register();
       
    81 
       
    82     // Create the battery monitor.
       
    83     DBatteryMonitor* pM = new DYourBatteryMonitor;
       
    84     if !(pM)
       
    85         {
       
    86         return(r);
       
    87         }
       
    88 
       
    89     r = KErrNone;
       
    90     return(r);
       
    91     }</codeblock> </section>
       
    92 <section id="GUID-DCD91EBA-CB0E-5EA9-84E0-8F8FED6FC91E"><title>DPowerController::RegisterResourceController()</title> <p>The function <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-42896B4D-9F77-3D91-82BD-50102A8F3DA4"><apiname>DPowerController::RegisterResourceController()</apiname></xref> allows the Resource Controller to register itself with the Power
       
    93 Controller. See <xref href="GUID-66FD040B-133E-57CF-80DD-9369F62709C6.dita#GUID-66FD040B-133E-57CF-80DD-9369F62709C6/GUID-08BFCAF4-9AF0-5999-A1C4-7BBD107C9354">registering with the resource controller</xref> in the PSL implementation
       
    94 document. </p> <p>To support idle power management the Power Controller's
       
    95 PSL must override <codeph>RegisterResourceController()</codeph> to
       
    96 include the registration of a list of resources whose states are of
       
    97 interest to idle power management. </p> <p><b>Idle power management</b> </p> <p>The Power Controller can assemble
       
    98 a list of resources whose state it is interested in from a NULL thread
       
    99 in an array of <xref href="GUID-586AF75A-8350-345D-ABF4-6542C8E75DED.dita"><apiname>SIdleResourceInfo</apiname></xref> structures. Each
       
   100 entry in the list contains the resource ID that the power controller
       
   101 must enter before registering with the PRM. The resource list should
       
   102 be created in the kernel heap or data section. </p> <p>The example
       
   103 below creates a buffer to capture the state of all static resources.
       
   104 The PRM captures the information using <xref href="GUID-46F2174F-0206-345B-8C5D-F8B5763652E0.dita#GUID-46F2174F-0206-345B-8C5D-F8B5763652E0/GUID-52DC308A-9DF1-3BDE-A905-A4DD3B692638"><apiname>DPowerResourceController::RegisterResourcesForIdle()</apiname></xref>. </p> <codeblock id="GUID-C6E907FD-094D-5412-8F81-FC02CDE8B411" xml:space="preserve">    ...
       
   105 //Allocate buffer for Idle resource management
       
   106     NKern::ThreadEnterCS();
       
   107     pBuf = HBuf::New(numResources * sizeof(SIdleResourceInfo)); 
       
   108     NKern::ThreadLeaveCS();
       
   109     if(!pBuf)
       
   110         {
       
   111            return KErrNoMemory;
       
   112         }
       
   113     SIdleResourceInfo* pI = (SIdleResourceInfo*)pBuf-&gt;Ptr();
       
   114 
       
   115 //Update resource ID
       
   116     for(TUint c = 0; c &lt; numResources; c++)
       
   117         {
       
   118         pI[c].iResourceId = c+1; 
       
   119         }
       
   120     r = (iResourceControllerData.iResourceController)-&gt;RegisterResourcesForIdle(iResourceControllerData.iClientId, numResources, (TPtr*)pI);
       
   121     ...</codeblock> <p>The first parameter passed to <codeph>RegisterResourcesForIdle()</codeph> is the client Id generated for the power controller this is the
       
   122 client ID passed by the PRM when calling <xref href="GUID-B2C466D1-0B65-3BB7-81B1-7297400E60C4.dita"><apiname>RegisterResourceController</apiname></xref>. </p> <p> <b>Note</b>: <codeph>RegisterResourcesForIdle()</codeph> is not exported and is only available for use by the Power Controller
       
   123 to register resources for idle power management. <b>Note</b>: <codeph>RegisterResourcesForIdle()</codeph> can only be called by the Power
       
   124 Controller once. </p> </section>
       
   125 <section id="GUID-5A0CAD08-AA12-56EE-B0A3-75548D1896C9"><title>DPowerController::EnableWakeupEvents()</title> <codeblock id="GUID-38714507-C38C-5787-997F-5D45F3A90357" xml:space="preserve">virtual void EnableWakeupEvents() = 0;</codeblock> <p>The Symbian Power Model defines 3 generic system-wide <xref href="GUID-113B3755-1797-5D1B-8E07-8A18F5FE1504.dita">power states</xref>: <i>Active</i>, <i>Standby</i> and <i>Off</i>, as defined in the <xref href="GUID-0C435514-EEC6-5660-BB5F-535790349632.dita">Symbian platform
       
   126 power model</xref>. </p> <p>Each of the system-wide low power states: <i>Standby</i> and <i>Off</i>, has a defined set of wake-up events.
       
   127 If a wake-up event occurs while the system is preparing to transition
       
   128 into one of these low power states, or when the system is in the <i>Standby</i> state, then this can result in the system moving back
       
   129 to the <i>Active</i> power state. Wake-up events may be different
       
   130 for different target power states. Wake-up events are platform-specific
       
   131 hardware events, and it is your base port that decides which events
       
   132 count as wake-up events. </p> <p><b>When is it called?</b> </p> <p> <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-0642129D-05F2-3AB0-B562-37A7BB7A275F"><apiname>DPowerController::EnableWakeupEvents()</apiname></xref> is called called by the <xref href="GUID-0C435514-EEC6-5660-BB5F-535790349632.dita#GUID-0C435514-EEC6-5660-BB5F-535790349632/GUID-330F07B2-BBDF-5675-B7D5-FF6B25DD03F4">power manager</xref> as a result of a user side call to <xref href="GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87.dita#GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87/GUID-C49C0A07-EAC7-32CB-956F-1FFEFF2FD326"><apiname>Power::EnableWakeupEvents()</apiname></xref>. The class <xref href="GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87.dita"><apiname>Power</apiname></xref> is the user side interface to the power manager, and is used by
       
   133 the user side entity that is responsible for moving the device into
       
   134 a low power state. </p> <p><b>Context</b> </p> <p>When the user side entity decides to move
       
   135 the device to a low power state, it sends a notification to all of
       
   136 the user side power domains registered with it, giving their applications
       
   137 a chance to save their data and state. However, before doing this,
       
   138 it calls <xref href="GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87.dita#GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87/GUID-C49C0A07-EAC7-32CB-956F-1FFEFF2FD326"><apiname>Power::EnableWakeupEvents()</apiname></xref>. It also calls <xref href="GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87.dita#GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87/GUID-6CFE19D9-249A-3305-8224-823D2FDB1859"><apiname>Power::RequestWakeupEventNotification()</apiname></xref> so that it can
       
   139 be informed of a wake-up event. If it is notified of a wake-up event,
       
   140 it can halt, and reverse the user side response to the power transition. </p> <fig id="GUID-ACC6E7E3-71E3-5553-B433-9017CB04513D">
       
   141 <image href="GUID-AEDBF425-6077-4C84-A698-508291671F2B_d0e27993_href.png" placement="inline"/>
       
   142 </fig> <p>Before calling <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-0642129D-05F2-3AB0-B562-37A7BB7A275F"><apiname>DPowerController::EnableWakeupEvents()</apiname></xref>, the power manager sets the <codeph>iTargetState</codeph> member
       
   143 of <codeph>DPowerController</codeph> to the applicable <xref href="GUID-87AB8B20-04EE-31D2-8F3D-EA904D05B8D0.dita"><apiname>TPowerState</apiname></xref>. This means that you can enable the appropriate set of wake-up events. </p> <p>Once the user side transition is complete, it calls <xref href="GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87.dita#GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87/GUID-7C6F3F0F-319B-3DEE-81BF-1EB5BB2EAB0A"><apiname>Power::PowerDown()</apiname></xref> in the user side interface to the <xref href="GUID-0C435514-EEC6-5660-BB5F-535790349632.dita#GUID-0C435514-EEC6-5660-BB5F-535790349632/GUID-330F07B2-BBDF-5675-B7D5-FF6B25DD03F4">power manager</xref>, which results in a call to <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-8AE99718-6B82-3920-9029-28C2041A3B10"><apiname>DPowerController::PowerDown()</apiname></xref> in the power controller. This starts the transition of all <xref href="GUID-0C435514-EEC6-5660-BB5F-535790349632.dita#GUID-0C435514-EEC6-5660-BB5F-535790349632/GUID-DC5F1ECD-CCA3-59FF-A2F1-A3DBD76CD458">power handlers</xref> to a low power state, a potentially long process.
       
   144 This means that the power controller needs the ability to detect wake-up
       
   145 events so that it can halt, and reverse the power transition. </p> <p><b>Implementation issues</b> </p> <p>There are three possibilities
       
   146 in dealing with wake-up events: </p> <ul>
       
   147 <li id="GUID-4243E6DD-C903-58DE-B125-38CEDB8B5269"><p>if wake-up events
       
   148 are not handled by specific peripheral drivers, you could set up the
       
   149 hardware so that wake-up events are recorded in a location accessible
       
   150 by the software. Prior to completing the system power transition,
       
   151 the Power controller would check the relevant hardware to see whether
       
   152 a wakeup event had occurred. On detecting a wake-up event it would
       
   153 tell the power manager by calling <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-C193F898-2C15-3C42-8353-14F00789BCDA"><apiname>DPowerController::WakeupEvent()</apiname></xref>. </p> </li>
       
   154 <li id="GUID-289B86C4-A578-5A42-A0DF-70A7BF3F440E"><p>if wake-up events
       
   155 are not handled by specific peripheral drivers, you could arrange
       
   156 for wake-up events to interrupt the CPU. The code that services those
       
   157 interrupts would tell the power manager by calling <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-FABDB7E2-DEC5-3EA9-8106-66C971C04AB7"><apiname>DPowerController::WakepEvent()</apiname></xref>. </p> </li>
       
   158 <li id="GUID-E51BAE55-0A81-5D1F-B509-096A7F2141EF"><p>if wakeup events
       
   159 are intercepted, serviced and cleared by peripheral drivers, then
       
   160 the following outline solution could be adopted: </p> <ul>
       
   161 <li id="GUID-5C942237-BBB2-5919-8578-B55BDAFAFC9F"><p>The power controller
       
   162 would need to publish a list of wake-up events, preferably as a bit
       
   163 mask, and export an API which peripheral drivers could use to notify
       
   164 the power controller that a wake-up event has occurred. The following
       
   165 interface class could be used for this purpose: </p> <codeblock id="GUID-084F7F46-66B6-5661-85AF-57D499250886" xml:space="preserve">class TPowerController
       
   166     {
       
   167 public:
       
   168     inline static void SetPowerControllerPointer(DPowerController* apPowerController)
       
   169     { iPowerControllerPointer = apPowerController; }
       
   170     IMPORT_C static void WakeupEventOccurred(TUint aWakeupEvent);
       
   171     …        // other methods if required
       
   172 private:
       
   173     DPowerController* iPowerControllerPointer;
       
   174     };
       
   175                       </codeblock> <p>The class would be implemented
       
   176 as part of the power management kernel extension and <codeph>SetPowerControllerPointer()</codeph> would be called when <xref href="GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703.dita#GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703/GUID-BCCDBA09-415D-5779-BCE5-CDEB2E1EF7D8">initialising the power controller</xref>, but after creation of the
       
   177 power controller object. </p> <p>Those peripheral drivers that intercept
       
   178 wake-up events would need to link to the power controller DLL (i.e.
       
   179 the power management kernel extension). </p> <p>On the occurrence
       
   180 of a wake-up event, the peripheral driver software servicing that
       
   181 event would notify the power controller by calling <codeph>WakeupEventOccurred()</codeph>, specifying the appropriate wake-up event bit(s). </p> <p>You might
       
   182 implement <codeph>WakeupEventOccurred()</codeph> as follows: </p> <codeblock id="GUID-501ABA28-81B9-52C1-9842-003E1E389045" xml:space="preserve">EXPORT_C void TPowerController::WakeupEventOccurred(TUint aWakeupEvent)
       
   183     {
       
   184     if(iPowerControllerPointer-&gt;iWakeupEvents &amp; aWakeupEvent)
       
   185         {
       
   186         iPowerControllerPointer-&gt;WakeupEvent();
       
   187         }
       
   188     }</codeblock> <p>where <codeph>iWakeupEvents</codeph> is a data
       
   189 member defined in your <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita"><apiname>DPowerController</apiname></xref> -derived
       
   190 class that contains the bitmask representing the wake-up events. The
       
   191 bitmask groups wakeup events according to the target power state. </p> </li>
       
   192 </ul> </li>
       
   193 </ul> <p>When the peripheral driver powers down, it should leave the
       
   194 hardware that generates the wake-up event powered and enabled for
       
   195 detection. Thus, if a wake-up event of the type handled by this peripheral
       
   196 driver occurs, it will not be serviced in the normal way, but will
       
   197 be left pending until the power controller services it. </p> <p>When
       
   198 the power controller’s <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-8AE99718-6B82-3920-9029-28C2041A3B10"><apiname>DPowerController::PowerDown()</apiname></xref> function is called, the power controller must check the peripheral
       
   199 hardware directly to see whether the wakeup event has happened, or
       
   200 is happening right now, prior to transitioning the device to the target
       
   201 system-wide low power state. If the wake-up event is found to have
       
   202 happened then <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-8AE99718-6B82-3920-9029-28C2041A3B10"><apiname>DPowerController::PowerDown()</apiname></xref> would
       
   203 return immediately, instead of initiating the <xref href="GUID-0C435514-EEC6-5660-BB5F-535790349632.dita#GUID-0C435514-EEC6-5660-BB5F-535790349632/GUID-DC5F1ECD-CCA3-59FF-A2F1-A3DBD76CD458">power handlers</xref> power down of the peripheral drivers. </p> </section>
       
   204 <section id="GUID-51D37A0C-AD46-52D5-A31C-CB3A8046CE84"><title> DPowerController::AbsoluteTimerExpired()</title> <codeblock id="GUID-5EC61B73-DA37-51C8-963F-4E4169AC1BE7" xml:space="preserve">virtual void AbsoluteTimerExpired() = 0;</codeblock> <p><b>When is it called?</b> </p> <p> <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-C6F792DB-1EC0-33F4-8F82-AB3F7B44B061"><apiname>DPowerController::AbsoluteTimerExpired()</apiname></xref> is called by the <xref href="GUID-0C435514-EEC6-5660-BB5F-535790349632.dita#GUID-0C435514-EEC6-5660-BB5F-535790349632/GUID-330F07B2-BBDF-5675-B7D5-FF6B25DD03F4">power manager</xref> whenever an absolute timer expires. An absolute
       
   205 timer is one that is set to complete at a specific time, as queued
       
   206 by a call to <xref href="GUID-8A423EA2-4264-30C9-9579-0466994E6E88.dita#GUID-8A423EA2-4264-30C9-9579-0466994E6E88/GUID-3F302410-5CC2-3CCB-82F4-47E953E7A29B"><apiname>RTimer::At()</apiname></xref>. </p> <p><b>Implementation issues</b> </p> <p>If absolute timer expiration
       
   207 is one of your wake-up events, then your implementation of <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-C6F792DB-1EC0-33F4-8F82-AB3F7B44B061"><apiname>DPowerController::AbsoluteTimerExpired()</apiname></xref> should call <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-C193F898-2C15-3C42-8353-14F00789BCDA"><apiname>DPowerController::WakeupEvent()</apiname></xref> to notify the power manager
       
   208 that a wake-up event has happened. </p> <p>It is recommended that
       
   209 you track absolute timers. </p> </section>
       
   210 <section id="GUID-1F77C71C-D226-58BB-ABAE-43F958CC0C61"><title>DPowerController::PowerDown()</title> <codeblock id="GUID-AD394AD5-8E3E-5FE3-938E-639C4E5E9F79" xml:space="preserve">virtual void PowerDown(TTimeK aWakeupTime) = 0;</codeblock> <p><b>When is it called?</b> </p> <p> <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-8AE99718-6B82-3920-9029-28C2041A3B10"><apiname>DPowerController::PowerDown()</apiname></xref> is called by the <xref href="GUID-0C435514-EEC6-5660-BB5F-535790349632.dita#GUID-0C435514-EEC6-5660-BB5F-535790349632/GUID-330F07B2-BBDF-5675-B7D5-FF6B25DD03F4">power manager</xref> to move the device into one of the system-wide
       
   211 low power states: <i>Standby</i> or <i>Off</i>. </p> <p>Typically,
       
   212 this is a result of the user side entity that is responsible for moving
       
   213 the device into a low power state calling <xref href="GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87.dita#GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87/GUID-7C6F3F0F-319B-3DEE-81BF-1EB5BB2EAB0A"><apiname>Power::PowerDown()</apiname></xref> in the user side interface to the <xref href="GUID-0C435514-EEC6-5660-BB5F-535790349632.dita#GUID-0C435514-EEC6-5660-BB5F-535790349632/GUID-330F07B2-BBDF-5675-B7D5-FF6B25DD03F4">power manager</xref>. </p> <p>If <xref href="GUID-26621CA5-B686-53FB-AF3E-96CDD38C8520.dita">physical RAM defragmentation</xref> is implemented you may wish to include calls to <xref href="GUID-AE7E0A8E-1513-3F6B-A6D5-150084C4E262.dita#GUID-AE7E0A8E-1513-3F6B-A6D5-150084C4E262/GUID-B4825007-E3DB-3559-9D58-637150EF3DB9"><apiname> TRamDefragRequest::DefragRam()</apiname></xref> within this function to enable defragmentation of RAM zones that
       
   214 can then be powered down. </p> <p><b>Context</b> </p> <p>The target state is defined by the value of
       
   215 the <codeph>iTargetState</codeph> member of <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita"><apiname>DPowerController</apiname></xref>, as set by the power manager. </p> <p><b>Implementation issues</b> </p> <p>Implementation depends on the
       
   216 target state: </p> <ul>
       
   217 <li id="GUID-0473B5C1-BEC0-5276-88C5-A4A8379A4621"><p>if the target
       
   218 state is <i>Standby</i>, as implied by a value of <xref href="GUID-87AB8B20-04EE-31D2-8F3D-EA904D05B8D0.dita#GUID-87AB8B20-04EE-31D2-8F3D-EA904D05B8D0/GUID-5604F598-8CBC-3A94-865F-CA58DA4492B0"><apiname>TPowerState::EPwStandby</apiname></xref> in <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-86A0C14F-B219-3E0B-BD5E-A2C20EEDBF64"><apiname>DPowerController::iTargetState</apiname></xref>, then the power
       
   219 controller should put the hardware into a state corresponding to the <i>Standby</i> state. </p> <p>If at least one wake-up event has been
       
   220 detected and recorded since the last call to <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-0642129D-05F2-3AB0-B562-37A7BB7A275F"><apiname>DPowerController::EnableWakeupEvents()</apiname></xref>, then <codeph>PowerDown()</codeph> should return immediately; otherwise,
       
   221 it should continue with the process of putting the device into <i>Standby</i>; execution of the function will halt, and can only continue,
       
   222 and return, when a wake-up event occurs. </p> </li>
       
   223 <li id="GUID-E38B9334-CFE4-5E91-9DD4-D7A0678AF344"><p>if the target
       
   224 state is <i>Off</i>, as implied by a value of <xref href="GUID-87AB8B20-04EE-31D2-8F3D-EA904D05B8D0.dita#GUID-87AB8B20-04EE-31D2-8F3D-EA904D05B8D0/GUID-0DAD6E93-BD08-3C90-BCE8-ADBFC2681227"><apiname>TPowerState::EPwOff</apiname></xref> in <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-86A0C14F-B219-3E0B-BD5E-A2C20EEDBF64"><apiname>DPowerController::iTargetState</apiname></xref>, then <codeph>PowerDown()</codeph> must <i>never</i> return. Typically, the power
       
   225 controller turns the device off, but can choose to perform other device-specific
       
   226 action such as a system reboot. </p> </li>
       
   227 </ul> <p>The <xref href="GUID-8C6E2996-24DE-3E59-927A-46D32290225E.dita"><apiname>TTimeK</apiname></xref> parameter passed to the function
       
   228 is a system time value. If non-zero, it specifies the time when the
       
   229 system should wakeup. The kernel calculates it as the time that the
       
   230 next absolute timer expires. Typically, your implementation will use
       
   231 the Real Time Clock module to generate an event at the specified time,
       
   232 and this will cause a return to the <i>Active</i> state. This implies
       
   233 that the base port should enable Real Time Clock event detection during <i>Standby</i>. </p> <p>The Symbian definition of the <i>Standby</i> state usually translates into the hardware manufacturer’s CPU “Standby”
       
   234 or “Sleep” modes of operation. Typically, the internal clocks associated
       
   235 with the core and some of the core peripherals, or their power supply,
       
   236 are suppressed, and their internal state is not preserved. In this
       
   237 case, the state of the core and core peripherals should be saved before
       
   238 going into <i>Standby</i> so that they can be restored when the system
       
   239 wakes-up. Note the following: </p> <ul>
       
   240 <li id="GUID-824D88FD-33FB-50DC-A904-F5F44BFBF90A"><p>for the core
       
   241 state, save the current mode, the banked registers for each mode,
       
   242 and the stack pointer for both the current mode and user mode </p> </li>
       
   243 <li id="GUID-E8CDFA98-E6F2-5D48-987F-E2591DAB242B"><p>for the core
       
   244 peripherals, save the state of the interrupt controller, the pin function
       
   245 controller, the bus state controller, and the clock controller </p> </li>
       
   246 <li id="GUID-90BEA663-F58C-5AD7-8578-353E5EFFBCCC"><p>for the MMU
       
   247 state, save the control register, the translation table base address,
       
   248 and the domain access control, if this is supported </p> </li>
       
   249 <li id="GUID-68AB9558-5CC7-573F-8A33-A38F16EAF304"><p>flush the data
       
   250 cache and drain the write buffer. </p> </li>
       
   251 </ul> <p>If all of this data is saved to a DRAM device, then this
       
   252 should be put into self refresh mode. </p> <p>Peripherals modules
       
   253 involved in the detection of wake-up events should be left powered. </p> <p>Tick timer events should be disabled, and the current count of
       
   254 this and any other system timers should be saved; relevant wake-up
       
   255 events should be left unmasked, and any others should be disabled. </p> </section>
       
   256 <section id="GUID-E2A072D0-A67F-5E6D-81ED-CFD77B6ED4F1"><title>DPowerController::CpuIdle()</title> <codeblock id="GUID-0E6F1B1D-F979-575B-BA3C-096CE4C0CA15" xml:space="preserve">virtual void CpuIdle()=0;</codeblock> <p><b>When is it called?</b> </p> <p> <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-473874CA-FC35-3EB2-BC23-A97D7176B833"><apiname>DPowerController::CpuIdle()</apiname></xref> is called whenever the Null thread is scheduled to run. This can
       
   257 happen as soon as the power model has been installed. It is the mechanism
       
   258 through which your base port can increase power savings when the system
       
   259 becomes inactive by moving the CPU or the system into a low power
       
   260 mode. </p> <p>If <xref href="GUID-26621CA5-B686-53FB-AF3E-96CDD38C8520.dita">physical RAM defragmentation</xref> is implemented you may wish to
       
   261 include calls to <xref href="GUID-AE7E0A8E-1513-3F6B-A6D5-150084C4E262.dita#GUID-AE7E0A8E-1513-3F6B-A6D5-150084C4E262/GUID-B4825007-E3DB-3559-9D58-637150EF3DB9"><apiname> TRamDefragRequest::DefragRam()</apiname></xref> within this function to enable defragmentation while the device
       
   262 is idle. </p> <p><b>Implementation issues</b> </p> <p>The implementation can call
       
   263 the Variant or ASSP implementation of <xref href="GUID-A83A7C3C-7DC0-3B9C-842F-70FCC751365D.dita#GUID-A83A7C3C-7DC0-3B9C-842F-70FCC751365D/GUID-6F242C0C-2EFC-30EC-9A5E-A34C8D15E0D7"><apiname>Asic::Idle()</apiname></xref>. </p> <p>The idle state is usually implemented via a Wait-For-Interrupt
       
   264 type instruction that will usually suspend execution of the CPU, possibly
       
   265 triggering other ASIC power saving actions, and will resume execution
       
   266 when any unmasked interrupt occurs. </p> <p><b>Suppressing the system tick interrupt</b> </p> <p>To further increase
       
   267 power savings during CPU Idle, a base port can choose to suppress
       
   268 the system tick interrupt until the next nanokernel Timer (as implemented
       
   269 by <xref href="GUID-D8CF05A3-5C9B-3662-92DA-3290C6EE7FD2.dita"><apiname>NTimer</apiname></xref>) is due to expire. Nanokernel timers
       
   270 are the basic timing service and all Symbian platform tick-based timers
       
   271 and time-of-day functions are derived from nanokernel timers. </p> <p>In EKA2, timing services rely on a hardware timer, which is programmed
       
   272 by the base port Variant code, to generate the system tick. We refer
       
   273 to this as the <i>system timer</i>. </p> <p>Typically, the platform-specific
       
   274 ASSP or Variant object has a pointer to the nanokernel timer queue,
       
   275 an <xref href="GUID-C54D99AA-FF6E-3023-8260-8F5A88FBFBE0.dita"><apiname>NTimerQ</apiname></xref> object. The number of ticks before the
       
   276 next <xref href="GUID-D8CF05A3-5C9B-3662-92DA-3290C6EE7FD2.dita"><apiname>NTimer</apiname></xref> is due to expire can be found by calling <xref href="GUID-C54D99AA-FF6E-3023-8260-8F5A88FBFBE0.dita#GUID-C54D99AA-FF6E-3023-8260-8F5A88FBFBE0/GUID-69103F26-2C21-3ECA-9DB5-C31A41F6C238"><apiname>NTimerQ::IdleTime()</apiname></xref>. </p> <p>Before going into Idle mode, <codeph>CpuIdle()</codeph> disables the hardware timer used to generate the
       
   277 system tick (i.e. the system timer) for the number of ticks to be
       
   278 suppressed; i.e. the system timer is reset to go off and generate
       
   279 an interrupt only when the <xref href="GUID-D8CF05A3-5C9B-3662-92DA-3290C6EE7FD2.dita"><apiname>NTimer</apiname></xref> expires. Note
       
   280 that the clock supply to the hardware timer must be left enabled. </p> <p>On returning from Idle mode, the software must examine the system
       
   281 timer and decide whether the <xref href="GUID-D8CF05A3-5C9B-3662-92DA-3290C6EE7FD2.dita"><apiname>NTimer</apiname></xref> expiration
       
   282 was responsible for waking up the processor, or whether it was due
       
   283 to some other interrupt. </p> <p>If waking up was due to the <xref href="GUID-D8CF05A3-5C9B-3662-92DA-3290C6EE7FD2.dita"><apiname>NTimer</apiname></xref>, the system timer must be reset to generate the
       
   284 system tick at the frequency desired, and the tick count, <xref href="GUID-C54D99AA-FF6E-3023-8260-8F5A88FBFBE0.dita#GUID-C54D99AA-FF6E-3023-8260-8F5A88FBFBE0/GUID-ACFDFE7C-19AE-3C81-9D38-3266A3A3EF1F"><apiname>NTimerQ::iMsCount</apiname></xref>, must be adjusted with the <xref href="GUID-D8CF05A3-5C9B-3662-92DA-3290C6EE7FD2.dita"><apiname>NTimer</apiname></xref> expiration time. As the expiration time is always an integer multiple
       
   285 of the number of ticks, then the <xref href="GUID-C54D99AA-FF6E-3023-8260-8F5A88FBFBE0.dita#GUID-C54D99AA-FF6E-3023-8260-8F5A88FBFBE0/GUID-AA1EC86F-8A6E-340D-848F-A86554772A13"><apiname>NTimerQ::Advance()</apiname></xref> function can be used for this purpose. </p> <p>If waking up was
       
   286 due to another interrupt, then the software must read the system timer
       
   287 and calculate the time elapsed since going into Idle mode, and adjust
       
   288 the system tick count with the elapsed time (which could be a fractional
       
   289 number of ticks) and reprogram the system timer to continue generating
       
   290 the tick after the correct interval, as above. </p> <p>If the hardware
       
   291 timer that is used to generate the system ticks does not use a Compare-Match
       
   292 function, then some care has to be taken not to introduce skewing
       
   293 when manipulating the timer value directly. If the timer needs to
       
   294 be reloaded with the new value to give the next tick, then the software
       
   295 usually “spins”, waiting for the hardware timer to change, and then
       
   296 reloads it. This way the timer will always be reloaded on an edge
       
   297 of its internal clock. </p> <p><b>Waking up from “Sleep” modes with long wakeup latencies</b> </p> <p>Often, to further enhance power savings, the CPU and some peripherals
       
   298 are moved into a hardware “sleep” mode when <codeph>CpuIdle()</codeph> is called. This could be of long latency, and waking up could take
       
   299 longer than the system Tick period. There are two situations: </p> <ul>
       
   300 <li id="GUID-7484F7CB-C824-5752-9043-736E95D4405D"><p>if the wakeup
       
   301 time can be determined precisely, then <codeph>CpuIdle()</codeph> programs
       
   302 the system timer to bring the CPU back from the “Sleep“ mode at a
       
   303 time corresponding to the next <xref href="GUID-D8CF05A3-5C9B-3662-92DA-3290C6EE7FD2.dita"><apiname>NTimer</apiname></xref> expiration
       
   304 (as a number of Ticks to suppress) <i>minus</i> the number of ticks
       
   305 it takes to wake up from that mode. On waking up on the timer, the
       
   306 System tick count should be adjusted with the total number of ticks
       
   307 suppressed, i.e. the count corresponding to the time of the <xref href="GUID-D8CF05A3-5C9B-3662-92DA-3290C6EE7FD2.dita"><apiname>NTimer</apiname></xref> expiration. </p> </li>
       
   308 <li id="GUID-C0A9B2A2-D98D-50C0-B58A-4E84FCEC12E4"><p>If the wakeup
       
   309 time cannot be known deterministically, then the above scheme must
       
   310 be combined with another system to allow adjusting the system timer
       
   311 from the hardware Real Time Clock (RTC). </p> <p>Typically, the hardware
       
   312 RTC is clocked with a 1Hz clock, and can be programmed to interrupt
       
   313 the CPU on multiples of one second intervals. The clock supply to
       
   314 the RTC must be left enabled on going into "sleep" mode. </p> </li>
       
   315 </ul> <p>To guarantee that timed events occur when they are due, the
       
   316 CPU should only be allowed to go to into the long latency hardware
       
   317 “sleep” mode if the RTC can be guaranteed to complete a second tick
       
   318 before the CPU is due to wakeup. </p> <p>Note that if waking up from
       
   319 hardware “Sleep” mode takes a non-negligible amount of time, extreme
       
   320 care should be taken when deciding to move the platform into that
       
   321 mode. For example, if a receive request is pending on a data input
       
   322 device <i>and</i> the CPU reaches the Idle mode <i>and</i> the platform
       
   323 is transitioned into a “sleep” state <i>and</i> data arrives while
       
   324 it is still in that state, <i>then</i> there is a possibility that
       
   325 the system will not wake up on time to service the incoming data. </p> </section>
       
   326 <section id="GUID-4B613C67-3A12-4AD5-8842-6ED510A68746"><title>Validation</title> <p>The <filepath>e32test</filepath> programs <filepath>t_power</filepath>, and <filepath>t_timer</filepath> will put the system into standby
       
   327 and resume off a timer. </p> </section>
       
   328 </conbody><related-links>
       
   329 <link href="GUID-0C435514-EEC6-5660-BB5F-535790349632.dita"><linktext>Power
       
   330 Management</linktext></link>
       
   331 </related-links></concept>