Symbian3/PDK/Source/GUID-80E0DB93-A96A-54A8-A201-E11935418BE7.dita
changeset 3 46218c8b8afa
parent 1 25a17d01db0c
child 5 f345bda72bc4
--- a/Symbian3/PDK/Source/GUID-80E0DB93-A96A-54A8-A201-E11935418BE7.dita	Thu Mar 11 15:24:26 2010 +0000
+++ b/Symbian3/PDK/Source/GUID-80E0DB93-A96A-54A8-A201-E11935418BE7.dita	Thu Mar 11 18:02:22 2010 +0000
@@ -1,236 +1,236 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
-<!-- This component and the accompanying materials are made available under the terms of the License 
-"Eclipse Public License v1.0" which accompanies this distribution, 
-and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
-<!-- Initial Contributors:
-    Nokia Corporation - initial contribution.
-Contributors: 
--->
-<!DOCTYPE concept
-  PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
-<concept id="GUID-80E0DB93-A96A-54A8-A201-E11935418BE7" xml:lang="en"><title>State
-Machines</title><shortdesc>Description of the structure and operation of state machines.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
-<p>The MultiMediaCard Controller uses state machines to manage the interactions
-with the MultiMediaCard hardware. </p>
-<p>State machines allows the controller to maintain the state of each submitted
-session – allowing it to schedule a second session when the first becomes
-blocked, for example. </p>
-<p>To handle the complex sequence of bus operations involved, the controller
-implements a state machine stack, allowing a parent state machine function
-to invoke a child state machine function. The state machine stack allows nesting
-of children down to a depth of 10 levels. </p>
-<p>Each session object has its own individual state machine stack because
-each session runs its own sequence of bus operations, with the controller
-managing these multiple sequences. This means that each session object has
-a state machine object, an instance of the <xref href="GUID-022AC0FE-86EE-3908-A9F8-4A33D04A68A5.dita"><apiname>TMMCStateMachine</apiname></xref> class. </p>
-<fig id="GUID-3CD3F1EF-FB6A-5D5D-B806-75536F8DF533">
-<image href="GUID-4592D493-A47C-5622-8C03-F24FABB4381C_d0e383692_href.png" placement="inline"/>
-</fig>
-<p>The state machine remembers the next state and child function name, and
-moves to that state as soon as control returns to the session. </p>
-<p>The stack chooses the next session to be handled and manages the state
-machine through the state machine dispatcher. </p>
-<ul>
-<li id="GUID-76BEBC23-FC9D-5244-A3EA-2A5424FC02D7"><p> <xref href="GUID-80E0DB93-A96A-54A8-A201-E11935418BE7.dita#GUID-80E0DB93-A96A-54A8-A201-E11935418BE7/GUID-44473E52-82B4-55E7-AE85-15AC88CE5BEB">Structure of the state machine stack</xref> </p> </li>
-<li id="GUID-0A56A8B9-65D7-54CB-A584-8C3C9AEFE339"><p> <xref href="GUID-80E0DB93-A96A-54A8-A201-E11935418BE7.dita#GUID-80E0DB93-A96A-54A8-A201-E11935418BE7/GUID-E8FCFD65-4664-52EE-B658-FCABF50D501D">Structure of a state machine function</xref> </p> </li>
-<li id="GUID-85E36E04-60CD-5560-93DE-5C15E8DBDD45"><p> <xref href="GUID-80E0DB93-A96A-54A8-A201-E11935418BE7.dita#GUID-80E0DB93-A96A-54A8-A201-E11935418BE7/GUID-667C5A70-0ABB-525F-A309-58102E380400">Example of a state machine calling sequence</xref> </p> </li>
-</ul>
-<section id="GUID-44473E52-82B4-55E7-AE85-15AC88CE5BEB"><title>Structure of
-the state machine stack</title> <p>The stack itself is represented as an array
-of <xref href="GUID-DDCE8054-1656-34EF-9CBC-53C796BFD5A6.dita"><apiname>TMMCMachineStackEntry</apiname></xref> objects contained within the state
-machine object <xref href="GUID-022AC0FE-86EE-3908-A9F8-4A33D04A68A5.dita"><apiname>TMMCStateMachine</apiname></xref>. </p> <p>The state machine
-maintains a "pointer", <xref href="GUID-022AC0FE-86EE-3908-A9F8-4A33D04A68A5.dita#GUID-022AC0FE-86EE-3908-A9F8-4A33D04A68A5/GUID-5EC9B7D0-A3A9-35DF-A91D-65920372C9A4"><apiname>TMMCStateMachine::iSP</apiname></xref>, to the current
-state entry. This is not a true pointer, but just a value that indexes into
-the array. However, for all practical purposes it has the effect of a pointer.
-Each state entry in the stack is thought of as having a parent-child relationship
-with the other. </p> <p>Each state entry maintains three pieces of information: </p> <ul>
-<li id="GUID-81454E68-4603-5211-8F9F-70F0F2F4B95D"><p>A pointer to the state
-machine function. </p> </li>
-<li id="GUID-B20834EB-3EAE-5D79-8564-8B2A5490A057"><p>A variable containing
-the current state; the value and meaning of the state is defined by the state
-machine function. </p> </li>
-<li id="GUID-32AFB296-0D5F-5FF7-9ECD-C9F798E04542"><p>A bitmask of <xref href="GUID-FF4AB1CF-7A2C-3FC6-B123-D6819E1BCDCA.dita"><apiname>TMMCErr</apiname></xref> defined
-error conditions; these are set by the parent state machine function so that
-it gets the chance to trap those errors if the child state machine function
-returns those errors. Errors are propagated up the stack, and any error conditions
-not trapped at any level in the state machine hierarchy leads to the state
-machine terminating with that error value. </p> </li>
-</ul> <fig id="GUID-064C53DB-6A96-5C6D-B3CD-B40A0251EF66">
-<image href="GUID-D8911BE6-100D-588A-8E5C-A429A72AFCDA_d0e383777_href.png" placement="inline"/>
-</fig> <p>In general, the overall state of the state machine reflects the
-state of the current state entry; for example, <xref href="GUID-E32D6BC3-F8D9-3F7E-94F6-56633B645D6A.dita#GUID-E32D6BC3-F8D9-3F7E-94F6-56633B645D6A/GUID-48F37107-2D11-3550-890B-D79844A97DBF"><apiname>TMMCStatemachine::State()</apiname></xref> returns
-the state held in the current state entry. </p> <p>While the flow of control
-through a stack can be complex, the following diagram shows a short example
-snapshot. Here, the current state in the current stack entry is <codeph>Sn</codeph> and
-is handled by the function <codeph>PF()</codeph>. The code decides to pass
-control to the child function <codeph>CF()</codeph>, but ensures that, on
-completion, the next state in the current stack entry will be <codeph>Sn+1</codeph>. </p> <fig id="GUID-6ACBC49E-14EE-526B-A1A3-426B64BF8476">
-<image href="GUID-D2D41326-BA88-5A02-805B-5EAEC29ADB5D_d0e383804_href.png" placement="inline"/>
-</fig> <p>For example, the <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-F71A4421-2F9E-39FD-A352-97ECAAFE822D"><apiname>DMMCStack::CIMUpdateAcqSM()</apiname></xref> function
-implements the CIM_UPDATE_ACQ macro as defined by the <i>MultiMediaCard System
-Specification</i>, and is a typical state machine function. </p> <p>Most commands
-and macros involve one or more asynchronous operations and while such operations
-are outstanding, a session is blocked. While a session is blocked, its state
-machine dispatch function is not called. As soon an asynchronous event removes
-the blocking condition, control returns to the state machine. </p> </section>
-<section id="GUID-E8FCFD65-4664-52EE-B658-FCABF50D501D"><title>Structure of
-a state machine function</title> <p>State machine functions are defined and
-implemented in the <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita"><apiname>DMMCStack</apiname></xref> class in pairs: one as a static
-function, and the other as a member function. The static variant takes a <codeph>TAny*</codeph> pointer
-that is cast to a <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita"><apiname>DMMCStack</apiname></xref> pointer, and the <codeph>DMMCStack</codeph> member
-function is then called: </p> <codeblock id="GUID-F5EEA20F-2312-5394-84C4-5E568995291A" xml:space="preserve">TMMCErr DMMCStack::FunctionNameSMST( TAny* aPtr )
-    {
-    return( STATIC_CAST(DMMCStack*,aPtr)-&gt;FunctionNameSM() );
-    }
-</codeblock> <codeblock id="GUID-3C01127E-4EBA-59AC-91F8-1F004A74E45B" xml:space="preserve">TMMCErr DMMCStack::FunctionNameSM()
-    {
-    enum states {EStBegin=0, EStNext,…, EStEnd };    // Enumeration of states for this state machine
-    DMMCSession&amp; s = Session();
-
-    SMF_BEGIN
-    // State EStBegin
-    // Actions for state EStBegin
-
-    SMF_STATE( EStNext )
-    // State EStNext
-    // Actions for state EStNext
-
-    SMF_END
-    }
-</codeblock> <p>A state machine function can release control and wait to be
-re-entered by returning zero. If its session is not blocked then that will
-happen immediately. If the state machine function returns non-zero, the session
-will be completed with that error code unless the parent state machine function
-has explicitly intercepted such an error by setting the trap mask. </p> <ul>
-<li id="GUID-BEE3954A-733D-55CE-B09C-4B49304B44E1"><p> <xref href="GUID-80E0DB93-A96A-54A8-A201-E11935418BE7.dita#GUID-80E0DB93-A96A-54A8-A201-E11935418BE7/GUID-901D8456-F8D3-5E92-B3DA-EFE556D8C48B">Important points to note</xref> </p> </li>
-<li id="GUID-DA29FD1E-93EF-56C1-9650-8CE22B655897"><p> <xref href="GUID-80E0DB93-A96A-54A8-A201-E11935418BE7.dita#GUID-80E0DB93-A96A-54A8-A201-E11935418BE7/GUID-DBBA1450-AE5A-50E5-9B8C-F697CEFAD590">Blocking on an asynchronous request</xref> </p> </li>
-</ul> <p id="GUID-901D8456-F8D3-5E92-B3DA-EFE556D8C48B"><b>Important points to note</b> </p> <p>Each
-state machine function must define a list of states that can exist. States
-are defined as an enumeration whose first and last values <i>must</i> be labelled <codeph>EStBegin</codeph> and <codeph>EStEnd</codeph>,
-respectively. <codeph>EStBegin</codeph> must have the value zero. Any other
-intermediate states are program defined. </p> <p>To make the state machine
-functions more readable, a number of macros exist to help with the layout
-of the function code, and to control program flow. The most basic macros are <xref href="GUID-C095E583-3E71-31F3-B092-627357D72958.dita"><apiname>SMF_BEGIN</apiname></xref>, <xref href="GUID-38811BD9-F27C-3408-A04F-053314A2CF84.dita"><apiname>SMF_STATE</apiname></xref> and <xref href="GUID-C1089896-DD68-399C-BF34-2495C51A0CA1.dita"><apiname>SMF_END</apiname></xref> that expand into a switch statement. The above code expands
-to: </p> <codeblock id="GUID-16AE9141-5BE1-5B54-B083-7F60133DD018" xml:space="preserve">TMMCErr DMMCStack::FunctionNameSM()
-{
-enum states {EStBegin=0, EStNext,…, EStEnd };    // Enumeration of states for this state machine
-DMMCSession&amp; s = Session();
-
-TMMCStateMachine&amp; m = Machine();            //SMF_BEGIN
-const TMMCErr err = m.SetExitCode( 0 );        //SMF_BEGIN
-for(;;)                                        //SMF_BEGIN
-    {                                        //SMF_BEGIN
-    switch(m.State())                        //SMF_BEGIN
-        {                                    //SMF_BEGIN
-        case EStBegin:                        //SMF_BEGIN
-            {                                //SMF_BEGIN
-            if(err) (void)0;                //SMF_BEGIN 
-            // State EStBegin
-            // Actions for state EStBegin
-
-            }                                //SMF_STATE
-        case EStNext:                        //SMF_STATE
-            {                                //SMF_STATE
-            // State EStNext
-            // Actions for state EStNext
-
-        case EStEnd:                                                //SMF_END
-            break;                                                    //SMF_END
-            default:                                                //SMF_END
-            DMMCController::Panic(DMMCController::EMMCMachineState);//SMF_END
-        }                                                            //SMF_END
-        break;                                                        //SMF_END
-    }                                                                //SMF_END
-return(m.Pop());                                                    //SMF_END
-}</codeblock> <p>Notes: </p> <ul>
-<li id="GUID-7542D030-2641-5A15-A5AF-A02C491B24BB"><p>be aware that SMF_BEGIN
-generates an open curly bracket while SMF_STATE generates a corresponding
-close bracket, and SMF_END closes the switch statement. </p> </li>
-</ul> <p>You need to be aware of the code that is generated by these macros.
-In particular, some such as SMF_BEGIN generate an opening curly brace, while
-others such as SMF_STATE generate a corresponding close curly brace. Also,
-you need to know whether a macro generates a <codeph>break;</codeph> or a <codeph>return;</codeph> statement.
-Lack of awareness here may cause code to be generated that flows from one
-case statement to another, which may not be your intent. </p> <ul>
-<li id="GUID-7C57CF3E-0EB9-56A4-A07A-86027F5B42BA"><p> <xref href="GUID-C095E583-3E71-31F3-B092-627357D72958.dita"><apiname>SMF_BEGIN</apiname></xref> </p> </li>
-<li id="GUID-9A87EEA6-6D40-53E1-BCEE-F9A20C22D51D"><p> <xref href="GUID-C1089896-DD68-399C-BF34-2495C51A0CA1.dita"><apiname>SMF_END</apiname></xref> </p> </li>
-<li id="GUID-3ADD2CCB-4C83-54EC-80DB-3C8CFDDDCB7A"><p> <xref href="GUID-2BA7F4A7-ECB0-3839-809B-4C32D4F451BA.dita"><apiname>SMF_NEXTS</apiname></xref> </p> </li>
-<li id="GUID-41D972A7-18DE-5CE5-B0D6-039B0126199C"><p> <xref href="GUID-ACD776A5-5439-3BE9-8DD8-B537D8C2C637.dita"><apiname>SMF_CALL</apiname></xref> </p> </li>
-<li id="GUID-87C8FC8C-F810-5B3F-A7CC-99D6515F8F04"><p> <xref href="GUID-3802119E-0FC0-3B7C-9582-21563EC9AF61.dita"><apiname>SMF_CALLWAIT</apiname></xref> </p> </li>
-<li id="GUID-89669A58-5168-508A-AF9F-34C3347F0A69"><p> <xref href="GUID-2B6FA032-F8F9-3205-9CBB-EFB96691ACC9.dita"><apiname>SMF_CALLMYS</apiname></xref> </p> </li>
-<li id="GUID-A6C9952A-223E-5687-B67C-D89D50070BDB"><p> <xref href="GUID-C1D65C79-F781-3E22-AA73-F75BA2516F6F.dita"><apiname>SMF_CALLMEWR</apiname></xref> </p> </li>
-<li id="GUID-7FF0DFC9-D9DC-5E08-B668-4BC62B6E50EC"><p> <xref href="GUID-A143CA61-AA6B-3C5F-9E58-50BAF3786262.dita"><apiname>SMF_INVOKES</apiname></xref> </p> </li>
-<li id="GUID-F02BE381-0BA2-5E9D-AFB7-9064FBADC64C"><p> <xref href="GUID-A73CAEB2-2413-371E-A56F-2757C0723514.dita"><apiname>SMF_INVOKEWAITS</apiname></xref> </p> </li>
-<li id="GUID-A39E56F8-DE55-5EDE-A955-24E198026F39"><p> <xref href="GUID-94214574-2CCD-3BE4-ABD4-6A58328B29A2.dita"><apiname>SMF_WAIT</apiname></xref> </p> </li>
-<li id="GUID-1CB69F09-3BAC-5C41-B20E-5A2896C0E18E"><p> <xref href="GUID-33FBF199-09B8-32C3-BAD6-92D277722DB3.dita"><apiname>SMF_WAITS</apiname></xref> </p> </li>
-<li id="GUID-46D7BB96-3EC7-5207-BEE4-1E3ABB145D6B"><p> <xref href="GUID-B13D0665-AD49-348F-8795-67E8761B0BC8.dita"><apiname>SMF_RETURN</apiname></xref> </p> </li>
-<li id="GUID-A9A4DB91-2648-534D-BEA3-57A23147D750"><p> <xref href="GUID-2BA73A03-7379-394C-B9E8-4525316AF91F.dita"><apiname>SMF_EXIT</apiname></xref> </p> </li>
-<li id="GUID-E75E1BF0-CD8B-5EEA-98EA-13176AE0A308"><p> <xref href="GUID-57CF6330-1EA6-36A9-B2A1-2BB360B1E7FD.dita"><apiname>SMF_EXITWAIT</apiname></xref> </p> </li>
-<li id="GUID-D0617F39-4CF6-5FA7-995C-50688A82E703"><p> <xref href="GUID-6E9EF7EB-A9A2-3FA1-902D-188B4930927F.dita"><apiname>SMF_JUMP</apiname></xref> </p> </li>
-<li id="GUID-83791CBF-298A-5B5F-A9A0-8FB902AE81EB"><p> <xref href="GUID-85E63D6B-521B-309A-A1B1-18FDFCF626A0.dita"><apiname>SMF_JUMPWAIT</apiname></xref> </p> </li>
-<li id="GUID-F657F501-47AE-57D0-BEB6-A051176FC279"><p> <xref href="GUID-BF735A08-6E69-374F-8052-EF6CA101A3C3.dita"><apiname>SMF_GOTONEXTS</apiname></xref> </p> </li>
-<li id="GUID-F7D1B6D8-51A2-5C73-A709-1BB10CD27620"><p> <xref href="GUID-AA215584-34D9-36DA-A05A-8A4DF4636D5E.dita"><apiname>SMF_GOTOS</apiname></xref> </p> </li>
-<li id="GUID-042539CB-3019-57A2-B0AD-F1417756F842"><p> <xref href="GUID-38811BD9-F27C-3408-A04F-053314A2CF84.dita"><apiname>SMF_STATE</apiname></xref> </p> </li>
-<li id="GUID-ADD382E6-32C0-5773-8958-057F440C3FEC"><p> <xref href="GUID-11B9D102-4548-3321-8318-26E940273880.dita"><apiname>SMF_BPOINT</apiname></xref> </p> </li>
-</ul> <p id="GUID-DBBA1450-AE5A-50E5-9B8C-F697CEFAD590"><b> Blocking on an asynchronous
-request</b> </p> <p>The state machine can be made to block. This is done so
-that you can wait for an asynchronous operation to complete. When the operation
-completes, it unblocks the state machine. There are two stages to blocking
-a state machine: </p> <ul>
-<li id="GUID-544A1BE8-2896-5CEB-ADEB-4F63E26389C4"><p>Call <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-E7B38752-F9AB-3A66-8FB6-E321717A63B5"><apiname>DMMCStack::BlockCurrentSession()</apiname></xref> to
-indicate that the state machine associated with the current session is to
-be blocked </p> </li>
-<li id="GUID-BDB03808-C220-5518-B0E7-232845FD0AD6"><p>Execute one of the SMF_xxxWAIT
-macros to return from the current state machine function and wait. </p> </li>
-</ul> <p>Note that the state machine function <i>must</i> return by calling
-one of the SMF_xxxWAIT macros. It must not poll or sit in a loop! The state
-machines are not threaded, and this means that CPU time can only be given
-to other tasks if the function returns. </p> <p> <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-E7B38752-F9AB-3A66-8FB6-E321717A63B5"><apiname>DMMCStack::BlockCurrentSession()</apiname></xref> takes
-an argument describing the type of block. The state machine will only unblock
-when an unblock request with the matching argument is called. In the platform
-specific layer of the MultiMediaCard controller, you should always set the <xref href="GUID-8A9A2DD2-C630-3651-8374-17BCF2A09AC4.dita"><apiname>KMMCBlockOnASSPFunction</apiname></xref> bit
-in the argument passed to <codeph>BlockCurrentSession()</codeph>. </p> <p>To
-unblock the state machine, call <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-E1FEFAD3-CD02-38AF-8E45-41099192D583"><apiname>DMMCStack::UnBlockCurrentSession()</apiname></xref> setting
-the <xref href="GUID-8A9A2DD2-C630-3651-8374-17BCF2A09AC4.dita"><apiname>KMMCBlockOnASSPFunction</apiname></xref> bit in the flags argument passed
-to the function, and also an error code. This will invoke the state machine
-scheduler, which will re-start the state machine. </p> <p>Note that further
-state machine processing must take place in a DFC rather than within the interrupt
-service routine (ISR), and this can be forced by ORing the session status, <xref href="GUID-0186BEDE-8E28-3F8C-8CAE-A8B92F41F47A.dita#GUID-0186BEDE-8E28-3F8C-8CAE-A8B92F41F47A/GUID-252B39FE-C203-37AD-82A4-63E9BFFD3473"><apiname>DMMCSession::iState</apiname></xref>,
-with the <xref href="GUID-5CF9ED11-2F3A-3E9B-9BFF-87DBE261F097.dita"><apiname>KMMCSessStateDoDFC</apiname></xref> bit <i>before</i> unblocking
-the session. The bit has the effect of queueing a DFC to resume the state
-machine at some later stage, before returning to the ISR. </p> <p>The following
-code shows the idea: </p> <codeblock id="GUID-C4C8C8EA-4A16-5E9C-A64D-194D7D17403C" xml:space="preserve">TMMCErr DMMCStackAssp::DoSomethingSM()
-    {
-    enum states {EStBegin=0, EStDone,EStEnd };    // enumeration of states for this state machine
-
-    SMF_BEGIN
-    // start the asynchronous operation
-    BlockCurrentSession( KMMCBlockOnASSPFunction );
-    StartAsynchronousOp();
-
-    // block and wait. Go to state EStDone when the asynchronous op is complete
-    SMF_WAITS( EStDone );
-    
-    SMF_STATE( EStDone )
-    // operation is complete, check for errors and return from state machine
-    TInt errors = CheckForHardwareErrors();
-    SMF_RETURN( errors );
-
-    SMF_END
-    }
-</codeblock> <codeblock id="GUID-5CE18C2D-2780-5966-BC26-DD33D31BB5B3" xml:space="preserve">void TMMCInterrupt::Service( TAny* aParam )
-    {
-    Session().iState |= KMMCSessStateDoDFC;
-    UnBlockCurrentSession(KMMCBlockOnASSPFunction, KMMCErrNone);
-    }
-</codeblock> </section>
-<section id="GUID-667C5A70-0ABB-525F-A309-58102E380400"><title>Example of
-a state machine calling sequence</title> <p>This shows the state machine calling
-sequence that implements the reading of a single block on a MultiMediaCard,
-where the card is not yet selected. Note that the lowest level state machine
-function called is <codeph>IssueMMCCommandSM()</codeph>, which is implemented
-by the base port. </p> <fig id="GUID-A67E1B8E-322A-5AC8-9EEA-AC24C8868E81">
-<image href="GUID-A51C3E48-3ED0-519B-A128-C5175D7E175B_d0e384203_href.png" placement="inline"/>
-</fig> </section>
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
+<!-- This component and the accompanying materials are made available under the terms of the License 
+"Eclipse Public License v1.0" which accompanies this distribution, 
+and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
+<!-- Initial Contributors:
+    Nokia Corporation - initial contribution.
+Contributors: 
+-->
+<!DOCTYPE concept
+  PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
+<concept id="GUID-80E0DB93-A96A-54A8-A201-E11935418BE7" xml:lang="en"><title>State
+Machines</title><shortdesc>Description of the structure and operation of state machines.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
+<p>The MultiMediaCard Controller uses state machines to manage the interactions
+with the MultiMediaCard hardware. </p>
+<p>State machines allows the controller to maintain the state of each submitted
+session – allowing it to schedule a second session when the first becomes
+blocked, for example. </p>
+<p>To handle the complex sequence of bus operations involved, the controller
+implements a state machine stack, allowing a parent state machine function
+to invoke a child state machine function. The state machine stack allows nesting
+of children down to a depth of 10 levels. </p>
+<p>Each session object has its own individual state machine stack because
+each session runs its own sequence of bus operations, with the controller
+managing these multiple sequences. This means that each session object has
+a state machine object, an instance of the <xref href="GUID-022AC0FE-86EE-3908-A9F8-4A33D04A68A5.dita"><apiname>TMMCStateMachine</apiname></xref> class. </p>
+<fig id="GUID-3CD3F1EF-FB6A-5D5D-B806-75536F8DF533">
+<image href="GUID-4592D493-A47C-5622-8C03-F24FABB4381C_d0e383692_href.png" placement="inline"/>
+</fig>
+<p>The state machine remembers the next state and child function name, and
+moves to that state as soon as control returns to the session. </p>
+<p>The stack chooses the next session to be handled and manages the state
+machine through the state machine dispatcher. </p>
+<ul>
+<li id="GUID-76BEBC23-FC9D-5244-A3EA-2A5424FC02D7"><p> <xref href="GUID-80E0DB93-A96A-54A8-A201-E11935418BE7.dita#GUID-80E0DB93-A96A-54A8-A201-E11935418BE7/GUID-44473E52-82B4-55E7-AE85-15AC88CE5BEB">Structure of the state machine stack</xref> </p> </li>
+<li id="GUID-0A56A8B9-65D7-54CB-A584-8C3C9AEFE339"><p> <xref href="GUID-80E0DB93-A96A-54A8-A201-E11935418BE7.dita#GUID-80E0DB93-A96A-54A8-A201-E11935418BE7/GUID-E8FCFD65-4664-52EE-B658-FCABF50D501D">Structure of a state machine function</xref> </p> </li>
+<li id="GUID-85E36E04-60CD-5560-93DE-5C15E8DBDD45"><p> <xref href="GUID-80E0DB93-A96A-54A8-A201-E11935418BE7.dita#GUID-80E0DB93-A96A-54A8-A201-E11935418BE7/GUID-667C5A70-0ABB-525F-A309-58102E380400">Example of a state machine calling sequence</xref> </p> </li>
+</ul>
+<section id="GUID-44473E52-82B4-55E7-AE85-15AC88CE5BEB"><title>Structure of
+the state machine stack</title> <p>The stack itself is represented as an array
+of <xref href="GUID-DDCE8054-1656-34EF-9CBC-53C796BFD5A6.dita"><apiname>TMMCMachineStackEntry</apiname></xref> objects contained within the state
+machine object <xref href="GUID-022AC0FE-86EE-3908-A9F8-4A33D04A68A5.dita"><apiname>TMMCStateMachine</apiname></xref>. </p> <p>The state machine
+maintains a "pointer", <xref href="GUID-022AC0FE-86EE-3908-A9F8-4A33D04A68A5.dita#GUID-022AC0FE-86EE-3908-A9F8-4A33D04A68A5/GUID-5EC9B7D0-A3A9-35DF-A91D-65920372C9A4"><apiname>TMMCStateMachine::iSP</apiname></xref>, to the current
+state entry. This is not a true pointer, but just a value that indexes into
+the array. However, for all practical purposes it has the effect of a pointer.
+Each state entry in the stack is thought of as having a parent-child relationship
+with the other. </p> <p>Each state entry maintains three pieces of information: </p> <ul>
+<li id="GUID-81454E68-4603-5211-8F9F-70F0F2F4B95D"><p>A pointer to the state
+machine function. </p> </li>
+<li id="GUID-B20834EB-3EAE-5D79-8564-8B2A5490A057"><p>A variable containing
+the current state; the value and meaning of the state is defined by the state
+machine function. </p> </li>
+<li id="GUID-32AFB296-0D5F-5FF7-9ECD-C9F798E04542"><p>A bitmask of <xref href="GUID-FF4AB1CF-7A2C-3FC6-B123-D6819E1BCDCA.dita"><apiname>TMMCErr</apiname></xref> defined
+error conditions; these are set by the parent state machine function so that
+it gets the chance to trap those errors if the child state machine function
+returns those errors. Errors are propagated up the stack, and any error conditions
+not trapped at any level in the state machine hierarchy leads to the state
+machine terminating with that error value. </p> </li>
+</ul> <fig id="GUID-064C53DB-6A96-5C6D-B3CD-B40A0251EF66">
+<image href="GUID-D8911BE6-100D-588A-8E5C-A429A72AFCDA_d0e383777_href.png" placement="inline"/>
+</fig> <p>In general, the overall state of the state machine reflects the
+state of the current state entry; for example, <xref href="GUID-E32D6BC3-F8D9-3F7E-94F6-56633B645D6A.dita#GUID-E32D6BC3-F8D9-3F7E-94F6-56633B645D6A/GUID-48F37107-2D11-3550-890B-D79844A97DBF"><apiname>TMMCStatemachine::State()</apiname></xref> returns
+the state held in the current state entry. </p> <p>While the flow of control
+through a stack can be complex, the following diagram shows a short example
+snapshot. Here, the current state in the current stack entry is <codeph>Sn</codeph> and
+is handled by the function <codeph>PF()</codeph>. The code decides to pass
+control to the child function <codeph>CF()</codeph>, but ensures that, on
+completion, the next state in the current stack entry will be <codeph>Sn+1</codeph>. </p> <fig id="GUID-6ACBC49E-14EE-526B-A1A3-426B64BF8476">
+<image href="GUID-D2D41326-BA88-5A02-805B-5EAEC29ADB5D_d0e383804_href.png" placement="inline"/>
+</fig> <p>For example, the <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-F71A4421-2F9E-39FD-A352-97ECAAFE822D"><apiname>DMMCStack::CIMUpdateAcqSM()</apiname></xref> function
+implements the CIM_UPDATE_ACQ macro as defined by the <i>MultiMediaCard System
+Specification</i>, and is a typical state machine function. </p> <p>Most commands
+and macros involve one or more asynchronous operations and while such operations
+are outstanding, a session is blocked. While a session is blocked, its state
+machine dispatch function is not called. As soon an asynchronous event removes
+the blocking condition, control returns to the state machine. </p> </section>
+<section id="GUID-E8FCFD65-4664-52EE-B658-FCABF50D501D"><title>Structure of
+a state machine function</title> <p>State machine functions are defined and
+implemented in the <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita"><apiname>DMMCStack</apiname></xref> class in pairs: one as a static
+function, and the other as a member function. The static variant takes a <codeph>TAny*</codeph> pointer
+that is cast to a <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita"><apiname>DMMCStack</apiname></xref> pointer, and the <codeph>DMMCStack</codeph> member
+function is then called: </p> <codeblock id="GUID-F5EEA20F-2312-5394-84C4-5E568995291A" xml:space="preserve">TMMCErr DMMCStack::FunctionNameSMST( TAny* aPtr )
+    {
+    return( STATIC_CAST(DMMCStack*,aPtr)-&gt;FunctionNameSM() );
+    }
+</codeblock> <codeblock id="GUID-3C01127E-4EBA-59AC-91F8-1F004A74E45B" xml:space="preserve">TMMCErr DMMCStack::FunctionNameSM()
+    {
+    enum states {EStBegin=0, EStNext,…, EStEnd };    // Enumeration of states for this state machine
+    DMMCSession&amp; s = Session();
+
+    SMF_BEGIN
+    // State EStBegin
+    // Actions for state EStBegin
+
+    SMF_STATE( EStNext )
+    // State EStNext
+    // Actions for state EStNext
+
+    SMF_END
+    }
+</codeblock> <p>A state machine function can release control and wait to be
+re-entered by returning zero. If its session is not blocked then that will
+happen immediately. If the state machine function returns non-zero, the session
+will be completed with that error code unless the parent state machine function
+has explicitly intercepted such an error by setting the trap mask. </p> <ul>
+<li id="GUID-BEE3954A-733D-55CE-B09C-4B49304B44E1"><p> <xref href="GUID-80E0DB93-A96A-54A8-A201-E11935418BE7.dita#GUID-80E0DB93-A96A-54A8-A201-E11935418BE7/GUID-901D8456-F8D3-5E92-B3DA-EFE556D8C48B">Important points to note</xref> </p> </li>
+<li id="GUID-DA29FD1E-93EF-56C1-9650-8CE22B655897"><p> <xref href="GUID-80E0DB93-A96A-54A8-A201-E11935418BE7.dita#GUID-80E0DB93-A96A-54A8-A201-E11935418BE7/GUID-DBBA1450-AE5A-50E5-9B8C-F697CEFAD590">Blocking on an asynchronous request</xref> </p> </li>
+</ul> <p id="GUID-901D8456-F8D3-5E92-B3DA-EFE556D8C48B"><b>Important points to note</b> </p> <p>Each
+state machine function must define a list of states that can exist. States
+are defined as an enumeration whose first and last values <i>must</i> be labelled <codeph>EStBegin</codeph> and <codeph>EStEnd</codeph>,
+respectively. <codeph>EStBegin</codeph> must have the value zero. Any other
+intermediate states are program defined. </p> <p>To make the state machine
+functions more readable, a number of macros exist to help with the layout
+of the function code, and to control program flow. The most basic macros are <xref href="GUID-C095E583-3E71-31F3-B092-627357D72958.dita"><apiname>SMF_BEGIN</apiname></xref>, <xref href="GUID-38811BD9-F27C-3408-A04F-053314A2CF84.dita"><apiname>SMF_STATE</apiname></xref> and <xref href="GUID-C1089896-DD68-399C-BF34-2495C51A0CA1.dita"><apiname>SMF_END</apiname></xref> that expand into a switch statement. The above code expands
+to: </p> <codeblock id="GUID-16AE9141-5BE1-5B54-B083-7F60133DD018" xml:space="preserve">TMMCErr DMMCStack::FunctionNameSM()
+{
+enum states {EStBegin=0, EStNext,…, EStEnd };    // Enumeration of states for this state machine
+DMMCSession&amp; s = Session();
+
+TMMCStateMachine&amp; m = Machine();            //SMF_BEGIN
+const TMMCErr err = m.SetExitCode( 0 );        //SMF_BEGIN
+for(;;)                                        //SMF_BEGIN
+    {                                        //SMF_BEGIN
+    switch(m.State())                        //SMF_BEGIN
+        {                                    //SMF_BEGIN
+        case EStBegin:                        //SMF_BEGIN
+            {                                //SMF_BEGIN
+            if(err) (void)0;                //SMF_BEGIN 
+            // State EStBegin
+            // Actions for state EStBegin
+
+            }                                //SMF_STATE
+        case EStNext:                        //SMF_STATE
+            {                                //SMF_STATE
+            // State EStNext
+            // Actions for state EStNext
+
+        case EStEnd:                                                //SMF_END
+            break;                                                    //SMF_END
+            default:                                                //SMF_END
+            DMMCController::Panic(DMMCController::EMMCMachineState);//SMF_END
+        }                                                            //SMF_END
+        break;                                                        //SMF_END
+    }                                                                //SMF_END
+return(m.Pop());                                                    //SMF_END
+}</codeblock> <p>Notes: </p> <ul>
+<li id="GUID-7542D030-2641-5A15-A5AF-A02C491B24BB"><p>be aware that SMF_BEGIN
+generates an open curly bracket while SMF_STATE generates a corresponding
+close bracket, and SMF_END closes the switch statement. </p> </li>
+</ul> <p>You need to be aware of the code that is generated by these macros.
+In particular, some such as SMF_BEGIN generate an opening curly brace, while
+others such as SMF_STATE generate a corresponding close curly brace. Also,
+you need to know whether a macro generates a <codeph>break;</codeph> or a <codeph>return;</codeph> statement.
+Lack of awareness here may cause code to be generated that flows from one
+case statement to another, which may not be your intent. </p> <ul>
+<li id="GUID-7C57CF3E-0EB9-56A4-A07A-86027F5B42BA"><p> <xref href="GUID-C095E583-3E71-31F3-B092-627357D72958.dita"><apiname>SMF_BEGIN</apiname></xref> </p> </li>
+<li id="GUID-9A87EEA6-6D40-53E1-BCEE-F9A20C22D51D"><p> <xref href="GUID-C1089896-DD68-399C-BF34-2495C51A0CA1.dita"><apiname>SMF_END</apiname></xref> </p> </li>
+<li id="GUID-3ADD2CCB-4C83-54EC-80DB-3C8CFDDDCB7A"><p> <xref href="GUID-2BA7F4A7-ECB0-3839-809B-4C32D4F451BA.dita"><apiname>SMF_NEXTS</apiname></xref> </p> </li>
+<li id="GUID-41D972A7-18DE-5CE5-B0D6-039B0126199C"><p> <xref href="GUID-ACD776A5-5439-3BE9-8DD8-B537D8C2C637.dita"><apiname>SMF_CALL</apiname></xref> </p> </li>
+<li id="GUID-87C8FC8C-F810-5B3F-A7CC-99D6515F8F04"><p> <xref href="GUID-3802119E-0FC0-3B7C-9582-21563EC9AF61.dita"><apiname>SMF_CALLWAIT</apiname></xref> </p> </li>
+<li id="GUID-89669A58-5168-508A-AF9F-34C3347F0A69"><p> <xref href="GUID-2B6FA032-F8F9-3205-9CBB-EFB96691ACC9.dita"><apiname>SMF_CALLMYS</apiname></xref> </p> </li>
+<li id="GUID-A6C9952A-223E-5687-B67C-D89D50070BDB"><p> <xref href="GUID-C1D65C79-F781-3E22-AA73-F75BA2516F6F.dita"><apiname>SMF_CALLMEWR</apiname></xref> </p> </li>
+<li id="GUID-7FF0DFC9-D9DC-5E08-B668-4BC62B6E50EC"><p> <xref href="GUID-A143CA61-AA6B-3C5F-9E58-50BAF3786262.dita"><apiname>SMF_INVOKES</apiname></xref> </p> </li>
+<li id="GUID-F02BE381-0BA2-5E9D-AFB7-9064FBADC64C"><p> <xref href="GUID-A73CAEB2-2413-371E-A56F-2757C0723514.dita"><apiname>SMF_INVOKEWAITS</apiname></xref> </p> </li>
+<li id="GUID-A39E56F8-DE55-5EDE-A955-24E198026F39"><p> <xref href="GUID-94214574-2CCD-3BE4-ABD4-6A58328B29A2.dita"><apiname>SMF_WAIT</apiname></xref> </p> </li>
+<li id="GUID-1CB69F09-3BAC-5C41-B20E-5A2896C0E18E"><p> <xref href="GUID-33FBF199-09B8-32C3-BAD6-92D277722DB3.dita"><apiname>SMF_WAITS</apiname></xref> </p> </li>
+<li id="GUID-46D7BB96-3EC7-5207-BEE4-1E3ABB145D6B"><p> <xref href="GUID-B13D0665-AD49-348F-8795-67E8761B0BC8.dita"><apiname>SMF_RETURN</apiname></xref> </p> </li>
+<li id="GUID-A9A4DB91-2648-534D-BEA3-57A23147D750"><p> <xref href="GUID-2BA73A03-7379-394C-B9E8-4525316AF91F.dita"><apiname>SMF_EXIT</apiname></xref> </p> </li>
+<li id="GUID-E75E1BF0-CD8B-5EEA-98EA-13176AE0A308"><p> <xref href="GUID-57CF6330-1EA6-36A9-B2A1-2BB360B1E7FD.dita"><apiname>SMF_EXITWAIT</apiname></xref> </p> </li>
+<li id="GUID-D0617F39-4CF6-5FA7-995C-50688A82E703"><p> <xref href="GUID-6E9EF7EB-A9A2-3FA1-902D-188B4930927F.dita"><apiname>SMF_JUMP</apiname></xref> </p> </li>
+<li id="GUID-83791CBF-298A-5B5F-A9A0-8FB902AE81EB"><p> <xref href="GUID-85E63D6B-521B-309A-A1B1-18FDFCF626A0.dita"><apiname>SMF_JUMPWAIT</apiname></xref> </p> </li>
+<li id="GUID-F657F501-47AE-57D0-BEB6-A051176FC279"><p> <xref href="GUID-BF735A08-6E69-374F-8052-EF6CA101A3C3.dita"><apiname>SMF_GOTONEXTS</apiname></xref> </p> </li>
+<li id="GUID-F7D1B6D8-51A2-5C73-A709-1BB10CD27620"><p> <xref href="GUID-AA215584-34D9-36DA-A05A-8A4DF4636D5E.dita"><apiname>SMF_GOTOS</apiname></xref> </p> </li>
+<li id="GUID-042539CB-3019-57A2-B0AD-F1417756F842"><p> <xref href="GUID-38811BD9-F27C-3408-A04F-053314A2CF84.dita"><apiname>SMF_STATE</apiname></xref> </p> </li>
+<li id="GUID-ADD382E6-32C0-5773-8958-057F440C3FEC"><p> <xref href="GUID-11B9D102-4548-3321-8318-26E940273880.dita"><apiname>SMF_BPOINT</apiname></xref> </p> </li>
+</ul> <p id="GUID-DBBA1450-AE5A-50E5-9B8C-F697CEFAD590"><b> Blocking on an asynchronous
+request</b> </p> <p>The state machine can be made to block. This is done so
+that you can wait for an asynchronous operation to complete. When the operation
+completes, it unblocks the state machine. There are two stages to blocking
+a state machine: </p> <ul>
+<li id="GUID-544A1BE8-2896-5CEB-ADEB-4F63E26389C4"><p>Call <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-E7B38752-F9AB-3A66-8FB6-E321717A63B5"><apiname>DMMCStack::BlockCurrentSession()</apiname></xref> to
+indicate that the state machine associated with the current session is to
+be blocked </p> </li>
+<li id="GUID-BDB03808-C220-5518-B0E7-232845FD0AD6"><p>Execute one of the SMF_xxxWAIT
+macros to return from the current state machine function and wait. </p> </li>
+</ul> <p>Note that the state machine function <i>must</i> return by calling
+one of the SMF_xxxWAIT macros. It must not poll or sit in a loop! The state
+machines are not threaded, and this means that CPU time can only be given
+to other tasks if the function returns. </p> <p> <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-E7B38752-F9AB-3A66-8FB6-E321717A63B5"><apiname>DMMCStack::BlockCurrentSession()</apiname></xref> takes
+an argument describing the type of block. The state machine will only unblock
+when an unblock request with the matching argument is called. In the platform
+specific layer of the MultiMediaCard controller, you should always set the <xref href="GUID-8A9A2DD2-C630-3651-8374-17BCF2A09AC4.dita"><apiname>KMMCBlockOnASSPFunction</apiname></xref> bit
+in the argument passed to <codeph>BlockCurrentSession()</codeph>. </p> <p>To
+unblock the state machine, call <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-E1FEFAD3-CD02-38AF-8E45-41099192D583"><apiname>DMMCStack::UnBlockCurrentSession()</apiname></xref> setting
+the <xref href="GUID-8A9A2DD2-C630-3651-8374-17BCF2A09AC4.dita"><apiname>KMMCBlockOnASSPFunction</apiname></xref> bit in the flags argument passed
+to the function, and also an error code. This will invoke the state machine
+scheduler, which will re-start the state machine. </p> <p>Note that further
+state machine processing must take place in a DFC rather than within the interrupt
+service routine (ISR), and this can be forced by ORing the session status, <xref href="GUID-0186BEDE-8E28-3F8C-8CAE-A8B92F41F47A.dita#GUID-0186BEDE-8E28-3F8C-8CAE-A8B92F41F47A/GUID-252B39FE-C203-37AD-82A4-63E9BFFD3473"><apiname>DMMCSession::iState</apiname></xref>,
+with the <xref href="GUID-5CF9ED11-2F3A-3E9B-9BFF-87DBE261F097.dita"><apiname>KMMCSessStateDoDFC</apiname></xref> bit <i>before</i> unblocking
+the session. The bit has the effect of queueing a DFC to resume the state
+machine at some later stage, before returning to the ISR. </p> <p>The following
+code shows the idea: </p> <codeblock id="GUID-C4C8C8EA-4A16-5E9C-A64D-194D7D17403C" xml:space="preserve">TMMCErr DMMCStackAssp::DoSomethingSM()
+    {
+    enum states {EStBegin=0, EStDone,EStEnd };    // enumeration of states for this state machine
+
+    SMF_BEGIN
+    // start the asynchronous operation
+    BlockCurrentSession( KMMCBlockOnASSPFunction );
+    StartAsynchronousOp();
+
+    // block and wait. Go to state EStDone when the asynchronous op is complete
+    SMF_WAITS( EStDone );
+    
+    SMF_STATE( EStDone )
+    // operation is complete, check for errors and return from state machine
+    TInt errors = CheckForHardwareErrors();
+    SMF_RETURN( errors );
+
+    SMF_END
+    }
+</codeblock> <codeblock id="GUID-5CE18C2D-2780-5966-BC26-DD33D31BB5B3" xml:space="preserve">void TMMCInterrupt::Service( TAny* aParam )
+    {
+    Session().iState |= KMMCSessStateDoDFC;
+    UnBlockCurrentSession(KMMCBlockOnASSPFunction, KMMCErrNone);
+    }
+</codeblock> </section>
+<section id="GUID-667C5A70-0ABB-525F-A309-58102E380400"><title>Example of
+a state machine calling sequence</title> <p>This shows the state machine calling
+sequence that implements the reading of a single block on a MultiMediaCard,
+where the card is not yet selected. Note that the lowest level state machine
+function called is <codeph>IssueMMCCommandSM()</codeph>, which is implemented
+by the base port. </p> <fig id="GUID-A67E1B8E-322A-5AC8-9EEA-AC24C8868E81">
+<image href="GUID-A51C3E48-3ED0-519B-A128-C5175D7E175B_d0e384203_href.png" placement="inline"/>
+</fig> </section>
 </conbody></concept>
\ No newline at end of file