## Sequential state machine Sequential state machine — State machine helpers |

## Functions

void | (*ssm_completed_fn) ()
void | (*ssm_handler_fn) ()
fpi_ssm * | fpi_ssm_new ()
void | fpi_ssm_free ()
void | fpi_ssm_start ()
void | fpi_ssm_start_subsm ()
void | fpi_ssm_next_state ()
void | fpi_ssm_next_state_timeout_cb ()
void | fpi_ssm_jump_to_state ()
void | fpi_ssm_mark_completed ()
void | fpi_ssm_mark_failed ()
void * | fpi_ssm_get_user_data ()
int | fpi_ssm_get_error ()
int | fpi_ssm_get_cur_state ()

## Types and Values

typedef | fpi_ssm

## Includes

    #include <fpi-ssm.h>

## 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 fpi_ssm functions help you implement such a machine.

e.g. `S1` ↦ `S2` ↦ `S3` ↦ `S4`

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

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 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 order to determine whether the fpi_ssm completed or failed. An error code of zero indicates successful completion.

## Functions

### ssm_completed_fn ()

    void
    (*ssm_completed_fn) (fpi_ssm *ssm,
                         struct fp_dev *dev,
                         void *user_data);

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

#### Parameters

ssm | a fpi_ssm state machine |
dev | the fp_dev fingerprint device |
user_data | the user data passed to `fpi_ssm_new()` |

### ssm_handler_fn ()

    void
    (*ssm_handler_fn) (fpi_ssm *ssm,
                       struct fp_dev *dev,
                       void *user_data);

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

#### Parameters

ssm | a fpi_ssm state machine |
dev | the fp_dev fingerprint device |
user_data | the user data passed to `fpi_ssm_new()` |

### fpi_ssm_new ()

    fpi_ssm *
    fpi_ssm_new (struct fp_dev *dev,
                 ssm_handler_fn handler,
                 int nr_states,
                 void *user_data);

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 |
user_data | the user data to pass to callbacks |

#### Returns

a new fpi_ssm state machine

### fpi_ssm_free ()

    void
    fpi_ssm_free (fpi_ssm *machine);

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

#### Parameters

machine | an fpi_ssm state machine |

### fpi_ssm_start ()

    void
    fpi_ssm_start (fpi_ssm *ssm,
                   ssm_completed_fn 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.

#### Parameters

ssm | an fpi_ssm state machine |
callback | the ssm_completed_fn callback to call on completion |

### fpi_ssm_start_subsm ()

    void
    fpi_ssm_start_subsm (fpi_ssm *parent,
                         fpi_ssm *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 fpi_ssm state machine |
child | an fpi_ssm state machine |

### fpi_ssm_next_state ()

    void
    fpi_ssm_next_state (fpi_ssm *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 fpi_ssm state machine |

### fpi_ssm_next_state_timeout_cb ()

    void
    fpi_ssm_next_state_timeout_cb (struct fp_dev *dev,
                                   void *data);

Same as `fpi_ssm_next_state()`, but to be used as a callback for an `fpi_timeout_add()` callback, when the state change needs to happen after a timeout.

Make sure to pass the fpi_ssm as the `user_data` argument for that `fpi_timeout_add()` call.

#### Parameters

dev | a struct fp_dev |
data | a pointer to an fpi_ssm state machine |

### fpi_ssm_jump_to_state ()

    void
    fpi_ssm_jump_to_state (fpi_ssm *machine,
                           int state);

Jump to the `state` state, bypassing intermediary states.

#### Parameters

machine | an fpi_ssm state machine |
state | the state to jump to |

### fpi_ssm_mark_completed ()

    void
    fpi_ssm_mark_completed (fpi_ssm *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 fpi_ssm state machine |

### fpi_ssm_mark_failed ()

    void
    fpi_ssm_mark_failed (fpi_ssm *machine,
                         int error);

Mark a state machine as failed with `error` as the error code.

#### Parameters

machine | an fpi_ssm state machine |
error | the error code |

### fpi_ssm_get_user_data ()

    void *
    fpi_ssm_get_user_data (fpi_ssm *machine);

Retrieve the pointer to user data set when `fpi_ssm_new()` is called.

#### Parameters

machine | an fpi_ssm state machine |

#### Returns

a pointer

### fpi_ssm_get_error ()

    int
    fpi_ssm_get_error (fpi_ssm *machine);

Returns the error code set by `fpi_ssm_mark_failed()`.

#### Parameters

machine | an fpi_ssm state machine |

#### Returns

a error code

### fpi_ssm_get_cur_state ()

    int
    fpi_ssm_get_cur_state (fpi_ssm *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 fpi_ssm state machine |

#### Returns

the current state.

## Types and Values

### fpi_ssm

    typedef struct fpi_ssm fpi_ssm;

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