11. State Machine¶
11.1. Description¶
- haka.state_machine.new(name, descr) → state_machine¶
Parameters: - name (string) – State machine name.
- descr (function) – Description function.
Returns: - state_machine (StateMachine ) – Compiled state machine.
A dissector that need to use a state machine need to describe it first. This function allows to do it.
The descr function is executed to define the states and the actions that are going to be part of the state machine. Its environment allows to access all state machine primitives listed in this pages. The functions and variables available in this scope are shown prefixed with state_machine.
A state machine can only have one kind of state. The first thing to do is to choose this type :
- state_machine state_type(state_type)¶
Parameters: Define the type of state that this state machine will work with. It will determine :
- the events availables.
- the parameters passed to actions.
- the parameters passed to state machine update function (see state_machine_instance).
State type can be one of the provided state or one locally defined (see StateMachine)
Usage:
state_type(BidirectionnalState) state_type{ events = { 'receive', 'drop' }, update = function (self, state_machine, direction, pkt) state_machine:trigger('receive', pkt, direction) end, }
Then it is required to declare all the states :
- <name> = state(...)
Parameters: - name (string) – State name.
- ... – Some parameters depending of state machine state type.
Returns: - entity (State) – a new state.
Declares a named state that will be avaible in all the state machine.
Finally it is required to define the initial state:
- state_machine initial(state)¶
Parameters: - state (State) – Initial state.
Define the initial state where the state machine should start.
11.1.1. State¶
Haka provides two kind of states type :
- object haka.state_machine.State¶
Simplest state. It won’t do anything except defining some default events that will be available from every another state types.
- State._events¶
This table contains a list of the events added by this type of state. If you create a class inheriting from State you can set this table to add some events.
- events init¶
event triggered on state machine initialization.
- events enter¶
event triggered right after state machine enter the state.
- events timeout(seconds)¶
Parameters: - seconds (number) – Time in seconds to wait before triggering this event
event triggered after a given elapsed time. The timeout are reset each time the state machine change its internal state.
- events fail¶
event triggered right before state machine enter the fail state.
- events finish¶
event triggered right before state machine enter the finish state.
- events leave¶
event triggered right before state machine leave the state.
State declaration in state machine of this type doesn’t requires any parameters.
State actions will be passed state machine context.
- <state>.execute(self)¶
Parameters: - self (object) – state machine context.
State machine defined with this type will have the following update function.
- state_machine_instance update(event)¶
Parameters: - event (String) – Event to be triggered on the state machine.
- object haka.state_machine.BidirectionnalState¶
Bidirectionnal state is a more advanced state. It can handle bidirectionnal connection and will handle data parsing. For this purpose it defines some more events :
- events up¶
event triggered when up coming data is received.
- events down¶
event triggered when down coming data is received.
- events missing_grammar¶
event triggered when no grammar is defined to handle data.
In order to be able to parse incoming data it is required to pass exported grammar entity (see Grammar) to state declaration :
- state_machine state(gup, gdown)
Parameters: - gup (CompiledGrammarEntity) – Up coming data grammar.
- gdown (CompiledGrammarEntity) – Down coming data grammar.
Returns: - state (State) – A state.
State actions attached to events.up or events.down events will be passed the following parameters :
- <state>.execute(self, res, ...)
Parameters: - self (object) – state machine context.
- res (abstract table) – Parse result.
- ... – Any another parameters as passed to update function.
State machine defined with this type will have the following update function.
- state_machine_instance update(payload, direction, ...)
Parameters: - payload (vbuffer_iterator) – Payload of the incoming data.
- direction (String 'up' or 'down') – Direction of the event.
- ... – Any another parameters that will be passed to actions.
Haka also declares two special states that are available in all state machines :
- fail
state reached in case of failure. It will raise an error.
- finish
final state which will terminate the state machine instance.
Naturally it is possible to define specific state types by extending State. It will allow to redefine update function and available events.
- haka.state_machine.new_state_type{events, name, parent, update} → state_class¶
Parameters: Returns: Create a new state type.
Note
None of the paramaters are required.
Usage:
local MyState = haka.state_machine.new_state_type{
name = "MyState",
parent = haka.state_machine.State,
events = { 'myevent' },
update = function (state_machine, myarg)
state_machine:trigger('myevent', myarg)
end
}
11.1.2. Actions¶
An action is composed of the following :
- a state to be defined on
- an event to attach to
- a check function
- an action to perform
- a state to jump to
A action is defined with :
- <state>:on{event, events, when, execute, jump}
Parameters: - event – One of the event defined by state machine state type.
- events (table) – A list of event to attach to.
- when (function) – An optional function to decide whether this action should be taken or not.
- execute (function) – An optional function to make some specific actions.
- jump (State) – An optional state to go to after executing the action.
Define a new action. The parameters passed to action and when function depends on state machine state type.
Only event or events is a required parameter. But an action must have one of action or jump otherwise it is useless.
Both action and when function are always passed the same parameters.
Haka allow to define default actions :
- any:on{event, when, execute, jump}¶
Parameters: - event – One of the event defined by state machine state type.
- events (table) – A list of event to attach to.
- when (function) – An optional function to decide whether this action should be taken or not.
- execute (function) – An optional function to make some specific actions.
- jump (State) – An optional state to go to after executing the action.
Sets default actions for the state machine. The parameter should be a table containing the exact same argument as a classic action. All those actions will exists on any state of this state machine.
Usage:
any:on{
event = events.fail,
execute = function()
haka.alert{
description = "fail on my state machine",
severity = 'low',
}
end,
}
11.2. Instance¶
- object StateMachine¶
This object contains the state machine compiled description.
- <state_machine>:instanciate(context) → instance¶
Parameters: - context – User data that are passed to every actions.
Returns: - instance (state_machine_instance) – State machine instance.
Instanciate the state machine. The context object will be given as the first parameter for every actions called.
- object state_machine_instance¶
Instance of a state machine.
- <state_machine_instance>:finish()¶
Terminate the state machine. This will also call the action finish on the current state.
- const <state_machine_instance>.current¶
Type: string Current state name.
- <state_machine_instance>:trigger(name, ...)¶
Parameters: - name (string) – Transition name.
Trigger an event on the current state.
- haka.state_machine.update(...)¶
Parameters: - ... – Variable parameters depending on state machine type.
Update the internal state of the state machine.
11.3. Example¶
-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this
-- file, You can obtain one at http://mozilla.org/MPL/2.0/.
local my_state_machine = haka.state_machine("test", function ()
state_type{
events = { 'test' },
update = function (self, state_machine)
state_machine:trigger('test')
end
}
foo = state()
bar = state()
foo:on{
event = events.test,
execute = function (self)
print("update")
end,
jump = bar -- jump to the state bar
}
bar:on{
event = events.enter,
execute = function (self)
print("finish")
end
}
initial(foo) -- start on state foo
end)
local context = {}
local instance = my_state_machine:instanciate(context)
instance:update() -- trigger the event test