feat(lwip): Restructure lwip folder to support different platform

This commit is contained in:
Wu Jian Gang
2018-05-19 21:13:51 +08:00
parent ae881ecda4
commit 6fbcd9f823
8 changed files with 22 additions and 16 deletions

View File

@ -0,0 +1,493 @@
/*
* 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>
*
*/
/* lwIP includes. */
#include "lwip/debug.h"
#include "lwip/def.h"
#include "lwip/sys.h"
#include "lwip/mem.h"
#include "arch/sys_arch.h"
#define LWIP_THREAD_TLS 0
/* Message queue constants. */
#define archMESG_QUEUE_LENGTH (100)//( 6 )
#define archPOST_BLOCK_TIME_MS ( ( unsigned portLONG ) 10000 )
struct timeoutlist {
//struct sys_timeouts timeouts;
xTaskHandle pid;
};
/* This is the number of threads that can be started with sys_thread_new() */
#define SYS_THREAD_MAX 4
//static struct timeoutlist timeoutlist[SYS_THREAD_MAX];
//static u16_t nextthread = 0;
int intlevel = 0;
/*-----------------------------------------------------------------------------------*/
// Initialize sys arch
void
sys_init(void)
{
}
/*-----------------------------------------------------------------------------------*/
// Creates and returns a new semaphore. The "count" argument specifies
// the initial state of the semaphore. TBD finish and test
err_t
sys_sem_new(sys_sem_t *sem, u8_t count)
{
err_t xReturn = ERR_MEM;
vSemaphoreCreateBinary(*sem);
if ((*sem) != NULL) {
if (count == 0) { // Means it can't be taken
xSemaphoreTake(*sem, 1);
}
xReturn = ERR_OK;
} else {
; // TBD need assert
}
return xReturn;
}
/*-----------------------------------------------------------------------------------*/
// Deallocates a semaphore
void
sys_sem_free(sys_sem_t *sem)
{
//vQueueDelete( sem );
vSemaphoreDelete(*sem);
}
/*-----------------------------------------------------------------------------------*/
// Signals a semaphore
void
sys_sem_signal(sys_sem_t *sem)
{
xSemaphoreGive(*sem);
}
/*-----------------------------------------------------------------------------------*/
/*
Blocks the thread while waiting for the semaphore to be
signaled. If the "timeout" argument is non-zero, the thread should
only be blocked for the specified time (measured in
milliseconds).
If the timeout argument is non-zero, the return value is the number of
milliseconds spent waiting for the semaphore to be signaled. If the
semaphore wasn't signaled within the specified time, the return value is
SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
(i.e., it was already signaled), the function may return zero.
Notice that lwIP implements a function with a similar name,
sys_sem_wait(), that uses the sys_arch_sem_wait() function.
*/
u32_t
sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
{
portTickType StartTime, EndTime, Elapsed;
unsigned long ulReturn;
StartTime = xTaskGetTickCount();
if (timeout != 0) {
if (xSemaphoreTake(*sem, timeout / portTICK_RATE_MS) == pdTRUE) {
EndTime = xTaskGetTickCount();
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
if (Elapsed == 0) {
Elapsed = 1;
}
ulReturn = Elapsed;
} else {
ulReturn = SYS_ARCH_TIMEOUT;
}
} else { // must block without a timeout
while (xSemaphoreTake(*sem, portMAX_DELAY) != pdTRUE);
EndTime = xTaskGetTickCount();
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
if (Elapsed == 0) {
Elapsed = 1;
}
ulReturn = Elapsed;
}
return ulReturn ; // return time blocked
}
/*-----------------------------------------------------------------------------------*/
// Creates an empty mailbox.
err_t
sys_mbox_new(sys_mbox_t *mbox, int size)
{
err_t xReturn = ERR_MEM;
*mbox = xQueueCreate(size, sizeof(void *));
if (*mbox != NULL) {
xReturn = ERR_OK;
}
return xReturn;
}
/*-----------------------------------------------------------------------------------*/
/*
Deallocates a mailbox. If there are messages still present in the
mailbox when the mailbox is deallocated, it is an indication of a
programming error in lwIP and the developer should be notified.
*/
void
sys_mbox_free(sys_mbox_t *mbox)
{
if (uxQueueMessagesWaiting(*mbox)) {
/* Line for breakpoint. Should never break here! */
// __asm volatile ( "NOP" );
}
vQueueDelete(*mbox);
}
/*-----------------------------------------------------------------------------------*/
// Posts the "msg" to the mailbox.
void
sys_mbox_post(sys_mbox_t *mbox, void *msg)
{
while (xQueueSendToBack(*mbox, &msg, portMAX_DELAY) != pdTRUE);
}
err_t
sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
{
err_t xReturn;
if (xQueueSend(*mbox, &msg, (portTickType)0) == pdPASS) {
xReturn = ERR_OK;
} else {
xReturn = ERR_MEM;
}
return xReturn;
}
/*-----------------------------------------------------------------------------------*/
/*
Blocks the thread until a message arrives in the mailbox, but does
not block the thread longer than "timeout" milliseconds (similar to
the sys_arch_sem_wait() function). The "msg" argument is a result
parameter that is set by the function (i.e., by doing "*msg =
ptr"). The "msg" parameter maybe NULL to indicate that the message
should be dropped.
The return values are the same as for the sys_arch_sem_wait() function:
Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
timeout.
Note that a function with a similar name, sys_mbox_fetch(), is
implemented by lwIP.
*/
u32_t
sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
{
void *dummyptr;
portTickType StartTime, EndTime, Elapsed;
unsigned long ulReturn;
StartTime = xTaskGetTickCount();
if (msg == NULL) {
msg = &dummyptr;
}
if (timeout != 0) {
if (pdTRUE == xQueueReceive(*mbox, &(*msg), timeout / portTICK_RATE_MS)) {
EndTime = xTaskGetTickCount();
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
if (Elapsed == 0) {
Elapsed = 1;
}
ulReturn = Elapsed;
} else { // timed out blocking for message
*msg = NULL;
ulReturn = SYS_ARCH_TIMEOUT;
}
} else { // block forever for a message.
while (pdTRUE != xQueueReceive(*mbox, &(*msg), portMAX_DELAY));
EndTime = xTaskGetTickCount();
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
if (Elapsed == 0) {
Elapsed = 1;
}
ulReturn = Elapsed;
}
return ulReturn ; // return time blocked TBD test
}
u32_t
sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
{
void *pvDummy;
unsigned long ulReturn;
if (msg == NULL) {
msg = &pvDummy;
}
if (pdTRUE == xQueueReceive(*mbox, &(*msg), 0)) {
ulReturn = ERR_OK;
} else {
ulReturn = SYS_MBOX_EMPTY;
}
return ulReturn;
}
/** Create a new mutex
* @param mutex pointer to the mutex to create
* @return a new mutex */
err_t
sys_mutex_new(sys_mutex_t *pxMutex)
{
err_t xReturn = ERR_MEM;
*pxMutex = xSemaphoreCreateMutex();
if (*pxMutex != NULL) {
xReturn = ERR_OK;
} else {
;
}
return xReturn;
}
/** Lock a mutex
* @param mutex the mutex to lock */
void
sys_mutex_lock(sys_mutex_t *pxMutex)
{
while (xSemaphoreTake(*pxMutex, portMAX_DELAY) != pdPASS);
}
err_t
sys_mutex_trylock(sys_mutex_t *pxMutex)
{
if (xSemaphoreTake(*pxMutex, 0) == pdPASS) return 0;
else return -1;
}
/** Unlock a mutex
* @param mutex the mutex to unlock */
void
sys_mutex_unlock(sys_mutex_t *pxMutex)
{
xSemaphoreGive(*pxMutex);
}
/** Delete a semaphore
* @param mutex the mutex to delete */
void
sys_mutex_free(sys_mutex_t *pxMutex)
{
vQueueDelete(*pxMutex);
}
u32_t
sys_now(void)
{
return xTaskGetTickCount() * portTICK_RATE_MS;
}
/*-----------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
// TBD
/*-----------------------------------------------------------------------------------*/
/*
Starts a new thread with priority "prio" that will begin its execution in the
function "thread()". The "arg" argument will be passed as an argument to the
thread() function. The id of the new thread is returned. Both the id and
the priority are system dependent.
*/
sys_thread_t
sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
{
xTaskHandle CreatedTask;
portBASE_TYPE result;
result = xTaskCreate(thread, (const char *)name, stacksize, arg, prio, &CreatedTask);
if (result == pdPASS) {
return CreatedTask;
} else {
return NULL;
}
}
/*
This optional function does a "fast" critical region protection and returns
the previous protection level. This function is only called during very short
critical regions. An embedded system which supports ISR-based drivers might
want to implement this function by disabling interrupts. Task-based systems
might want to implement this by using a mutex or disabling tasking. This
function should support recursive calls from the same task or interrupt. In
other words, sys_arch_protect() could be called while already protected. In
that case the return value indicates that it is already protected.
sys_arch_protect() is only required if your port is supporting an operating
system.
*/
sys_prot_t
sys_arch_protect(void)
{
vPortEnterCritical();
return (sys_prot_t) 1;
}
/*
This optional function does a "fast" set of critical region protection to the
value specified by pval. See the documentation for sys_arch_protect() for
more information. This function is only required if your port is supporting
an operating system.
*/
void
sys_arch_unprotect(sys_prot_t pval)
{
(void) pval;
vPortExitCritical();
}
/*
* Prints an assertion messages and aborts execution.
*/
void
sys_arch_assert(const char *file, int line)
{
os_printf("\nAssertion: %d in %s\n", line, file);
while(1);
}
void
sys_arch_msleep(int ms)
{
vTaskDelay(ms / portTICK_RATE_MS);
}
#if LWIP_NETCONN_SEM_PER_THREAD
static void sys_thread_sem_free(int index, void *data) // destructor for TLS semaphore
{
sys_sem_t *sem = (sys_sem_t *)(data);
if (sem && *sem){
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sem del, sem=%p\n", *sem));
vSemaphoreDelete(*sem);
}
if (sem) {
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sem pointer del, sem_p=%p\n", sem));
free(sem);
}
}
/*
* get per thread semphore
*/
sys_sem_t* sys_thread_sem_init(void)
{
sys_sem_t *sem = (sys_sem_t*)mem_malloc(sizeof(sys_sem_t*));
if (!sem){
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, "thread_sem_init: out of memory\n");
return 0;
}
*sem = xSemaphoreCreateBinary();
if (!(*sem)){
free(sem);
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, "thread_sem_init: out of memory\n");
return 0;
}
vTaskSetThreadLocalStoragePointerAndDelCallback(NULL, LWIP_THREAD_TLS, sem, sys_thread_sem_free);
return sem;
}
/*
* get per thread semphore
*/
sys_sem_t* sys_thread_sem_get(void)
{
sys_sem_t *sem = pvTaskGetThreadLocalStoragePointer(NULL, LWIP_THREAD_TLS);
if (!sem) {
sem = sys_thread_sem_init();
}
LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sem_get s=%p\n", sem));
return sem;
}
void sys_thread_sem_deinit(void)
{
sys_sem_t *sem = pvTaskGetThreadLocalStoragePointer(NULL, LWIP_THREAD_TLS);
if (sem != NULL) {
sys_thread_sem_free(LWIP_THREAD_TLS, sem);
vTaskSetThreadLocalStoragePointerAndDelCallback(NULL, LWIP_THREAD_TLS, NULL, NULL);
}
}
#endif

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2001, 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. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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>
*
*/
#ifndef __ARCH_CC_H__
#define __ARCH_CC_H__
#include "c_types.h"
#define EFAULT 14
#define LWIP_ERRNO_INCLUDE "sys/errno.h"
#if (1)
#define BYTE_ORDER LITTLE_ENDIAN
#else
#define BYTE_ORDER BIG_ENDIAN
#endif
typedef int sys_prot_t;
#define S16_F "d"
#define U16_F "d"
#define X16_F "x"
#define S32_F "d"
#define U32_F "d"
#define X32_F "x"
//#define PACK_STRUCT_FIELD(x) x __attribute__((packed))
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_STRUCT __attribute__((packed))
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_END
#include <stdio.h>
#ifndef os_printf
#define os_printf(fmt, ...) do { \
static const char flash_str[] ICACHE_RODATA_ATTR STORE_ATTR = fmt; \
printf(flash_str, ##__VA_ARGS__); \
} while(0)
#endif
#ifdef LWIP_DEBUG
#define LWIP_PLATFORM_DIAG(x) do {os_printf x;} while(0)
#define LWIP_PLATFORM_ASSERT(x) do {os_printf(x); sys_arch_assert(__FILE__, __LINE__);} while(0)
#else
#define LWIP_PLATFORM_DIAG(x)
#define LWIP_PLATFORM_ASSERT(x)
#endif
#ifndef LWIP_PLATFORM_BYTESWAP
#define LWIP_PLATFORM_BYTESWAP 1
#endif
#define LWIP_PLATFORM_HTONS(_n) ((u16_t)((((_n) & 0xff) << 8) | (((_n) >> 8) & 0xff)))
#define LWIP_PLATFORM_HTONL(_n) ((u32_t)( (((_n) & 0xff) << 24) | (((_n) & 0xff00) << 8) | (((_n) >> 8) & 0xff00) | (((_n) >> 24) & 0xff) ))
#define LWIP_TIMEVAL_PRIVATE 0
#endif /* __ARCH_CC_H__ */

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2001, 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. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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>
*
*/
#ifndef __PERF_H__
#define __PERF_H__
#define PERF_START /* null definition */
#define PERF_STOP(x) /* null definition */
#endif /* __PERF_H__ */

