123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543 |
- #include "sdk_common.h"
- #if NRF_MODULE_ENABLED(TASK_MANAGER)
- #include "nrf_mpu_lib.h"
- #include "nrf_atomic.h"
- #include "app_util_platform.h"
- #include "task_manager.h"
- #if TASK_MANAGER_CLI_CMDS
- #include "nrf_cli.h"
- #endif
- #define NRF_LOG_MODULE_NAME task_manager
- #if TASK_MANAGER_CONFIG_LOG_ENABLED
- #define NRF_LOG_LEVEL TASK_MANAGER_CONFIG_LOG_LEVEL
- #define NRF_LOG_INFO_COLOR TASK_MANAGER_CONFIG_INFO_COLOR
- #define NRF_LOG_DEBUG_COLOR TASK_MANAGER_CONFIG_DEBUG_COLOR
- #endif
- #include "nrf_log.h"
- NRF_LOG_MODULE_REGISTER();
- #if TASK_MANAGER_CONFIG_STACK_GUARD
- #define STACK_GUARD_SIZE (1 << (TASK_MANAGER_CONFIG_STACK_GUARD + 1))
- STATIC_ASSERT((TASK_MANAGER_CONFIG_STACK_SIZE % STACK_GUARD_SIZE) == 0);
- #endif
- STATIC_ASSERT((TASK_MANAGER_CONFIG_MAX_TASKS) > 0);
- STATIC_ASSERT((TASK_MANAGER_CONFIG_STACK_SIZE % 8) == 0);
- #if (__CORTEX_M == 4)
- # ifndef CONTROL_FPCA_Pos
- # define CONTROL_FPCA_Pos 2u
- # define CONTROL_FPCA_Msk (1ul << CONTROL_FPCA_Pos)
- # endif
- # ifndef CONTROL_SPSEL_Pos
- # define CONTROL_SPSEL_Pos 1u
- # define CONTROL_SPSEL_Msk (1ul << CONTROL_SPSEL_Pos)
- # endif
- #endif
- extern void task_switch(void);
- #define IDLE_TASK_ID TASK_MANAGER_CONFIG_MAX_TASKS
- #define TASK_STACK_MAGIC_WORD 0xDEADD00E
- #define TASK_FLAG_SIGNAL_MASK 0x00FFFFFF
- #define TASK_FLAG_DESTROY 0x80000000
- #define TOTAL_NUM_OF_TASKS (TASK_MANAGER_CONFIG_MAX_TASKS + 1)
- typedef struct
- {
- uint32_t r0;
- uint32_t r4;
- uint32_t r5;
- uint32_t r6;
- uint32_t r7;
- uint32_t r8;
- uint32_t r9;
- uint32_t r10;
- uint32_t r11;
- uint32_t r12;
- uint32_t lr;
- uint32_t control;
- } task_stack_t;
- typedef struct
- {
- void *p_stack;
- const char *p_task_name;
- nrf_atomic_u32_t flags;
- } task_state_t;
- typedef struct
- {
- #if TASK_MANAGER_CONFIG_STACK_GUARD
- uint8_t guard[STACK_GUARD_SIZE];
- #endif
- uint8_t stack[TASK_MANAGER_CONFIG_STACK_SIZE];
- } task_manager_stack_t;
- #if TASK_MANAGER_CONFIG_STACK_GUARD
- static nrf_mpu_lib_region_t s_guard_region;
- __ALIGN(STACK_GUARD_SIZE)
- #else
- __ALIGN(8)
- #endif
- static task_manager_stack_t s_task_stacks[TOTAL_NUM_OF_TASKS];
- static task_state_t s_task_state[TOTAL_NUM_OF_TASKS];
- static nrf_atomic_u32_t s_runnable_tasks_mask;
- static task_id_t s_current_task_id;
- #define TASK_GUARD_ATTRIBUTES ((0x05 << MPU_RASR_TEX_Pos) | (1 << MPU_RASR_B_Pos) | \
- (0x07 << MPU_RASR_AP_Pos) | (1 << MPU_RASR_XN_Pos))
- #define BOTTOM_OF_TASK_STACK(_task_id) ((void *)(&s_task_stacks[(_task_id)].stack[0]))
- #define TOP_OF_TASK_STACK(_task_id) ((void *)(&s_task_stacks[(_task_id)].stack[TASK_MANAGER_CONFIG_STACK_SIZE]))
- #define TASK_STACK_GUARD_BASE(_task_id) ((void *)(&s_task_stacks[(_task_id)].guard[0]))
- #define TASK_ID_TO_MASK(_task_id) (0x80000000 >> (_task_id))
- #define TASK_STATE_RUNNABLE(_task_id) \
- (void)nrf_atomic_u32_or(&s_runnable_tasks_mask, TASK_ID_TO_MASK(_task_id))
- #define TASK_STATE_SUSPENDED(_task_id) \
- (void)nrf_atomic_u32_and(&s_runnable_tasks_mask, ~TASK_ID_TO_MASK(_task_id));
- static void task_stack_poison(task_id_t task_id)
- {
- #if TASK_MANAGER_CONFIG_STACK_PROFILER_ENABLED
- unsigned int i = TASK_MANAGER_CONFIG_STACK_SIZE / sizeof(uint32_t);
- uint32_t *p_stack_top = TOP_OF_TASK_STACK(task_id);
- while (i--)
- {
- *(--p_stack_top) = TASK_STACK_MAGIC_WORD;
- }
- #endif
- }
- static void task_stack_protect(task_id_t task_id)
- {
- #if TASK_MANAGER_CONFIG_STACK_GUARD
- APP_ERROR_CHECK(nrf_mpu_lib_region_create(&s_guard_region,
- TASK_STACK_GUARD_BASE(task_id),
- STACK_GUARD_SIZE,
- TASK_GUARD_ATTRIBUTES));
- #endif
- }
- PRAGMA_OPTIMIZATION_FORCE_START
- void task_manager_start(task_main_t idle_task, void *p_idle_task_context)
- {
- unsigned long control;
-
- ASSERT(idle_task != NULL);
-
- ASSERT((__get_IPSR() & IPSR_ISR_Msk) == 0);
- ASSERT((__get_CONTROL() & CONTROL_nPRIV_Msk) == 0);
- ASSERT((__get_CONTROL() & CONTROL_SPSEL_Msk) == 0);
-
- s_current_task_id = IDLE_TASK_ID;
- s_task_state[s_current_task_id].p_task_name = "Idle Task";
-
- task_stack_poison(s_current_task_id);
- task_stack_protect(s_current_task_id);
- NRF_LOG_INFO("Task %u created (name: '%s', stack: 0x%08X-0x%08X).",
- s_current_task_id,
- s_task_state[s_current_task_id].p_task_name,
- (uint32_t)BOTTOM_OF_TASK_STACK(s_current_task_id),
- (uint32_t)TOP_OF_TASK_STACK(s_current_task_id) - 1);
-
- __disable_irq();
-
- __set_PSP((uint32_t)(TOP_OF_TASK_STACK(s_current_task_id)));
- __set_MSP((uint32_t)(STACK_TOP));
-
- control = __get_CONTROL();
- control &= CONTROL_FPCA_Msk;
- control |= CONTROL_SPSEL_Msk;
- __set_CONTROL(control);
-
- __enable_irq();
-
- task_switch();
-
- idle_task(p_idle_task_context);
-
- APP_ERROR_CHECK_BOOL(false);
- }
- PRAGMA_OPTIMIZATION_FORCE_END
- task_id_t task_create(task_main_t task, char const * p_task_name, void *p_context)
- {
- task_state_t *p_state = NULL;
- task_stack_t *p_stack;
- task_id_t task_id;
-
- if (task == NULL)
- {
- return TASK_ID_INVALID;
- }
-
- CRITICAL_REGION_ENTER();
- for (task_id = 0; task_id < TASK_MANAGER_CONFIG_MAX_TASKS; task_id++)
- {
- if (s_task_state[task_id].p_stack == NULL)
- {
- p_state = &s_task_state[task_id];
- p_state->p_stack = TOP_OF_TASK_STACK(task_id);
- break;
- }
- }
- CRITICAL_REGION_EXIT();
-
- if (p_state == NULL)
- {
- return TASK_ID_INVALID;
- }
-
- task_stack_poison(task_id);
- p_state->p_stack = (uint8_t *)(p_state->p_stack) - sizeof(*p_stack);
- p_state->p_task_name = (char *)p_task_name;
- p_state->flags = 0;
- p_stack = p_state->p_stack;
- p_stack->control = CONTROL_SPSEL_Msk;
- p_stack->lr = (uint32_t)(task);
- p_stack->r0 = (uint32_t)(p_context);
-
- TASK_STATE_RUNNABLE(task_id);
- NRF_LOG_INFO("Task %u created (name: '%s', stack: 0x%08X-0x%08X).",
- task_id,
- p_task_name,
- (uint32_t)BOTTOM_OF_TASK_STACK(task_id),
- (uint32_t)TOP_OF_TASK_STACK(task_id) - 1);
- return task_id;
- }
- void *task_schedule(void *p_stack)
- {
- uint32_t runnable_tasks_mask;
- #if TASK_MANAGER_CONFIG_STACK_GUARD
-
- APP_ERROR_CHECK(nrf_mpu_lib_region_destroy(s_guard_region));
- #endif
-
- if ((s_task_state[s_current_task_id].flags & TASK_FLAG_DESTROY) == 0)
- {
- s_task_state[s_current_task_id].p_stack = p_stack;
- }
- else
- {
- TASK_STATE_SUSPENDED(s_current_task_id);
- s_task_state[s_current_task_id].p_stack = NULL;
- NRF_LOG_INFO("Task %u terminated (name: '%s').",
- s_current_task_id,
- s_task_state[s_current_task_id].p_task_name);
- }
-
- runnable_tasks_mask = s_runnable_tasks_mask;
-
- if (runnable_tasks_mask != 0)
- {
-
- if ((runnable_tasks_mask << (s_current_task_id + 1)) != 0)
- {
-
- s_current_task_id += 1 + __CLZ((runnable_tasks_mask << (s_current_task_id + 1)));
- }
- else
- {
-
- s_current_task_id = __CLZ(runnable_tasks_mask);
- }
- }
- else
- {
-
- s_current_task_id = IDLE_TASK_ID;
- }
- task_stack_protect(s_current_task_id);
-
- return s_task_state[s_current_task_id].p_stack;
- }
- void task_yield(void)
- {
-
- ASSERT((__get_IPSR() & IPSR_ISR_Msk) == 0);
- ASSERT((__get_CONTROL() & CONTROL_nPRIV_Msk) == 0);
- ASSERT((__get_CONTROL() & CONTROL_SPSEL_Msk) != 0);
-
- task_switch();
- }
- uint32_t task_events_wait(uint32_t evt_mask)
- {
- uint32_t current_events;
- ASSERT((evt_mask & ~TASK_FLAG_SIGNAL_MASK) == 0);
- for (;;)
- {
- current_events = s_task_state[s_current_task_id].flags & evt_mask;
- if (current_events != 0)
- {
- (void)nrf_atomic_u32_and(&s_task_state[s_current_task_id].flags, ~current_events);
- break;
- }
- TASK_STATE_SUSPENDED(s_current_task_id);
- task_yield();
- }
- return current_events;
- }
- void task_events_set(task_id_t task_id, uint32_t evt_mask)
- {
- ASSERT((task_id != TASK_ID_INVALID) && (task_id < TASK_MANAGER_CONFIG_MAX_TASKS));
- ASSERT((evt_mask & ~TASK_FLAG_SIGNAL_MASK) == 0);
- ASSERT(s_task_state[task_id].p_stack != NULL);
- (void)nrf_atomic_u32_or(&s_task_state[task_id].flags, evt_mask);
- TASK_STATE_RUNNABLE(task_id);
- }
- void task_exit(void)
- {
-
- ASSERT((__get_IPSR() & IPSR_ISR_Msk) == 0);
- ASSERT((__get_CONTROL() & CONTROL_nPRIV_Msk) == 0);
- ASSERT((__get_CONTROL() & CONTROL_SPSEL_Msk) != 0);
- s_task_state[s_current_task_id].flags = TASK_FLAG_DESTROY;
- task_switch();
- }
- task_id_t task_id_get(void)
- {
-
- ASSERT((__get_IPSR() & IPSR_ISR_Msk) == 0);
- ASSERT((__get_CONTROL() & CONTROL_nPRIV_Msk) == 0);
- ASSERT((__get_CONTROL() & CONTROL_SPSEL_Msk) != 0);
- return s_current_task_id;
- }
- uint32_t task_stack_max_usage_get(task_id_t task_id)
- {
- #if TASK_MANAGER_CONFIG_STACK_PROFILER_ENABLED
- unsigned int stack_usage;
- uint32_t *p_stack, *p_stack_top;
- ASSERT((task_id != TASK_ID_INVALID) || (task_id < TASK_MANAGER_CONFIG_MAX_TASKS));
- ASSERT(s_task_state[task_id].p_stack != NULL);
- p_stack_top = TOP_OF_TASK_STACK(task_id);
- p_stack = BOTTOM_OF_TASK_STACK(task_id);
- stack_usage = TASK_MANAGER_CONFIG_STACK_SIZE;
- while (p_stack < p_stack_top)
- {
- if (*(p_stack++) != TASK_STACK_MAGIC_WORD)
- {
- break;
- }
- stack_usage -= sizeof(*p_stack);
- }
- return stack_usage;
- #else
- return 0;
- #endif
- }
- #if TASK_MANAGER_CLI_CMDS
- static void task_mnanager_info(nrf_cli_t const * p_cli, size_t argc, char **argv)
- {
- task_id_t task_id;
- for (task_id = 0; task_id < TOTAL_NUM_OF_TASKS; task_id++)
- {
- const char *p_task_name = NULL;
- CRITICAL_REGION_ENTER();
- if (s_task_state[task_id].p_stack != NULL)
- {
- p_task_name = (s_task_state[task_id].p_task_name) ? s_task_state[task_id].p_task_name
- : "<NULL>";
- }
- CRITICAL_REGION_EXIT();
- if (p_task_name)
- {
- uint32_t stack_usage = task_stack_max_usage_get(task_id);
- nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Task %u:\r\n", task_id);
- nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "\tName:\t'%s'\r\n", p_task_name);
- if (stack_usage)
- {
- nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "\tStack:\t0x%08X-0x%08X used in %u%% (%u out of %u bytes)\r\n",
- (uint32_t)BOTTOM_OF_TASK_STACK(task_id),
- (uint32_t)TOP_OF_TASK_STACK(task_id) - 1,
- 100 * stack_usage / TASK_MANAGER_CONFIG_STACK_SIZE,
- stack_usage,
- TASK_MANAGER_CONFIG_STACK_SIZE);
- }
- else
- {
- nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "\tStack:\t0x%08X-0x%08X\r\n",
- (uint32_t)BOTTOM_OF_TASK_STACK(task_id),
- (uint32_t)TOP_OF_TASK_STACK(task_id) - 1);
- }
- nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "\tState:\t%s\r\n",
- (s_current_task_id == task_id) ? "Running" :
- (s_runnable_tasks_mask & TASK_ID_TO_MASK(task_id)) ? "Runnable" : "Suspended");
- nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "\tFlags:\t0x%08X\r\n\r\n",
- s_task_state[task_id].flags);
- }
- }
- }
- NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_task_mngr)
- {
- NRF_CLI_CMD(info, NULL, "tasks info", task_mnanager_info),
- NRF_CLI_SUBCMD_SET_END
- };
- NRF_CLI_CMD_REGISTER(task_manager, &m_sub_task_mngr, "commands for task manager", NULL);
- #endif
- #else
- void *task_schedule(void *p_stack)
- {
- return (void *)0;
- }
- #endif
|