10. State Machine

10.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:
  • state_type (class extending State or a lua table.) – State type.

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.

10.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_machine state() → state
Returns:
  • state (State) – A state.

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 parse_error

event triggered on data parsing error. See Grammar.

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:
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:
  • events (table) – State machine events.
  • name (string) – State type name.
  • parent (class extending State) – State type parent.
  • update (function) – State type update function.
Returns:
  • state_class (class extending State) – New state type class

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
}

10.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,
}

10.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:

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.

10.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