638 lines
15 KiB
C
638 lines
15 KiB
C
/**
|
|
* @file - sys_arch.c
|
|
* System Architecture support routines for TI Tiva devices.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
* 3. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
* OF SUCH DAMAGE.
|
|
*
|
|
* This file is part of the lwIP TCP/IP stack.
|
|
*
|
|
* Author: Adam Dunkels <adam@sics.se>
|
|
*
|
|
*/
|
|
|
|
/* Copyright (c) 2008 Texas Instruments Incorporated */
|
|
|
|
/* lwIP includes. */
|
|
#include "lwip/opt.h"
|
|
#include "lwip/sys.h"
|
|
|
|
#if NO_SYS
|
|
|
|
#if SYS_LIGHTWEIGHT_PROT
|
|
|
|
/* TivaWare header files required for this interface driver. */
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include "inc/hw_types.h"
|
|
#include "driverlib/interrupt.h"
|
|
#include "driverlib/rom.h"
|
|
#include "driverlib/rom_map.h"
|
|
|
|
/**
|
|
* This global is defined in lwiplib.c and contains a count of the number of
|
|
* elapsed milliseconds since lwIP started.
|
|
*/
|
|
extern uint32_t g_ui32LocalTimer;
|
|
|
|
/**
|
|
* This function returns the system time in milliseconds.
|
|
*/
|
|
u32_t
|
|
sys_now(void)
|
|
{
|
|
return(g_ui32LocalTimer);
|
|
}
|
|
|
|
|
|
/**
|
|
* This function is used to lock access to critical sections when lwipopt.h
|
|
* defines SYS_LIGHTWEIGHT_PROT. It disables interrupts and returns a value
|
|
* indicating the interrupt enable state when the function entered. This
|
|
* value must be passed back on the matching call to sys_arch_unprotect().
|
|
*
|
|
* @return the interrupt level when the function was entered.
|
|
*/
|
|
sys_prot_t
|
|
sys_arch_protect(void)
|
|
{
|
|
return((sys_prot_t)MAP_IntMasterDisable());
|
|
}
|
|
|
|
/**
|
|
* This function is used to unlock access to critical sections when lwipopt.h
|
|
* defines SYS_LIGHTWEIGHT_PROT. It enables interrupts if the value of the lev
|
|
* parameter indicates that they were enabled when the matching call to
|
|
* sys_arch_protect() was made.
|
|
*
|
|
* @param lev is the interrupt level when the matching protect function was
|
|
* called
|
|
*/
|
|
void
|
|
sys_arch_unprotect(sys_prot_t lev)
|
|
{
|
|
/* Only turn interrupts back on if they were originally on when the matching
|
|
sys_arch_protect() call was made. */
|
|
if(!(lev & 1)) {
|
|
MAP_IntMasterEnable();
|
|
}
|
|
}
|
|
#endif /* SYS_LIGHTWEIGHT_PROT */
|
|
|
|
#else /* NO_SYS */
|
|
|
|
/* A structure to contain the variables for a sys_thread_t. */
|
|
typedef struct {
|
|
void *stackstart;
|
|
void *stackend;
|
|
void (*thread)(void *arg);
|
|
void *arg;
|
|
#if RTOS_FREERTOS
|
|
xTaskHandle taskhandle;
|
|
#endif /* RTOS_FREERTOS */
|
|
} thread_t;
|
|
|
|
/* Provide a default maximum number of threads. */
|
|
#ifndef SYS_THREAD_MAX
|
|
#define SYS_THREAD_MAX 4
|
|
#endif /* SYS_THREAD_MAX */
|
|
|
|
/* Provide a default maximum number of semaphores. */
|
|
#ifndef SYS_SEM_MAX
|
|
#define SYS_SEM_MAX 4
|
|
#endif /* SYS_SEM_MAX */
|
|
|
|
/* Provide a default maximum number of mailboxes. */
|
|
#ifndef SYS_MBOX_MAX
|
|
#define SYS_MBOX_MAX 4
|
|
#endif /* SYS_MBOX_MAX */
|
|
|
|
/* An array to hold the memory for the available semaphores. */
|
|
static sem_t sems[SYS_SEM_MAX];
|
|
|
|
/* An array to hold the memory for the available mailboxes. */
|
|
static mbox_t mboxes[SYS_MBOX_MAX];
|
|
|
|
/* An array to hold the memory for the available threads. */
|
|
static thread_t threads[SYS_THREAD_MAX];
|
|
|
|
/**
|
|
* Initializes the system architecture layer.
|
|
*
|
|
*/
|
|
void
|
|
sys_init(void)
|
|
{
|
|
u32_t i;
|
|
|
|
/* Clear out the mailboxes. */
|
|
for(i = 0; i < SYS_MBOX_MAX; i++) {
|
|
mboxes[i].queue = 0;
|
|
}
|
|
|
|
/* Clear out the semaphores. */
|
|
for(i = 0; i < SYS_SEM_MAX; i++) {
|
|
sems[i].queue = 0;
|
|
}
|
|
|
|
/* Clear out the threads. */
|
|
for(i = 0; i < SYS_THREAD_MAX; i++) {
|
|
threads[i].stackstart = NULL;
|
|
threads[i].stackend = NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates a new semaphore.
|
|
*
|
|
* @param count is non-zero if the semaphore should be acquired initially.
|
|
* @return the handle of the created semaphore.
|
|
*/
|
|
err_t
|
|
sys_sem_new(sys_sem_t *sem, u8_t count)
|
|
{
|
|
void *temp;
|
|
u32_t i;
|
|
|
|
/* Find a semaphore that is not in use. */
|
|
for(i = 0; i < SYS_SEM_MAX; i++) {
|
|
if(sems[i].queue == 0) {
|
|
break;
|
|
}
|
|
}
|
|
if(i == SYS_SEM_MAX) {
|
|
#if SYS_STATS
|
|
STATS_INC(sys.sem.err);
|
|
#endif /* SYS_STATS */
|
|
return ERR_MEM;
|
|
}
|
|
|
|
/* Create a single-entry queue to act as a semaphore. */
|
|
#if RTOS_FREERTOS
|
|
sem->queue = xQueueCreate(1, sizeof(void *));
|
|
if(sem->queue == NULL) {
|
|
#endif /* RTOS_FREERTOS */
|
|
|
|
#if SYS_STATS
|
|
STATS_INC(sys.sem.err);
|
|
#endif /* SYS_STATS */
|
|
return ERR_MEM;
|
|
}
|
|
|
|
/* Acquired the semaphore if necessary. */
|
|
if(count == 0) {
|
|
temp = 0;
|
|
xQueueSend(sem->queue, &temp, 0);
|
|
}
|
|
|
|
/* Update the semaphore statistics. */
|
|
#if SYS_STATS
|
|
STATS_INC(sys.sem.used);
|
|
#if LWIP_STATS
|
|
if(lwip_stats.sys.sem.max < lwip_stats.sys.sem.used) {
|
|
lwip_stats.sys.sem.max = lwip_stats.sys.sem.used;
|
|
}
|
|
#endif
|
|
#endif /* SYS_STATS */
|
|
|
|
/* Save the queue handle. */
|
|
sems[i].queue = sem->queue;
|
|
|
|
/* Return this semaphore. */
|
|
return (ERR_OK);
|
|
}
|
|
|
|
/**
|
|
* Signal a semaphore.
|
|
*
|
|
* @param sem is the semaphore to signal.
|
|
*/
|
|
void
|
|
sys_sem_signal(sys_sem_t *sem)
|
|
{
|
|
void *msg;
|
|
|
|
/* Receive a message from the semaphore's queue. */
|
|
xQueueReceive(sem->queue, &msg, 0);
|
|
}
|
|
|
|
/**
|
|
* Wait for a semaphore to be signalled.
|
|
*
|
|
* @param sem is the semaphore
|
|
* @param timeout is the maximum number of milliseconds to wait for the
|
|
* semaphore to be signalled
|
|
* @return the number of milliseconds that passed before the semaphore was
|
|
* acquired, or SYS_ARCH_TIMEOUT if the timeout occurred
|
|
*/
|
|
u32_t
|
|
sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
|
|
{
|
|
portTickType starttime;
|
|
void *msg = 0;
|
|
|
|
/* Get the starting time. */
|
|
starttime = xTaskGetTickCount();
|
|
|
|
/* See if there is a timeout. */
|
|
if(timeout != 0) {
|
|
/* Send a message to the queue. */
|
|
if(xQueueSend(sem->queue, &msg, timeout / portTICK_RATE_MS) == pdPASS) {
|
|
/* Return the amount of time it took for the semaphore to be
|
|
signalled. */
|
|
return (xTaskGetTickCount() - starttime) * portTICK_RATE_MS;
|
|
} else {
|
|
/* The semaphore failed to signal in the allotted time. */
|
|
return SYS_ARCH_TIMEOUT;
|
|
}
|
|
} else {
|
|
/* Try to send a message to the queue until it succeeds. */
|
|
while(xQueueSend(sem->queue, &msg, portMAX_DELAY) != pdPASS);
|
|
|
|
/* Return the amount of time it took for the semaphore to be signalled. */
|
|
return (xTaskGetTickCount() - starttime) * portTICK_RATE_MS;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Destroys a semaphore.
|
|
*
|
|
* @param sem is the semaphore to be destroyed.
|
|
*/
|
|
void
|
|
sys_sem_free(sys_sem_t *sem)
|
|
{
|
|
/* Clear the queue handle. */
|
|
sem->queue = 0;
|
|
|
|
/* Update the semaphore statistics. */
|
|
#if SYS_STATS
|
|
STATS_DEC(sys.sem.used);
|
|
#endif /* SYS_STATS */
|
|
}
|
|
|
|
/**
|
|
* Creates a new mailbox.
|
|
*
|
|
* @param size is the number of entries in the mailbox.
|
|
* @return the handle of the created mailbox.
|
|
*/
|
|
err_t
|
|
sys_mbox_new(sys_mbox_t *mbox, int size)
|
|
{
|
|
u32_t i;
|
|
|
|
/* Fail if the mailbox size is too large. */
|
|
if(size > MBOX_MAX) {
|
|
#if SYS_STATS
|
|
STATS_INC(sys.mbox.err);
|
|
#endif /* SYS_STATS */
|
|
return ERR_MEM;
|
|
}
|
|
|
|
/* Find a mailbox that is not in use. */
|
|
for(i = 0; i < SYS_MBOX_MAX; i++) {
|
|
if(mboxes[i].queue == 0) {
|
|
break;
|
|
}
|
|
}
|
|
if(i == SYS_MBOX_MAX) {
|
|
#if SYS_STATS
|
|
STATS_INC(sys.mbox.err);
|
|
#endif /* SYS_STATS */
|
|
return ERR_MEM;
|
|
}
|
|
|
|
#if RTOS_FREERTOS
|
|
/* Create a queue for this mailbox. */
|
|
mbox->queue = xQueueCreate(size, sizeof(void *));
|
|
if(mbox == NULL) {
|
|
#endif /* RTOS_FREERTOS */
|
|
|
|
#if SYS_STATS
|
|
STATS_INC(sys.mbox.err);
|
|
#endif /* SYS_STATS */
|
|
return ERR_MEM;
|
|
}
|
|
|
|
/* Update the mailbox statistics. */
|
|
#if SYS_STATS
|
|
STATS_INC(sys.mbox.used);
|
|
#if LWIP_STATS
|
|
if(lwip_stats.sys.mbox.max < lwip_stats.sys.mbox.used) {
|
|
lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used;
|
|
}
|
|
#endif
|
|
#endif /* SYS_STATS */
|
|
|
|
/* Save the queue handle. */
|
|
mboxes[i].queue = mbox->queue;
|
|
|
|
/* Return this mailbox. */
|
|
return ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* Sends a message to a mailbox.
|
|
*
|
|
* @param mbox is the mailbox
|
|
* @param msg is the message to send
|
|
*/
|
|
void
|
|
sys_mbox_post(sys_mbox_t *mbox, void *msg)
|
|
{
|
|
/* Send this message to the queue. */
|
|
while(xQueueSend(mbox->queue, &msg, portMAX_DELAY) != pdPASS);
|
|
}
|
|
|
|
/**
|
|
* Tries to send a message to a mailbox.
|
|
*
|
|
* @param mbox is the mailbox
|
|
* @param msg is the message to send
|
|
* @return ERR_OK if the message was sent and ERR_MEM if there was no space for
|
|
* the message
|
|
*/
|
|
err_t
|
|
sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
|
|
{
|
|
/* Send this message to the queue. */
|
|
if(xQueueSend(mbox->queue, &msg, 0) == pdPASS) {
|
|
return ERR_OK;
|
|
}
|
|
|
|
/* Update the mailbox statistics. */
|
|
#if SYS_STATS
|
|
STATS_INC(sys.mbox.err);
|
|
#endif /* SYS_STATS */
|
|
|
|
/* The message could not be sent. */
|
|
return ERR_MEM;
|
|
}
|
|
|
|
/**
|
|
* Retrieve a message from a mailbox.
|
|
*
|
|
* @param mbox is the mailbox
|
|
* @param msg is a pointer to the location to receive the message
|
|
* @param timeout is the maximum number of milliseconds to wait for the message
|
|
* @return the number of milliseconds that passed before the message was
|
|
* received, or SYS_ARCH_TIMEOUT if the tmieout occurred
|
|
*/
|
|
u32_t
|
|
sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
|
|
{
|
|
portTickType starttime;
|
|
void *dummyptr;
|
|
|
|
/* If the actual message contents are not required, provide a local variable
|
|
to recieve the message. */
|
|
if(msg == NULL) {
|
|
msg = &dummyptr;
|
|
}
|
|
|
|
/* Get the starting time. */
|
|
starttime = xTaskGetTickCount();
|
|
|
|
/* See if there is a timeout. */
|
|
if(timeout != 0) {
|
|
/* Receive a message from the queue. */
|
|
if(xQueueReceive(mbox->queue, msg, timeout / portTICK_RATE_MS) == pdPASS) {
|
|
/* Return the amount of time it took for the message to be received. */
|
|
return (xTaskGetTickCount() - starttime) * portTICK_RATE_MS;
|
|
} else {
|
|
/* No message arrived in the allotted time. */
|
|
*msg = NULL;
|
|
return SYS_ARCH_TIMEOUT;
|
|
}
|
|
} else {
|
|
/* Try to receive a message until one arrives. */
|
|
while(xQueueReceive(mbox->queue, msg, portMAX_DELAY) != pdPASS);
|
|
|
|
/* Return the amount of time it took for the message to be received. */
|
|
return (xTaskGetTickCount() - starttime) * portTICK_RATE_MS;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Try to receive a message from a mailbox, returning immediately if one is not
|
|
* available.
|
|
*
|
|
* @param mbox is the mailbox
|
|
* @param msg is a pointer to the location to receive the message
|
|
* @return ERR_OK if a message was available and SYS_MBOX_EMPTY if one was not
|
|
* available
|
|
*/
|
|
u32_t
|
|
sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
|
|
{
|
|
void *dummyptr;
|
|
|
|
/* If the actual message contents are not required, provide a local variable
|
|
to recieve the message. */
|
|
if(msg == NULL) {
|
|
msg = &dummyptr;
|
|
}
|
|
|
|
/* Recieve a message from the queue. */
|
|
if(xQueueReceive(mbox->queue, msg, 0) == pdPASS) {
|
|
/* A message was available. */
|
|
return ERR_OK;
|
|
} else {
|
|
/* A message was not available. */
|
|
return SYS_MBOX_EMPTY;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Destroys a mailbox.
|
|
*
|
|
* @param mbox is the mailbox to be destroyed.
|
|
*/
|
|
void
|
|
sys_mbox_free(sys_mbox_t *mbox)
|
|
{
|
|
/* There should not be any messages waiting (if there are it is a bug). If
|
|
any are waiting, increment the mailbox error count. */
|
|
#if RTOS_FREERTOS
|
|
if(uxQueueMessagesWaiting(mbox->queue) != 0) {
|
|
#endif /* RTOS_FREERTOS */
|
|
|
|
#if SYS_STATS
|
|
STATS_INC(sys.mbox.err);
|
|
#endif /* SYS_STATS */
|
|
}
|
|
|
|
/* Clear the queue handle. */
|
|
mbox->queue = 0;
|
|
|
|
/* Update the mailbox statistics. */
|
|
#if SYS_STATS
|
|
STATS_DEC(sys.mbox.used);
|
|
#endif /* SYS_STATS */
|
|
}
|
|
|
|
/**
|
|
* Checks the validity of a mailbox.
|
|
*
|
|
* @param mbox is the mailbox whose validity is to be checked.
|
|
*/
|
|
int
|
|
sys_mbox_valid(sys_mbox_t *mbox)
|
|
{
|
|
/*Check if a mailbox has been created*/
|
|
if(mbox->queue == SYS_MBOX_NULL){
|
|
return 0;
|
|
}
|
|
else{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The routine for a thread. This handles some housekeeping around the
|
|
* applications's thread routine.
|
|
*
|
|
* @param arg is the index into the thread structure for this thread
|
|
*/
|
|
static void
|
|
sys_arch_thread(void *arg)
|
|
{
|
|
u32_t i;
|
|
|
|
/* Get this threads index. */
|
|
i = (u32_t)arg;
|
|
|
|
/* Call the application's thread routine. */
|
|
threads[i].thread(threads[i].arg);
|
|
|
|
/* Free the memory used by this thread's stack. */
|
|
mem_free(threads[i].stackstart);
|
|
|
|
/* Clear the stack from the thread structure. */
|
|
threads[i].stackstart = NULL;
|
|
threads[i].stackend = NULL;
|
|
|
|
/* Delete this task. */
|
|
#if RTOS_FREERTOS
|
|
vTaskDelete(NULL);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Creates a new thread.
|
|
*
|
|
* @param name is the name of this thread
|
|
* @param thread is a pointer to the function to run in the new thread
|
|
* @param arg is the argument to pass to the thread's function
|
|
* @param stacksize is the size of the stack to allocate for this thread
|
|
* @param prio is the priority of the new thread
|
|
* @return the handle fo the created thread
|
|
*/
|
|
sys_thread_t
|
|
sys_thread_new(const char *name, lwip_thread_fn thread, void *arg,
|
|
int stacksize, int prio)
|
|
{
|
|
sys_thread_t created_thread;
|
|
void *data;
|
|
u32_t i;
|
|
|
|
/* Find a thread that is not in use. */
|
|
for(i = 0; i < SYS_THREAD_MAX; i++) {
|
|
if(threads[i].stackstart == NULL) {
|
|
break;
|
|
}
|
|
}
|
|
if(i == SYS_THREAD_MAX) {
|
|
return NULL;
|
|
}
|
|
|
|
/* Allocate memory for the thread's stack. */
|
|
data = mem_malloc(stacksize);
|
|
if(!data) {
|
|
return NULL;
|
|
}
|
|
|
|
/* Save the details of this thread. */
|
|
threads[i].stackstart = data;
|
|
threads[i].stackend = (void *)((char *)data + stacksize);
|
|
threads[i].thread = thread;
|
|
threads[i].arg = arg;
|
|
|
|
/* Create a new thread. */
|
|
#if RTOS_FREERTOS
|
|
if(xTaskCreate(sys_arch_thread, (signed portCHAR *)name,
|
|
stacksize/sizeof(int), (void *)i, tskIDLE_PRIORITY+prio,
|
|
&threads[i].taskhandle) != pdTRUE){
|
|
threads[i].stackstart = NULL;
|
|
threads[i].stackend = NULL;
|
|
return NULL;
|
|
}
|
|
created_thread = threads[i].taskhandle;
|
|
#endif /* RTOS_FREERTOS */
|
|
|
|
/* Return this thread. */
|
|
return created_thread;
|
|
}
|
|
|
|
/**
|
|
* Enters a critical section.
|
|
*
|
|
* @return the previous protection level
|
|
*/
|
|
sys_prot_t
|
|
sys_arch_protect(void)
|
|
{
|
|
#if RTOS_FREERTOS
|
|
taskENTER_CRITICAL();
|
|
#endif
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Leaves a critical section.
|
|
*
|
|
* @param the preivous protection level
|
|
*/
|
|
void
|
|
sys_arch_unprotect(sys_prot_t val)
|
|
{
|
|
#if RTOS_FREERTOS
|
|
taskEXIT_CRITICAL();
|
|
#endif
|
|
}
|
|
|
|
u32_t
|
|
sys_now(void)
|
|
{
|
|
return xTaskGetTickCount() * portTICK_PERIOD_MS;
|
|
}
|
|
|
|
#endif /* NO_SYS */
|