libosmocore  1.4.0.358-967e
Osmocom core library
Tnnn timer configuration

Implementation to define Tnnn timers globally and use for FSM state changes. More...

Files

file  tdef.h
 API to define Tnnn timers globally and use for FSM state changes.
 
file  tdef.c
 Implementation to define Tnnn timers globally and use for FSM state changes.
 

Data Structures

struct  osmo_tdef
 Define a GSM timer of the form Tnnn, with unit, default value and doc string. More...
 
struct  osmo_tdef_state_timeout
 Using osmo_tdef for osmo_fsm_inst: array entry for a mapping of state numbers to timeout definitions. More...
 
struct  osmo_tdef_group
 Manage timer definitions in named groups. More...
 

Macros

#define osmo_tdef_for_each(t, tdefs)   for (t = tdefs; t && (t->T || t->default_val || t->desc); t++)
 Iterate an array of struct osmo_tdef, the last item should be fully zero, i.e. More...
 
#define osmo_tdef_fsm_inst_state_chg(fi, state, timeouts_array, tdefs, default_timeout)
 Call osmo_fsm_inst_state_chg() or osmo_fsm_inst_state_chg_keep_timer(), depending on the timeouts_array, tdefs and default_timeout. More...
 
#define osmo_tdef_groups_for_each(g, tdef_groups)   for (g = tdef_groups; g && g->tdefs; g++)
 Iterate an array of struct osmo_tdef_group, the last item should be fully zero, i.e. More...
 

Enumerations

enum  osmo_tdef_unit {
  OSMO_TDEF_S = 0,
  OSMO_TDEF_MS,
  OSMO_TDEF_M,
  OSMO_TDEF_CUSTOM,
  OSMO_TDEF_US
}
 

Functions

static const char * osmo_tdef_unit_name (enum osmo_tdef_unit val)
 
void osmo_tdefs_reset (struct osmo_tdef *tdefs)
 Set all osmo_tdef values to the default_val. More...
 
unsigned long osmo_tdef_get (const struct osmo_tdef *tdefs, int T, enum osmo_tdef_unit as_unit, long val_if_not_present)
 Return the value of a T timer from a list of osmo_tdef, in the given unit. More...
 
struct osmo_tdefosmo_tdef_get_entry (struct osmo_tdef *tdefs, int T)
 Find tdef entry matching T. More...
 
int osmo_tdef_set (struct osmo_tdef *tdefs, int T, unsigned long val, enum osmo_tdef_unit val_unit)
 Set value in entry matching T, converting val from val_unit to unit of T. More...
 
bool osmo_tdef_val_in_range (struct osmo_tdef *tdef, unsigned long new_val)
 Check if value new_val is in range of valid possible values for timer entry tdef. More...
 
int osmo_tdef_range_str_buf (char *buf, size_t buf_len, struct osmo_tdef *t)
 Write string representation of osmo_tdef range into buf. More...
 
const struct osmo_tdef_state_timeoutosmo_tdef_get_state_timeout (uint32_t state, const struct osmo_tdef_state_timeout *timeouts_array)
 Using osmo_tdef for osmo_fsm_inst: find a given state's osmo_tdef_state_timeout entry. More...
 
int _osmo_tdef_fsm_inst_state_chg (struct osmo_fsm_inst *fi, uint32_t state, const struct osmo_tdef_state_timeout *timeouts_array, const struct osmo_tdef *tdefs, unsigned long default_timeout, const char *file, int line)
 See invocation macro osmo_tdef_fsm_inst_state_chg() instead. More...
 
static unsigned long osmo_tdef_factor (enum osmo_tdef_unit a, enum osmo_tdef_unit b)
 a = return_val * b. More...
 
static unsigned long osmo_tdef_round (unsigned long val, enum osmo_tdef_unit from_unit, enum osmo_tdef_unit to_unit)
 

Variables

const struct value_string osmo_tdef_unit_names []
 
const struct value_string osmo_tdef_unit_names []
 

Detailed Description

Implementation to define Tnnn timers globally and use for FSM state changes.

See also Tnnn timer VTY configuration

osmo_tdef provides:

By keeping separate osmo_tdef arrays, several groups of timers can be kept separately. The VTY tests in tests/tdef/ showcase different schemes:

osmo_tdef was introduced because:

Macro Definition Documentation

◆ osmo_tdef_for_each

#define osmo_tdef_for_each (   t,
  tdefs 
)    for (t = tdefs; t && (t->T || t->default_val || t->desc); t++)

Iterate an array of struct osmo_tdef, the last item should be fully zero, i.e.

"{}". Example:

struct osmo_tdef *t;
osmo_tdef_for_each(t, tdefs) {
        printf("%lu %s %s\n", t->val, osmo_tdef_unit_name(t->unit), t->desc);
}
Parameters
[in,out]tA struct osmo_tdef *t used for iteration, will point at the current entry inside the loop scope.
[in]tdefsArray of struct osmo_tdef to iterate, zero-terminated.

