Sequential state machine

Sequential state machine — State machine helpers

Functions

Types and Values

Description

Asynchronous driver design encourages some kind of state machine behind it. In most cases, the state machine is entirely linear - you only go to the next state, you never jump or go backwards. The FpiSsm functions help you implement such a machine.

e.g. S1S2S3S4

S1 is the start state There is also an implicit error state and an implicit accepting state (both with implicit edges from every state).

You can also jump to any arbitrary state (while marking completion of the current state) while the machine is running. In other words there are implicit edges linking one state to every other state.

To create an fpi_ssm, you pass a state handler function and the total number of states (4 in the above example) to fpi_ssm_new(). Note that the state numbers start at zero, making them match the first value in a C enumeration.

To start a ssm, you pass in a completion callback function to fpi_ssm_start() which gets called when the ssm completes (both on error and on failure). Starting a ssm also takes ownership of it.

To iterate to the next state, call fpi_ssm_next_state(). It is legal to attempt to iterate beyond the final state - this is equivalent to marking the ssm as successfully completed.

To mark successful completion of a SSM, either iterate beyond the final state or call fpi_ssm_mark_completed() from any state. This will also invalidate the machine, freeing it.

To mark failed completion of a SSM, call fpi_ssm_mark_failed() from any state. You must pass a non-zero error code.

Your state handling function looks at the return value of fpi_ssm_get_cur_state() in order to determine the current state and hence which operations to perform (a switch statement is appropriate).

Typically, the state handling function fires off an asynchronous communication with the device (such as a libsub transfer), and the callback function iterates the machine to the next state upon success (or fails).

Your completion callback should examine the return value of fpi_ssm_get_error() in ordater to determine whether the FpiSsm completed or failed. An error code of zero indicates successful completion.

Functions

FpiSsmCompletedCallback ()

void
(*FpiSsmCompletedCallback) (FpiSsm *ssm,
                            FpDevice *dev,
                            GError *error);

The callback called when a state machine completes successfully, as set when calling fpi_ssm_start().

Parameters

ssm

a FpiSsm state machine

 

dev

the fp_dev fingerprint device

 

error

The GError or NULL on successful completion.

[transfer full]

FpiSsmHandlerCallback ()

void
(*FpiSsmHandlerCallback) (FpiSsm *ssm,
                          FpDevice *dev);

The callback called when a state machine transitions from one state to the next, as set when calling fpi_ssm_new().

Parameters

ssm

a FpiSsm state machine

 

dev

the fp_dev fingerprint device

 

fpi_ssm_new()

#define             fpi_ssm_new(dev, handler, nr_states)

Allocate a new ssm, with nr_states states. The handler callback will be called after each state transition. This is a macro that calls fpi_ssm_new_full() using the stringified version of nr_states , so will work better with named parameters.

Parameters

dev

a fp_dev fingerprint device

 

handler

the callback function

 

nr_states

the number of states

 

Returns

a new FpiSsm state machine


fpi_ssm_new_full ()

FpiSsm *
fpi_ssm_new_full (FpDevice *dev,
                  FpiSsmHandlerCallback handler,
                  int nr_states,
                  const char *machine_name);

Allocate a new ssm, with nr_states states. The handler callback will be called after each state transition.

Parameters

dev

a fp_dev fingerprint device

 

handler

the callback function

 

nr_states

the number of states

 

machine_name

the name of the state machine (for debug purposes)

 

Returns

a new FpiSsm state machine


fpi_ssm_free ()

void
fpi_ssm_free (FpiSsm *machine);

Frees a state machine. This does not call any error or success callbacks, so you need to do this yourself.

Parameters

machine

an FpiSsm state machine

 

fpi_ssm_start ()

void
fpi_ssm_start (FpiSsm *ssm,
               FpiSsmCompletedCallback callback);

Starts a state machine. You can also use this function to restart a completed or failed state machine. The callback will be called on completion.

Note that ssm will be stolen when this function is called. So that all associated data will be free'ed automatically, after the callback is ran.

Parameters

ssm

an FpiSsm state machine.

[transfer full]

callback

the FpiSsmCompletedCallback callback to call on completion

 

fpi_ssm_start_subsm ()

void
fpi_ssm_start_subsm (FpiSsm *parent,
                     FpiSsm *child);

Starts a state machine as a child of another. if the child completes successfully, the parent will be advanced to the next state. if the child fails, the parent will be marked as failed with the same error code.

The child will be automatically freed upon completion or failure.

Parameters

parent

an FpiSsm state machine

 

child

an FpiSsm state machine

 

fpi_ssm_next_state ()

void
fpi_ssm_next_state (FpiSsm *machine);

Iterate to next state of a state machine. If the current state is the last state, then the state machine will be marked as completed, as if calling fpi_ssm_mark_completed().

Parameters

machine

an FpiSsm state machine

 

fpi_ssm_jump_to_state ()

void
fpi_ssm_jump_to_state (FpiSsm *machine,
                       int state);

Jump to the state state, bypassing intermediary states. If state is the last state, the machine won't be completed unless fpi_ssm_mark_completed() isn't explicitly called.

Parameters

machine

an FpiSsm state machine

 

state

the state to jump to

 

fpi_ssm_next_state_delayed ()

void
fpi_ssm_next_state_delayed (FpiSsm *machine,
                            int delay,
                            GCancellable *cancellable);

Iterate to next state of a state machine with a delay of delay ms. If the current state is the last state, then the state machine will be marked as completed, as if calling fpi_ssm_mark_completed(). Passing a valid GCancellable will cause the action to be cancelled when cancellable is.

