Skip to content

State machines

Konstantin Khait edited this page Jul 22, 2026 · 1 revision

il1

Loviisa lets you define state machines in a declarative style, simplifying your code and making it unified, compact and predictable.

State machine is described as a single multi-block description that is actual within a single C file.

The following primitives let you describe and manage state machines (name is always a name of the state machine):

LVS_DEFINE_STATES(name) - starts states descriptions section

LVS_STATE(state) is used to introduce the new state name within the section

LVS_DEFINE_ACTIONS(name) - ends states description and starts actions description

LVS_ACTION(action) introduces new action within the actions section

LVS_DEFINE_REACTIONS(name) - ends actions description and starts reactions description. Reactions description contains multiple definitions of what shall be done in a given state upon the given action

Special variables state and action are available within this section to access current state and action. These variables can be compared with values retrieved from the name of a state or an action with using LVS_GET_STATE or LVS_GET_ACTION.

LVS_ON_ACTION(state, action) starts statements to be performed in a given state if given action happens

LVS_ON_ANY_ACTION(state) starts statements that shall be performed on any action in this state. This block is only executed if no special LVS_ON_ACTION is defined earlier for this state and action

LVS_ON_UNDEFINED_STATE() is performed if the machine is in initial or undefined state

LVS_SWITCH_STATE(state) is used within the reactions section to initiate the transition to the new state

LVS_END_DEFINITION(name) finishes state machine definition

LVS_DO_ACTION(name, action) sends the given action to the state machine

Below is a real example of the state machine use:

LVS_DEFINE_STATES(msg_to_write)
  LVS_STATE(preamble)
  LVS_STATE(length)
  LVS_STATE(timestamp)
  LVS_STATE(prop_no)
  LVS_STATE(value)
  LVS_STATE(checksum)
  LVS_STATE(bypass)
LVS_DEFINE_ACTIONS(msg_to_write)
  LVS_ACTION(new_char)
LVS_DEFINE_REACTIONS(msg_to_write)
  LVS_ON_UNDEFINED_STATE()
    if (__value == 0xC0)
    {
      LVS_SWITCH_STATE(preamble)
      __counter = 1;
    }
    else
      LVS_SWITCH_STATE(bypass)
  LVS_ON_ANY_ACTION(preamble)
    if (__value == 0xC0)
    {
      LVS_SWITCH_STATE(length)
      __counter = 0;
    }
    else
      LVS_SWITCH_STATE(bypass)
  LVS_ON_ANY_ACTION(length)
    __length <<= 8;
    __length |= __value;
    __counter += 1;
    if (__counter == 2)
    {
      LVS_SWITCH_STATE(timestamp)
      __counter = 0;
    }
  LVS_ON_ANY_ACTION(timestamp)
    __counter += 1;
    if (__counter == 6)
    {
      LVS_SWITCH_STATE(prop_no)
      __counter = 0;
    }
  LVS_ON_ANY_ACTION(prop_no)
    __prop_num <<= 8;
    __prop_num |= __value;
    __counter += 1;
    if (__counter == 2)
    {
      LVS_SWITCH_STATE(value)
      __counter = 0;
    }
  LVS_ON_ANY_ACTION(value)
    int idx = __counter / 2;
    __prop_vals[idx] <<= 8;
    __prop_vals[idx] |= __value;
    __counter += 1;
    if (__counter >= (__length - 8 + 1) * 2)
    {
      LVS_SWITCH_STATE(checksum);
      __counter = 0;
    };
  LVS_ON_ANY_ACTION(checksum)
    boiler_WriteProperty(__prop_num, 0x01, __prop_vals);
    LVS_SWITCH_STATE(bypass)
  LVS_ON_ANY_ACTION(bypass)
    if (__value == 0xC0)
    {
      LVS_SWITCH_STATE(preamble);
      __counter = 1;
    };
LVS_END_DEFINITION(msg_to_write);

Clone this wiki locally