--- /dev/null
+/* This source file is part of the ATMEL FREERTOS-0.9.0 Release */\r
+\r
+/*This file has been prepared for Doxygen automatic documentation generation.*/\r
+/*! \file *********************************************************************\r
+ *\r
+ * \brief lwIP abstraction layer for AVR32 UC3.\r
+ *\r
+ * - Compiler: GNU GCC for AVR32\r
+ * - Supported devices: All AVR32 devices can be used.\r
+ * - AppNote:\r
+ *\r
+ * \author Atmel Corporation: http://www.atmel.com \n\r
+ * Support email: avr32@atmel.com\r
+ *\r
+ *****************************************************************************/\r
+\r
+/* Copyright (c) 2007, Atmel Corporation All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ * this list of conditions and the following disclaimer.\r
+ *\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ * this list of conditions and the following disclaimer in the documentation\r
+ * and/or other materials provided with the distribution.\r
+ *\r
+ * 3. The name of ATMEL may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND\r
+ * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,\r
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+\r
+#include "conf_eth.h"\r
+\r
+#if (HTTP_USED == 1)\r
+ #include "BasicWEB.h"\r
+#endif\r
+\r
+#if (TFTP_USED == 1)\r
+ #include "BasicTFTP.h"\r
+#endif\r
+\r
+#if (SMTP_USED == 1)\r
+ #include "BasicSMTP.h"\r
+#endif\r
+\r
+/* lwIP includes. */\r
+#include "lwip/debug.h"\r
+#include "lwip/def.h"\r
+#include "lwip/sys.h"\r
+#include "lwip/mem.h"\r
+\r
+/* Message queue constants. */\r
+#define archMESG_QUEUE_LENGTH ( 6 )\r
+#define archPOST_BLOCK_TIME_MS ( ( unsigned portLONG ) 10000 )\r
+\r
+struct timeoutlist \r
+{\r
+ struct sys_timeouts timeouts;\r
+ xTaskHandle pid;\r
+};\r
+\r
+static struct timeoutlist timeoutlist[SYS_THREAD_MAX];\r
+static u16_t nextthread = 0;\r
+int intlevel = 0;\r
+\r
+extern void ethernetif_input( void * pvParameters );\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+// Creates an empty mailbox.\r
+sys_mbox_t\r
+sys_mbox_new(void)\r
+{\r
+ xQueueHandle mbox;\r
+\r
+ mbox = xQueueCreate( archMESG_QUEUE_LENGTH, sizeof( void * ) );\r
+\r
+ return mbox;\r
+}\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+/*\r
+ Deallocates a mailbox. If there are messages still present in the\r
+ mailbox when the mailbox is deallocated, it is an indication of a\r
+ programming error in lwIP and the developer should be notified.\r
+*/\r
+void\r
+sys_mbox_free(sys_mbox_t mbox)\r
+{\r
+ if( uxQueueMessagesWaiting( mbox ) )\r
+ {\r
+ /* Line for breakpoint. Should never break here! */\r
+ __asm volatile ( "NOP" );\r
+ }\r
+\r
+ vQueueDelete( mbox );\r
+}\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+// Posts the "msg" to the mailbox.\r
+void\r
+sys_mbox_post(sys_mbox_t mbox, void *data)\r
+{ \r
+ xQueueSend( mbox, &data, ( portTickType ) ( archPOST_BLOCK_TIME_MS / portTICK_RATE_MS ) );\r
+}\r
+\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+/*\r
+ Blocks the thread until a message arrives in the mailbox, but does\r
+ not block the thread longer than "timeout" milliseconds (similar to\r
+ the sys_arch_sem_wait() function). The "msg" argument is a result\r
+ parameter that is set by the function (i.e., by doing "*msg =\r
+ ptr"). The "msg" parameter maybe NULL to indicate that the message\r
+ should be dropped.\r
+\r
+ The return values are the same as for the sys_arch_sem_wait() function:\r
+ Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a\r
+ timeout.\r
+\r
+ Note that a function with a similar name, sys_mbox_fetch(), is\r
+ implemented by lwIP. \r
+*/\r
+u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)\r
+{\r
+void *dummyptr;\r
+portTickType StartTime, EndTime, Elapsed;\r
+\r
+ StartTime = xTaskGetTickCount();\r
+\r
+ if( msg == NULL )\r
+ {\r
+ msg = &dummyptr;\r
+ }\r
+ \r
+ if( timeout != 0 )\r
+ {\r
+ if(pdTRUE == xQueueReceive( mbox, &(*msg), timeout ) )\r
+ {\r
+ EndTime = xTaskGetTickCount();\r
+ Elapsed = EndTime - StartTime;\r
+ if( Elapsed == 0 )\r
+ {\r
+ Elapsed = 1;\r
+ }\r
+ return ( Elapsed );\r
+ }\r
+ else // timed out blocking for message\r
+ {\r
+ *msg = NULL;\r
+ return SYS_ARCH_TIMEOUT;\r
+ }\r
+ }\r
+ else // block forever for a message.\r
+ {\r
+ while( pdTRUE != xQueueReceive( mbox, &(*msg), 10000 ) ) // time is arbitrary\r
+ {\r
+ ;\r
+ }\r
+ EndTime = xTaskGetTickCount();\r
+ Elapsed = EndTime - StartTime;\r
+ if( Elapsed == 0 )\r
+ {\r
+ Elapsed = 1;\r
+ }\r
+ return ( Elapsed ); // return time blocked TBD test\r
+ }\r
+}\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+// Creates and returns a new semaphore. The "count" argument specifies\r
+// the initial state of the semaphore. TBD finish and test\r
+sys_sem_t\r
+sys_sem_new(u8_t count)\r
+{\r
+ xSemaphoreHandle xSemaphore = NULL;\r
+\r
+ portENTER_CRITICAL();\r
+ vSemaphoreCreateBinary( xSemaphore );\r
+ if( xSemaphore == NULL )\r
+ {\r
+ return NULL; // TBD need assert\r
+ }\r
+ if(count == 0) // Means we want the sem to be unavailable at init state.\r
+ {\r
+ xSemaphoreTake(xSemaphore,1);\r
+ }\r
+ portEXIT_CRITICAL();\r
+\r
+ return xSemaphore;\r
+}\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+/*\r
+ Blocks the thread while waiting for the semaphore to be\r
+ signaled. If the "timeout" argument is non-zero, the thread should\r
+ only be blocked for the specified time (measured in\r
+ milliseconds).\r
+\r
+ If the timeout argument is non-zero, the return value is the number of\r
+ milliseconds spent waiting for the semaphore to be signaled. If the\r
+ semaphore wasn't signaled within the specified time, the return value is\r
+ SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore\r
+ (i.e., it was already signaled), the function may return zero.\r
+\r
+ Notice that lwIP implements a function with a similar name,\r
+ sys_sem_wait(), that uses the sys_arch_sem_wait() function.\r
+*/\r
+u32_t\r
+sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)\r
+{\r
+portTickType StartTime, EndTime, Elapsed;\r
+\r
+ StartTime = xTaskGetTickCount();\r
+\r
+ if( timeout != 0)\r
+ {\r
+ if( xSemaphoreTake( sem, timeout ) == pdTRUE )\r
+ {\r
+ EndTime = xTaskGetTickCount();\r
+ Elapsed = EndTime - StartTime;\r
+ if( Elapsed == 0 )\r
+ {\r
+ Elapsed = 1;\r
+ }\r
+ return (Elapsed); // return time blocked TBD test\r
+ }\r
+ else\r
+ {\r
+ return SYS_ARCH_TIMEOUT;\r
+ }\r
+ }\r
+ else // must block without a timeout\r
+ {\r
+ while( xSemaphoreTake( sem, 10000 ) != pdTRUE )\r
+ {\r
+ ;\r
+ }\r
+ EndTime = xTaskGetTickCount();\r
+ Elapsed = EndTime - StartTime;\r
+ if( Elapsed == 0 )\r
+ {\r
+ Elapsed = 1;\r
+ }\r
+\r
+ return ( Elapsed ); // return time blocked\r
+ \r
+ }\r
+}\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+// Signals a semaphore\r
+void\r
+sys_sem_signal(sys_sem_t sem)\r
+{\r
+ xSemaphoreGive( sem );\r
+}\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+// Deallocates a semaphore\r
+void\r
+sys_sem_free(sys_sem_t sem)\r
+{\r
+ vQueueDelete( sem );\r
+}\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+// Initialize sys arch\r
+void\r
+sys_init(void)\r
+{\r
+\r
+ int i;\r
+\r
+ // Initialize the the per-thread sys_timeouts structures\r
+ // make sure there are no valid pids in the list\r
+ for(i = 0; i < SYS_THREAD_MAX; i++)\r
+ {\r
+ timeoutlist[i].pid = 0;\r
+ timeoutlist[i].timeouts.next = NULL;\r
+ }\r
+\r
+ // keep track of how many threads have been created\r
+ nextthread = 0;\r
+}\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+/*\r
+ Returns a pointer to the per-thread sys_timeouts structure. In lwIP,\r
+ each thread has a list of timeouts which is represented as a linked\r
+ list of sys_timeout structures. The sys_timeouts structure holds a\r
+ pointer to a linked list of timeouts. This function is called by\r
+ the lwIP timeout scheduler and must not return a NULL value. \r
+\r
+ In a single threaded sys_arch implementation, this function will\r
+ simply return a pointer to a global sys_timeouts variable stored in\r
+ the sys_arch module.\r
+*/\r
+struct sys_timeouts *\r
+sys_arch_timeouts(void)\r
+{\r
+int i;\r
+xTaskHandle pid;\r
+struct timeoutlist *tl; \r
+\r
+ pid = xTaskGetCurrentTaskHandle( );\r
+\r
+ for(i = 0; i < nextthread; i++)\r
+ {\r
+ tl = &(timeoutlist[i]);\r
+ if(tl->pid == pid)\r
+ {\r
+ return &(tl->timeouts);\r
+ }\r
+ }\r
+\r
+\r
+ // If we're here, this means the scheduler gave the focus to the task as it was\r
+ // being created(because of a higher priority). Since timeoutlist[] update is\r
+ // done just after the task creation, the array is not up-to-date.\r
+ // => the last array entry must be the one of the current task.\r
+ return( &( timeoutlist[nextthread].timeouts ) );\r
+/*\r
+ // Error\r
+ return NULL;\r
+*/\r
+}\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+/*-----------------------------------------------------------------------------------*/\r
+// TBD \r
+/*-----------------------------------------------------------------------------------*/\r
+/*\r
+ Starts a new thread with priority "prio" that will begin its execution in the\r
+ function "thread()". The "arg" argument will be passed as an argument to the\r
+ thread() function. The id of the new thread is returned. Both the id and\r
+ the priority are system dependent.\r
+*/\r
+sys_thread_t sys_thread_new(void (* thread)(void *arg), void *arg, int prio)\r
+{\r
+xTaskHandle CreatedTask;\r
+int result = pdFAIL;\r
+static int iCall = 0;\r
+\r
+ if( thread == ethernetif_input )\r
+ {\r
+ result = xTaskCreate( thread, ( signed portCHAR * ) "ETHINT", netifINTERFACE_TASK_STACK_SIZE, arg, prio, &CreatedTask );\r
+ }\r
+ else if( iCall == 0 )\r
+ {\r
+ /* The first time this is called we are creating the lwIP handler. */\r
+ result = xTaskCreate( thread, ( signed portCHAR * ) "lwIP", lwipINTERFACE_STACK_SIZE, arg, prio, &CreatedTask );\r
+ iCall++;\r
+ }\r
+#if (HTTP_USED == 1)\r
+ else if (thread == vBasicWEBServer)\r
+ {\r
+ result = xTaskCreate( thread, ( signed portCHAR * ) "WEB", lwipBASIC_WEB_SERVER_STACK_SIZE, arg, prio, &CreatedTask );\r
+ }\r
+#endif\r
+#if (TFTP_USED == 1)\r
+ else if (thread == vBasicTFTPServer)\r
+ {\r
+ result = xTaskCreate( thread, ( signed portCHAR * ) "TFTP", lwipBASIC_TFTP_SERVER_STACK_SIZE, arg, prio, &CreatedTask );\r
+ }\r
+#endif\r
+#if (SMTP_USED == 1)\r
+ else if (thread == vBasicSMTPHost)\r
+ {\r
+ result = xTaskCreate( thread, ( signed portCHAR * ) "SMTP", lwipBASIC_SMTP_HOST_STACK_SIZE, arg, prio, &CreatedTask );\r
+ }\r
+#endif\r
+\r
+\r
+ // For each task created, store the task handle (pid) in the timers array.\r
+ // This scheme doesn't allow for threads to be deleted\r
+ timeoutlist[nextthread++].pid = CreatedTask;\r
+\r
+ if(result == pdPASS)\r
+ {\r
+ return CreatedTask;\r
+ }\r
+ else\r
+ {\r
+ return NULL;\r
+ }\r
+}\r
+\r
+/*\r
+ This optional function does a "fast" critical region protection and returns\r
+ the previous protection level. This function is only called during very short\r
+ critical regions. An embedded system which supports ISR-based drivers might\r
+ want to implement this function by disabling interrupts. Task-based systems\r
+ might want to implement this by using a mutex or disabling tasking. This\r
+ function should support recursive calls from the same task or interrupt. In\r
+ other words, sys_arch_protect() could be called while already protected. In\r
+ that case the return value indicates that it is already protected.\r
+\r
+ sys_arch_protect() is only required if your port is supporting an operating\r
+ system.\r
+*/\r
+sys_prot_t sys_arch_protect(void)\r
+{\r
+ vPortEnterCritical();\r
+ return 1;\r
+}\r
+\r
+/*\r
+ This optional function does a "fast" set of critical region protection to the\r
+ value specified by pval. See the documentation for sys_arch_protect() for\r
+ more information. This function is only required if your port is supporting\r
+ an operating system.\r
+*/\r
+void sys_arch_unprotect(sys_prot_t pval)\r
+{ \r
+ ( void ) pval;\r
+ vPortExitCritical();\r
+}\r
+\r