From 5d9d3e205b25bae2aaaafcbf9cfa5d19e08aa559 Mon Sep 17 00:00:00 2001 From: irrlicht Date: Tue, 12 May 2026 14:17:44 +0200 Subject: [PATCH] Wifi, TCP-Client and Ping/Pong --- wifi_tcp/CMakeLists.txt | 34 ++++++++ wifi_tcp/lwipopts.h | 46 +++++++++++ wifi_tcp/pico_sdk_import.cmake | 73 ++++++++++++++++++ wifi_tcp/wifi_tcp.c | 137 +++++++++++++++++++++++++++++++++ 4 files changed, 290 insertions(+) create mode 100644 wifi_tcp/CMakeLists.txt create mode 100644 wifi_tcp/lwipopts.h create mode 100644 wifi_tcp/pico_sdk_import.cmake create mode 100644 wifi_tcp/wifi_tcp.c diff --git a/wifi_tcp/CMakeLists.txt b/wifi_tcp/CMakeLists.txt new file mode 100644 index 0000000..0e16a27 --- /dev/null +++ b/wifi_tcp/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.13) + +include(pico_sdk_import.cmake) + +project(wifi_tcp C CXX ASM) + +pico_sdk_init() + +if (NOT WIFI_SSID OR NOT WIFI_PASSWORD) + message(FATAL_ERROR "Bitte WIFI_SSID und WIFI_PASSWORD per -D setzen") +endif() + +add_executable(wifi_tcp + wifi_tcp.c +) + +target_compile_definitions(wifi_tcp PRIVATE + WIFI_SSID=\"${WIFI_SSID}\" + WIFI_PASSWORD=\"${WIFI_PASSWORD}\" +) + +target_include_directories(wifi_tcp PRIVATE + ${CMAKE_CURRENT_LIST_DIR} +) + +target_link_libraries(wifi_tcp + pico_stdlib + pico_cyw43_arch_lwip_threadsafe_background +) + +pico_enable_stdio_usb(wifi_tcp 1) +pico_enable_stdio_uart(wifi_tcp 0) + +pico_add_extra_outputs(wifi_tcp) diff --git a/wifi_tcp/lwipopts.h b/wifi_tcp/lwipopts.h new file mode 100644 index 0000000..fafb9ee --- /dev/null +++ b/wifi_tcp/lwipopts.h @@ -0,0 +1,46 @@ +#ifndef _LWIPOPTS_H +#define _LWIPOPTS_H + +// lwIP-Konfig fuer pico_cyw43_arch_lwip_threadsafe_background. +// Werte uebernommen aus pico-examples/pico_w/wifi/lwipopts_examples_common.h. + +#define NO_SYS 1 +#define LWIP_SOCKET 0 +#define MEM_LIBC_MALLOC 0 +#define MEM_ALIGNMENT 4 +#define MEM_SIZE 4000 +#define MEMP_NUM_TCP_SEG 32 +#define MEMP_NUM_ARP_QUEUE 10 +#define PBUF_POOL_SIZE 24 + +#define LWIP_ARP 1 +#define LWIP_ETHERNET 1 +#define LWIP_ICMP 1 +#define LWIP_RAW 1 +#define LWIP_DHCP 1 +#define LWIP_IPV4 1 +#define LWIP_TCP 1 +#define LWIP_UDP 1 +#define LWIP_DNS 1 +#define LWIP_TCP_KEEPALIVE 1 +#define LWIP_NETCONN 0 + +#define TCP_MSS 1460 +#define TCP_WND (8 * TCP_MSS) +#define TCP_SND_BUF (8 * TCP_MSS) +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS)) + +#define LWIP_NETIF_STATUS_CALLBACK 1 +#define LWIP_NETIF_LINK_CALLBACK 1 +#define LWIP_NETIF_HOSTNAME 1 +#define LWIP_NETIF_TX_SINGLE_PBUF 1 +#define DHCP_DOES_ARP_CHECK 0 +#define LWIP_DHCP_DOES_ACD_CHECK 0 +#define LWIP_CHKSUM_ALGORITHM 3 + +#define MEM_STATS 0 +#define SYS_STATS 0 +#define MEMP_STATS 0 +#define LINK_STATS 0 + +#endif diff --git a/wifi_tcp/pico_sdk_import.cmake b/wifi_tcp/pico_sdk_import.cmake new file mode 100644 index 0000000..65f8a6f --- /dev/null +++ b/wifi_tcp/pico_sdk_import.cmake @@ -0,0 +1,73 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG master + GIT_SUBMODULES_RECURSE FALSE + ) + else () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG master + ) + endif () + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + FetchContent_Populate(pico_sdk) + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/wifi_tcp/wifi_tcp.c b/wifi_tcp/wifi_tcp.c new file mode 100644 index 0000000..fac1895 --- /dev/null +++ b/wifi_tcp/wifi_tcp.c @@ -0,0 +1,137 @@ +#include +#include + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" + +#include "lwip/pbuf.h" +#include "lwip/tcp.h" + +#define SERVER_IP "192.168.161.25" +#define SERVER_PORT 8080 + +typedef struct { + struct tcp_pcb *pcb; + ip_addr_t remote; + volatile bool done; +} client_t; + +static void finish(client_t *c) { + if (c->pcb) { + tcp_arg(c->pcb, NULL); + tcp_recv(c->pcb, NULL); + tcp_err(c->pcb, NULL); + tcp_close(c->pcb); + c->pcb = NULL; + } + c->done = true; +} + +static void send_line(struct tcp_pcb *pcb, const char *msg) { + err_t err = tcp_write(pcb, msg, strlen(msg), TCP_WRITE_FLAG_COPY); + if (err == ERR_OK) { + tcp_output(pcb); + } else { + printf("tcp_write err=%d\n", err); + } +} + +static err_t on_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { + client_t *c = (client_t *)arg; + if (!p) { + printf("Server hat Verbindung geschlossen\n"); + finish(c); + return ERR_OK; + } + + char buf[64]; + uint16_t n = pbuf_copy_partial(p, buf, sizeof(buf) - 1, 0); + buf[n] = '\0'; + + printf("<< %s", buf); + + if (strstr(buf, "ping")) { + printf(">> pong\n"); + send_line(pcb, "pong\n"); + } + + tcp_recved(pcb, p->tot_len); + pbuf_free(p); + return ERR_OK; +} + +static void on_err(void *arg, err_t err) { + client_t *c = (client_t *)arg; + printf("TCP-Fehler: %d\n", err); + // lwIP hat das pcb in diesem Callback bereits freigegeben. + c->pcb = NULL; + c->done = true; +} + +static err_t on_connected(void *arg, struct tcp_pcb *pcb, err_t err) { + client_t *c = (client_t *)arg; + if (err != ERR_OK) { + printf("connect-Callback err=%d\n", err); + finish(c); + return err; + } + printf("Verbunden — sende Hallo\n"); + const char *msg = "Hallo vom Pico 2W\n"; + err = tcp_write(pcb, msg, strlen(msg), TCP_WRITE_FLAG_COPY); + if (err == ERR_OK) { + tcp_output(pcb); + } else { + printf("tcp_write err=%d\n", err); + } + return err; +} + +int main(void) { + stdio_init_all(); + sleep_ms(2000); // Zeit, das USB-Serial-Terminal zu oeffnen + + if (cyw43_arch_init()) { + printf("cyw43_arch_init fehlgeschlagen\n"); + return 1; + } + cyw43_arch_enable_sta_mode(); + + printf("Verbinde mit WLAN \"%s\"...\n", WIFI_SSID); + if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, + CYW43_AUTH_WPA2_AES_PSK, 30000)) { + printf("WLAN-Verbindung fehlgeschlagen\n"); + return 1; + } + printf("WLAN OK\n"); + + client_t client = {0}; + if (!ip4addr_aton(SERVER_IP, &client.remote)) { + printf("Ungueltige Server-IP\n"); + return 1; + } + + client.pcb = tcp_new_ip_type(IP_GET_TYPE(&client.remote)); + if (!client.pcb) { + printf("tcp_new fehlgeschlagen\n"); + return 1; + } + tcp_arg(client.pcb, &client); + tcp_recv(client.pcb, on_recv); + tcp_err(client.pcb, on_err); + + printf("Verbinde TCP %s:%d\n", SERVER_IP, SERVER_PORT); + cyw43_arch_lwip_begin(); + err_t err = tcp_connect(client.pcb, &client.remote, SERVER_PORT, on_connected); + cyw43_arch_lwip_end(); + if (err != ERR_OK) { + printf("tcp_connect err=%d\n", err); + return 1; + } + + while (!client.done) { + sleep_ms(100); + } + + cyw43_arch_deinit(); + return 0; +}