stm32: Integrate lwIP as implementation of usocket module.

This patch allows to use lwIP as the implementation of the usocket module,
instead of the existing socket-multiplexer that delegates the entire TCP/IP
layer to the NIC itself.

This is disabled by default, and enabled by defining MICROPY_PY_LWIP to 1.

When enabled, the lwIP TCP/IP stack will be included in the build with
default settings for memory usage and performance (see
lwip_inc/lwipopts.h).  It is then up to a particular NIC to register itself
with lwIP using the standard lwIP netif API.
This commit is contained in:
Damien George 2018-05-21 16:48:24 +10:00
parent 41766ba7e6
commit cda964198a
9 changed files with 183 additions and 3 deletions

View File

@ -184,6 +184,7 @@ SRC_LIBM = $(addprefix lib/libm/,\
endif
EXTMOD_SRC_C = $(addprefix extmod/,\
modlwip.c \
modonewire.c \
)
@ -337,6 +338,47 @@ SRC_MOD += $(addprefix $(CC3000_DIR)/src/,\
)
endif
LWIP_DIR = lib/lwip/src
INC += -I$(TOP)/$(LWIP_DIR)/include -Ilwip_inc
$(BUILD)/$(LWIP_DIR)/core/ipv4/dhcp.o: CFLAGS += -Wno-address
SRC_MOD += $(addprefix $(LWIP_DIR)/,\
core/def.c \
core/dns.c \
core/inet_chksum.c \
core/init.c \
core/ip.c \
core/mem.c \
core/memp.c \
core/netif.c \
core/pbuf.c \
core/raw.c \
core/stats.c \
core/sys.c \
core/tcp.c \
core/tcp_in.c \
core/tcp_out.c \
core/timeouts.c \
core/udp.c \
core/ipv4/autoip.c \
core/ipv4/dhcp.c \
core/ipv4/etharp.c \
core/ipv4/icmp.c \
core/ipv4/igmp.c \
core/ipv4/ip4_addr.c \
core/ipv4/ip4.c \
core/ipv4/ip4_frag.c \
core/ipv6/dhcp6.c \
core/ipv6/ethip6.c \
core/ipv6/icmp6.c \
core/ipv6/inet6.c \
core/ipv6/ip6_addr.c \
core/ipv6/ip6.c \
core/ipv6/ip6_frag.c \
core/ipv6/mld6.c \
core/ipv6/nd6.c \
netif/ethernet.c \
)
OBJ =
OBJ += $(PY_O)
OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o))

View File

@ -0,0 +1,8 @@
#ifndef MICROPY_INCLUDED_STM32_LWIP_ARCH_CC_H
#define MICROPY_INCLUDED_STM32_LWIP_ARCH_CC_H
#include <assert.h>
#define LWIP_PLATFORM_DIAG(x)
#define LWIP_PLATFORM_ASSERT(x) { assert(1); }
#endif // MICROPY_INCLUDED_STM32_LWIP_ARCH_CC_H

View File

@ -0,0 +1 @@
// empty

View File

@ -0,0 +1,61 @@
#ifndef MICROPY_INCLUDED_STM32_LWIP_LWIPOPTS_H
#define MICROPY_INCLUDED_STM32_LWIP_LWIPOPTS_H
#include <stdint.h>
#define NO_SYS 1
#define SYS_LIGHTWEIGHT_PROT 1
#define MEM_ALIGNMENT 4
#define LWIP_CHKSUM_ALGORITHM 3
#define LWIP_ARP 1
#define LWIP_ETHERNET 1
#define LWIP_NETCONN 0
#define LWIP_SOCKET 0
#define LWIP_STATS 0
#define LWIP_NETIF_HOSTNAME 1
#define LWIP_IPV6 0
#define LWIP_DHCP 1
#define LWIP_DHCP_CHECK_LINK_UP 1
#define LWIP_DNS 1
#define LWIP_IGMP 1
#define SO_REUSE 1
extern uint32_t rng_get(void);
#define LWIP_RAND() rng_get()
// default
// lwip takes 15800 bytes; TCP d/l: 380k/s local, 7.2k/s remote
// TCP u/l is very slow
#if 0
// lwip takes 19159 bytes; TCP d/l and u/l are around 320k/s on local network
#define MEM_SIZE (5000)
#define TCP_WND (4 * TCP_MSS)
#define TCP_SND_BUF (4 * TCP_MSS)
#endif
#if 1
// lwip takes 26700 bytes; TCP dl/ul are around 750/600 k/s on local network
#define MEM_SIZE (8000)
#define TCP_MSS (800)
#define TCP_WND (8 * TCP_MSS)
#define TCP_SND_BUF (8 * TCP_MSS)
#define MEMP_NUM_TCP_SEG (32)
#endif
#if 0
// lwip takes 45600 bytes; TCP dl/ul are around 1200/1000 k/s on local network
#define MEM_SIZE (16000)
#define TCP_MSS (1460)
#define TCP_WND (8 * TCP_MSS)
#define TCP_SND_BUF (8 * TCP_MSS)
#define MEMP_NUM_TCP_SEG (32)
#endif
typedef uint32_t sys_prot_t;
#endif // MICROPY_INCLUDED_STM32_LWIP_LWIPOPTS_H

View File

