Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Kconfig.defaults.core
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ configdefault FILE_SYSTEM_RAW_API
configdefault INFUSE_EPOCH_TIME
default y

configdefault INFUSE_APPLICATION_STATES
default y

# Application management
if BOOTLOADER_MCUBOOT || BUILD_WITH_TFM
configdefault STREAM_FLASH
Expand Down
3 changes: 3 additions & 0 deletions Kconfig.defaults.nrf
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ configdefault NRF_OBERON
default y if !BUILD_WITH_TFM

# LTE defaults
configdefault AT_MONITOR_HEAP_SIZE
default 512
configdefault NET_IPV6_MLD
default n if NRF_MODEM_LIB
configdefault NET_IPV6_NBR_CACHE
Expand All @@ -33,6 +35,7 @@ configdefault LTE_LC_MODEM_SLEEP_PRE_WARNING_TIME_MS
default 500
configdefault LTE_LC_MODEM_SLEEP_NOTIFICATIONS_THRESHOLD_MS
default 10240

# Default PSM mode
configdefault LTE_PSM_REQ
default y
Expand Down
91 changes: 91 additions & 0 deletions include/infuse/states.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/**
* @file
* @brief Application state framework
* @copyright 2024 Embeint Inc
* @author Jordan Yates <[email protected]>
*
* SPDX-License-Identifier: LicenseRef-Embeint
*/

#ifndef INFUSE_SDK_INCLUDE_INFUSE_STATES_H_
#define INFUSE_SDK_INCLUDE_INFUSE_STATES_H_

#include <stdint.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* @defgroup states_apis Infuse-IoT application state APIs
* @{
*/

/**
* @brief Infuse-IoT application states
*
* 1 - 127: Infuse-IoT defined states
* 128 - 255: Application specific states
*/
enum infuse_state {
/* Device is about to reboot */
INFUSE_STATE_REBOOTING = 1,
/* Application is active according to KV-store values */
INFUSE_STATE_APPLICATION_ACTIVE = 2,
/* Application has a valid time source */
INFUSE_STATE_TIME_KNOWN = 3,
/* Start of application-specific state range */
INFUSE_STATES_APP_START = 128,
INFUSE_STATES_END = UINT8_MAX
};

/**
* @brief Set an application state
*
* Application state will remain set until @ref infuse_state_clear is called.
*
* @param state State to set
*/
void infuse_state_set(enum infuse_state state);

/**
* @brief Set an application state that times out after a duration
*
* @param state State to set
* @param timeout Seconds that state should be set for
*/
void infuse_state_set_timeout(enum infuse_state state, uint16_t timeout);

/**
* @brief Clear an application state
*
* @param state State to clear
*/
void infuse_state_clear(enum infuse_state state);

/**
* @brief Get an application state
*
* @param state State to query
* @retval true Application state is set
* @retval false Application state is not set
*/
bool infuse_state_get(enum infuse_state state);

/**
* @brief Run one tick of the state timeouts.
*
* @note This function must be run once and only once per second for correct operation
*/
void infuse_states_tick(void);

/**
* @}
*/

#ifdef __cplusplus
}
#endif

