1 /*
2  * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include "pico/async_context.h"
8 #include "pico/time.h"
9 #include "lwip/tcpip.h"
10 #include "lwip/timeouts.h"
11 
12 #include "FreeRTOS.h"
13 #include "semphr.h"
14 
15 #if NO_SYS
16 #error lwip_freertos_async_context_bindings requires NO_SYS=0
17 #endif
18 
19 static async_context_t * volatile lwip_context;
20 // lwIP tcpip_task cannot be shutdown, so we block it when we are de-initialized.
21 static SemaphoreHandle_t tcpip_task_blocker;
22 
tcpip_init_done(void * param)23 static void tcpip_init_done(void *param) {
24     xSemaphoreGive((SemaphoreHandle_t)param);
25 }
26 
lwip_freertos_init(async_context_t * context)27 bool lwip_freertos_init(async_context_t *context) {
28     assert(!lwip_context);
29     lwip_context = context;
30     static bool done_lwip_init;
31     if (!done_lwip_init) {
32         done_lwip_init = true;
33         SemaphoreHandle_t init_sem = xSemaphoreCreateBinary();
34         tcpip_task_blocker = xSemaphoreCreateBinary();
35         tcpip_init(tcpip_init_done, init_sem);
36         xSemaphoreTake(init_sem, portMAX_DELAY);
37         vSemaphoreDelete(init_sem);
38     } else {
39         xSemaphoreGive(tcpip_task_blocker);
40     }
41     return true;
42 }
43 
clear_lwip_context(__unused void * param)44 static uint32_t clear_lwip_context(__unused void *param) {
45     lwip_context = NULL;
46     return 0;
47 }
48 
lwip_freertos_deinit(__unused async_context_t * context)49 void lwip_freertos_deinit(__unused async_context_t *context) {
50     // clear the lwip context under lock as lwIP may still be running in tcpip_task
51     async_context_execute_sync(context, clear_lwip_context, NULL);
52 }
53 
pico_lwip_custom_lock_tcpip_core(void)54 void pico_lwip_custom_lock_tcpip_core(void) {
55     while (!lwip_context) {
56         xSemaphoreTake(tcpip_task_blocker, portMAX_DELAY);
57     }
58     async_context_acquire_lock_blocking(lwip_context);
59 }
60 
pico_lwip_custom_unlock_tcpip_core(void)61 void pico_lwip_custom_unlock_tcpip_core(void) {
62     async_context_release_lock(lwip_context);
63 }
64