fpi-ssm: Add possibility to jump to a state (or next one) with delay

This allows to have an automatic cleanup of the timeout source when the
the callback is reached and to avoid to do further state changes in the
middle.
This commit is contained in:
Marco Trevisan (Treviño) 2019-11-22 17:19:27 +01:00
parent 3ed73aa17c
commit 7ec2df2405
3 changed files with 127 additions and 0 deletions

View file

@ -215,7 +215,10 @@ fpi_ssm_free
fpi_ssm_start
fpi_ssm_start_subsm
fpi_ssm_next_state
fpi_ssm_next_state_delayed
fpi_ssm_jump_to_state
fpi_ssm_jump_to_state_delayed
fpi_ssm_cancel_delayed_state_change
fpi_ssm_mark_completed
fpi_ssm_mark_failed
fpi_ssm_set_data

View file

@ -87,6 +87,7 @@ struct _FpiSsm
int nr_states;
int cur_state;
gboolean completed;
GSource *timeout;
GError *error;
FpiSsmCompletedCallback callback;
FpiSsmHandlerCallback handler;
@ -170,6 +171,7 @@ fpi_ssm_free (FpiSsm *machine)
if (machine->ssm_data_destroy)
g_clear_pointer (&machine->ssm_data, machine->ssm_data_destroy);
g_clear_pointer (&machine->error, g_error_free);
g_clear_pointer (&machine->timeout, g_source_destroy);
g_free (machine);
}
@ -231,7 +233,9 @@ __subsm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
void
fpi_ssm_start_subsm (FpiSsm *parent, FpiSsm *child)
{
BUG_ON (parent->timeout);
child->parentsm = parent;
g_clear_pointer (&parent->timeout, g_source_destroy);
fpi_ssm_start (child, __subsm_complete);
}
@ -246,7 +250,12 @@ void
fpi_ssm_mark_completed (FpiSsm *machine)
{
BUG_ON (machine->completed);
BUG_ON (machine->timeout);
BUG_ON (machine->timeout != NULL);
g_clear_pointer (&machine->timeout, g_source_destroy);
machine->completed = TRUE;
if (machine->error)
fp_dbg ("%p completed with error: %s", machine, machine->error->message);
else
@ -297,6 +306,10 @@ fpi_ssm_next_state (FpiSsm *machine)
g_return_if_fail (machine != NULL);
BUG_ON (machine->completed);
BUG_ON (machine->timeout != NULL);
g_clear_pointer (&machine->timeout, g_source_destroy);
machine->cur_state++;
if (machine->cur_state == machine->nr_states)
fpi_ssm_mark_completed (machine);
@ -304,6 +317,56 @@ fpi_ssm_next_state (FpiSsm *machine)
__ssm_call_handler (machine);
}
void
fpi_ssm_cancel_delayed_state_change (FpiSsm *machine)
{
g_return_if_fail (machine);
BUG_ON (machine->completed);
BUG_ON (machine->timeout == NULL);
g_clear_pointer (&machine->timeout, g_source_destroy);
}
static void
on_device_timeout_next_state (FpDevice *dev,
gpointer user_data)
{
FpiSsm *machine = user_data;
machine->timeout = NULL;
fpi_ssm_next_state (machine);
}
/**
* fpi_ssm_next_state_delayed:
* @machine: an #FpiSsm state machine
* @delay: the milliseconds to wait before switching to the next state
*
* 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().
*/
void
fpi_ssm_next_state_delayed (FpiSsm *machine,
int delay)
{
g_autofree char *source_name = NULL;
g_return_if_fail (machine != NULL);
BUG_ON (machine->completed);
BUG_ON (machine->timeout != NULL);
g_clear_pointer (&machine->timeout, g_source_destroy);
machine->timeout = fpi_device_add_timeout (machine->dev, delay,
on_device_timeout_next_state,
machine);
source_name = g_strdup_printf ("[%s] ssm %p jump to next state %d",
fp_device_get_device_id (machine->dev),
machine, machine->cur_state + 1);
g_source_set_name (machine->timeout, source_name);
}
/**
* fpi_ssm_jump_to_state:
* @machine: an #FpiSsm state machine
@ -318,10 +381,65 @@ fpi_ssm_jump_to_state (FpiSsm *machine, int state)
{
BUG_ON (machine->completed);
BUG_ON (state < 0 || state >= machine->nr_states);
BUG_ON (machine->timeout != NULL);
g_clear_pointer (&machine->timeout, g_source_destroy);
machine->cur_state = state;
__ssm_call_handler (machine);
}
typedef struct
{
FpiSsm *machine;
int next_state;
} FpiSsmJumpToStateDelayedData;
static void
on_device_timeout_jump_to_state (FpDevice *dev,
gpointer user_data)
{
FpiSsmJumpToStateDelayedData *data = user_data;
data->machine->timeout = NULL;
fpi_ssm_jump_to_state (data->machine, data->next_state);
}
/**
* fpi_ssm_jump_to_state_delayed:
* @machine: an #FpiSsm state machine
* @state: the state to jump to
* @delay: the milliseconds to wait before switching to @state state
*
* Jump to the @state state with a delay of @delay milliseconds, bypassing
* intermediary states.
*/
void
fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
int state,
int delay)
{
FpiSsmJumpToStateDelayedData *data;
g_autofree char *source_name = NULL;
g_return_if_fail (machine != NULL);
BUG_ON (machine->completed);
BUG_ON (machine->timeout != NULL);
data = g_new0 (FpiSsmJumpToStateDelayedData, 1);
data->machine = machine;
data->next_state = state;
g_clear_pointer (&machine->timeout, g_source_destroy);
machine->timeout = fpi_device_add_timeout_full (machine->dev, delay,
on_device_timeout_jump_to_state,
data, g_free);
source_name = g_strdup_printf ("[%s] ssm %p jump to state %d",
fp_device_get_device_id (machine->dev),
machine, state);
g_source_set_name (machine->timeout, source_name);
}
/**
* fpi_ssm_get_cur_state:
* @machine: an #FpiSsm state machine

View file

@ -73,6 +73,12 @@ void fpi_ssm_start_subsm (FpiSsm *parent,
void fpi_ssm_next_state (FpiSsm *machine);
void fpi_ssm_jump_to_state (FpiSsm *machine,
int state);
void fpi_ssm_next_state_delayed (FpiSsm *machine,
int delay);
void fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
int state,
int delay);
void fpi_ssm_cancel_delayed_state_change (FpiSsm *machine);
void fpi_ssm_mark_completed (FpiSsm *machine);
void fpi_ssm_mark_failed (FpiSsm *machine,
GError *error);