/** * @file sys_arch.c * @brief LwIP system architecture implementation for FreeRTOS */ #include "lwip/opt.h" #include "lwip/sys.h" #include "lwip/stats.h" #include "arch/sys_arch.h" #include "FreeRTOS.h" #include "task.h" #include "queue.h" #include "semphr.h" #include /* Timeout for infinite wait */ #define LWIP_ARCH_TICK_PER_MS (1000 / configTICK_RATE_HZ) /*--------------------------------------------------------------------------- * System Initialization *---------------------------------------------------------------------------*/ /** * @brief Initialize the system architecture layer */ void sys_init(void) { /* Nothing to do here for FreeRTOS */ } /** * @brief Get current time in milliseconds * @return Current time in milliseconds */ u32_t sys_now(void) { return xTaskGetTickCount() * portTICK_PERIOD_MS; } /*--------------------------------------------------------------------------- * Semaphore Functions *---------------------------------------------------------------------------*/ /** * @brief Create a new semaphore * @param sem Pointer to the semaphore to create * @param count Initial count of the semaphore * @return ERR_OK if successful, ERR_MEM if out of memory */ err_t sys_sem_new(sys_sem_t *sem, u8_t count) { *sem = xSemaphoreCreateCounting(0xFF, count); if (*sem == NULL) { SYS_STATS_INC(sem.err); return ERR_MEM; } SYS_STATS_INC_USED(sem); return ERR_OK; } /** * @brief Free a semaphore * @param sem Pointer to the semaphore to free */ void sys_sem_free(sys_sem_t *sem) { if (*sem != SYS_SEM_NULL) { vSemaphoreDelete(*sem); *sem = SYS_SEM_NULL; SYS_STATS_DEC(sem.used); } } /** * @brief Signal a semaphore * @param sem Pointer to the semaphore to signal */ void sys_sem_signal(sys_sem_t *sem) { xSemaphoreGive(*sem); } /** * @brief Wait for a semaphore * @param sem Pointer to the semaphore to wait on * @param timeout Timeout in milliseconds (0 = wait forever) * @return Time waited in milliseconds, or SYS_ARCH_TIMEOUT on timeout */ u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) { TickType_t start_time = xTaskGetTickCount(); TickType_t wait_ticks; if (timeout == 0) { wait_ticks = portMAX_DELAY; } else { wait_ticks = pdMS_TO_TICKS(timeout); } if (xSemaphoreTake(*sem, wait_ticks) == pdTRUE) { u32_t elapsed = (xTaskGetTickCount() - start_time) * portTICK_PERIOD_MS; return elapsed; } return SYS_ARCH_TIMEOUT; } /*--------------------------------------------------------------------------- * Mutex Functions *---------------------------------------------------------------------------*/ /** * @brief Create a new mutex * @param mutex Pointer to the mutex to create * @return ERR_OK if successful, ERR_MEM if out of memory */ err_t sys_mutex_new(sys_mutex_t *mutex) { *mutex = xSemaphoreCreateMutex(); if (*mutex == NULL) { SYS_STATS_INC(mutex.err); return ERR_MEM; } SYS_STATS_INC_USED(mutex); return ERR_OK; } /** * @brief Free a mutex * @param mutex Pointer to the mutex to free */ void sys_mutex_free(sys_mutex_t *mutex) { if (*mutex != SYS_MUTEX_NULL) { vSemaphoreDelete(*mutex); *mutex = SYS_MUTEX_NULL; SYS_STATS_DEC(mutex.used); } } /** * @brief Lock a mutex * @param mutex Pointer to the mutex to lock */ void sys_mutex_lock(sys_mutex_t *mutex) { xSemaphoreTake(*mutex, portMAX_DELAY); } /** * @brief Unlock a mutex * @param mutex Pointer to the mutex to unlock */ void sys_mutex_unlock(sys_mutex_t *mutex) { xSemaphoreGive(*mutex); } /*--------------------------------------------------------------------------- * Mailbox Functions *---------------------------------------------------------------------------*/ /** * @brief Create a new mailbox * @param mbox Pointer to the mailbox to create * @param size Size of the mailbox * @return ERR_OK if successful, ERR_MEM if out of memory */ err_t sys_mbox_new(sys_mbox_t *mbox, int size) { *mbox = xQueueCreate(size, sizeof(void *)); if (*mbox == NULL) { SYS_STATS_INC(mbox.err); return ERR_MEM; } SYS_STATS_INC_USED(mbox); return ERR_OK; } /** * @brief Free a mailbox * @param mbox Pointer to the mailbox to free */ void sys_mbox_free(sys_mbox_t *mbox) { if (*mbox != SYS_MBOX_NULL) { /* Wait for mailbox to be empty */ while (uxQueueMessagesWaiting(*mbox) != 0) { vTaskDelay(1); } vQueueDelete(*mbox); *mbox = SYS_MBOX_NULL; SYS_STATS_DEC(mbox.used); } } /** * @brief Post a message to a mailbox * @param mbox Pointer to the mailbox * @param msg Message to post */ void sys_mbox_post(sys_mbox_t *mbox, void *msg) { while (xQueueSendToBack(*mbox, &msg, portMAX_DELAY) != pdTRUE); } /** * @brief Try to post a message to a mailbox * @param mbox Pointer to the mailbox * @param msg Message to post * @return ERR_OK if successful, ERR_MEM if mailbox is full */ err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg) { if (xQueueSendToBack(*mbox, &msg, 0) == pdTRUE) { return ERR_OK; } SYS_STATS_INC(mbox.err); return ERR_MEM; } /** * @brief Try to post a message to front of mailbox * @param mbox Pointer to the mailbox * @param msg Message to post * @return ERR_OK if successful, ERR_MEM if mailbox is full */ err_t sys_mbox_trypost_fromisr(sys_mbox_t *mbox, void *msg) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; if (xQueueSendToBackFromISR(*mbox, &msg, &xHigherPriorityTaskWoken) == pdTRUE) { portYIELD_FROM_ISR(xHigherPriorityTaskWoken); return ERR_OK; } return ERR_MEM; } /** * @brief Fetch a message from a mailbox * @param mbox Pointer to the mailbox * @param msg Pointer to store the received message * @param timeout Timeout in milliseconds (0 = wait forever) * @return Time waited in milliseconds, or SYS_ARCH_TIMEOUT on timeout */ u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) { TickType_t start_time = xTaskGetTickCount(); TickType_t wait_ticks; void *received_msg; if (timeout == 0) { wait_ticks = portMAX_DELAY; } else { wait_ticks = pdMS_TO_TICKS(timeout); } if (xQueueReceive(*mbox, &received_msg, wait_ticks) == pdTRUE) { if (msg != NULL) { *msg = received_msg; } u32_t elapsed = (xTaskGetTickCount() - start_time) * portTICK_PERIOD_MS; return elapsed; } if (msg != NULL) { *msg = NULL; } return SYS_ARCH_TIMEOUT; } /** * @brief Try to fetch a message from a mailbox * @param mbox Pointer to the mailbox * @param msg Pointer to store the received message * @return 0 if successful, SYS_MBOX_EMPTY if mailbox is empty */ u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) { void *received_msg; if (xQueueReceive(*mbox, &received_msg, 0) == pdTRUE) { if (msg != NULL) { *msg = received_msg; } return 0; } return SYS_MBOX_EMPTY; } /*--------------------------------------------------------------------------- * Thread Functions *---------------------------------------------------------------------------*/ /** * @brief Create a new thread * @param name Thread name * @param thread Thread function * @param arg Argument to pass to thread function * @param stacksize Stack size in words * @param prio Thread priority * @return Thread handle */ sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio) { TaskHandle_t task_handle = NULL; BaseType_t result = xTaskCreate( (TaskFunction_t)thread, name, stacksize, arg, prio, &task_handle ); if (result != pdPASS) { return NULL; } return task_handle; } /*--------------------------------------------------------------------------- * Critical Section Protection *---------------------------------------------------------------------------*/ /** * @brief Enter critical section * @return Previous interrupt state */ sys_prot_t sys_arch_protect(void) { taskENTER_CRITICAL(); return 0; } /** * @brief Leave critical section * @param pval Previous interrupt state (unused in FreeRTOS) */ void sys_arch_unprotect(sys_prot_t pval) { (void)pval; taskEXIT_CRITICAL(); }