Referenced by osmo_tdef_get_entry(), and osmo_tdefs_reset().

◆ osmo_tdef_fsm_inst_state_chg

#define osmo_tdef_fsm_inst_state_chg (   fi,
  state,
  timeouts_array,
  tdefs,
  default_timeout 
)
Value:
_osmo_tdef_fsm_inst_state_chg(fi, state, timeouts_array, tdefs, default_timeout, \
__FILE__, __LINE__)
struct osmo_tdef * tdefs
int _osmo_tdef_fsm_inst_state_chg(struct osmo_fsm_inst *fi, uint32_t state, const struct osmo_tdef_state_timeout *timeouts_array, const struct osmo_tdef *tdefs, unsigned long default_timeout, const char *file, int line)
See invocation macro osmo_tdef_fsm_inst_state_chg() instead.
Definition: tdef.c:332

Call osmo_fsm_inst_state_chg() or osmo_fsm_inst_state_chg_keep_timer(), depending on the timeouts_array, tdefs and default_timeout.

A T timer configured in sub-second precision is rounded up to the next full second. A timer in unit = OSMO_TDEF_CUSTOM is applied as if the unit is in seconds (i.e. this macro does not make sense for custom units!).

See osmo_tdef_get_state_timeout() and osmo_tdef_get().

If no T timer is defined for the given state (T == 0), invoke the state change without a timeout.

Should a T number be defined in timeouts_array that is not defined in tdefs, use default_timeout (in seconds). If default_timeout is negative, a missing T definition in tdefs instead causes a program abort.

This is best used by wrapping this function call in a macro suitable for a specific FSM implementation, which can become as short as: my_fsm_state_chg(fi, NEXT_STATE):

#define my_fsm_state_chg(fi, NEXT_STATE) \
        osmo_tdef_fsm_inst_state_chg(fi, NEXT_STATE, my_fsm_timeouts, global_T_defs, 5)

my_fsm_state_chg(fi, MY_FSM_STATE_1);
// -> No timeout configured, will enter state without timeout.

my_fsm_state_chg(fi, MY_FSM_STATE_3);
// T423 configured for this state, will look up T423 in tdefs, or use 5 seconds if unset.

my_fsm_state_chg(fi, MY_FSM_STATE_8);
// keep_timer == true for this state, will invoke osmo_fsm_inst_state_chg_keep_timer().
Parameters
[in,out]fiosmo_fsm_inst to transition to another state.
[in]stateState number to transition to.
[in]timeouts_arrayArray of struct osmo_tdef_state_timeout[32] to look up state in.
[in]tdefsArray of struct osmo_tdef (last entry zero initialized) to look up T in.
[in]default_timeoutIf a T is set in timeouts_array, but no timeout value is configured for T, then use this default timeout value as fallback, or pass -1 to abort the program.
Returns
Return value from osmo_fsm_inst_state_chg() or osmo_fsm_inst_state_chg_keep_timer().

◆ osmo_tdef_groups_for_each

#define osmo_tdef_groups_for_each (   g,
  tdef_groups 
)    for (g = tdef_groups; g && g->tdefs; g++)

Iterate an array of struct osmo_tdef_group, the last item should be fully zero, i.e.

"{}".

Parameters
[in,out]gA struct osmo_tdef_group *g used for iteration, will point at the current entry inside the loop scope.
[in]tdefsArray of struct osmo_tdef_group to iterate, zero-terminated.

Enumeration Type Documentation

◆ osmo_tdef_unit

Enumerator
OSMO_TDEF_S 

most T are in seconds, keep 0 as default.

OSMO_TDEF_MS 

milliseconds

OSMO_TDEF_M 

minutes

OSMO_TDEF_CUSTOM 

unspecified unit, explained in osmo_tdef.desc.

OSMO_TDEF_US 

microseconds

Function Documentation

◆ _osmo_tdef_fsm_inst_state_chg()

int _osmo_tdef_fsm_inst_state_chg ( struct osmo_fsm_inst fi,
uint32_t  state,
const struct osmo_tdef_state_timeout timeouts_array,
const struct osmo_tdef tdefs,
unsigned long  default_timeout,
const char *  file,
int  line 
)

◆ osmo_tdef_factor()

static unsigned long osmo_tdef_factor ( enum osmo_tdef_unit  a,
enum osmo_tdef_unit  b 
)
static

a = return_val * b.

Returns
0 if factor is below 1.

References OSMO_TDEF_CUSTOM, OSMO_TDEF_M, OSMO_TDEF_MS, OSMO_TDEF_S, and OSMO_TDEF_US.

Referenced by osmo_tdef_round().

