Magic Lantern Firmware Wiki

Background - By: Coutts[]

500d v1.1.0 state objects. I am looking into state objects for the first time, writing my notes here. Hope this will help others as much as it will help me! See also 550D_StateObjects and 2.0.4_StateObjects

As a quick background, I will quote the definition of a state machine from wikipedia:

"A finite-state machine (FSM) or finite-state automaton (plural: automata), or simply a state machine, is a behavioral model used to design computer programs. It is composed of a finite number of states associated to transitions. A transition is a set of actions that starts from one state and ends in another (or the same) state. A transition is started by a trigger, and a trigger can be an event or a condition."

From what I have studied and concluded, each state machine has it's own message queue and event system. Events trigger state changes. I have also noticed there are property slaves registered during initilization of some state machines. I have only briefly looked at them, but they appear to send events as their callback.

My understanding is still very premature of all of this. I will update this page as I learn more.

State Object Initialization[]

For my analysis, I will use the LVC_AE state object as an example. I am looking at the main initialization function located at sub_FF0350B8(). First things first, a structure is created with length 0x10 for the state object and a string is stored at off_0x00 with the state object's name. In our case it will look like this:

off_0x00  -  "LVC_AE"


Next, CreateTaskClass() (located at 0xFF1A6790) is called with these arguments:

  • arg0: "LVC_AE"
  • arg1: 0x14
  • arg2: 0
  • arg3: 0xC8
  • arg4: lvcaeEventDispatch() (located at 0xFF035048)

In this function, I believe a task class is created, though I am still exploring what that means. A structure is allocated with size 0x18. It looks like this in our case:

off_0x00  -  "TaskClass"
off_0x04  -  "LVC_AE"
off_0x08  -  1
off_0x0C  -  ret_task_create()
off_0x10  -  ret_KernelDry_KerQueue.c__create_message_queue__R0.name__R1.size__maybe()
off_0x14  -  lvcaeEventDispatch() (located at 0xFF035048)

task_create() is called with these arguments:

  • arg0: "LVC_AE"
  • arg1: 0x14
  • arg2: 0
  • arg3: sub_FF1A671C
  • arg4: ret_AllocateMemory (pointer to task class structure location)

Also the message queue function mentioned above is called with arg0 (name): "LVC_AE", and arg1 (size) 0xC8.

If the return of task_create is 0, KernelDry_KerQueue.c_or_AJ_guess_USB_CreateMessageQueue() is called with arg0 as the return of the message queue creation function above, followed by FreeMemory with arg0 as the location of the structure. Otherwise, the function returns the location of the structure that was created.

--- so basically, if the return of task_create() is 0, free up the resources created here (the structure allocated and message queue created), otherwise just return the location of the structure allocated in this function. From this finding, I think that KernelDry_KerQueue.c_or_AJ_guess_USB_CreateMessageQueue() can be renamed to DeleteMessageQueue().

Now we return to where we were above, and the return value of CreateTaskClass() is stored at off_0x04 of our main state object structure. Also, the value of arg0 to the function the main state object initialization function; the one that called AllocateMemory() earlier, then called CreateTaskClass(), is stored at off_0x08 of the main state object structure. So now the main state object structure looks like this:

off_0x00  -  "LVC_AE"
off_0x04  -  ret_CreateTaskClass()   //points to the location of the task class structure for this state object
off_0x08  -  0x46

initialize__LVCAE__FSM() - located at 0xFF0EADA4[]

Now, a function which I will call initialize__LVCAE__FSM() (located at 0xFF0EADA4) is called. It takes no arguments. It calls a funtion which I have determined creates a state object, so I have named it accordingly:

CreateStateObject() - located at 0xFF1A62C4[]

This function seems to create state objects. In the 500d v1.1.0 firwmare, it is called 48 times. Here is the function broken down by me:

CreateStateObject(arg0, arg1, arg2, arg3, arg4)
	AllocateMemory(0x20);  //ret_AllocateMemory = state_struct
	if (ret_AllocateMemory != 0)
		*(state_struct->off_0x00) = "StateObject";
		*(state_struct->off_0x04) = arg0 //[state object name];
		*(state_struct->off_0x08) = arg1 //(always 0?)
		*(state_struct->off_0x0C) = state_object_handler__maybe()  //located at 0xFF1A620C
		*(state_struct->off_0x10) = arg2
		*(state_struct->off_0x14) = arg3 //number of states
		*(state_struct->off_0x18) = arg4 //number of transitions
		*(state_struct->off_0x1C) = 0 //i think this is an event counter	
		return state_struct;
	return 5;

When CreateStateObject() returns, the return value (location of the structure created) is stored at off_0x10 of another location which acts as a pointer to this structure. This location is accessed by other functions related to this state object.

So in the case of LVC_AE, the structure created by CreateStateObject() will look like this:

off_0x00  -  "StateObject"
off_0x04  -  "LVCAEState"
off_0x08  -  0
off_0x0C  -  StateTransition() (located at 0xFF1A620C, goes to next state and fires a function, based on input)
off_0x10  -  address --> location of the state matrix in ROM
off_0x14  -  0xA --> number of transition trigger events. dwEventID from lvcaeEventDispatch().
off_0x18  -  0x6 --> number of states.
off_0x1C  -  0 --> i think this is the value of the current state number.

