From d85cdffa6f643d4b97ddde2faa4fcd94c409e12f Mon Sep 17 00:00:00 2001 From: aixiao Date: Sun, 10 Nov 2024 21:36:07 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B5=8B=E8=AF=95WIFI=20TCP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 3 +- SOFTWARE/CMakeLists.txt | 1 + SOFTWARE/Source/MAIN.cpp | 55 ++++++++-- SOFTWARE/Source/WIFI.c | 229 +++++++++++++++++++++++++++++++++++++++ SOFTWARE/Source/WIFI.h | 26 +++++ 5 files changed, 302 insertions(+), 12 deletions(-) create mode 100644 SOFTWARE/Source/WIFI.c create mode 100644 SOFTWARE/Source/WIFI.h diff --git a/.vscode/settings.json b/.vscode/settings.json index 170fe14..d8467fc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,7 @@ "cmake.sourceDirectory": "/mnt/c/Users/niuyuling/Desktop/raspberry-pico/Danger-alarm/SOFTWARE", "C_Cpp.errorSquiggles": "disabled", "files.associations": { - "cstring": "cpp" + "cstring": "cpp", + "random": "cpp" } } \ No newline at end of file diff --git a/SOFTWARE/CMakeLists.txt b/SOFTWARE/CMakeLists.txt index 6b097aa..fe31167 100644 --- a/SOFTWARE/CMakeLists.txt +++ b/SOFTWARE/CMakeLists.txt @@ -23,6 +23,7 @@ target_sources(Danger-alarm PRIVATE ${CMAKE_CURRENT_LIST_DIR}/Source/DTH11.cpp ${CMAKE_CURRENT_LIST_DIR}/Source/HC-12.cpp ${CMAKE_CURRENT_LIST_DIR}/Source/ZC13.cpp + ${CMAKE_CURRENT_LIST_DIR}/Source/WIFI.c ) pico_enable_stdio_uart(Danger-alarm 1) diff --git a/SOFTWARE/Source/MAIN.cpp b/SOFTWARE/Source/MAIN.cpp index b399731..6d42708 100644 --- a/SOFTWARE/Source/MAIN.cpp +++ b/SOFTWARE/Source/MAIN.cpp @@ -16,10 +16,14 @@ #include "HC-12.hpp" #include "ZC13.hpp" -#ifndef PICO_DEFAULT_LED_PIN -#warning pio/hello_pio example requires a board with a regular LED -#define PICO_DEFAULT_LED_PIN 25 +extern "C" { + #include "WIFI.h" +} + +#ifndef PICO_DEFAULT_LED_PIN + #warning pio/hello_pio example requires a board with a regular LED + #define PICO_DEFAULT_LED_PIN 25 #endif static inline bool uart_rx_program_available(PIO pio, uint sm) @@ -254,6 +258,42 @@ static void core1_main() return; } +int main(int argc, char *argv[]) +{ + stdio_init_all(); + sleep_ms(1000); + + if (cyw43_arch_init()) { + DEBUG_printf("failed to initialise\n"); + return 1; + } + cyw43_arch_enable_sta_mode(); + + printf("Connecting to Wi-Fi...\n"); + if (cyw43_arch_wifi_connect_timeout_ms("root", "@aixiao.19960623", CYW43_AUTH_WPA2_AES_PSK, 30000)) { + printf("failed to connect.\n"); + return 1; + } else { + printf("Connected.\n"); + } + + while (1) + { + run_tcp_client_test(); + sleep_ms(3000); + } + + + + cyw43_arch_deinit(); + + + + return 0; +} + + +/* int main(int argc, char *argv[]) { stdio_init_all(); @@ -310,14 +350,6 @@ int main(int argc, char *argv[]) } watchdog_update(); // 喂狗 - /* - if (1 == CH4()) { - printf("Kitchen danger (fire) alarm detects CH4!!!\n"); - light_flashing(); - _HC_12("Kitchen danger (fire) alarm detects CH4!!!\n"); - } - watchdog_update(); // 喂狗 - */ // DS18B20 TEMPERATURE = DS18B20(); @@ -379,3 +411,4 @@ int main(int argc, char *argv[]) return 0; } +*/ \ No newline at end of file diff --git a/SOFTWARE/Source/WIFI.c b/SOFTWARE/Source/WIFI.c new file mode 100644 index 0000000..eb23b02 --- /dev/null +++ b/SOFTWARE/Source/WIFI.c @@ -0,0 +1,229 @@ +#include "WIFI.h" + +#if 0 +static void dump_bytes(const uint8_t *bptr, uint32_t len) { + unsigned int i = 0; + + printf("dump_bytes %d", len); + for (i = 0; i < len;) { + if ((i & 0x0f) == 0) { + printf("\n"); + } else if ((i & 0x07) == 0) { + printf(" "); + } + printf("%02x ", bptr[i++]); + } + printf("\n"); +} +#define DUMP_BYTES dump_bytes // 调试用的字节转储函数 +#else +#define DUMP_BYTES(A,B) +#endif + +typedef struct TCP_CLIENT_T_ { + struct tcp_pcb *tcp_pcb; // TCP控制块指针 + ip_addr_t remote_addr; // 远程地址 + uint8_t buffer[BUF_SIZE]; // 接收缓冲区 + int buffer_len; // 缓冲区当前长度 + int sent_len; // 已发送的数据长度 + bool complete; // 是否完成测试 + int run_count; // 运行次数 + bool connected; // 是否已连接 +} TCP_CLIENT_T; + +static err_t tcp_client_close(void *arg) { + TCP_CLIENT_T *state = (TCP_CLIENT_T*)arg; + err_t err = ERR_OK; + if (state->tcp_pcb != NULL) { + tcp_arg(state->tcp_pcb, NULL); // 清除回调参数 + tcp_poll(state->tcp_pcb, NULL, 0); // 清除轮询回调 + tcp_sent(state->tcp_pcb, NULL); // 清除发送回调 + tcp_recv(state->tcp_pcb, NULL); // 清除接收回调 + tcp_err(state->tcp_pcb, NULL); // 清除错误回调 + err = tcp_close(state->tcp_pcb); // 关闭TCP连接 + if (err != ERR_OK) { + DEBUG_printf("close failed %d, calling abort\n", err); // 如果关闭失败,调用abort + tcp_abort(state->tcp_pcb); + err = ERR_ABRT; + } + state->tcp_pcb = NULL; // 清除TCP控制块指针 + } + return err; +} + +// 操作结果回调 +static err_t tcp_result(void *arg, int status) { + TCP_CLIENT_T *state = (TCP_CLIENT_T*)arg; + if (status == 0) { + DEBUG_printf("test success\n"); // 测试成功 + } else { + DEBUG_printf("test failed %d\n", status); // 测试失败 + } + state->complete = true; // 标记测试完成 + return tcp_client_close(arg); // 关闭连接 +} + +// 轮询回调 +static err_t tcp_client_poll(void *arg, struct tcp_pcb *tpcb) { + DEBUG_printf("tcp_client_poll\n"); + return tcp_result(arg, -1); // 无响应视为错误 +} + +// 错误处理回调 +static void tcp_client_err(void *arg, err_t err) { + if (err != ERR_ABRT) { + DEBUG_printf("tcp_client_err %d\n", err); // 打印错误信息 + tcp_result(arg, err); + } +} + +// 连接建立回调 +static err_t tcp_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err) { + TCP_CLIENT_T *state = (TCP_CLIENT_T*)arg; + if (err != ERR_OK) { + printf("connect failed %d\n", err); // 连接失败 + return tcp_result(arg, err); + } + state->connected = true; // 标记已连接 + DEBUG_printf("连接成功,准备发送消息!!!\n"); // 连接成功,准备发送消息 + + // 定义要发送的字符串 + const char *message = "PICO W\n"; + state->buffer_len = strlen(message); // 设置要发送的字符串长度 + memcpy(state->buffer, message, state->buffer_len); // 将字符串复制到缓冲区 + + // 发送字符串到服务器 + err = tcp_write(tpcb, state->buffer, state->buffer_len, TCP_WRITE_FLAG_COPY); + if (err != ERR_OK) { + DEBUG_printf("发送失败: %d\n", err); // 发送失败 + return tcp_result(arg, -1); + } + DEBUG_printf("发送数据: %s\n", message); // 打印发送的消息 + + memset(state->buffer, 0, state->buffer_len); + state->buffer_len = 0; + + return ERR_OK; +} + +err_t tcp_client_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { + TCP_CLIENT_T *state = (TCP_CLIENT_T*)arg; + if (!p) { + DEBUG_printf("接收数据失败,p 为 NULL\n"); // 添加调试信息 + return tcp_result(arg, -1); + } + // this method is callback from lwIP, so cyw43_arch_lwip_begin is not required, however you + // can use this method to cause an assertion in debug mode, if this method is called when + // cyw43_arch_lwip_begin IS needed + cyw43_arch_lwip_check(); + if (p->tot_len > 0) { + DEBUG_printf("recv %d err %d\n", p->tot_len, err); + for (struct pbuf *q = p; q != NULL; q = q->next) { + DUMP_BYTES(q->payload, q->len); + } + // Receive the buffer + const uint16_t buffer_left = BUF_SIZE - state->buffer_len; + state->buffer_len += pbuf_copy_partial(p, state->buffer + state->buffer_len, + p->tot_len > buffer_left ? buffer_left : p->tot_len, 0); + tcp_recved(tpcb, p->tot_len); + } + + // 打印当前缓冲区内容 + printf("接收数据: %s", state->buffer); + + pbuf_free(p); + + memset(state->buffer, 0, state->buffer_len); + state->buffer_len = 0; + + return ERR_OK; +} + +// 发送数据回调 +static err_t tcp_client_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) { + TCP_CLIENT_T *state = (TCP_CLIENT_T*)arg; + DEBUG_printf("tcp_client_sent %u\n", len); // 打印发送的数据长度 + state->sent_len += len; // 更新已发送的数据长度 + + if (state->sent_len >= BUF_SIZE) { + state->run_count++; // 增加运行次数 + if (state->run_count >= TEST_ITERATIONS) { + tcp_result(arg, 0); // 达到迭代次数,测试成功 + return ERR_OK; + } + + // 准备接收新的数据缓冲区 + state->buffer_len = 0; + state->sent_len = 0; + DEBUG_printf("Waiting for buffer from server\n"); + } + + return ERR_OK; +} + +// 打开TCP连接 +static bool tcp_client_open(void *arg) { + TCP_CLIENT_T *state = (TCP_CLIENT_T*)arg; + DEBUG_printf("Connecting to %s port %u\n", ip4addr_ntoa(&state->remote_addr), TCP_PORT); + state->tcp_pcb = tcp_new_ip_type(IP_GET_TYPE(&state->remote_addr)); // 创建TCP控制块 + if (!state->tcp_pcb) { + DEBUG_printf("failed to create pcb\n"); // 创建失败 + return false; + } + + tcp_arg(state->tcp_pcb, state); // 设置回调参数 + tcp_poll(state->tcp_pcb, tcp_client_poll, POLL_TIME_S * 2); // 设置轮询回调 + tcp_sent(state->tcp_pcb, tcp_client_sent); // 设置发送回调 + tcp_recv(state->tcp_pcb, tcp_client_recv); // 设置接收回调 + tcp_err(state->tcp_pcb, tcp_client_err); // 设置错误回调 + + state->buffer_len = 0; // 初始化缓冲区长度 + + // 使用cyw43_arch_lwip_begin/end确保正确锁定 + cyw43_arch_lwip_begin(); + err_t err = tcp_connect(state->tcp_pcb, &state->remote_addr, TCP_PORT, tcp_client_connected); // 尝试连接 + cyw43_arch_lwip_end(); + + return err == ERR_OK; +} + +// 初始化TCP客户端 +static TCP_CLIENT_T* tcp_client_init(void) { + TCP_CLIENT_T *state = calloc(1, sizeof(TCP_CLIENT_T)); // 分配内存 + if (!state) { + DEBUG_printf("failed to allocate state\n"); // 分配失败 + return NULL; + } + ip4addr_aton(TEST_TCP_SERVER_IP, &state->remote_addr); // 解析服务器IP地址 + return state; +} + +// 运行TCP客户端测试 +void run_tcp_client_test(void) { + TCP_CLIENT_T *state = tcp_client_init(); // 初始化客户端 + if (!state) { + return; + } + if (!tcp_client_open(state)) { // 打开连接 + tcp_result(state, -1); // 连接失败 + + return; + } + while(!state->complete) { // 循环等待测试完成 +#if PICO_CYW43_ARCH_POLL + // 如果使用pico_cyw43_arch_poll,需要定期调用cyw43_arch_poll + cyw43_arch_poll(); + // 可以选择休眠直到有工作需要做 + cyw43_arch_wait_for_work_until(make_timeout_time_ms(1000)); +#else + cyw43_arch_poll(); + // 可以选择休眠直到有工作需要做 + cyw43_arch_wait_for_work_until(make_timeout_time_ms(1000)); + + + // 如果不使用pico_cyw43_arch_poll,可以通过中断在后台处理 + //sleep_ms(1000); // 示例中的阻塞操作 +#endif + } + free(state); // 释放内存 +} \ No newline at end of file diff --git a/SOFTWARE/Source/WIFI.h b/SOFTWARE/Source/WIFI.h new file mode 100644 index 0000000..48f0f85 --- /dev/null +++ b/SOFTWARE/Source/WIFI.h @@ -0,0 +1,26 @@ +#ifndef WIFI_H +#define WIFI_H + +#include +#include +#include + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" + +#include "lwip/pbuf.h" +#include "lwip/tcp.h" + +#define TEST_TCP_SERVER_IP "192.168.9.90" +#define TCP_PORT 91 + +#define DEBUG_printf printf +#define BUF_SIZE 2048 + +#define TEST_ITERATIONS 10 +#define POLL_TIME_S 5 + + +extern void run_tcp_client_test(void); + +#endif