◆ osmo_tdef_get()

unsigned long osmo_tdef_get ( const struct osmo_tdef tdefs,
int  T,
enum osmo_tdef_unit  as_unit,
long  val_if_not_present 
)

Return the value of a T timer from a list of osmo_tdef, in the given unit.

If no such timer is defined, return the default value passed, or abort the program if default < 0.

Round up any value match as_unit: 1100 ms as OSMO_TDEF_S becomes 2 seconds, as OSMO_TDEF_M becomes one minute. However, always return a value of zero as zero (0 ms as OSMO_TDEF_M still is 0 m).

Range: even though the value range is unsigned long here, in practice, using ULONG_MAX as value for a timeout in seconds may actually wrap to negative or low timeout values (e.g. in struct timeval). It is recommended to stay below INT_MAX seconds. See also osmo_fsm_inst_state_chg().

Usage example:

    struct osmo_tdef global_T_defs[] = {
            { .T=7, .default_val=50, .desc="Water Boiling Timeout" },  // default is .unit=OSMO_TDEF_S == 0
            { .T=8, .default_val=300, .desc="Tea brewing" },
            { .T=9, .default_val=5, .unit=OSMO_TDEF_M, .desc="Let tea cool down before drinking" },
            { .T=10, .default_val=20, .unit=OSMO_TDEF_M, .desc="Forgot to drink tea while it's warm" },
            {}  //  <-- important! last entry shall be zero
    };
    osmo_tdefs_reset(global_T_defs); // make all values the default
    osmo_tdef_vty_init(global_T_defs, CONFIG_NODE);

    val = osmo_tdef_get(global_T_defs, 7, OSMO_TDEF_S, -1); // -> 50
    sleep(val);

    val = osmo_tdef_get(global_T_defs, 7, OSMO_TDEF_M, -1); // 50 seconds becomes 1 minute -> 1
    sleep_minutes(val);

    val = osmo_tdef_get(global_T_defs, 99, OSMO_TDEF_S, 3); // not defined, returns 3

    val = osmo_tdef_get(global_T_defs, 99, OSMO_TDEF_S, -1); // not defined, program aborts!
Parameters
[in]tdefsArray of timer definitions, last entry must be fully zero initialized.
[in]TTimer number to get the value for.
[in]as_unitReturn timeout value in this unit.
[in]val_if_not_presentFallback value to return if no timeout is defined.
Returns
Timeout value in the unit given by as_unit, rounded up if necessary, or val_if_not_present.

References OSMO_ASSERT, osmo_tdef_get_entry(), osmo_tdef_round(), osmo_tdef::unit, and osmo_tdef::val.

Referenced by _osmo_tdef_fsm_inst_state_chg().

◆ osmo_tdef_get_entry()

struct osmo_tdef * osmo_tdef_get_entry ( struct osmo_tdef tdefs,
int  T 
)

Find tdef entry matching T.

This is useful for manipulation, which is usually limited to the VTY configuration. To retrieve a timeout value, most callers probably should use osmo_tdef_get() instead.

Parameters
[in]tdefsArray of timer definitions, last entry being fully zero.
[in]TTimer number to get the entry for.
Returns
osmo_tdef entry matching T in given array, or NULL if no match is found.

References osmo_tdef_for_each, and osmo_tdef::T.

Referenced by osmo_tdef_get(), and osmo_tdef_set().

◆ osmo_tdef_get_state_timeout()

const struct osmo_tdef_state_timeout * osmo_tdef_get_state_timeout ( uint32_t  state,
const struct osmo_tdef_state_timeout timeouts_array 
)

Using osmo_tdef for osmo_fsm_inst: find a given state's osmo_tdef_state_timeout entry.

The timeouts_array shall contain exactly 32 elements, regardless whether only some of them are actually populated with nonzero values. 32 corresponds to the number of states allowed by the osmo_fsm_* API. Lookup is by array index. Not populated entries imply a state change invocation without timeout.

For example:

    struct osmo_tdef_state_timeout my_fsm_timeouts[32] = {
            [MY_FSM_STATE_3] = { .T = 423 }, // look up timeout configured for T423
            [MY_FSM_STATE_7] = { .keep_timer = true, .T = 235 }, // keep previous timer if running, or start T235
            [MY_FSM_STATE_8] = { .keep_timer = true }, // keep previous state's T number, continue timeout.
            // any state that is omitted will remain zero == no timeout
 };
 osmo_tdef_get_state_timeout(MY_FSM_STATE_0, &my_fsm_timeouts) -> NULL,
 osmo_tdef_get_state_timeout(MY_FSM_STATE_7, &my_fsm_timeouts) -> { .T = 235 }

The intention is then to obtain the timer like osmo_tdef_get(global_T_defs, T=235); see also fsm_inst_state_chg_T() below.

