381 lines
8.5 KiB
C
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();
|
|
}
|