Parameters

machine

an FpiSsm state machine

 

delay

the milliseconds to wait before switching to the next state

 

cancellable

a GCancellable to cancel the delayed operation.

[nullable]

fpi_ssm_jump_to_state_delayed ()

void
fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
                               int state,
                               int delay,
                               GCancellable *cancellable);

Jump to the state state with a delay of delay milliseconds, bypassing intermediary states. Passing a valid GCancellable will cause the action to be cancelled when cancellable is.

Parameters

machine

an FpiSsm state machine

 

state

the state to jump to

 

delay

the milliseconds to wait before switching to state state

 

cancellable

a GCancellable to cancel the delayed operation.

[nullable]

fpi_ssm_cancel_delayed_state_change ()

void
fpi_ssm_cancel_delayed_state_change (FpiSsm *machine);

fpi_ssm_mark_completed ()

void
fpi_ssm_mark_completed (FpiSsm *machine);

Mark a ssm as completed successfully. The callback set when creating the state machine with fpi_ssm_new() will be called synchronously.

Parameters

machine

an FpiSsm state machine

 

fpi_ssm_mark_completed_delayed ()

void
fpi_ssm_mark_completed_delayed (FpiSsm *machine,
                                int delay,
                                GCancellable *cancellable);

Mark a ssm as completed successfully with a delay of delay ms. The callback set when creating the state machine with fpi_ssm_new() will be called when the timeout is over. The request can be cancelled passing a GCancellable as cancellable .

Parameters

machine

an FpiSsm state machine

 

delay

the milliseconds to wait before switching to the next state

 

cancellable

a GCancellable to cancel the delayed operation.

[nullable]

fpi_ssm_mark_failed ()

void
fpi_ssm_mark_failed (FpiSsm *machine,
                     GError *error);

Mark a state machine as failed with error as the error code, completing it.

Parameters

machine

an FpiSsm state machine

 

error

a GError.

[transfer full]

fpi_ssm_set_data ()

void
fpi_ssm_set_data (FpiSsm *machine,
                  gpointer ssm_data,
                  GDestroyNotify ssm_data_destroy);

Sets machine 's data (freeing the existing data, if any).

Parameters

machine

an FpiSsm state machine

 

ssm_data

a pointer to machine data.

[nullable]

ssm_data_destroy

GDestroyNotify for ssm_data .

[nullable]

fpi_ssm_get_data ()

gpointer
fpi_ssm_get_data (FpiSsm *machine);

Retrieve the pointer to SSM data set with fpi_ssm_set_ssm_data()

Parameters

machine

an FpiSsm state machine

 

Returns

a pointer


fpi_ssm_get_error ()

GError *
fpi_ssm_get_error (FpiSsm *machine);

Returns the error code set by fpi_ssm_mark_failed().

Parameters

machine

an FpiSsm state machine

 

Returns

a error code.

[transfer none]


fpi_ssm_dup_error ()

GError *
fpi_ssm_dup_error (FpiSsm *machine);

Returns the error code set by fpi_ssm_mark_failed().

Parameters

machine

an FpiSsm state machine

 

Returns

a error code.

[transfer full]


fpi_ssm_get_cur_state ()

int
fpi_ssm_get_cur_state (FpiSsm *machine);

Returns the value of the current state. Note that states are 0-indexed, so a value of 0 means “the first state”.

Parameters

machine

an FpiSsm state machine

 

Returns

the current state.


fpi_ssm_usb_transfer_cb ()

void
fpi_ssm_usb_transfer_cb (FpiUsbTransfer *transfer,
                         FpDevice *device,
                         gpointer unused_data,
                         GError *error);

Can be used in as a FpiUsbTransfer callback handler to automatically advance or fail a statemachine on transfer completion.

Make sure to set the FpiSsm on the transfer.

Parameters

transfer

a FpiUsbTransfer

 

device

a FpDevice

 

unused_data

User data (unused)

 

error

The GError or NULL

 

fpi_ssm_usb_transfer_with_weak_pointer_cb ()

void
fpi_ssm_usb_transfer_with_weak_pointer_cb
                               (FpiUsbTransfer *transfer,
                                FpDevice *device,
                                gpointer weak_ptr,
                                GError *error);

Can be used in as a FpiUsbTransfer callback handler to automatically advance or fail a statemachine on transfer completion. Passing a gpointer* as weak_ptr permits to nullify it once we're done with the transfer.

Make sure to set the FpiSsm on the transfer.

Parameters

transfer

a FpiUsbTransfer

 

device

a FpDevice

 

weak_ptr

A gpointer pointer to nullify. You can pass a pointer to any gpointer to nullify when the callback is completed. I.e a pointer to the current FpiUsbTransfer.

 

error

The GError or NULL

 

Types and Values

FpiSsm

typedef struct _FpiSsm FpiSsm;

Sequential state machine that iterates sequentially over a predefined series of states. Can be terminated by either completion or failure error conditions.


FpiUsbTransfer

typedef struct {
  FpDevice *device;

  FpiSsm   *ssm;

  gssize    length;
  gssize    actual_length;

  guchar   *buffer;
} FpiUsbTransfer;

Helper for handling USB transfers.

Members

FpDevice *device;

The FpDevice that the transfer belongs to.

 

FpiSsm *ssm;

Storage slot to associate the transfer with a state machine. Used by fpi_ssm_usb_transfer_cb() to modify the given state machine.

 

gssize length;

The requested length of the transfer in bytes.

 

gssize actual_length;

The actual length of the transfer (see also fpi_usb_transfer_set_short_error())

 

guchar *buffer;

The transfered data.