mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-05-22 17:47:04 +08:00
feat(lwip): Add socket UDP sync function
This commit is contained in:
@ -27,6 +27,23 @@ config LWIP_SOCKET_MULTITHREAD
|
|||||||
Enable the option can enable LWIP socket multithread and all
|
Enable the option can enable LWIP socket multithread and all
|
||||||
function will be thread safe.
|
function will be thread safe.
|
||||||
|
|
||||||
|
config ESP_UDP_SYNC_SEND
|
||||||
|
bool "LWIP socket UDP sync send"
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Enable the option can enable LWIP socket UDP sync send. CPU cost
|
||||||
|
should decrease but memory cost increase and it can make UDP
|
||||||
|
throughput increase a lot.
|
||||||
|
|
||||||
|
config ESP_UDP_SYNC_RETRY_MAX
|
||||||
|
int "LWIP socket UDP sync send retry max count"
|
||||||
|
range 1 10
|
||||||
|
default 5
|
||||||
|
depends on ESP_UDP_SYNC_SEND
|
||||||
|
help
|
||||||
|
When UDP sync send count reaches the value, then the packet should
|
||||||
|
be lost and LWIP core thread wake up the up-level send thread.
|
||||||
|
|
||||||
config LWIP_MAX_SOCKETS
|
config LWIP_MAX_SOCKETS
|
||||||
int "Max number of open sockets"
|
int "Max number of open sockets"
|
||||||
range 1 16
|
range 1 16
|
||||||
|
@ -1409,6 +1409,9 @@ lwip_netconn_do_send(void *m)
|
|||||||
#endif
|
#endif
|
||||||
#if LWIP_UDP
|
#if LWIP_UDP
|
||||||
case NETCONN_UDP:
|
case NETCONN_UDP:
|
||||||
|
#if ESP_UDP
|
||||||
|
udp_sync_regitser(msg);
|
||||||
|
#endif /* ESP_UDP */
|
||||||
#if LWIP_CHECKSUM_ON_COPY
|
#if LWIP_CHECKSUM_ON_COPY
|
||||||
if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
|
if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) {
|
||||||
msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
|
msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
|
||||||
@ -1432,7 +1435,11 @@ lwip_netconn_do_send(void *m)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ESP_UDP
|
||||||
|
udp_sync_ack(msg);
|
||||||
|
#else
|
||||||
TCPIP_APIMSG_ACK(msg);
|
TCPIP_APIMSG_ACK(msg);
|
||||||
|
#endif /* ESP_UDP */
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LWIP_TCP
|
#if LWIP_TCP
|
||||||
|
@ -415,6 +415,10 @@ again:
|
|||||||
extern void send_from_list();
|
extern void send_from_list();
|
||||||
send_from_list();
|
send_from_list();
|
||||||
|
|
||||||
|
#if ESP_UDP
|
||||||
|
udp_sync_proc();
|
||||||
|
#endif
|
||||||
|
|
||||||
sleeptime = sys_timeouts_sleeptime();
|
sleeptime = sys_timeouts_sleeptime();
|
||||||
if (sleeptime == 0 || sys_arch_mbox_fetch(mbox, msg, sleeptime) == SYS_ARCH_TIMEOUT) {
|
if (sleeptime == 0 || sys_arch_mbox_fetch(mbox, msg, sleeptime) == SYS_ARCH_TIMEOUT) {
|
||||||
/* If a SYS_ARCH_TIMEOUT value is returned, a timeout occurred
|
/* If a SYS_ARCH_TIMEOUT value is returned, a timeout occurred
|
||||||
|
175
components/lwip/port/esp8266/freertos/udp_sync.c
Normal file
175
components/lwip/port/esp8266/freertos/udp_sync.c
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
// Copyright 2018-2019 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 <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <sys/errno.h>
|
||||||
|
#include "lwip/udp.h"
|
||||||
|
#include "lwip/priv/api_msg.h"
|
||||||
|
#include "lwip/priv/tcp_priv.h"
|
||||||
|
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
#if ESP_UDP
|
||||||
|
|
||||||
|
#define UDP_SYNC_MAX MEMP_NUM_NETCONN
|
||||||
|
#define UDP_SYNC_RETRY_MAX CONFIG_ESP_UDP_SYNC_RETRY_MAX
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All function has no mutex, so they must put into one task(LWIP main task).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if LWIP_TCPIP_CORE_LOCKING
|
||||||
|
#define TCPIP_APIMSG_ACK(m) NETCONN_SET_SAFE_ERR((m)->conn, (m)->err)
|
||||||
|
#else /* LWIP_TCPIP_CORE_LOCKING */
|
||||||
|
#define TCPIP_APIMSG_ACK(m) do { NETCONN_SET_SAFE_ERR((m)->conn, (m)->err); sys_sem_signal(LWIP_API_MSG_SEM(m)); } while(0)
|
||||||
|
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
||||||
|
|
||||||
|
typedef struct udp_sync {
|
||||||
|
struct api_msg *msg;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
int retry;
|
||||||
|
} udp_sync_t;
|
||||||
|
|
||||||
|
static const char *TAG = "udp_sync";
|
||||||
|
static size_t s_udp_sync_num;
|
||||||
|
static udp_sync_t s_udp_sync[UDP_SYNC_MAX];
|
||||||
|
static bool s_register_locked;
|
||||||
|
static struct api_msg *s_cur_msg;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief initialize UDP sync module
|
||||||
|
*/
|
||||||
|
void udp_sync_init(void)
|
||||||
|
{
|
||||||
|
memset(s_udp_sync, 0, sizeof(s_udp_sync));
|
||||||
|
s_register_locked = false;
|
||||||
|
s_udp_sync_num = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief register a UDP API message(struct api_msg) to module
|
||||||
|
*/
|
||||||
|
void udp_sync_regitser(void *in_msg)
|
||||||
|
{
|
||||||
|
s_cur_msg = in_msg;
|
||||||
|
|
||||||
|
if (s_register_locked == true)
|
||||||
|
return ;
|
||||||
|
|
||||||
|
struct api_msg *msg = (struct api_msg *)in_msg;
|
||||||
|
int s = msg->conn->socket;
|
||||||
|
|
||||||
|
if (s < 0 || s >= UDP_SYNC_MAX) {
|
||||||
|
ESP_LOGE(TAG, "UDP sync register error, socket is %d", s);
|
||||||
|
return ;
|
||||||
|
} else if (s_udp_sync[s].msg) {
|
||||||
|
ESP_LOGE(TAG, "UDP sync register error, msg is %p", s_udp_sync[s].msg);
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_udp_sync_num++;
|
||||||
|
s_udp_sync[s].ret = ERR_OK;
|
||||||
|
s_udp_sync[s].retry = 0;
|
||||||
|
s_udp_sync[s].msg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief ack the message
|
||||||
|
*/
|
||||||
|
void udp_sync_ack(void *in_msg)
|
||||||
|
{
|
||||||
|
struct api_msg *msg = (struct api_msg *)in_msg;
|
||||||
|
int s = msg->conn->socket;
|
||||||
|
|
||||||
|
if (s < 0 || s >= UDP_SYNC_MAX) {
|
||||||
|
ESP_LOGE(TAG, "UDP sync ack error, socket is %d", s);
|
||||||
|
return ;
|
||||||
|
} else if (!s_udp_sync[s].msg) {
|
||||||
|
ESP_LOGE(TAG, "UDP sync ack error, msg is NULL");
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only cache when low-level has no buffer to send packet */
|
||||||
|
if (s_udp_sync[s].ret != ERR_MEM || s_udp_sync[s].retry >= UDP_SYNC_RETRY_MAX) {
|
||||||
|
s_udp_sync[s].msg = NULL;
|
||||||
|
s_udp_sync[s].retry = 0;
|
||||||
|
s_udp_sync[s].ret = ERR_OK;
|
||||||
|
s_udp_sync_num--;
|
||||||
|
|
||||||
|
/* Todo: return real result */
|
||||||
|
msg->err = ESP_OK;
|
||||||
|
|
||||||
|
TCPIP_APIMSG_ACK(msg);
|
||||||
|
} else {
|
||||||
|
s_udp_sync[s].retry++;
|
||||||
|
ESP_LOGD(TAG, "UDP sync ack error, errno %d", s_udp_sync[s].ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
s_cur_msg = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief set the current message send result
|
||||||
|
*/
|
||||||
|
void udp_sync_set_ret(int ret)
|
||||||
|
{
|
||||||
|
/* Only poll and regitser can set current message */
|
||||||
|
if (!s_cur_msg) {
|
||||||
|
/* You may use it to debug */
|
||||||
|
//ESP_LOGE(TAG, "UDP sync ack error, current message is NULL");
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct api_msg *msg = s_cur_msg;
|
||||||
|
int s = msg->conn->socket;
|
||||||
|
|
||||||
|
if (s < 0 || s >= UDP_SYNC_MAX) {
|
||||||
|
ESP_LOGE(TAG, "UDP sync ack error, socket is %d", s);
|
||||||
|
return ;
|
||||||
|
} else if (!s_udp_sync[s].msg) {
|
||||||
|
ESP_LOGE(TAG, "UDP sync ack error, msg is NULL");
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_udp_sync[s].ret = ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief process the sync
|
||||||
|
*/
|
||||||
|
void udp_sync_proc(void)
|
||||||
|
{
|
||||||
|
if (!s_udp_sync_num)
|
||||||
|
return ;
|
||||||
|
|
||||||
|
s_register_locked = true;
|
||||||
|
for (int i = 0; i < UDP_SYNC_MAX; i++) {
|
||||||
|
if (!s_udp_sync[i].msg)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
lwip_netconn_do_send(s_udp_sync[i].msg);
|
||||||
|
#if 0
|
||||||
|
//Todo: Add this later
|
||||||
|
if (s_udp_sync[i].ret != ERR_OK)
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
s_register_locked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ESP_UDP */
|
@ -52,6 +52,10 @@
|
|||||||
|
|
||||||
#define ESP_LWIP 1
|
#define ESP_LWIP 1
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP_UDP_SYNC_SEND
|
||||||
|
#define ESP_UDP 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_LWIP_SOCKET_MULTITHREAD
|
#ifdef CONFIG_LWIP_SOCKET_MULTITHREAD
|
||||||
#define SOCKETS_MT
|
#define SOCKETS_MT
|
||||||
#endif
|
#endif
|
||||||
@ -2213,4 +2217,12 @@ void *memp_malloc_ll(size_t type);
|
|||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if ESP_UDP
|
||||||
|
#if !LWIP_UDP || !LWIP_SOCKET || !ESP_LWIP
|
||||||
|
#error "LWIP_UDP & LWIP_SOCKET & ESP_LWIP must be enable"
|
||||||
|
#else
|
||||||
|
#include "udp_sync.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __LWIP_HDR_LWIPOPTS_H__ */
|
#endif /* __LWIP_HDR_LWIPOPTS_H__ */
|
||||||
|
59
components/lwip/port/esp8266/include/udp_sync.h
Normal file
59
components/lwip/port/esp8266/include/udp_sync.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// Copyright 2018-2019 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.
|
||||||
|
|
||||||
|
#ifndef _UDP_SYNC_H
|
||||||
|
#define _UDP_SYNC_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief initialize UDP sync module
|
||||||
|
*/
|
||||||
|
void udp_sync_init(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief register a UDP API message(struct api_msg) to module
|
||||||
|
*
|
||||||
|
* @param in_msg message pointer
|
||||||
|
*/
|
||||||
|
void udp_sync_regitser(void *in_msg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief ack the message
|
||||||
|
*
|
||||||
|
* @param in_msg message pointer
|
||||||
|
*/
|
||||||
|
void udp_sync_ack(void *in_msg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief set the current message send result
|
||||||
|
*
|
||||||
|
* @param ret current message send result
|
||||||
|
*/
|
||||||
|
void udp_sync_set_ret(int ret);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief process the sync
|
||||||
|
*
|
||||||
|
* @param ret current message send result
|
||||||
|
*/
|
||||||
|
void udp_sync_proc(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _UDP_SYNC_H */
|
@ -302,6 +302,9 @@ static int8_t low_level_output(struct netif* netif, struct pbuf* p)
|
|||||||
* header, meaning we should not pass target low-level address here.
|
* header, meaning we should not pass target low-level address here.
|
||||||
*/
|
*/
|
||||||
err = esp_aio_sendto(&aio, NULL, 0);
|
err = esp_aio_sendto(&aio, NULL, 0);
|
||||||
|
#if ESP_UDP
|
||||||
|
udp_sync_set_ret(err);
|
||||||
|
#endif
|
||||||
if (err != ERR_OK) {
|
if (err != ERR_OK) {
|
||||||
if (err == ERR_MEM){
|
if (err == ERR_MEM){
|
||||||
insert_to_list(aio.fd, p);
|
insert_to_list(aio.fd, p);
|
||||||
|
Reference in New Issue
Block a user