diff --git a/libraries/ms-common/inc/log.h b/libraries/ms-common/inc/log.h index b5dbef4..6ca72e7 100644 --- a/libraries/ms-common/inc/log.h +++ b/libraries/ms-common/inc/log.h @@ -4,7 +4,7 @@ * log.h * * Header file for the logging library used to debug all modules - * + * * Created: 2024-10-27 * Midnight Sun Team #24 - MSXVI ************************************************************************************************/ diff --git a/libraries/ms-common/inc/misc.h b/libraries/ms-common/inc/misc.h index 770d47d..ded3b0f 100644 --- a/libraries/ms-common/inc/misc.h +++ b/libraries/ms-common/inc/misc.h @@ -4,7 +4,7 @@ * misc.h * * Common helper functions - * + * * Created: 2024-10-27 * Midnight Sun Team #24 - MSXVI ************************************************************************************************/ diff --git a/libraries/ms-common/inc/status.h b/libraries/ms-common/inc/status.h index 9ceac82..b816a7a 100644 --- a/libraries/ms-common/inc/status.h +++ b/libraries/ms-common/inc/status.h @@ -4,7 +4,7 @@ * status.h * * Status Library for more verbose error handling - * + * * Created: 2024-10-27 * Midnight Sun Team #24 - MSXVI ************************************************************************************************/ @@ -34,7 +34,7 @@ typedef enum { NUM_STATUS_CODES, } StatusCode; -/** +/** * @brief Use to forward failures or continue on success. */ #define status_ok_or_return(code) \ diff --git a/libraries/ms-common/inc/tasks.h b/libraries/ms-common/inc/tasks.h index de2a64c..88ce1d8 100644 --- a/libraries/ms-common/inc/tasks.h +++ b/libraries/ms-common/inc/tasks.h @@ -26,7 +26,8 @@ * @details The generated function has the following signature: * void _prv_your_task_function(void *context) * where context is the context pointer passed to tasks_init_task. - * @param task_name is the name of your task, which should match any previous DECLARE_TASK declarations. + * @param task_name is the name of your task, which should match any previous DECLARE_TASK + * declarations. * @param task_stack_size is the depth of your task's stack - use your judgement to choose. */ #define TASK(task_name, task_stack_size) \ @@ -99,7 +100,7 @@ void tasks_start(void); */ StatusCode tasks_init(void); -/** +/** * @brief Waits for num_tasks of RTOS tasks to finish * @param num_tasks Number of task completions to wait for * @details Takes num_tasks from end task semaphore, tracking the number of tasks completed @@ -108,7 +109,7 @@ StatusCode tasks_init(void); */ StatusCode wait_tasks(uint16_t num_tasks); -/** +/** * @brief A wrapper to give to the semaphore, to be called by tasks when they complete * @return STATUS_CODE_OK if succesfully release sempahore */ diff --git a/libraries/ms-common/inc/test_helpers.h b/libraries/ms-common/inc/test_helpers.h index 6994faa..fc79916 100644 --- a/libraries/ms-common/inc/test_helpers.h +++ b/libraries/ms-common/inc/test_helpers.h @@ -4,7 +4,7 @@ * test_helpers.h * * Unity test framework helper library - * + * * Created: 2024-10-27 * Midnight Sun Team #24 - MSXVI ************************************************************************************************/ diff --git a/libraries/ms-common/src/semaphore.c b/libraries/ms-common/src/semaphore.c new file mode 100644 index 0000000..08682d2 --- /dev/null +++ b/libraries/ms-common/src/semaphore.c @@ -0,0 +1,96 @@ +/************************************************************************************************ + * tasks.c + * + * Source code for the RTOS tasks wrapper + * + * Created: 2024-10-30 + * Midnight Sun Team #24 - MSXVI + ************************************************************************************************/ + +/* Standard library headers */ +#include + +/* Inter-component Headers */ + +/* Intra-component Headers */ +#include "semaphore.h" + +StatusCode mutex_init(Mutex *mutex) { + mutex->handle = xSemaphoreCreateMutexStatic(&mutex->buffer); + if (mutex->handle == NULL) { + return STATUS_CODE_UNINITIALIZED; + } else { + return STATUS_CODE_OK; + } +} + +StatusCode mutex_lock(Mutex *mutex, uint16_t ms_to_wait) { + TickType_t ticks_to_wait; + + /* Handle invalid args */ + if (mutex == NULL || mutex->handle == NULL) { + return STATUS_CODE_INVALID_ARGS; + } + if (ms_to_wait == BLOCK_INDEFINITELY) { + ticks_to_wait = portMAX_DELAY; + } else { + ticks_to_wait = pdMS_TO_TICKS(ms_to_wait); + } + + if (xSemaphoreTake(mutex->handle, ticks_to_wait) == pdFALSE) { + return STATUS_CODE_TIMEOUT; + } + return STATUS_CODE_OK; +} + +StatusCode mutex_unlock(Mutex *mutex) { + /* Handle invalid args */ + if (mutex == NULL || mutex->handle == NULL) { + return STATUS_CODE_INVALID_ARGS; + } + + if (xSemaphoreGive(mutex->handle) == pdFALSE) { + return STATUS_CODE_INTERNAL_ERROR; + } + return STATUS_CODE_OK; +} + +StatusCode sem_init(Semaphore *sem, uint32_t max_count, uint32_t initial_count) { + if (sem == NULL) { + return STATUS_CODE_INVALID_ARGS; + } + sem->handle = xSemaphoreCreateCountingStatic(max_count, initial_count, &sem->buffer); + if (sem->handle == NULL) { + return STATUS_CODE_UNINITIALIZED; + } else { + return STATUS_CODE_OK; + } +} + +StatusCode sem_wait(Semaphore *sem, uint32_t timeout_ms) { + if (sem == NULL) { + return STATUS_CODE_INVALID_ARGS; + } + if (xSemaphoreTake(sem->handle, timeout_ms) == pdFALSE) { + return STATUS_CODE_TIMEOUT; + } + return STATUS_CODE_OK; +} + +StatusCode sem_post(Semaphore *sem) { + if (sem == NULL) { + return STATUS_CODE_INVALID_ARGS; + } + if (xSemaphoreGive(sem->handle) == pdFALSE) { + return STATUS_CODE_INTERNAL_ERROR; + } + return STATUS_CODE_OK; +} + +uint32_t sem_num_items(Semaphore *sem) { + if (sem == NULL) { + return STATUS_CODE_INVALID_ARGS; + } + UBaseType_t count = uxSemaphoreGetCount(sem->handle); + return count; +} \ No newline at end of file diff --git a/libraries/ms-common/src/tasks.c b/libraries/ms-common/src/tasks.c new file mode 100644 index 0000000..f214118 --- /dev/null +++ b/libraries/ms-common/src/tasks.c @@ -0,0 +1,115 @@ +/************************************************************************************************ + * tasks.c + * + * Source code for the RTOS tasks wrapper + * + * Created: 2024-10-30 + * Midnight Sun Team #24 - MSXVI + ************************************************************************************************/ + +/* Standard library headers */ +#include + +/* Inter-component Headers */ +#include "FreeRTOS.h" + +/* Intra-component Headers */ +#include "log.h" +#include "status.h" +#include "tasks.h" + +static StaticSemaphore_t s_end_task_sem; +static SemaphoreHandle_t s_end_task_handle = NULL; + +// Add any setup or teardown that needs to be done for every task here. +static void prv_task(void *params) { + Task *task = params; + if (task == NULL) { // guard just in case, error should have been caught previously + LOG_CRITICAL("CRITICAL: Tried to start null task!\n"); + return; + } + + LOG_DEBUG("Task %s starting.\n", task->name); + + // Call the task function. This shouldn't exit. + task->task_func(task->context); + + // If the task somehow exits, warn and clean up properly. + LOG_WARN("WARNING: Task %s exited.\n", task->name); + vTaskDelete(NULL); +} + +StatusCode tasks_init_task(Task *task, TaskPriority priority, void *context) { + // Defensively guard against invalid initialization - it's bad to get this wrong. + if (task == NULL || task->task_func == NULL) { + LOG_CRITICAL("CRITICAL: Tried to create null task!\n"); + return STATUS_CODE_INVALID_ARGS; + } + + // Priorities range from 0 to configMAX_PRIORITIES-1 with a higher number meaning higher priority. + if (priority >= configMAX_PRIORITIES) { + LOG_CRITICAL("CRITICAL: task '%s' priority is too high, not creating! Was %d, max is %d\n", + task->name, (int)priority, configMAX_PRIORITIES - 1); + return STATUS_CODE_INVALID_ARGS; + } + + if (task->stack_size < TASK_MIN_STACK_SIZE) { + LOG_WARN("Task '%s' had too small stack size, defaulting to minimum %d\n", task->name, + TASK_MIN_STACK_SIZE); + task->stack_size = TASK_MIN_STACK_SIZE; + } + + // Task already created + if (task->handle != NULL) { + return STATUS_CODE_OK; + } + + task->context = context; + task->handle = xTaskCreateStatic(prv_task, task->name, task->stack_size, task, priority, + task->stack, &task->tcb); + if (task->handle == NULL) { + LOG_CRITICAL("Failed to create Task %s", task->name); + } else { + LOG_DEBUG("Create Task %s", task->name); + } + return STATUS_CODE_OK; +} + +void tasks_start(void) { + if (s_end_task_handle == NULL) { + LOG_CRITICAL("s_end_task_sem not initialized! Call tasks_init() first\n"); + return; + } + + vTaskStartScheduler(); +} + +StatusCode tasks_init(void) { + // Initialize the end task semaphore. + s_end_task_handle = xSemaphoreCreateCountingStatic(MAX_NUM_TASKS, 0, &s_end_task_sem); + + if (s_end_task_handle == NULL) { + return STATUS_CODE_UNINITIALIZED; + } else { + return STATUS_CODE_OK; + } +} + +StatusCode wait_tasks(uint16_t num_tasks) { + for (uint16_t i = 0; i < num_tasks; ++i) { + if (xSemaphoreTake(s_end_task_handle, pdMS_TO_TICKS(WAIT_TASK_TIMEOUT_MS)) != pdTRUE) { + // Task took longer than 1 second for its execution cycle, return timeout + return STATUS_CODE_TIMEOUT; + } + } + return STATUS_CODE_OK; +} + +StatusCode send_task_end() { + if (xSemaphoreGive(s_end_task_handle) != pdTRUE) { + // if giving to semaphore failed, we ran out of space in the buffer + LOG_CRITICAL("CRITICAL: Out of buffer space in semaphore.\n"); + return STATUS_CODE_RESOURCE_EXHAUSTED; + } + return STATUS_CODE_OK; +} diff --git a/libraries/ms-freertos/inc/FreeRTOSConfig.h b/libraries/ms-freertos/inc/FreeRTOSConfig.h index dedf553..2a36278 100644 --- a/libraries/ms-freertos/inc/FreeRTOSConfig.h +++ b/libraries/ms-freertos/inc/FreeRTOSConfig.h @@ -37,7 +37,6 @@ extern uint32_t SystemCoreClock; #define configAPPLICATION_ALLOCATED_HEAP 0 #define configSYSTEM_CALL_STACK_SIZE 128 - /* Hook function related definitions. */ #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 diff --git a/libraries/ms-freertos/src/static_alloc.c b/libraries/ms-freertos/src/static_alloc.c index 180c4e6..5521ac0 100644 --- a/libraries/ms-freertos/src/static_alloc.c +++ b/libraries/ms-freertos/src/static_alloc.c @@ -2,7 +2,7 @@ * static_alloc.c * * Static allocation helpers for FreeRTOS. - * + * * Created: 2024-10-27 * Midnight Sun Team #24 - MSXVI ************************************************************************************************/ @@ -12,6 +12,7 @@ /* Inter-component Headers */ #include "FreeRTOS.h" +#include "log.h" #include "task.h" /* Intra-component Headers */ @@ -20,21 +21,19 @@ /** * This is needed handle stack overflows. - * See https://www.freertos.org/Documentation/02-Kernel/02-Kernel-features/09-Memory-management/02-Stack-usage-and-stack-overflow-checking + * See + * https://www.freertos.org/Documentation/02-Kernel/02-Kernel-features/09-Memory-management/02-Stack-usage-and-stack-overflow-checking */ void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) { - (void)xTask; - (void)pcTaskName; - taskDISABLE_INTERRUPTS(); - for (;;); + LOG_CRITICAL("CRITICAL: Task '%s' has overflowed its allocated stack space.\n", pcTaskName); } /** * This is needed to handle memory allocation failures during task memory allocation. */ void vApplicationMallocFailedHook(void) { - taskDISABLE_INTERRUPTS(); - for (;;); + taskDISABLE_INTERRUPTS(); + for (;;); } #endif diff --git a/smoke/rtos_sample/src/main.c b/smoke/rtos_sample/src/main.c index c01fc9c..8234e76 100644 --- a/smoke/rtos_sample/src/main.c +++ b/smoke/rtos_sample/src/main.c @@ -2,7 +2,7 @@ * main.c * * Main file for RTOS Sample. - * + * * Created: 2024-10-27 * Midnight Sun Team #24 - MSXVI ************************************************************************************************/