The return of CreateStateObject() (location of this structure) is then stored at 0x496C->off_0x10 --- *(0x497C), and the function returns the location of the structure that was just stored at 0x497C.

Now we are back to the function that called CreateTaskClass() and initialize__LVCAE__FSM(), the function that created the "main" state object structure of size 0x10 way at the top of this page. The location of the structure created in CreateStateObject() is stored at off_0xC of the first structure (from top of this page). So now that structure looks like this for our example:

off_0x00  -  "LVC_AE"
off_0x04  -  [pointer to CreateTaskClass() structure]   //points to the location of the task class structure for this state object
off_0x08  -  0x46
off_0x0C  -  [pointer to CreateStateObject() structure] //same as *(0x497C)

A pointer to this structure is at *(0x1D80)

State transitions[]

next_state = MEM(state_obj_base_addr + 8*current_state + 8*num_states*input )
transition_function = MEM(state_obj_base_addr + 8*current_state + 8*num_states*input + 4)

Almost to the end :)

Unfortunately things get a little confusing at this point for me. If anyone would like to contribute, feel free to edit this page. I will add to this if I figure it out eventually.

State Objects Created[]

Here is a list of the state objects created in the 500d v1.1.0 firmware, along with their initialize funtion (the one that calls CreateStateObject):

  • SCSState - initialize_SCS_related_FSMs (0xFF07B0D4)
  • SCSEshutState - initialize_SCS_related_FSMs (0xFF07B0D4)
  • SCSSRState - initialize_SCS_related_FSMs (0xFF07B0D4)
  • SBSState - initialize_SBS_FSM (0xFF07D7D0)
  • SPSState - initialize_SPS_FSM (0xFF07FB04)
  • SDSRearState - initialize_SDSRear_FSM (0xFF0820C8)
  • SDSFrontState - initialize_SDSFront_FSM (0xFF083FB8)
  • SDSFrontState - initialize_SDSFront_FSM (0xFF083FB8)
  • SDSFrontState - initialize_SDSFront_FSM (0xFF083FB8)
  • SDSFrontState - initialize_SDSFront_FSM (0xFF083FB8)
  • FSSState - initialize_FSS_FSM (0xFF09AC70)
  • FCSState - initialize_FCS_FSM (0xFF0A0A94)
  • RMTState - initialize_RMT_FSM (0xFF0A4D54)
  • EMState - initialize_EM_FSM (0xFF0A5E20)
  • SRMState - initialize_SRM_FSM (0xFF0AE560)
  • DpImgEditState - initialize_DpImgEdit_FSM (0xFF0D98CC)
  • LVState - initialize_LV_and_LVRec_FSMs (0xFF0E5D30)
  • LVCAEState - initialize_LVCAE_FSM (0xFF0EADA4)
  • LVCAFState - initialize_LVCAF_FSM (0xFF0EB66C)
  • LVCDEVState - initialize_LVCDEV_FSM (0xFF0EC22C)
  • MotionDetectState - initialize_MotionDetect_FSM (0xFF1015F8)
  • RDStaet - initialize_RD_FSM (0xFF102770)
  • PtpDpsState - initialize_PtpDps_FSMs (0xFF10C8BC)
  • PtpDpsState - initialize_PtpDps_FSMs (0xFF10C8BC)
  • PtpSdioEventState - initialize_PtpSdioEvent_FSM (0xFF10FD0C)
  • TOMState - initialize_TOM_FSM (0xFF120754)
  • CeresState - initialize_Ceres_FSM (0xFF124ECC)
  • FMNormalState - initialize_FMNormal_FSM (0xFF1308AC)
  • unk - initialize_unk_FSM (0xFF14B838) --> FSM name stored at *(0x7A58)
  • MovRecState - initialize_MovRec_FSM (0xFF14FF54)
  • USBControlPipe - InitializeUSBDriver (0xFF1839F0)
  • PropState - initialize_PROP_FSM (0xFF187F64)
  • DMState - initialize_DM_FSM (0xFF19E960)
  • DpState - initialize_Dp_FSM (0xFF1E36E4)
  • LVAngelState - initialize_LVAngel_FSM (0xFF1F611C)
  • PtpEvent - initialize_PtpEvent_FSM (0xFF20D09C)
  • PtpTrans - initialize_PtpTrans_FSM (0xFF20FE70)
  • PtpSdioTrans - initialize_PtpSdioTrans_FSM (0xFF212530)
  • PtpSdioHddTrans - initialize_PtpSdioHddTrans_FSM (0xFF216228)
  • SdioDrvState - initialize_SdioDrv_FSM (0xFF218B58)
  • MrkState - initialize_Mrk_FSM (0xFF21F210)
  • FRState - initialize_FR_FSM (0xFF227CA8)
  • FWState - initialize_FW_FSM (0xFF2282D8)
  • IPCMasterState - initialize_IPCMaster_FSM (0xFF294630)
  • IPCSlaveState - initialize_IPCSlave_FSM (0xFF294674)
  • SdioTskState - initialize_SdioTsk_FSM (0xFF2EB924)
  • CrpDecState - initialize_CrpDec_FSM (0xFF2F59A8)