refactor: 完成R8裸机lwIP移植并更新文档

This commit is contained in:
2026-03-30 18:08:54 +08:00
parent 68c64959c7
commit 9efa2cdc59
24 changed files with 1845 additions and 3619 deletions
+1
View File
@@ -12,6 +12,7 @@
* Modified for STM32F103 HAL Library with FreeRTOS support.
******************************************************************************/
#include "stm32f1xx_hal.h"
#include "main.h"
#include "CH390.h"
#include "CH390_Interface.h"
+4 -5
View File
@@ -22,6 +22,8 @@ typedef int16_t s16_t;
typedef uint32_t u32_t;
typedef int32_t s32_t;
typedef uint32_t sys_prot_t;
typedef uintptr_t mem_ptr_t;
/* Byte order - ARM Cortex-M is little endian */
@@ -62,15 +64,12 @@ typedef uintptr_t mem_ptr_t;
/* Platform specific diagnostic output */
#ifndef LWIP_PLATFORM_DIAG
#define LWIP_PLATFORM_DIAG(x) do { printf x; } while(0)
#define LWIP_PLATFORM_DIAG(x) do { } while(0)
#endif
/* Platform specific assertion handling */
#ifndef LWIP_PLATFORM_ASSERT
#define LWIP_PLATFORM_ASSERT(x) do { \
printf("Assertion \"%s\" failed at line %d in %s\n", x, __LINE__, __FILE__); \
while(1); \
} while(0)
#define LWIP_PLATFORM_ASSERT(x) do { while(1) { } } while(0)
#endif
/* Get current time in milliseconds (provided by sys_arch.c) */
+37 -247
View File
@@ -1,201 +1,77 @@
/**
* @file lwipopts.h
* @brief LwIP configuration for STM32F103 + FreeRTOS + CH390 Ethernet
*
* This configuration is optimized for:
* - STM32F103 with limited RAM (~20KB available)
* - FreeRTOS integration (NO_SYS=0)
* - TCP Server + Client dual link transparent transmission
* - CH390 Ethernet controller
* @brief lwIP configuration for STM32F103 + CH390 in NO_SYS mode.
*/
#ifndef LWIP_LWIPOPTS_H
#define LWIP_LWIPOPTS_H
/*-----------------------------------------------------------------------------
* Platform and OS Options
*---------------------------------------------------------------------------*/
/* Use FreeRTOS - this enables the sequential API (netconn, sockets) */
#define NO_SYS 0
/* Enable socket API */
#define LWIP_SOCKET 1
#define LWIP_NETCONN 1
#define NO_SYS 1
#define LWIP_SOCKET 0
#define LWIP_NETCONN 0
#define LWIP_NETIF_API 0
/* Critical section protection */
#define SYS_LIGHTWEIGHT_PROT 1
#define LWIP_PROVIDE_ERRNO 0
/* Use FreeRTOS memory allocation */
#define MEM_LIBC_MALLOC 0
#define MEMP_MEM_MALLOC 0
/* Let lwIP provide the errno values used by sockets/netconn. */
#define LWIP_PROVIDE_ERRNO 1
/*-----------------------------------------------------------------------------
* Memory Configuration (optimized for STM32F103 with ~20KB RAM)
*---------------------------------------------------------------------------*/
/* Memory alignment (ARM Cortex-M3 = 4 byte alignment) */
#define MEM_ALIGNMENT 4
#define MEM_SIZE (4 * 1024)
/* Heap size for dynamic memory allocation */
#define MEM_SIZE (4 * 1024) /* 4KB for LwIP heap */
/* Number of pbufs in pool */
#define PBUF_POOL_SIZE 8
/* Size of each pbuf in pool (must hold one Ethernet frame) */
#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS + 40 + PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN)
/* Number of memp struct pbufs */
#define MEMP_NUM_PBUF 8
/* Number of raw PCBs */
#define MEMP_NUM_RAW_PCB 2
/* Number of UDP PCBs */
#define MEMP_NUM_UDP_PCB 4
/* Number of simultaneously active TCP connections */
#define MEMP_NUM_UDP_PCB 1
#define MEMP_NUM_TCP_PCB 4
/* Number of listening TCP connections */
#define MEMP_NUM_TCP_PCB_LISTEN 2
/* Number of simultaneously queued TCP segments */
#define MEMP_NUM_TCP_SEG 17
/* Number of simultaneously active timeouts */
#define MEMP_NUM_TCP_SEG 16
#define MEMP_NUM_SYS_TIMEOUT 8
/* Number of netbufs (for sequential API) */
#define MEMP_NUM_NETBUF 4
/* Number of netconns */
#define MEMP_NUM_NETCONN 6
/* TCPIP message queue size */
#define MEMP_NUM_TCPIP_MSG_API 8
#define MEMP_NUM_TCPIP_MSG_INPKT 8
/*-----------------------------------------------------------------------------
* IP Configuration
*---------------------------------------------------------------------------*/
#define MEMP_NUM_NETBUF 0
#define MEMP_NUM_NETCONN 0
#define MEMP_NUM_TCPIP_MSG_API 0
#define MEMP_NUM_TCPIP_MSG_INPKT 0
#define LWIP_IPV4 1
#define LWIP_IPV6 0
/* No IP forwarding (single interface device) */
#define IP_FORWARD 0
/* IP fragment reassembly */
#define IP_REASSEMBLY 0
#define IP_FRAG 0
/* IP options processing */
#define IP_OPTIONS_ALLOWED 1
/*-----------------------------------------------------------------------------
* ICMP Configuration
*---------------------------------------------------------------------------*/
#define LWIP_ICMP 1
#define ICMP_TTL 255
/*-----------------------------------------------------------------------------
* ARP Configuration
*---------------------------------------------------------------------------*/
#define LWIP_ARP 1
#define ARP_TABLE_SIZE 10
#define ARP_QUEUEING 1
#define ETHARP_SUPPORT_STATIC_ENTRIES 1
/*-----------------------------------------------------------------------------
* DHCP Configuration
*---------------------------------------------------------------------------*/
#define LWIP_DHCP 1
#define LWIP_DHCP 0
#define DHCP_DOES_ARP_CHECK 1
/*-----------------------------------------------------------------------------
* UDP Configuration
*---------------------------------------------------------------------------*/
#define LWIP_UDP 1
#define UDP_TTL 255
/*-----------------------------------------------------------------------------
* TCP Configuration (optimized for transparent transmission)
*---------------------------------------------------------------------------*/
#define LWIP_UDP 0
#define LWIP_TCP 1
#define TCP_TTL 255
/* TCP Maximum Segment Size */
#define TCP_MSS 536 /* Conservative value for compatibility */
/* TCP sender buffer space (bytes) */
#define TCP_SND_BUF (4 * TCP_MSS)
/* TCP sender buffer space (pbufs) */
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS))
/* TCP receive window */
#define TCP_WND (4 * TCP_MSS)
/* TCP writable space threshold */
#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1)
/* Enable TCP keepalive */
#define LWIP_TCP_KEEPALIVE 1
/* TCP segment queue handling */
#define TCP_QUEUE_OOSEQ 0 /* Disable out-of-order segment queuing to save RAM */
/* Maximum number of retransmissions */
#define TCP_MAXRTX 12
#define TCP_SYNMAXRTX 6
/* TCP listen backlog */
#define TCP_LISTEN_BACKLOG 1
/* TCP timestamp option */
#define LWIP_TCP_TIMESTAMPS 0
/*-----------------------------------------------------------------------------
* RAW API (used for ping, etc.)
*---------------------------------------------------------------------------*/
#define LWIP_RAW 1
/*-----------------------------------------------------------------------------
* DNS Configuration
*---------------------------------------------------------------------------*/
#define TCP_TTL 255
#define UDP_TTL 255
#define ICMP_TTL 255
#define LWIP_DNS 0 /* Disable DNS to save RAM */
#define TCP_MSS 536
#define TCP_SND_BUF (4 * TCP_MSS)
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS))
#define TCP_WND (4 * TCP_MSS)
#define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1)
#define LWIP_TCP_KEEPALIVE 1
#define TCP_QUEUE_OOSEQ 0
#define TCP_MAXRTX 12
#define TCP_SYNMAXRTX 6
#define TCP_LISTEN_BACKLOG 1
#define LWIP_TCP_TIMESTAMPS 0
/*-----------------------------------------------------------------------------
* IGMP Configuration
*---------------------------------------------------------------------------*/
#define LWIP_DNS 0
#define LWIP_IGMP 0
#define LWIP_IGMP 0 /* Disable IGMP to save RAM */
#define LWIP_NETIF_STATUS_CALLBACK 0
#define LWIP_NETIF_LINK_CALLBACK 0
/*-----------------------------------------------------------------------------
* Callback Configuration
*---------------------------------------------------------------------------*/
#define LWIP_NETIF_STATUS_CALLBACK 1
#define LWIP_NETIF_LINK_CALLBACK 1
/*-----------------------------------------------------------------------------
* Checksum Configuration
*---------------------------------------------------------------------------*/
/* Use software checksums (CH390 doesn't have checksum offload) */
#define CHECKSUM_GEN_IP 1
#define CHECKSUM_GEN_UDP 1
#define CHECKSUM_GEN_TCP 1
@@ -205,106 +81,20 @@
#define CHECKSUM_CHECK_TCP 1
#define CHECKSUM_CHECK_ICMP 1
/*-----------------------------------------------------------------------------
* Statistics (disabled to save RAM)
*---------------------------------------------------------------------------*/
#define LWIP_STATS 0
#define LWIP_STATS_DISPLAY 0
/*-----------------------------------------------------------------------------
* Debug Options (disabled for production)
*---------------------------------------------------------------------------*/
#define LWIP_DEBUG 0
#if LWIP_DEBUG
#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL
#define LWIP_DBG_TYPES_ON LWIP_DBG_ON
#define ETHARP_DEBUG LWIP_DBG_OFF
#define NETIF_DEBUG LWIP_DBG_OFF
#define PBUF_DEBUG LWIP_DBG_OFF
#define API_LIB_DEBUG LWIP_DBG_OFF
#define API_MSG_DEBUG LWIP_DBG_OFF
#define SOCKETS_DEBUG LWIP_DBG_OFF
#define ICMP_DEBUG LWIP_DBG_OFF
#define IGMP_DEBUG LWIP_DBG_OFF
#define INET_DEBUG LWIP_DBG_OFF
#define IP_DEBUG LWIP_DBG_OFF
#define IP_REASS_DEBUG LWIP_DBG_OFF
#define RAW_DEBUG LWIP_DBG_OFF
#define MEM_DEBUG LWIP_DBG_OFF
#define MEMP_DEBUG LWIP_DBG_OFF
#define SYS_DEBUG LWIP_DBG_OFF
#define TIMERS_DEBUG LWIP_DBG_OFF
#define TCP_DEBUG LWIP_DBG_OFF
#define TCP_INPUT_DEBUG LWIP_DBG_OFF
#define TCP_FR_DEBUG LWIP_DBG_OFF
#define TCP_RTO_DEBUG LWIP_DBG_OFF
#define TCP_CWND_DEBUG LWIP_DBG_OFF
#define TCP_WND_DEBUG LWIP_DBG_OFF
#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
#define TCP_RST_DEBUG LWIP_DBG_OFF
#define TCP_QLEN_DEBUG LWIP_DBG_OFF
#define UDP_DEBUG LWIP_DBG_OFF
#define TCPIP_DEBUG LWIP_DBG_OFF
#define DHCP_DEBUG LWIP_DBG_OFF
#endif /* LWIP_DEBUG */
/*-----------------------------------------------------------------------------
* FreeRTOS Specific Options
*---------------------------------------------------------------------------*/
/* Task stack sizes */
#define TCPIP_THREAD_STACKSIZE 512
#define TCPIP_THREAD_PRIO (configMAX_PRIORITIES - 2)
#define DEFAULT_THREAD_STACKSIZE 256
#define DEFAULT_THREAD_PRIO (configMAX_PRIORITIES - 3)
/* Mailbox sizes */
#define TCPIP_MBOX_SIZE 8
#define DEFAULT_RAW_RECVMBOX_SIZE 4
#define DEFAULT_UDP_RECVMBOX_SIZE 4
#define DEFAULT_TCP_RECVMBOX_SIZE 8
#define DEFAULT_ACCEPTMBOX_SIZE 4
/* Thread name length */
#define LWIP_NETCONN_SEM_PER_THREAD 1
/*-----------------------------------------------------------------------------
* Ethernet Specific
*---------------------------------------------------------------------------*/
/* Ethernet MTU */
#define LWIP_ETHERNET 1
/* Link layer header overhead */
#define PBUF_LINK_HLEN 14 /* Ethernet header size */
#define PBUF_LINK_HLEN 14
#define PBUF_LINK_ENCAPSULATION_HLEN 0
#define LWIP_NETIF_HOSTNAME 0
/* Use static Ethernet address (configured at runtime) */
#define LWIP_NETIF_HOSTNAME 1
/*-----------------------------------------------------------------------------
* Socket Options
*---------------------------------------------------------------------------*/
#define LWIP_SO_SNDTIMEO 1
#define LWIP_SO_RCVTIMEO 1
#define LWIP_SO_RCVBUF 0
#define SO_REUSE 1
/*-----------------------------------------------------------------------------
* Additional Options
*---------------------------------------------------------------------------*/
/* Enable loop interface for testing */
#define LWIP_HAVE_LOOPIF 0
#define LWIP_NETIF_LOOPBACK 0
#define LWIP_TIMERS 1
#define LWIP_TIMERS_CUSTOM 0
/* Random number generator (required for some TCP operations) */
#define LWIP_RAND() ((uint32_t)rand())
#endif /* LWIP_LWIPOPTS_H */
#endif
+16 -78
View File
@@ -1,90 +1,28 @@
/**
* @file sys_arch.h
* @brief LwIP system architecture for FreeRTOS
* @brief Minimal sys_arch definitions for lwIP NO_SYS mode.
*/
#ifndef __SYS_ARCH_H__
#define __SYS_ARCH_H__
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "lwip/arch.h"
#include <stdlib.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
typedef uint32_t sys_prot_t;
sys_prot_t sys_arch_protect(void);
void sys_arch_unprotect(sys_prot_t pval);
#ifndef SYS_ARCH_DECL_PROTECT
#define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev
#endif
/* Semaphore type */
typedef SemaphoreHandle_t sys_sem_t;
/* Mutex type */
typedef SemaphoreHandle_t sys_mutex_t;
/* Mailbox (message queue) type */
typedef QueueHandle_t sys_mbox_t;
/* Thread type */
typedef TaskHandle_t sys_thread_t;
/* Protection level type */
typedef u32_t sys_prot_t;
/* Null values */
#define SYS_SEM_NULL ((sys_sem_t)NULL)
#define SYS_MBOX_NULL ((sys_mbox_t)NULL)
#define SYS_MUTEX_NULL ((sys_mutex_t)NULL)
/* Use one per-thread semaphore for lwIP netconn/socket API calls. */
#define LWIP_NETCONN_THREAD_SEM_TLS_INDEX 0
#define LWIP_NETCONN_THREAD_SEM_GET() \
((sys_sem_t *)pvTaskGetThreadLocalStoragePointer(NULL, LWIP_NETCONN_THREAD_SEM_TLS_INDEX))
#define LWIP_NETCONN_THREAD_SEM_ALLOC() \
do { \
sys_sem_t *sem = (sys_sem_t *)mem_malloc(sizeof(sys_sem_t)); \
if (sem != NULL) { \
*sem = SYS_SEM_NULL; \
if (sys_sem_new(sem, 0) == ERR_OK) { \
vTaskSetThreadLocalStoragePointer(NULL, \
LWIP_NETCONN_THREAD_SEM_TLS_INDEX,\
sem); \
} else { \
mem_free(sem); \
} \
} \
} while (0)
#define LWIP_NETCONN_THREAD_SEM_FREE() \
do { \
sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET(); \
if (sem != NULL) { \
sys_sem_free(sem); \
mem_free(sem); \
vTaskSetThreadLocalStoragePointer(NULL, \
LWIP_NETCONN_THREAD_SEM_TLS_INDEX, \
NULL); \
} \
} while (0)
/* Check if semaphore/mbox is valid */
#define sys_sem_valid(sem) ((sem) != NULL && (*(sem)) != SYS_SEM_NULL)
#define sys_sem_set_invalid(sem) do { if ((sem) != NULL) { *(sem) = SYS_SEM_NULL; } } while(0)
#define sys_mbox_valid(mbox) ((mbox) != NULL && (*(mbox)) != SYS_MBOX_NULL)
#define sys_mbox_set_invalid(mbox) do { if ((mbox) != NULL) { *(mbox) = SYS_MBOX_NULL; } } while(0)
#define sys_mutex_valid(mutex) ((mutex) != NULL && (*(mutex)) != SYS_MUTEX_NULL)
#define sys_mutex_set_invalid(mutex) do { if ((mutex) != NULL) { *(mutex) = SYS_MUTEX_NULL; } } while(0)
/* System initialization */
void sys_init(void);
/* Get current time in milliseconds */
u32_t sys_now(void);
#ifdef __cplusplus
}
#ifndef SYS_ARCH_PROTECT
#define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect()
#endif
#endif /* __SYS_ARCH_H__ */
#ifndef SYS_ARCH_UNPROTECT
#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev)
#endif
#endif
+6 -12
View File
@@ -5,23 +5,17 @@
extern struct netif ch390_netif;
/**
* Helper struct to hold private data used to operate your ethernet interface.
* Keeping the ethernet address of the MAC in this struct is not necessary
* as it is already kept in the struct netif.
* But this is only an example, anyway...
*/
struct ethernetif {
// struct eth_addr *ethaddr;
/* Add whatever per-interface state that is needed here. */
uint16_t rx_len;
uint8_t rx_status;
};
void init_lwip_netif(const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw);
void lwip_netif_init(const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw);
err_t ethernetif_init(struct netif *netif);
void ethernetif_input(struct netif *netif);
void ethernetif_check_link(void);
void ethernetif_poll(void);
void ethernetif_set_irq_pending(void);
uint8_t ethernetif_is_irq_pending(void);
void print_netif(struct netif *netif);
#endif /* _ETHERNETIF_H_ */
#endif
+213
View File
@@ -0,0 +1,213 @@
/**
* @file
* Ethernet common functions
*
* @defgroup ethernet Ethernet
* @ingroup callbackstyle_api
*/
#include "lwip/opt.h"
#if LWIP_ARP || LWIP_ETHERNET
#include "netif/ethernet.h"
#include "lwip/def.h"
#include "lwip/stats.h"
#include "lwip/etharp.h"
#include "lwip/ip.h"
#include "lwip/snmp.h"
#include <string.h>
#include "netif/ppp/ppp_opts.h"
#if PPPOE_SUPPORT
#include "netif/ppp/pppoe.h"
#endif
#ifdef LWIP_HOOK_FILENAME
#include LWIP_HOOK_FILENAME
#endif
const struct eth_addr ethbroadcast = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
const struct eth_addr ethzero = {{0, 0, 0, 0, 0, 0}};
err_t ethernet_input(struct pbuf *p, struct netif *netif)
{
struct eth_hdr *ethhdr;
u16_t type;
#if LWIP_ARP || ETHARP_SUPPORT_VLAN || LWIP_IPV6
u16_t next_hdr_offset = SIZEOF_ETH_HDR;
#endif
LWIP_ASSERT_CORE_LOCKED();
if (p->len <= SIZEOF_ETH_HDR) {
ETHARP_STATS_INC(etharp.proterr);
ETHARP_STATS_INC(etharp.drop);
MIB2_STATS_NETIF_INC(netif, ifinerrors);
goto free_and_return;
}
ethhdr = (struct eth_hdr *)p->payload;
type = ethhdr->type;
#if ETHARP_SUPPORT_VLAN
if (type == PP_HTONS(ETHTYPE_VLAN)) {
struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr *)(((char *)ethhdr) + SIZEOF_ETH_HDR);
next_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR;
if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) {
ETHARP_STATS_INC(etharp.proterr);
ETHARP_STATS_INC(etharp.drop);
MIB2_STATS_NETIF_INC(netif, ifinerrors);
goto free_and_return;
}
type = vlan->tpid;
}
#endif
#if LWIP_ARP_FILTER_NETIF
netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, lwip_htons(type));
#endif
if (p->if_idx == NETIF_NO_INDEX) {
p->if_idx = netif_get_index(netif);
}
if (ethhdr->dest.addr[0] & 1) {
if (ethhdr->dest.addr[0] == LL_IP4_MULTICAST_ADDR_0) {
#if LWIP_IPV4
if ((ethhdr->dest.addr[1] == LL_IP4_MULTICAST_ADDR_1) &&
(ethhdr->dest.addr[2] == LL_IP4_MULTICAST_ADDR_2)) {
p->flags |= PBUF_FLAG_LLMCAST;
}
#endif
}
#if LWIP_IPV6
else if ((ethhdr->dest.addr[0] == LL_IP6_MULTICAST_ADDR_0) &&
(ethhdr->dest.addr[1] == LL_IP6_MULTICAST_ADDR_1)) {
p->flags |= PBUF_FLAG_LLMCAST;
}
#endif
else if (eth_addr_cmp(&ethhdr->dest, &ethbroadcast)) {
p->flags |= PBUF_FLAG_LLBCAST;
}
}
switch (type) {
#if LWIP_IPV4 && LWIP_ARP
case PP_HTONS(ETHTYPE_IP):
if (!(netif->flags & NETIF_FLAG_ETHARP)) {
goto free_and_return;
}
if (pbuf_remove_header(p, next_hdr_offset)) {
goto free_and_return;
} else {
ip4_input(p, netif);
}
break;
case PP_HTONS(ETHTYPE_ARP):
if (!(netif->flags & NETIF_FLAG_ETHARP)) {
goto free_and_return;
}
if (pbuf_remove_header(p, next_hdr_offset)) {
ETHARP_STATS_INC(etharp.lenerr);
ETHARP_STATS_INC(etharp.drop);
goto free_and_return;
} else {
etharp_input(p, netif);
}
break;
#endif
#if PPPOE_SUPPORT
case PP_HTONS(ETHTYPE_PPPOEDISC):
pppoe_disc_input(netif, p);
break;
case PP_HTONS(ETHTYPE_PPPOE):
pppoe_data_input(netif, p);
break;
#endif
#if LWIP_IPV6
case PP_HTONS(ETHTYPE_IPV6):
if ((p->len < next_hdr_offset) || pbuf_remove_header(p, next_hdr_offset)) {
goto free_and_return;
} else {
ip6_input(p, netif);
}
break;
#endif
default:
#ifdef LWIP_HOOK_UNKNOWN_ETH_PROTOCOL
if (LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(p, netif) == ERR_OK) {
break;
}
#endif
ETHARP_STATS_INC(etharp.proterr);
ETHARP_STATS_INC(etharp.drop);
MIB2_STATS_NETIF_INC(netif, ifinunknownprotos);
goto free_and_return;
}
return ERR_OK;
free_and_return:
pbuf_free(p);
return ERR_OK;
}
err_t ethernet_output(struct netif *netif, struct pbuf *p,
const struct eth_addr *src, const struct eth_addr *dst,
u16_t eth_type)
{
struct eth_hdr *ethhdr;
u16_t eth_type_be = lwip_htons(eth_type);
#if ETHARP_SUPPORT_VLAN && (defined(LWIP_HOOK_VLAN_SET) || LWIP_VLAN_PCP)
s32_t vlan_prio_vid;
#ifdef LWIP_HOOK_VLAN_SET
vlan_prio_vid = LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type);
#elif LWIP_VLAN_PCP
vlan_prio_vid = -1;
if (netif->hints && (netif->hints->tci >= 0)) {
vlan_prio_vid = (u16_t)netif->hints->tci;
}
#endif
if (vlan_prio_vid >= 0) {
struct eth_vlan_hdr *vlanhdr;
LWIP_ASSERT("prio_vid must be <= 0xFFFF", vlan_prio_vid <= 0xFFFF);
if (pbuf_add_header(p, SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) != 0) {
goto pbuf_header_failed;
}
vlanhdr = (struct eth_vlan_hdr *)(((u8_t *)p->payload) + SIZEOF_ETH_HDR);
vlanhdr->tpid = eth_type_be;
vlanhdr->prio_vid = lwip_htons((u16_t)vlan_prio_vid);
eth_type_be = PP_HTONS(ETHTYPE_VLAN);
} else
#endif
{
if (pbuf_add_header(p, SIZEOF_ETH_HDR) != 0) {
goto pbuf_header_failed;
}
}
LWIP_ASSERT_CORE_LOCKED();
ethhdr = (struct eth_hdr *)p->payload;
ethhdr->type = eth_type_be;
SMEMCPY(&ethhdr->dest, dst, ETH_HWADDR_LEN);
SMEMCPY(&ethhdr->src, src, ETH_HWADDR_LEN);
return netif->linkoutput(netif, p);
pbuf_header_failed:
LINK_STATS_INC(link.lenerr);
return ERR_BUF;
}
#endif
+141 -285
View File
@@ -1,150 +1,120 @@
/**
* @file ethernetif.c
* @brief Ethernet interface implementation for CH390 + LwIP + FreeRTOS
* @brief CH390 Ethernet interface for lwIP NO_SYS mode.
*/
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/init.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include "lwip/etharp.h"
#include "lwip/tcpip.h"
#include "lwip/timeouts.h"
#include "netif/ethernet.h"
#include "ethernetif.h"
#include "CH390.h"
#include "CH390_Interface.h"
#include "config.h"
#include "stm32f1xx_hal.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include <string.h>
/* Interface name */
#define IFNAME0 'e'
#define IFNAME1 'n'
/* Global network interface */
struct netif ch390_netif;
static volatile uint8_t g_ch390_irq_pending;
static void ethernetif_unlock(uint32_t primask);
/* Mutex for SPI access protection */
static SemaphoreHandle_t spi_mutex = NULL;
static uint32_t ethernetif_lock(void)
{
uint32_t primask = __get_PRIMASK();
__disable_irq();
return primask;
}
/* Forward declarations */
static void low_level_init(struct netif *netif);
static err_t low_level_output(struct netif *netif, struct pbuf *p);
static struct pbuf *low_level_input(struct netif *netif);
sys_prot_t sys_arch_protect(void)
{
return (sys_prot_t)ethernetif_lock();
}
/*---------------------------------------------------------------------------
* Low Level Hardware Functions
*---------------------------------------------------------------------------*/
void sys_arch_unprotect(sys_prot_t pval)
{
ethernetif_unlock((uint32_t)pval);
}
static void ethernetif_unlock(uint32_t primask)
{
if ((primask & 1u) == 0u) {
__enable_irq();
}
}
void ethernetif_set_irq_pending(void)
{
g_ch390_irq_pending = 1u;
}
uint8_t ethernetif_is_irq_pending(void)
{
return g_ch390_irq_pending;
}
/**
* @brief Initialize the CH390 hardware
* @param netif Network interface structure
*/
static void low_level_init(struct netif *netif)
{
struct ethernetif *ethernetif = netif->state;
/* Create SPI mutex */
if (spi_mutex == NULL)
{
spi_mutex = xSemaphoreCreateMutex();
}
/* Initialize CH390 GPIO and SPI */
ch390_gpio_init();
ch390_spi_init();
/* Hardware reset CH390 */
ch390_hardware_reset();
/* Configure CH390 with default settings */
ch390_default_config();
/* Set MAC hardware address length */
ch390_set_mac_address((uint8_t *)config_get()->mac);
netif->hwaddr_len = ETHARP_HWADDR_LEN;
/* Get MAC address from CH390 */
ch390_get_mac(netif->hwaddr);
/* Maximum transfer unit */
netif->mtu = 1500;
/* Device capabilities */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
/* Initialize state */
ethernetif->rx_len = 0;
ethernetif->rx_status = 0;
/* Enable CH390 interrupt */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
ethernetif->rx_len = 0u;
ethernetif->rx_status = 0u;
ch390_interrupt_init();
}
/**
* @brief Transmit a packet via CH390
* @param netif Network interface structure
* @param p Packet buffer to transmit
* @return ERR_OK on success
*/
static err_t low_level_output(struct netif *netif, struct pbuf *p)
{
struct pbuf *q;
/* Take SPI mutex */
if (spi_mutex != NULL)
{
xSemaphoreTake(spi_mutex, portMAX_DELAY);
}
uint32_t primask;
LWIP_UNUSED_ARG(netif);
primask = ethernetif_lock();
#if ETH_PAD_SIZE
pbuf_remove_header(p, ETH_PAD_SIZE);
#endif
/* Copy data to CH390 TX buffer */
for (q = p; q != NULL; q = q->next)
{
for (q = p; q != NULL; q = q->next) {
ch390_write_mem(q->payload, q->len);
}
/* Wait until last transmit complete */
while (ch390_read_reg(CH390_TCR) & TCR_TXREQ)
{
taskYIELD();
while (ch390_read_reg(CH390_TCR) & TCR_TXREQ) {
}
/* Set packet length */
ch390_write_reg(CH390_TXPLL, p->tot_len & 0xFF);
ch390_write_reg(CH390_TXPLH, (p->tot_len >> 8) & 0xFF);
/* Issue transmit request */
ch390_write_reg(CH390_TXPLL, p->tot_len & 0xFFu);
ch390_write_reg(CH390_TXPLH, (p->tot_len >> 8) & 0xFFu);
ch390_send_request();
/* Release SPI mutex */
if (spi_mutex != NULL)
{
xSemaphoreGive(spi_mutex);
}
ethernetif_unlock(primask);
#if ETH_PAD_SIZE
pbuf_add_header(p, ETH_PAD_SIZE);
#endif
LINK_STATS_INC(link.xmit);
return ERR_OK;
}
/**
* @brief Receive a packet from CH390
* @param netif Network interface structure
* @return Packet buffer containing received data, or NULL if no packet
*/
static struct pbuf *low_level_input(struct netif *netif)
{
struct ethernetif *ethernetif = netif->state;
@@ -153,281 +123,167 @@ static struct pbuf *low_level_input(struct netif *netif)
uint16_t len;
uint8_t rx_ready;
uint8_t rx_header[4];
/* Take SPI mutex */
if (spi_mutex != NULL)
{
xSemaphoreTake(spi_mutex, portMAX_DELAY);
}
/* Check if packet is ready */
ch390_read_reg(CH390_MRCMDX); /* Dummy read */
uint32_t primask;
primask = ethernetif_lock();
ch390_read_reg(CH390_MRCMDX);
rx_ready = ch390_read_reg(CH390_MRCMDX);
if (rx_ready & CH390_PKT_ERR)
{
/* RX error - reset RX FIFO */
ch390_write_reg(CH390_RCR, 0); /* RX disable */
ch390_write_reg(CH390_MPTRCR, 0x01); /* Reset RX FIFO pointer */
ch390_write_reg(CH390_MRRH, 0x0C);
ch390_delay_us(1000);
ch390_write_reg(CH390_RCR, RCR_RXEN | RCR_DIS_CRC); /* RX Enable */
if (rx_ready & CH390_PKT_ERR) {
ch390_write_reg(CH390_RCR, 0u);
ch390_write_reg(CH390_MPTRCR, 0x01u);
ch390_write_reg(CH390_MRRH, 0x0Cu);
ch390_delay_us(1000u);
ch390_write_reg(CH390_RCR, RCR_RXEN | RCR_DIS_CRC);
ethernetif->rx_len = 0u;
LINK_STATS_INC(link.drop);
ethernetif->rx_len = 0;
if (spi_mutex != NULL)
{
xSemaphoreGive(spi_mutex);
}
ethernetif_unlock(primask);
return NULL;
}
if (!(rx_ready & CH390_PKT_RDY))
{
/* No packet ready */
ethernetif->rx_len = 0;
if (spi_mutex != NULL)
{
xSemaphoreGive(spi_mutex);
}
if ((rx_ready & CH390_PKT_RDY) == 0u) {
ethernetif->rx_len = 0u;
ethernetif_unlock(primask);
return NULL;
}
/* Read RX header (status + length) */
ch390_read_mem(rx_header, 4);
ethernetif->rx_status = rx_header[1];
/* Length includes 4-byte CRC, subtract it */
ethernetif->rx_len = (rx_header[2] | (rx_header[3] << 8)) - 4;
ethernetif->rx_len = (uint16_t)(((uint16_t)rx_header[2] | ((uint16_t)rx_header[3] << 8)) - 4u);
len = ethernetif->rx_len;
#if ETH_PAD_SIZE
len += ETH_PAD_SIZE;
#endif
/* Allocate pbuf chain */
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
if (p != NULL)
{
if (p != NULL) {
#if ETH_PAD_SIZE
pbuf_remove_header(p, ETH_PAD_SIZE);
#endif
/* Read packet data into pbuf chain */
for (q = p; q != NULL; q = q->next)
{
for (q = p; q != NULL; q = q->next) {
ch390_read_mem(q->payload, q->len);
}
#if ETH_PAD_SIZE
pbuf_add_header(p, ETH_PAD_SIZE);
#endif
/* Skip CRC (4 bytes) */
ch390_drop_packet(4);
ch390_drop_packet(4u);
LINK_STATS_INC(link.recv);
}
else
{
/* No memory - drop packet */
ch390_drop_packet(ethernetif->rx_len + 4);
} else {
ch390_drop_packet((uint16_t)(ethernetif->rx_len + 4u));
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
}
/* Release SPI mutex */
if (spi_mutex != NULL)
{
xSemaphoreGive(spi_mutex);
}
ethernetif_unlock(primask);
return p;
}
/*---------------------------------------------------------------------------
* Public Interface Functions
*---------------------------------------------------------------------------*/
/**
* @brief Process received ethernet packets
* @param netif Network interface structure
*/
void ethernetif_input(struct netif *netif)
{
struct pbuf *p;
/* Get received packet */
p = low_level_input(netif);
if (p != NULL)
{
/* Pass to LwIP stack */
if (netif->input(p, netif) != ERR_OK)
{
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
struct pbuf *p = low_level_input(netif);
if (p != NULL) {
if (netif->input(p, netif) != ERR_OK) {
pbuf_free(p);
}
}
}
/**
* @brief Initialize the ethernet interface
* @param netif Network interface structure
* @return ERR_OK on success
*/
err_t ethernetif_init(struct netif *netif)
{
struct ethernetif *ethernetif;
LWIP_ASSERT("netif != NULL", (netif != NULL));
/* Allocate ethernetif state structure */
ethernetif = mem_malloc(sizeof(struct ethernetif));
if (ethernetif == NULL)
{
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));
if (ethernetif == NULL) {
return ERR_MEM;
}
memset(ethernetif, 0, sizeof(struct ethernetif));
#if LWIP_NETIF_HOSTNAME
netif->hostname = "tcp2uart";
#endif
/* Initialize SNMP variables */
MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, 100000000);
netif->state = ethernetif;
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
/* Set output functions */
#if LWIP_NETIF_HOSTNAME
netif->hostname = "tcp2uart";
#endif
MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, 100000000);
#if LWIP_IPV4
netif->output = etharp_output;
#endif
netif->linkoutput = low_level_output;
/* Initialize hardware */
low_level_init(netif);
return ERR_OK;
}
/**
* @brief Initialize LwIP network interface
* @param ipaddr IP address
* @param netmask Network mask
* @param gw Gateway address
*/
void lwip_netif_init(const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw)
{
/* Add network interface */
netif_add(&ch390_netif, ipaddr, netmask, gw, NULL,
&ethernetif_init, &tcpip_input);
/* Set as default interface */
netif_add(&ch390_netif, ipaddr, netmask, gw, NULL, &ethernetif_init, &ethernet_input);
netif_set_default(&ch390_netif);
/* Set interface down initially */
netif_set_link_down(&ch390_netif);
netif_set_up(&ch390_netif);
}
/**
* @brief Check and handle CH390 link status
*/
void ethernetif_check_link(void)
{
uint8_t link_status;
/* Take SPI mutex */
if (spi_mutex != NULL)
{
xSemaphoreTake(spi_mutex, portMAX_DELAY);
}
link_status = ch390_get_link_status();
/* Release SPI mutex */
if (spi_mutex != NULL)
{
xSemaphoreGive(spi_mutex);
}
if (link_status)
{
if (!netif_is_link_up(&ch390_netif))
{
uint8_t link_up;
uint32_t primask = ethernetif_lock();
link_up = (uint8_t)ch390_get_link_status();
ethernetif_unlock(primask);
if (link_up) {
if (!netif_is_link_up(&ch390_netif)) {
netif_set_link_up(&ch390_netif);
}
}
else
{
if (netif_is_link_up(&ch390_netif))
{
netif_set_link_down(&ch390_netif);
}
} else if (netif_is_link_up(&ch390_netif)) {
netif_set_link_down(&ch390_netif);
}
}
/**
* @brief Process all pending RX packets
*/
void ethernetif_poll(void)
{
uint8_t int_status;
/* Take SPI mutex */
if (spi_mutex != NULL)
{
xSemaphoreTake(spi_mutex, portMAX_DELAY);
uint32_t primask;
if (g_ch390_irq_pending == 0u) {
return;
}
/* Read interrupt status */
primask = ethernetif_lock();
int_status = ch390_read_reg(CH390_ISR);
/* Clear interrupt flags */
ch390_write_reg(CH390_ISR, int_status);
/* Release SPI mutex */
if (spi_mutex != NULL)
{
xSemaphoreGive(spi_mutex);
}
/* Handle link change */
if (int_status & ISR_LNKCHG)
{
g_ch390_irq_pending = 0u;
ethernetif_unlock(primask);
if ((int_status & ISR_LNKCHG) != 0u) {
ethernetif_check_link();
}
/* Handle RX overflow */
if (int_status & ISR_ROS)
{
/* RX overflow - packets might be corrupted */
if ((int_status & ISR_ROS) != 0u) {
LINK_STATS_INC(link.err);
}
/* Process received packets */
if (int_status & ISR_PR)
{
/* Process all available packets */
while (1)
{
if ((int_status & ISR_PR) != 0u) {
while (1) {
struct pbuf *p = low_level_input(&ch390_netif);
if (p == NULL)
{
if (p == NULL) {
break;
}
if (ch390_netif.input(p, &ch390_netif) != ERR_OK)
{
if (ch390_netif.input(p, &ch390_netif) != ERR_OK) {
pbuf_free(p);
}
}
}
}
u32_t sys_now(void)
{
return HAL_GetTick();
}
u32_t sys_jiffies(void)
{
return HAL_GetTick();
}
+5 -41
View File
@@ -1,63 +1,27 @@
/**
* @file ethernetif.h
* @brief Ethernet interface header for CH390 + LwIP + FreeRTOS
* @brief CH390 Ethernet interface for lwIP NO_SYS mode.
*/
#ifndef __ETHERNETIF_H__
#define __ETHERNETIF_H__
#include "lwip/netif.h"
#include "lwip/err.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Ethernet interface state structure */
struct ethernetif {
uint16_t rx_len;
uint8_t rx_status;
uint8_t rx_status;
};
/* Global network interface */
extern struct netif ch390_netif;
/**
* @brief Initialize the ethernet interface
* @param netif Network interface structure
* @return ERR_OK on success
*/
err_t ethernetif_init(struct netif *netif);
/**
* @brief Process received ethernet packets
* @param netif Network interface structure
* @note Call this from the LwIP task when packets are available
*/
void ethernetif_input(struct netif *netif);
/**
* @brief Initialize LwIP network interface with static IP
* @param ipaddr IP address
* @param netmask Network mask
* @param gw Gateway address
*/
void lwip_netif_init(const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw);
/**
* @brief Check and handle CH390 interrupt status
* @note Call this from the LwIP task periodically or on interrupt
*/
void ethernetif_check_link(void);
/**
* @brief Process all pending RX packets
* @note Call this from the LwIP task when RX interrupt occurs
*/
void ethernetif_poll(void);
void ethernetif_set_irq_pending(void);
uint8_t ethernetif_is_irq_pending(void);
#ifdef __cplusplus
}
#endif
#endif /* __ETHERNETIF_H__ */