110#ifdef USE_LWIP_FAST_SELECT
114#include <lwip/priv/sockets_priv.h>
118#include <freertos/FreeRTOS.h>
119#include <freertos/task.h>
141_Static_assert(
sizeof(TaskHandle_t) <= 4,
"TaskHandle_t must be <= 4 bytes for atomic access");
142_Static_assert(
sizeof(netconn_callback) <= 4,
"netconn_callback must be <= 4 bytes for atomic access");
146_Static_assert(
sizeof(((
struct lwip_sock *) 0)->rcvevent) == 2,
147 "rcvevent size changed — update int16_t cast in esphome_lwip_socket_has_data() in lwip_fast_select.h");
151_Static_assert(offsetof(
struct netconn, callback) %
sizeof(netconn_callback) == 0,
152 "netconn.callback must be naturally aligned for atomic access");
153_Static_assert(offsetof(
struct lwip_sock, rcvevent) %
sizeof(((
struct lwip_sock *) 0)->rcvevent) == 0,
154 "lwip_sock.rcvevent must be naturally aligned for atomic access");
158 "lwip_sock.rcvevent offset changed — update ESPHOME_LWIP_SOCK_RCVEVENT_OFFSET in lwip_fast_select.h");
161static TaskHandle_t s_main_loop_task = NULL;
164static netconn_callback s_original_callback = NULL;
168static void esphome_socket_event_callback(
struct netconn *conn,
enum netconn_evt evt, u16_t
len) {
173 s_original_callback(conn, evt,
len);
179 if (evt == NETCONN_EVT_RCVPLUS) {
180 TaskHandle_t task = s_main_loop_task;
182 xTaskNotifyGive(task);
197static inline struct lwip_sock *get_sock(
int fd) {
198 struct lwip_sock *sock = lwip_socket_dbg_get_socket(fd);
199 if (sock == NULL || sock->conn == NULL)
211 if (s_original_callback == NULL) {
212 s_original_callback = sock->conn->callback;
217 sock->conn->callback = esphome_socket_event_callback;
221 if (sock == NULL || sock->conn == NULL)
223 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP)
225 if (sock->conn->pcb.tcp == NULL)
228 tcp_nagle_disable(sock->conn->pcb.tcp);
230 tcp_nagle_enable(sock->conn->pcb.tcp);
237 TaskHandle_t task = s_main_loop_task;
239 xTaskNotifyGive(task);
245 TaskHandle_t task = s_main_loop_task;
247 vTaskNotifyGiveFromISR(task, (BaseType_t *) px_higher_priority_task_woken);
256 if (xPortInIsrContext()) {
257 int px_higher_priority_task_woken = 0;
259 portYIELD_FROM_ISR(px_higher_priority_task_woken);
void IRAM_ATTR esphome_lwip_wake_main_loop_any_context(void)
Wake the main loop task from any context (ISR, thread, or main loop).
void esphome_lwip_fast_select_init(void)
Initialize fast select — must be called from the main loop task during setup().
void IRAM_ATTR esphome_lwip_wake_main_loop_from_isr(int *px_higher_priority_task_woken)
Wake the main loop task from an ISR — costs <1 us.
bool esphome_lwip_set_nodelay(struct lwip_sock *sock, bool enable)
Set or clear TCP_NODELAY on a socket's tcp_pcb directly.
void esphome_lwip_hook_socket(struct lwip_sock *sock)
Hook a socket's netconn callback to notify the main loop task on receive events.
struct lwip_sock * esphome_lwip_get_sock(int fd)
Look up a LwIP socket struct from a file descriptor.
void esphome_lwip_wake_main_loop(void)
Wake the main loop task from another FreeRTOS task — costs <1 us.
@ ESPHOME_LWIP_SOCK_RCVEVENT_OFFSET