rFSM - dynamically modifying a state machine

Hi all,
I was trying to modify a state machine "dinamically" (after that rfsm.init
has been called on the state machine) and I saw that there is an
fsm_merge(...) method in rfsm.lua that I could probably use but that at the
moment does not handle composite states.

For example, I have

fsm = rfsm.init(rfsm.load("fsm.lua"))
task = rfsm.init(rfsm.load("task.lua"))

with "fsm" that has inside a state "task": I'd like to replace the original
"fsm.task" with the new one, included all the related transitions. I have
seen this example<http://www.orocos.org/wiki/orocos/toolchain/luacookbook#toc52>
but
this way of replacing a state (or one of its parts) only works before the
call to "rfsm.init".

This is the function to which I am referring:

function fsm_merge(fsm, parent, obj, id)

rFSM - dynamically modifying a state machine

Hi Nicola,

On Wed, Nov 14, 2012 at 04:59:26PM +0100, Nicola Preda wrote:

> I was trying to modify a state machine "dinamically" (after that rfsm.init has
> been called on the state machine) and I saw that there is an fsm_merge(...)
> method in rfsm.lua that I could probably use but that at the moment does not
> handle composite states.

Yes, it's currently only used for merging initial connectors.

> For example, I have
>
> fsm = rfsm.init(rfsm.load("fsm.lua"))
> task = rfsm.init(rfsm.load("task.lua"))

The 'task' fsm for merging should better not be initalized, since that
will assume it is to be run standalone. Instead

> with "fsm" that has inside a state "task": I'd like to replace the original
> "fsm.task" with the new one, included all the related transitions. I have seen
> this example but this way of replacing a state (or one of its parts) only
> works before the call to "rfsm.init".

You also don't only want merge, but replace. For that you'll also need
to update transitions that point to the replaced state.

> This is the function to which I am referring:
>
> function fsm_merge(fsm, parent, obj, id)
>

rFSM - dynamically modifying a state machine

2012/11/15 Markus Klotzbuecher <markus [dot] klotzbuecher [..] ...>

> Hi Nicola,
>

Hi Markus,

>
> On Wed, Nov 14, 2012 at 04:59:26PM +0100, Nicola Preda wrote:
>
> > I was trying to modify a state machine "dinamically" (after that
> rfsm.init has
> > been called on the state machine) and I saw that there is an
> fsm_merge(...)
> > method in rfsm.lua that I could probably use but that at the moment does
> not
> > handle composite states.
>
> Yes, it's currently only used for merging initial connectors.
>
> > For example, I have
> >
> > fsm = rfsm.init(rfsm.load("fsm.lua"))
> > task = rfsm.init(rfsm.load("task.lua"))
>
> The 'task' fsm for merging should better not be initalized, since that
> will assume it is to be run standalone. Instead
>
> > with "fsm" that has inside a state "task": I'd like to replace the
> original
> > "fsm.task" with the new one, included all the related transitions. I
> have seen
> > this example but this way of replacing a state (or one of its parts)
> only
> > works before the call to "rfsm.init".
>
> You also don't only want merge, but replace. For that you'll also need
> to update transitions that point to the replaced state.
>
> > This is the function to which I am referring:
> >
> > function fsm_merge(fsm, parent, obj, id)
> >
> > -- do some checking
> > ...
> >
> > -- merge the object
> > if is_leaf(obj) or is_conn(obj) then
> > parent[id] = obj
> > obj._parent = parent
> > obj._id = id
> > obj._fqn = parent._fqn ..'.' .. id
> > -- tbd: update otrs?
> > elseif is_trans(obj) then
> > parent[#parent+1] = obj
> > obj.src._otrs[#obj.src._otrs+1] = obj
> > else
> > fsm.err("ERROR: merging of " .. obj:type() .. " objects not
> implemented
> > (" .. id .. ")")
> > return false
> > end
> >
> > return true
> > end
> >
> > My idea is to add a new block that should deal with a "state type"..
> something
> > like that:
> >
> > elseif is_state(obj) then -- if the object is an
> > "initialized state type"
> > parent[id] = obj -- copy the object
> > obj._parent = parent -- update the reference to
> the
> > object's parent
> > obj._id = id -- update the object's
> id
> > obj._fqn = parent._fqn ..'.' .. id -- update the path to the
> object
> >
> > then I still need to update the field _otrs that should keep trace of the
> > outgoing transitions.. but how? I've tried my "modded" fsm_merge and if
> I print
> > the fsm table I see that the state "task" has been updated after the
> merge
> > operation.. anyway something is still missing because if I send an event
> in
> > order to go to the overrided state, what I get is a transitions to the
> old
> > state (the one that I had before the merging).
> >
> > Anyone has an idea about what is going wrong?
>
> Yes, the transition still points to the old one. You need to figure
> out all transition that point to the old state and change them to
> point to the new state. You'll also need to repeat the steps carried
> out during init: add_parent_links, add_ids, add_fqns, add_defcons,
> verify_early. Some of these can be just re-run on the root, but some
> need to be run only on the new subtree. An other thing to consider is
> plugins, some of them like time_events need to be re-run in order to
> do their job.

> I'm interesting to get this working, but I unfortunately can't put
> much time in it right now.
>

I'd like to work on this functionality.. if I get something working I'll
send you my patch!

Thank you for your help!

> Markus
>
>
Nicola