@ -34,6 +34,7 @@
#include "lib/mp-readline/readline.h"
#include "lib/utils/pyexec.h"
#include "lib/oofatfs/ff.h"
#include "lwip/init.h"
#include "extmod/vfs.h"
#include "extmod/vfs_fat.h"
@ -512,6 +513,12 @@ void stm32_main(uint32_t reset_mode) {
sdcard_init();
#endif
storage_init();
#if MICROPY_PY_LWIP
// lwIP doesn't allow to reinitialise itself by subsequent calls to this function
// because the system timeout list (next_timeout) is only ever reset by BSS clearing.
// So for now we only init the lwIP stack once on power-up.
lwip_init();
#endif
soft_reset:
@ -726,6 +733,9 @@ soft_reset_exit:
storage_flush();
printf("PYB: soft reboot\n");
#if MICROPY_PY_NETWORK
mod_network_deinit();
#endif
timer_deinit();
uart_deinit();
#if MICROPY_HW_ENABLE_CAN

View File

@ -30,10 +30,34 @@
#include "py/objlist.h"
#include "py/runtime.h"
#include "py/mphal.h"
#include "modnetwork.h"
#if MICROPY_PY_NETWORK
#if MICROPY_PY_LWIP
#include "lwip/netif.h"
#include "lwip/timeouts.h"
u32_t sys_now(void) {
return mp_hal_ticks_ms();
}
void pyb_lwip_poll(void) {
// Poll all the NICs for incoming data
for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) {
if (netif->flags & NETIF_FLAG_LINK_UP) {
mod_network_nic_type_t *nic = netif->state;
nic->poll_callback(nic, netif);
}
}
// Run the lwIP internal updates
sys_check_timeouts();
}
#endif
/// \module network - network configuration
///
/// This module provides network drivers and routing configuration.
@ -42,6 +66,15 @@ void mod_network_init(void) {
mp_obj_list_init(&MP_STATE_PORT(mod_network_nic_list), 0);
}
void mod_network_deinit(void) {
#if MICROPY_PY_LWIP
for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) {
netif_remove(netif);
}
// TODO there may be some timeouts that are still pending...
#endif
}
void mod_network_register_nic(mp_obj_t nic) {
for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) {
if (MP_STATE_PORT(mod_network_nic_list).items[i] == nic) {

View File

@ -35,6 +35,17 @@
#define MOD_NETWORK_SOCK_DGRAM (2)
#define MOD_NETWORK_SOCK_RAW (3)
#if MICROPY_PY_LWIP
struct netif;
typedef struct _mod_network_nic_type_t {
mp_obj_type_t base;
void (*poll_callback)(void *data, struct netif *netif);
} mod_network_nic_type_t;
#else
struct _mod_network_socket_obj_t;
typedef struct _mod_network_nic_type_t {
@ -73,10 +84,13 @@ typedef struct _mod_network_socket_obj_t {
};
} mod_network_socket_obj_t;
#endif
extern const mod_network_nic_type_t mod_network_nic_type_wiznet5k;
extern const mod_network_nic_type_t mod_network_nic_type_cc3k;
void mod_network_init(void);
void mod_network_deinit(void);
void mod_network_register_nic(mp_obj_t nic);
mp_obj_t mod_network_find_nic(const uint8_t *ip);

View File

@ -35,7 +35,7 @@
#include "lib/netutils/netutils.h"
#include "modnetwork.h"
#if MICROPY_PY_USOCKET
#if MICROPY_PY_USOCKET && !MICROPY_PY_LWIP
/******************************************************************************/
// socket class
@ -465,4 +465,4 @@ const mp_obj_module_t mp_module_usocket = {
.globals = (mp_obj_dict_t*)&mp_module_usocket_globals,
};
#endif // MICROPY_PY_USOCKET
#endif // MICROPY_PY_USOCKET && !MICROPY_PY_LWIP

View File

@ -192,12 +192,21 @@ extern const struct _mp_obj_module_t mp_module_onewire;
#define STM_BUILTIN_MODULE
#endif
#if MICROPY_PY_USOCKET
#if MICROPY_PY_USOCKET && MICROPY_PY_LWIP
// usocket implementation provided by lwIP
#define SOCKET_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_lwip) },
#define SOCKET_BUILTIN_MODULE_WEAK_LINKS { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_lwip) },
#define SOCKET_POLL extern void pyb_lwip_poll(void); pyb_lwip_poll();
#elif MICROPY_PY_USOCKET
// usocket implementation provided by skeleton wrapper
#define SOCKET_BUILTIN_MODULE { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_usocket) },
#define SOCKET_BUILTIN_MODULE_WEAK_LINKS { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_usocket) },
#define SOCKET_POLL
#else
// no usocket module
#define SOCKET_BUILTIN_MODULE
#define SOCKET_BUILTIN_MODULE_WEAK_LINKS
#define SOCKET_POLL
#endif
#if MICROPY_PY_NETWORK
@ -313,6 +322,7 @@ static inline mp_uint_t disable_irq(void) {
do { \
extern void mp_handle_pending(void); \
mp_handle_pending(); \
SOCKET_POLL \
if (pyb_thread_enabled) { \
MP_THREAD_GIL_EXIT(); \
pyb_thread_yield(); \
@ -328,6 +338,7 @@ static inline mp_uint_t disable_irq(void) {
do { \
extern void mp_handle_pending(void); \
mp_handle_pending(); \
SOCKET_POLL \
__WFI(); \
} while (0);