View File

@ -0,0 +1,65 @@
/*
* 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>
*
*/
#ifndef __SYS_ARCH_H__
#define __SYS_ARCH_H__
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
typedef xSemaphoreHandle sys_sem_t;
typedef xSemaphoreHandle sys_mutex_t;
typedef xQueueHandle sys_mbox_t;
typedef xTaskHandle sys_thread_t;
#define sys_mbox_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE )
#define sys_mbox_set_invalid( x ) ( ( *x ) = NULL )
#define sys_sem_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE )
#define sys_sem_set_invalid( x ) ( ( *x ) = NULL )
#define LWIP_COMPAT_MUTEX 0
#if LWIP_NETCONN_SEM_PER_THREAD
sys_sem_t* sys_thread_sem_init(void);
void sys_thread_sem_deinit(void);
sys_sem_t* sys_thread_sem_get(void);
#define LWIP_NETCONN_THREAD_SEM_ALLOC() sys_thread_sem_init()
#define LWIP_NETCONN_THREAD_SEM_FREE() sys_thread_sem_deinit()
#define LWIP_NETCONN_THREAD_SEM_GET() sys_thread_sem_get()
#endif
#endif /* __SYS_ARCH_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,309 @@
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "lwip/pbuf.h"
#include "lwip/ethip6.h"
#include "netif/etharp.h"
#include "esp_libc.h"
#include "esp_wifi.h"
#include "tcpip_adapter.h"
#include "esp_socket.h"
int8_t ieee80211_output_pbuf(uint8_t fd, uint8_t* dataptr, uint16_t datalen);
int8_t wifi_get_netif(uint8_t fd);
void wifi_station_set_default_hostname(uint8_t* hwaddr);
/**
* In this function, the hardware should be initialized.
* Called from ethernetif_init().
*
* @param netif the already initialized lwip network interface structure
* for this ethernetif
*/
static void low_level_init(struct netif* netif)
{
if (netif == NULL) {
TCPIP_ATAPTER_LOG("ERROR netif is NULL\n");
return;
}
/* set MAC hardware address length */
netif->hwaddr_len = ETHARP_HWADDR_LEN;
/* maximum transfer unit */
netif->mtu = 1500;
/* device capabilities */
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP | NETIF_FLAG_UP;
#if LWIP_IGMP
netif->flags |= NETIF_FLAG_IGMP;
#endif
/* Do whatever else is needed to initialize interface. */
}
/*
* @brief LWIP low-level AI/O sending callback function, it is to free pbuf
*
* @param aio AI/O control block pointer
*
* @return 0 meaning successs
*/
static int low_level_send_cb(esp_aio_t *aio)
{
struct pbuf *pbuf = aio->arg;
pbuf_free(pbuf);
return 0;
}
/*
* @brief transform custom pbuf to LWIP core pbuf, LWIP may use input custom pbuf
* to send ARP data directly
*
* @param pbuf LWIP pbuf pointer
*
* @return LWIP pbuf pointer which it not "PBUF_FLAG_IS_CUSTOM" attribute
*/
static inline struct pbuf *ethernetif_transform_pbuf(struct pbuf *pbuf)
{
struct pbuf *p;
if (!(pbuf->flags & PBUF_FLAG_IS_CUSTOM)) {
/*
* Add ref to pbuf to avoid it to be freed by upper layer.
*/
pbuf_ref(pbuf);
return pbuf;
}
p = pbuf_alloc(PBUF_RAW, pbuf->len, PBUF_RAM);
if (!p)
return NULL;
memcpy(p->payload, pbuf->payload, pbuf->len);
/*
* The input pbuf(named "pbuf") should not be freed, becasue it will be
* freed by upper layer.
*
* The output pbuf(named "p") should not be freed either, becasue it will
* be freed at callback function "low_level_send_cb".
*/
return p;
}
/**
* This function should do the actual transmission of the packet. The packet is
* contained in the pbuf that is passed to the function. This pbuf
* might be chained.
*
* @param netif the lwip network interface structure for this ethernetif
* @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
* @return ERR_OK if the packet could be sent
* an int8_t value if the packet couldn't be sent
*
* @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
* strange results. You might consider waiting for space in the DMA queue
* to become availale since the stack doesn't retry to send a packet
* dropped because of memory failure (except for the TCP timers).
*/
static int8_t low_level_output(struct netif* netif, struct pbuf* p)
{
esp_aio_t aio;
int8_t err = ERR_OK;
if (netif == NULL) {
TCPIP_ATAPTER_LOG("ERROR netif is NULL\n");
return ERR_ARG;
}
#if ETH_PAD_SIZE
pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
#endif
p = ethernetif_transform_pbuf(p);
if (!p)
return ERR_OK;
aio.fd = (int)netif->state;
aio.pbuf = p->payload;
aio.len = p->len;
aio.cb = low_level_send_cb;
aio.arg = p;
aio.ret = 0;
/*
* we use "SOCK_RAW" to create socket, so all input/output datas include full ethernet
* header, meaning we should not pass target low-level address here.
*/
err = esp_aio_sendto(&aio, NULL, 0);
if (err == ERR_MEM) {
err = ERR_OK;
}
// signal that packet should be sent();
#if ETH_PAD_SIZE
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif
#if LWIP_STATS
LINK_STATS_INC(link.xmit);
#endif
return err;
}
/**
* This function should be called when a packet is ready to be read
* from the interface. It uses the function low_level_input() that
* should handle the actual reception of bytes from the network
* interface. Then the type of the received packet is determined and
* the appropriate input function is called.
*
* @param netif the lwip network interface structure for this ethernetif
*/
void ethernetif_input(struct netif* netif, struct pbuf* p)
{
struct eth_hdr* ethhdr;
if (p == NULL) {
TCPIP_ATAPTER_LOG("ERROR pbuf is NULL\n");
goto _exit;
}
if (p->payload == NULL) {
TCPIP_ATAPTER_LOG("ERROR payload is NULL\n");
pbuf_free(p);
goto _exit;
}
if (netif == NULL) {
TCPIP_ATAPTER_LOG("ERROR netif is NULL\n");
goto _exit;
}
if (!(netif->flags & NETIF_FLAG_LINK_UP)) {
TCPIP_ATAPTER_LOG("ERROR netif is not up\n");
pbuf_free(p);
p = NULL;
goto _exit;
}
/* points to packet payload, which starts with an Ethernet header */
ethhdr = p->payload;
switch (htons(ethhdr->type)) {
/* IP or ARP packet? */
case ETHTYPE_IP:
case ETHTYPE_IPV6:
case ETHTYPE_ARP:
#if PPPOE_SUPPORT
/* PPPoE packet? */
case ETHTYPE_PPPOEDISC:
case ETHTYPE_PPPOE:
#endif /* PPPOE_SUPPORT */
/* full packet send to tcpip_thread to process */
if (netif->input(p, netif) != ERR_OK) {
TCPIP_ATAPTER_LOG("ERROR IP input error\n");
pbuf_free(p);
p = NULL;
}
break;
default:
pbuf_free(p);
p = NULL;
break;
}
_exit:
;
}
/**
* Should be called at the beginning of the program to set up the
* network interface. It calls the function low_level_init() to do the
* actual setup of the hardware.
*
* This function should be passed as a parameter to netif_add().
*
* @param netif the lwip network interface structure for this ethernetif
* @return ERR_OK if the loopif is initialized
* ERR_MEM if private data couldn't be allocated
* any other int8_t on error
*/
int8_t ethernetif_init(struct netif* netif)
{
uint8_t mac[NETIF_MAX_HWADDR_LEN];
if (netif == NULL) {
TCPIP_ATAPTER_LOG("ERROR netif is NULL\n");
}
/* set MAC hardware address */
if (wifi_get_netif(TCPIP_ADAPTER_IF_STA) == TCPIP_ADAPTER_IF_STA) {
wifi_get_macaddr(TCPIP_ADAPTER_IF_STA, mac);
} else {
wifi_get_macaddr(TCPIP_ADAPTER_IF_AP, mac);
}
memcpy(netif->hwaddr, mac, NETIF_MAX_HWADDR_LEN);
#if LWIP_NETIF_HOSTNAME
if (wifi_get_netif(TCPIP_ADAPTER_IF_STA) == TCPIP_ADAPTER_IF_STA) {
if (default_hostname == 1) {
wifi_station_set_default_hostname(netif->hwaddr);
}
/* Initialize interface hostname */
netif->hostname = hostname;
} else {
netif->hostname = NULL;
}
#endif /* LWIP_NETIF_HOSTNAME */
/*
* Initialize the snmp variables and counters inside the struct netif.
* The last argument should be replaced with your link speed, in units
* of bits per second.
*/
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
/* We directly use etharp_output() here to save a function call.
* You can instead declare your own function an call etharp_output()
* from it if you have to do some checks before sending (e.g. if link
* is available...) */
netif->output = etharp_output;
#if LWIP_IPV6
netif->output_ip6 = ethip6_output;
#endif /* LWIP_IPV6 */
netif->linkoutput = low_level_output;
/* initialize the hardware */
low_level_init(netif);
return ERR_OK;
}