Magic Lantern Forum

Developing Magic Lantern => Reverse Engineering => Topic started by: coutts on January 24, 2013, 04:06:05 AM

Title: How do State Machines change states?
Post by: coutts on January 24, 2013, 04:06:05 AM
I've often wondered what (who) makes state machines change their state. Last year while porting the 5dc I mapped some complex structures in VxWorks that all tied into state machines. I've finally done the same for DryOS while investigating EVF (live view) state.

Here's a comment from my commit here (https://bitbucket.org/hudson/magic-lantern/commits/74bacd30681fabfc6732c1ac0295ff3415e2c63c) which explains how state machines change states:


/**
*  EVF Manager - 6D v1.1.2
*
*  Managers are a high-level data structure in DryOS and VxWorks. For structure definitions, look in state-object.h
*
*  Before, state-objects were the highest level data structure we understood in DryOS, now I understand what actually
*  triggers the state changes, so we can track down the functions that do these changes. For this demonstration I'll
*  examine the EVF Manager in the 6D v1.1.2 firmware.
*
*  The Taskclass structure is pretty important, as this is where events are queued up before processed. Events are
*  posted to the taskclass queue by taskclass_post_message (0x39F04). Arg2 to this function is the event number to
*  post. A taskclass has a generic task, which takes events posted to the taskclass message queue, and calls the
*  respective EventDispatch function, in our case it's evfEventDispatch (0xFF0DD22C). This function is called by the
*  taskclass task via a pointer stored in the Manager struct. It's because of this that we can hijack the EventDispatch
*  handler just like state objects, to catch taskclass events as they're processed.
*
*  All we need to look for to find who posts the events are calls to taskclass_post_message, specifically the ones that
*  reference the EVF Manager's struct. I hijacked the EVF Manager's event dispatch here, and got the same results as when
*  I hijacked the state machine, so it works! For EVF state, i observed 3 events happening in each frame: 5, 3, and 4.
*  Look at my youtube video here of live view slowed down to 2fps, the Tick message happens once every second (on another task).
*      --> www.youtube.com/watch?v=B4n1eh8YUtE
*
*  The debug log after running this looked like:
*
*  [MAGIC] name|arg1|arg2|arg3: Evf | 0x5 | 0x0 | 0x0
*  [MAGIC] name|arg1|arg2|arg3: Evf | 0x3 | 0x0 | 0x0
*  [MAGIC] name|arg1|arg2|arg3: Evf | 0x4 | 0x0 | 0x0
*      (repeated)
*
**/



//~ Structures for DryOS, derived from research on VxWorks.
struct Manager
{
    const char *                    name;                   //~ off_0x00    name of manager. ie: Evf
    int                             off_0x04;               //~ off_0x04    unknown
    struct TaskClass *              taskclass_ptr;          //~ off_0x08    pointer to taskclass struct
    const struct state_object *     stateobj_ptr;           //~ off_0x0C    pointer to stateobject struct
};

struct TaskClass    //~ size=0x18
{
    const char *                identifier;             //~ off_0x00    "TaskClass"
    const char *                name;                   //~ off_0x04    task class name. ie: PropMgr
    int                         off_0x08;               //~ unknown     initialized to 1 in CreateTaskClass
    const struct task *         task_struct_ptr;        //~ off_0x0c    ret_CreateTask (ptr to task struct) called from CreateTaskClass
    const struct msg_queue *    msg_queue_ptr_maybe;    //~ off_0x10    some kind of message queue pointer (very low level functions at work)
    void *                      eventdispatch_func_ptr; //~ off_0x14    event dispatch pointer. ie: propmgrEventDispatch
};




The taskclass reminds me a lot of generics from object-oriented languages like Java. There's one "generic" task for every taskclass, they just rely on the Manage struct passed to them to keep track of the name and state machine associated with the events.


Summary:
Functions post events to the taskclass queue using taskclass_post_message. Each taskclass has a task running at all times, constantly checking a message queue for new "events". If there's an event to process, the taskclass calls the EventDispatch function associated with the manage struct (passed as arg0 to taskclass_post_message), passing the event number as one of the arguments. Through hijacking this EventDispatch function, I've figured out that this is what triggers the state machine to change states. There's a function called by the EventDispatch; a generic "change state" function, which uses the event number to find the offset in the state matrix, to know which state change to call. The state machine changes states, and remains in that state until a new event tells it to change to a different state.

Now, what calls the functions that post to the taskclass queue? From what I've seen, they appear to be callback routine (CBR) functions as far as EVF goes. I'll keep digging, but we're getting close to understanding what copies the LV frame data from the sensor to the LV and HD buffers.