Files

381 lines
8.5 KiB
C

/**
* @file sys_arch.c
* @brief LwIP system architecture implementation for FreeRTOS
*/
#include "lwip/opt.h"
#include "lwip/mem.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 <string.h>
int errno;
/* 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();
}