Magic Lantern Firmware Wiki

Code: state-object.h and state-object.c

Ref: 2.0.4_StateObjects, Rebel T1i / 500d State Object Initialization, 500d/T1i Task Sequencers, 550d_108_StateObjects, State machine diagrams.

StateObject structure[]

0: 'StateObject'
4: name
8: ?
c: @StateTransition
10: address
14: inputs
18: states
1c: current state maybe


arg0: state object
arg1: ?
arg2: input
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)

State machine task (AJ_UserLevel_task)[]

from [1]

struct TaskClass {
      uint32_t TaskClass_label
      uint32_t name;
      uint32_t enabled;   // off_0x08
      uint32_t task_handle;
      uint32_t msg_queue;
      void (*EventDispatch)(uint32_t, uint32_t, uint32_t, uint32_t); // off_0x14
void AJ_UserLevel_task( struct TaskClass * tc )
      uint32_t x, y, z, w;
      while (tc->enabled)
              int rc = TaskClass_GetEvent(tc, &x, &y, &z, &w);
              if (rc != 0)
              if (!tc->enabled)
              tc->EventDispatch(x, y, z, w);

      return 0;

How to trigger state changes?[]

Pure theory: TryPostEvent.

  • TryPostEvent does this: msg_queue_post(arg0->off_0x10, ...)
  • TaskClass_GetEvent does this: msg_queue_receive(arg0->off_0x10, ...)


TryPostEvent(TaskClass_obj, x, y, z, w)

should result in indirect call of:

TaskClass_obj->EventDispatch(x, y, z, w).

EventDispatch functions may be task-specific, but they seem to follow a pattern.

mvrEventDispatch, voiEventDispatch:
s = StateTransition_main(stateobj, x, y, z, w)
if (s)
   stateobj = s // state functions from this particular state will return the state object
   return s
cs = GetCurrentState(stateobj)
DebugMsg(*, 6, msg='***EventDispatch : Current = %d, dwEventID = %d, dwParam = %#x', cs, y, z)