Parameters
[in]stateState constant to look up.
[in]timeouts_arrayArray[32] of struct osmo_tdef_state_timeout defining which timer number to use per state.
Returns
A struct osmo_tdef_state_timeout entry, or NULL if that entry is zero initialized.

References osmo_tdef_state_timeout::keep_timer, OSMO_ASSERT, and osmo_tdef_state_timeout::T.

Referenced by _osmo_tdef_fsm_inst_state_chg().

◆ osmo_tdef_range_str_buf()

int osmo_tdef_range_str_buf ( char *  buf,
size_t  buf_len,
struct osmo_tdef t 
)

Write string representation of osmo_tdef range into buf.

Parameters
[in]bufThe buffer where the string representation is stored.
[in]buf_lenLength of buffer in bytes.
[in]tdefTimer entry from a timer definition table.
Returns
The number of characters printed on success (or number of characters which would have been written to the final string if enough space had been available), negative on error. See snprintf().

References len(), osmo_tdef::max_val, osmo_tdef::min_val, and OSMO_SNPRINTF_RET.

Referenced by osmo_tdefs_reset().

◆ osmo_tdef_round()

static unsigned long osmo_tdef_round ( unsigned long  val,
enum osmo_tdef_unit  from_unit,
enum osmo_tdef_unit  to_unit 
)
static
Returns
val in unit to_unit, rounded up to the next integer value and clamped to ULONG_MAX, or 0 if val == 0.

References osmo_tdef_factor().

Referenced by osmo_tdef_get(), and osmo_tdef_set().

◆ osmo_tdef_set()

int osmo_tdef_set ( struct osmo_tdef tdefs,
int  T,
unsigned long  val,
enum osmo_tdef_unit  val_unit 
)

Set value in entry matching T, converting val from val_unit to unit of T.

The converted value is rounded up to the next integer value of T's unit and clamped to ULONG_MAX, or 0 if val == 0.

Parameters
[in]tdefsArray of timer definitions, last entry being fully zero.
[in]TTimer number to set the value for.
[in]valThe new timer value to set.
[in]val_unitUnits of value in parameter val.
Returns
0 on success, negative on error.

References osmo_tdef_get_entry(), osmo_tdef_round(), osmo_tdef_val_in_range(), osmo_tdef::unit, and osmo_tdef::val.

◆ osmo_tdef_unit_name()

static const char* osmo_tdef_unit_name ( enum osmo_tdef_unit  val)
inlinestatic
Returns
enum osmo_tdef_unit value as human readable unit letter, or "custom-unit".

References get_value_string(), and osmo_tdef_unit_names.

◆ osmo_tdef_val_in_range()

bool osmo_tdef_val_in_range ( struct osmo_tdef tdef,
unsigned long  new_val 
)

Check if value new_val is in range of valid possible values for timer entry tdef.

Parameters
[in]tdefTimer entry from a timer definition table.
[in]new_valThe value whose validity to check, in units as per this timer entry.
Returns
true if inside range, false otherwise.

References osmo_tdef::max_val, and osmo_tdef::min_val.

Referenced by osmo_tdef_set(), and osmo_tdefs_reset().

◆ osmo_tdefs_reset()

void osmo_tdefs_reset ( struct osmo_tdef tdefs)

Set all osmo_tdef values to the default_val.

It is convenient to define a tdefs array by setting only the default_val, and calling osmo_tdefs_reset() once for program startup. (See also osmo_tdef_vty_init()). During call to this function, default values are verified to be inside valid range; process is aborted otherwise.

Parameters
[in]tdefsArray of timer definitions, last entry being fully zero.

References osmo_tdef::default_val, osmo_panic(), OSMO_T_FMT, OSMO_T_FMT_ARGS, osmo_tdef_for_each, osmo_tdef_range_str_buf(), osmo_tdef_val_in_range(), osmo_tdef::T, and osmo_tdef::val.

Variable Documentation

◆ osmo_tdef_unit_names [1/2]

const struct value_string osmo_tdef_unit_names[]

Referenced by osmo_tdef_unit_name().

◆ osmo_tdef_unit_names [2/2]

const struct value_string osmo_tdef_unit_names[]
Initial value:
= {
{ OSMO_TDEF_S, "s" },
{ OSMO_TDEF_MS, "ms" },
{ OSMO_TDEF_M, "m" },
{ OSMO_TDEF_CUSTOM, "custom-unit" },
{ OSMO_TDEF_US, "us" },
{}
}
most T are in seconds, keep 0 as default.
Definition: tdef.h:39
minutes
Definition: tdef.h:41
milliseconds
Definition: tdef.h:40
microseconds
Definition: tdef.h:43
unspecified unit, explained in osmo_tdef.desc.
Definition: tdef.h:42

Referenced by osmo_tdef_unit_name().