## Sequential state machine

Sequential state machine — State machine helpers

## Functions

void | (*FpiSsmCompletedCallback) ()
void | (*FpiSsmHandlerCallback) ()
#define | fpi_ssm_new()
FpiSsm * | fpi_ssm_new_full ()
void | fpi_ssm_free ()
void | fpi_ssm_start ()
void | fpi_ssm_start_subsm ()
void | fpi_ssm_next_state ()
void | fpi_ssm_next_state_delayed ()
void | fpi_ssm_jump_to_state ()
void | fpi_ssm_jump_to_state_delayed ()
void | fpi_ssm_cancel_delayed_state_change ()
void | fpi_ssm_mark_completed ()
void | fpi_ssm_mark_failed ()
void | fpi_ssm_set_data ()
gpointer | fpi_ssm_get_data ()
FpDevice * | fpi_ssm_get_device ()
GError * | fpi_ssm_get_error ()
GError * | fpi_ssm_dup_error ()
int | fpi_ssm_get_cur_state ()
void | fpi_ssm_silence_debug ()
void | fpi_ssm_spi_transfer_cb ()
void | fpi_ssm_spi_transfer_with_weak_pointer_cb ()
void | fpi_ssm_usb_transfer_cb ()
void | fpi_ssm_usb_transfer_with_weak_pointer_cb ()

## Types and Values

| FpiSsm

## Description

Asynchronous driver design encourages some kind of state machine behind it. FpiSsm provides a simple mechanism to implement a state machine, which is often entirely linear. You can however also jump to a specific state or do an early return from the SSM by completing it.

e.g. `S1` ↦ `S2` ↦ `S3` ↦ `S4` ↦ `C1` ↦ `C2` ↦ `final`

Where `S1` is the start state. The `C1` and later states are cleanup states that may be defined. The difference is that these states will never be skipped when marking the SSM as completed.

Use `fpi_ssm_new()` to create a new state machine with a defined number of states. 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 failure and on success). Starting a ssm also takes ownership of it and it will be automatically free'ed after the callback function has been called.

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.

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 USB transfer), and the callback function iterates the machine to the next state upon success (or fails).

## 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 `nr_states` as the cleanup states and using the stringified version of `nr_states` . It should be used with an enum value.

#### 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,
                      int start_cleanup,
                      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 |
start_cleanup | the first cleanup state |
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_next_state_delayed ()

    void
    fpi_ssm_next_state_delayed (FpiSsm *machine,
                                int delay);

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()`.

#### Parameters

machine | an FpiSsm state machine |
delay | the milliseconds to wait before switching to the next state |

### 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_jump_to_state_delayed ()

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

Jump to the `state` state with a delay of `delay` milliseconds, bypassing intermediary states.

#### Parameters

machine | an FpiSsm state machine |
state | the state to jump to |
delay | the milliseconds to wait before switching to `state` state |

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

Note that any later cleanup state will still be executed.

#### Parameters

machine | an FpiSsm state machine |

### 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_device ()

    FpDevice *
    fpi_ssm_get_device (FpiSsm *machine);

Retrieve the device that the SSM is for.

#### Parameters

machine | an FpiSsm state machine |

#### Returns

FpDevice

### 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_silence_debug ()

    void
    fpi_ssm_silence_debug (FpiSsm *machine);

Turn off state change debug messages from this SSM. This does not disable all messages, as e.g. the initial state, SSM completion and cleanup states are still printed out.

Use if the SSM loops and would flood the debug log otherwise.

#### Parameters

machine | an FpiSsm state machine |

### fpi_ssm_spi_transfer_cb ()

    void
    fpi_ssm_spi_transfer_cb (FpiSpiTransfer *transfer,
                             FpDevice *device,
                             gpointer unused_data,
                             GError *error);

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

Make sure to set the FpiSsm on the transfer.

#### Parameters

transfer | a FpiSpiTransfer |
device | a FpDevice |
unused_data | User data (unused) |
error | The GError or `NULL` |

### fpi_ssm_spi_transfer_with_weak_pointer_cb ()

    void
    fpi_ssm_spi_transfer_with_weak_pointer_cb
                                   (FpiSpiTransfer *transfer,
                                    FpDevice *device,
                                    gpointer weak_ptr,
                                    GError *error);

Can be used in as a FpiSpiTransfer 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 FpiSpiTransfer |
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 FpiSpiTransfer. |
error | The GError or `NULL` |

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