libosmocore 1.10.0.57-8972
Osmocom core library
|
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[_ms]() or osmo_fsm_inst_state_chg_keep_timer[_ms](), 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_tdef * | osmo_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_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. 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, signed long default_timeout, const char *file, int line) |
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) |
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, long default_timeout, const char *file, int line) |
See invocation macro osmo_tdef_fsm_inst_state_chg() instead. More... | |
Variables | |
const struct value_string | osmo_tdef_unit_names [] |
const struct value_string | osmo_tdef_unit_names [] |
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:
#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); }
#define osmo_tdef_fsm_inst_state_chg | ( | fi, | |
state, | |||
timeouts_array, | |||
tdefs, | |||
default_timeout | |||
) |
Call osmo_fsm_inst_state_chg[_ms]() or osmo_fsm_inst_state_chg_keep_timer[_ms](), depending on the timeouts_array, tdefs and default_timeout.
A timer defined with sub-millisecond precision (e.g OSMO_TDEF_US) is rounded up to the next full millisecond. A timer value defined in units higher than millisecond (e.g. OSMO_TDEF_S, OSMO_TDEF_M) is converted to milliseconds. 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().
[in,out] | fi | osmo_fsm_inst to transition to another state. |
[in] | state | State number to transition to. |
[in] | timeouts_array | Array of struct osmo_tdef_state_timeout[32] to look up state in. |
[in] | tdefs | Array of struct osmo_tdef (last entry zero initialized) to look up T in. |
[in] | default_timeout | If a T is set in timeouts_array, but no timeout value is configured for T, then use this default timeout value (in seconds) as fallback, or pass a negative number to abort the program. |
Iterate an array of struct osmo_tdef_group, the last item should be fully zero, i.e.
"{}".
[in,out] | g | A struct osmo_tdef_group *g used for iteration, will point at the current entry inside the loop scope. |
[in] | tdefs | Array of struct osmo_tdef_group to iterate, zero-terminated. |
enum 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 |
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, | ||
long | default_timeout, | ||
const char * | file, | ||
int | line | ||
) |
See invocation macro osmo_tdef_fsm_inst_state_chg() instead.
[in] | file | Source file name, like FILE. |
[in] | line | Source file line number, like LINE. |
References _osmo_fsm_inst_state_chg(), _osmo_fsm_inst_state_chg_keep_or_start_timer_ms(), _osmo_fsm_inst_state_chg_keep_timer(), _osmo_fsm_inst_state_chg_ms(), file(), osmo_tdef_state_timeout::keep_timer, OSMO_ASSERT, OSMO_TDEF_CUSTOM, osmo_tdef_get_entry(), osmo_tdef_get_state_timeout(), OSMO_TDEF_MS, osmo_tdef_round(), osmo_tdef_state_timeout::T, tdefs, osmo_tdef::unit, and osmo_tdef::val.
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, | ||
signed long | default_timeout, | ||
const char * | file, | ||
int | line | ||
) |
|
static |
a = return_val * b.
References OSMO_TDEF_CUSTOM, OSMO_TDEF_M, OSMO_TDEF_MS, OSMO_TDEF_S, and OSMO_TDEF_US.
Referenced by osmo_tdef_round().
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!
[in] | tdefs | Array of timer definitions, last entry must be fully zero initialized. |
[in] | T | Timer number to get the value for. |
[in] | as_unit | Return timeout value in this unit. |
[in] | val_if_not_present | Fallback value to return if no timeout is defined; if this is a negative number, a missing T timer definition aborts the program via OSMO_ASSERT(). |
References OSMO_ASSERT, osmo_tdef_get_entry(), osmo_tdef_round(), osmo_tdef::T, tdefs, osmo_tdef::unit, and osmo_tdef::val.
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.
[in] | tdefs | Array of timer definitions, last entry being fully zero. |
[in] | T | Timer number to get the entry for. |
References osmo_tdef_for_each, osmo_tdef::T, and tdefs.
Referenced by _osmo_tdef_fsm_inst_state_chg(), osmo_tdef_get(), and osmo_tdef_set().
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.
[in] | state | State constant to look up. |
[in] | timeouts_array | Array[32] of struct osmo_tdef_state_timeout defining which timer number to use per state. |
References osmo_tdef_state_timeout::keep_timer, OSMO_ASSERT, and osmo_tdef_state_timeout::T.
Referenced by _osmo_tdef_fsm_inst_state_chg().
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.
[in] | buf | The buffer where the string representation is stored. |
[in] | buf_len | Length of buffer in bytes. |
[in] | tdef | Timer entry from a timer definition table. |
References len(), osmo_tdef::max_val, osmo_tdef::min_val, and OSMO_SNPRINTF_RET.
Referenced by osmo_tdefs_reset().
|
static |
References osmo_tdef_factor().
Referenced by _osmo_tdef_fsm_inst_state_chg(), osmo_tdef_get(), and 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.
[in] | tdefs | Array of timer definitions, last entry being fully zero. |
[in] | T | Timer number to set the value for. |
[in] | val | The new timer value to set. |
[in] | val_unit | Units of value in parameter val. |
References osmo_tdef_get_entry(), osmo_tdef_round(), osmo_tdef_val_in_range(), osmo_tdef::T, tdefs, osmo_tdef::unit, and osmo_tdef::val.
|
inlinestatic |
References get_value_string(), and osmo_tdef_unit_names.
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.
[in] | tdef | Timer entry from a timer definition table. |
[in] | new_val | The value whose validity to check, in units as per this timer entry. |
References osmo_tdef::max_val, and osmo_tdef::min_val.
Referenced by osmo_tdef_set(), and 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.
[in] | tdefs | Array 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, tdefs, and osmo_tdef::val.
|
extern |
Referenced by osmo_tdef_unit_name().
const struct value_string osmo_tdef_unit_names[] |
Referenced by osmo_tdef_unit_name().