#endif /* INFUSE_SDK_INCLUDE_INFUSE_STATES_H_ */
1 change: 1 addition & 0 deletions include/infuse/task_runner/runner.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ void task_runner_iterate(uint32_t uptime, uint32_t gps_time, uint8_t battery_cha
* @brief Automatically iterate the task runner
*
* Automatically calls @ref task_runner_iterate once a second forever.
* Also calls @ref infuse_states_tick if CONFIG_INFUSE_APPLICATION_STATES is enabled.
*
* @warning Do NOT call @ref task_runner_iterate after this function.
*/
Expand Down
1 change: 1 addition & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ zephyr_sources_ifdef(CONFIG_INFUSE_EPOCH_TIME time/epoch.c)

add_subdirectory(auto)
add_subdirectory(math)
add_subdirectory(states)
add_subdirectory_ifdef(CONFIG_INFUSE_SDK vendor)
add_subdirectory_ifdef(CONFIG_INFUSE_SECURITY crypto/hardware_unique_key)
add_subdirectory_ifdef(CONFIG_CRYPTO_ASCON crypto/ascon)
Expand Down
1 change: 1 addition & 0 deletions lib/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ endif # INFUSE_COMMON_BOOT
rsource "auto/Kconfig"
rsource "crypto/Kconfig"
rsource "nrf_modem_lib/Kconfig"
rsource "states/Kconfig"
6 changes: 6 additions & 0 deletions lib/reboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <zephyr/net/conn_mgr_connectivity.h>
#include <zephyr/logging/log_ctrl.h>

#include <infuse/states.h>
#include <infuse/drivers/watchdog.h>
#include <infuse/time/epoch.h>
#include <infuse/reboot.h>
Expand Down Expand Up @@ -116,6 +117,11 @@ void infuse_reboot_delayed(enum infuse_reboot_reason reason, uint32_t info1, uin
{
static struct k_work_delayable reboot_worker;

#ifdef CONFIG_INFUSE_APPLICATION_STATES
/* Set rebooting state */
infuse_state_set(INFUSE_STATE_REBOOTING);
#endif

/* Init the worker */
k_work_init_delayable(&reboot_worker, delayed_do_reboot);

Expand Down
3 changes: 3 additions & 0 deletions lib/states/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Infuse-IoT application states

zephyr_sources_ifdef(CONFIG_INFUSE_APPLICATION_STATES application_states.c)
16 changes: 16 additions & 0 deletions lib/states/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Infuse-IoT application states

config INFUSE_APPLICATION_STATES
bool "Application states"

if INFUSE_APPLICATION_STATES

module = INFUSE_APPLICATION_STATES
module-str = states
source "subsys/logging/Kconfig.template.log_config"

config INFUSE_APPLICATION_STATES_MAX_TIMEOUTS
int "Maximum number of timeouts that can be pending at a time"
default 8

endif
82 changes: 82 additions & 0 deletions lib/states/application_states.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* @file
* @copyright 2024 Embeint Inc
* @author Jordan Yates <[email protected]>
*
* SPDX-License-Identifier: LicenseRef-Embeint
*/

#include <zephyr/logging/log.h>
#include <zephyr/spinlock.h>
#include <zephyr/sys/atomic.h>

#include <infuse/states.h>

struct timeout_state {
uint8_t state;
uint16_t timeout;
};

static ATOMIC_DEFINE(application_states, UINT8_MAX);
static struct timeout_state timeout_states[CONFIG_INFUSE_APPLICATION_STATES_MAX_TIMEOUTS];
static uint32_t timeout_mask;
static struct k_spinlock timeout_lock;

LOG_MODULE_REGISTER(states, CONFIG_INFUSE_APPLICATION_STATES_LOG_LEVEL);

void infuse_state_set(enum infuse_state state)
{
atomic_set_bit(application_states, state);
LOG_DBG("%d", state);
}

void infuse_state_set_timeout(enum infuse_state state, uint16_t timeout)
{
if (timeout == 0) {
return;
}

K_SPINLOCK(&timeout_lock) {
if (__builtin_popcount(timeout_mask) == ARRAY_SIZE(timeout_states)) {
LOG_WRN("Insufficient timeout contexts");
K_SPINLOCK_BREAK;
}
uint8_t first_free = __builtin_ffs(~timeout_mask) - 1;

atomic_set_bit(application_states, state);
timeout_mask |= (1 << first_free);
timeout_states[first_free].state = state;
timeout_states[first_free].timeout = timeout;
}
LOG_DBG("%d for %d", state, timeout);
}

void infuse_state_clear(enum infuse_state state)
{
atomic_clear_bit(application_states, state);
LOG_DBG("%d", state);
}

bool infuse_state_get(enum infuse_state state)
{
return atomic_test_bit(application_states, state);
}

void infuse_states_tick(void)
{
K_SPINLOCK(&timeout_lock) {
uint32_t mask = timeout_mask;

while (mask) {
uint8_t first_used = __builtin_ffs(mask) - 1;

if (--timeout_states[first_used].timeout == 0) {
atomic_clear_bit(application_states,
timeout_states[first_used].state);
timeout_mask ^= (1 << first_used);
LOG_DBG("%d timed out", timeout_states[first_used].state);
}
mask ^= 1 << first_used;
}
}
}
5 changes: 5 additions & 0 deletions subsys/task_runner/auto_iterate.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <infuse/task_runner/runner.h>
#include <infuse/tdf/definitions.h>
#include <infuse/zbus/channels.h>
#include <infuse/states.h>

static struct k_work_delayable iterate_work;
extern struct k_work_q task_runner_workq;
Expand All @@ -38,6 +39,10 @@ static void iterate_worker(struct k_work *work)
/* Iterate the runner */
task_runner_iterate(k_uptime_seconds(), gps_time, charge);

#ifdef CONFIG_INFUSE_APPLICATION_STATES
infuse_states_tick();
#endif

/* Schedule the next iteration */
k_work_schedule_for_queue(&task_runner_workq, &iterate_work,
K_TIMEOUT_ABS_MS(next_iter * MSEC_PER_SEC));
Expand Down
15 changes: 15 additions & 0 deletions subsys/task_runner/schedule.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* SPDX-License-Identifier: LicenseRef-Embeint
*/

#include <infuse/states.h>
#include <infuse/task_runner/schedule.h>

bool task_schedule_validate(const struct task_schedule *schedule)
Expand Down Expand Up @@ -38,6 +39,13 @@ bool task_schedule_should_start(const struct task_schedule *schedule,
bool periodicity = true;
bool battery = true;

#ifdef CONFIG_INFUSE_APPLICATION_STATES
/* No tasks should be started when system is about to go down */
if (infuse_state_get(INFUSE_STATE_REBOOTING)) {
return false;
}
#endif

if (schedule->periodicity_type == TASK_PERIODICITY_FIXED) {
periodicity = (epoch_time % schedule->periodicity.fixed.period_s) == 0;
}
Expand All @@ -56,6 +64,13 @@ bool task_schedule_should_terminate(const struct task_schedule *schedule,
bool periodicity = false;
bool battery = false;

#ifdef CONFIG_INFUSE_APPLICATION_STATES
/* Tasks should be terminated when system is about to go down */
if (infuse_state_get(INFUSE_STATE_REBOOTING)) {
return true;
}
#endif

if (schedule->timeout_s) {
periodicity = state->runtime >= schedule->timeout_s;
}
Expand Down
9 changes: 9 additions & 0 deletions tests/lib/application_states/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(application_states)

target_sources(app PRIVATE
src/main.c
)
2 changes: 2 additions & 0 deletions tests/lib/application_states/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
CONFIG_ZTEST=y
CONFIG_INFUSE_APPLICATION_STATES=y
Loading
Loading