#include #include "osal.h" #include "lwip/init.h" #include "lwip/netif.h" #include "lwip/tcpip.h" #include "lwip/dhcp.h" #include "lwip/sockets.h" #include "drv_eth.h" #include "lwip/icmp.h" #include "lwip/inet_chksum.h" #include #include "lwip/prot/ip4.h" /* Utility macros */ #define MIN(a, b) ((a) < (b) ? (a) : (b)) /* Network Interface */ struct netif gnetif; osal_sem_t sem_ip_ready = NULL; /* Static IP Configuration (Fallback) */ #define STATIC_IP_ADDR0 192 #define STATIC_IP_ADDR1 168 #define STATIC_IP_ADDR2 1 #define STATIC_IP_ADDR3 10 #define STATIC_NETMASK0 255 #define STATIC_NETMASK1 255 #define STATIC_NETMASK2 255 #define STATIC_NETMASK3 0 #define STATIC_GW_ADDR0 192 #define STATIC_GW_ADDR1 168 #define STATIC_GW_ADDR2 1 #define STATIC_GW_ADDR3 1 /* TCP Server Configuration */ #define SERVER_IP_ADDR "192.168.1.116" /* PC IP Address */ #define SERVER_PORT 5588 /* Blink Thread */ static void blink_entry(void *parameter) { /* Initialize PA6 */ __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_6; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); while (1) { HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_6); // osal_log_i("System Running..."); osal_thread_mdelay(1000); } } /* Ethernet Input Thread */ static void ethernet_input_entry(void *parameter) { while(1) { /* Block until packet received */ ethernetif_input(&gnetif); } } /* Ping Configuration */ #define PING_ID 0xAFAF #define PING_DATA_SIZE 32 #define PING_RCV_TIMEO 5000 // 5 seconds static void ping_prepare_echo(struct icmp_echo_hdr *iecho, u16_t len, u16_t seq) { size_t i; size_t data_len = len - sizeof(struct icmp_echo_hdr); ICMPH_TYPE_SET(iecho, ICMP_ECHO); ICMPH_CODE_SET(iecho, 0); iecho->chksum = 0; iecho->id = PING_ID; iecho->seqno = lwip_htons(seq); for(i = 0; i < data_len; i++) { ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i; } iecho->chksum = inet_chksum(iecho, len); } static int ping_check(const char *target_ip) { int s; struct timeval timeout; struct sockaddr_in to; struct icmp_echo_hdr *iecho; size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE; int ret = 0; int seq_num = 0; /* Create raw socket */ s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (s < 0) { osal_log_e("Ping: Failed to create socket"); return 0; } /* Set receive timeout */ timeout.tv_sec = PING_RCV_TIMEO / 1000; timeout.tv_usec = (PING_RCV_TIMEO % 1000) * 1000; setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); /* Prepare destination address */ memset(&to, 0, sizeof(to)); to.sin_len = sizeof(to); to.sin_family = AF_INET; to.sin_addr.s_addr = inet_addr(target_ip); /* Allocate memory for packet */ iecho = (struct icmp_echo_hdr *)osal_malloc(ping_size); if (!iecho) { osal_log_e("Ping: Failed to allocate memory"); closesocket(s); return 0; } osal_log_i("Ping: Pinging %s...", target_ip); /* Try to ping a few times */ for (int i = 0; i < 3; i++) { ping_prepare_echo(iecho, (u16_t)ping_size, ++seq_num); if (sendto(s, iecho, ping_size, 0, (struct sockaddr*)&to, sizeof(to)) <= 0) { osal_log_e("Ping: Send failed"); continue; } char buf[64]; struct sockaddr_in from; socklen_t fromlen = sizeof(from); int len; while ((len = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, &fromlen)) > 0) { if (len >= (int)(sizeof(struct ip_hdr) + sizeof(struct icmp_echo_hdr))) { struct ip_hdr *iphdr = (struct ip_hdr *)buf; struct icmp_echo_hdr *iecho_reply = (struct icmp_echo_hdr *)(buf + (IPH_HL(iphdr) * 4)); if (ICMPH_TYPE(iecho_reply) != ICMP_ER) { continue; } if (iecho_reply->id == PING_ID && iecho_reply->seqno == lwip_htons(seq_num)) { osal_log_i("Ping: Reply from %s", inet_ntoa(from.sin_addr)); ret = 1; goto exit; } } } } osal_log_w("Ping: Timeout or no reply"); exit: osal_free(iecho); closesocket(s); return ret; } /* TCP Client Configuration */ #define TCP_CLIENT_AUTH_USERNAME "admin" #define TCP_CLIENT_AUTH_PASSWORD "password123" #define TCP_CLIENT_MAX_RECONNECT_DELAY 10000 // 最大重连延迟 10 秒 #define TCP_CLIENT_INIT_RECONNECT_DELAY 1000 // 初始重连延迟 1 秒 #define TCP_CLIENT_HEARTBEAT_INTERVAL 500 // 心跳间隔 500ms #define TCP_CLIENT_AUTH_TIMEOUT 3000 // 认证超时 3 秒 #define TCP_CLIENT_CONNECT_TIMEOUT 5000 // 连接超时 5 秒 /* Helper function: Check if authentication response is successful */ static int is_auth_success(const char *response) { if (!response) return 0; // 移除末尾的换行符和空格 char *p = (char *)response; while (*p && (*p == ' ' || *p == '\n' || *p == '\r')) p++; char *end = p + strlen(p) - 1; while (end > p && (*end == ' ' || *end == '\n' || *end == '\r')) end--; *(end + 1) = '\0'; // 转换为小写进行比较 char lower_data[128]; for (int i = 0; p[i]; i++) { lower_data[i] = tolower(p[i]); } lower_data[strlen(p)] = '\0'; osal_log_i("Processed auth response: '%s'", p); osal_log_i("Lowercase auth response: '%s'", lower_data); /* Check if authentication was successful */ if (strstr(lower_data, "ok") != NULL || strstr(lower_data, "success") != NULL || strstr(lower_data, "auth_success") != NULL) { return 1; } return 0; } /* Helper function: Create and configure socket */ static int create_and_configure_socket(void) { int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { osal_log_e("Socket creation error: %d", errno); return -1; } /* Set non-blocking mode */ int flags = fcntl(sock, F_GETFL, 0); if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) { osal_log_e("Failed to set non-blocking mode: %d", errno); closesocket(sock); return -1; } /* Set socket options for better performance */ int keepalive = 1; int keepidle = 60; int keepintvl = 10; int keepcnt = 3; setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive)); setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof(keepidle)); setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepintvl, sizeof(keepintvl)); setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(keepcnt)); return sock; } /* Helper function: Connect to server with timeout */ static int connect_to_server(int sock, struct sockaddr_in *server_addr) { int ret = connect(sock, (struct sockaddr *)server_addr, sizeof(struct sockaddr)); if (ret == -1 && errno != EINPROGRESS) { osal_log_e("Connect failed: %d", errno); return -1; } /* Use select to wait for connection completion */ fd_set wset; struct timeval tv; FD_ZERO(&wset); FD_SET(sock, &wset); tv.tv_sec = TCP_CLIENT_CONNECT_TIMEOUT / 1000; tv.tv_usec = (TCP_CLIENT_CONNECT_TIMEOUT % 1000) * 1000; if (select(sock + 1, NULL, &wset, NULL, &tv) > 0) { int error = 0; socklen_t len = sizeof(error); getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len); if (error != 0) { osal_log_e("Connect failed: %d", error); return -1; } } else { osal_log_e("Connect timeout"); return -1; } return 0; } /* Helper function: Send authentication and wait for response */ static int authenticate_server(int sock) { /* Send authentication information */ char auth_data[64]; snprintf(auth_data, sizeof(auth_data), "AUTH %s %s\n", TCP_CLIENT_AUTH_USERNAME, TCP_CLIENT_AUTH_PASSWORD); if (send(sock, auth_data, strlen(auth_data), 0) < 0) { osal_log_e("Failed to send authentication: %d", errno); return 0; } osal_log_i("Sent authentication: %s", auth_data); /* Wait for authentication response */ char recv_data[128]; fd_set rset; struct timeval tv; FD_ZERO(&rset); FD_SET(sock, &rset); tv.tv_sec = TCP_CLIENT_AUTH_TIMEOUT / 1000; tv.tv_usec = (TCP_CLIENT_AUTH_TIMEOUT % 1000) * 1000; if (select(sock + 1, &rset, NULL, NULL, &tv) > 0) { int bytes_received = recv(sock, recv_data, sizeof(recv_data) - 1, 0); if (bytes_received > 0) { recv_data[bytes_received] = '\0'; osal_log_i("Authentication response: '%s'", recv_data); if (is_auth_success(recv_data)) { osal_log_i("Authentication successful!"); return 1; } else { osal_log_e("Authentication failed: %s", recv_data); return 0; } } else if (bytes_received == 0) { osal_log_w("Connection closed by server during authentication"); return 0; } else { osal_log_e("Recv error during authentication: %d", errno); return 0; } } else { osal_log_w("No authentication response received"); return 0; } } /* TCP Client Thread */ static void tcp_client_entry(void *parameter) { int sock = -1; struct sockaddr_in server_addr; char recv_data[128]; int bytes_received; int reconnect_count = 0; int reconnect_delay = TCP_CLIENT_INIT_RECONNECT_DELAY; /* Wait for IP address ready */ if (osal_sem_take(sem_ip_ready, OSAL_WAIT_FOREVER) != OSAL_OK) { osal_log_e("Failed to take IP ready semaphore"); return; } osal_log_i("TCP Client Starting..."); /* Prepare server address */ server_addr.sin_family = AF_INET; server_addr.sin_port = htons(SERVER_PORT); server_addr.sin_addr.s_addr = inet_addr(SERVER_IP_ADDR); memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero)); while (1) { /* Check Link Status */ if (!netif_is_link_up(&gnetif)) { osal_log_w("Link down, waiting for link up..."); osal_thread_mdelay(1000); continue; } /* Create and configure socket */ sock = create_and_configure_socket(); if (sock < 0) { osal_log_e("Failed to create socket, reconnecting in %d ms...", reconnect_delay); osal_thread_mdelay(reconnect_delay); // 指数退避重连 reconnect_count++; reconnect_delay = MIN(reconnect_delay * 2, TCP_CLIENT_MAX_RECONNECT_DELAY); continue; } osal_log_i("Connecting to server %s:%d...", SERVER_IP_ADDR, SERVER_PORT); /* Connect to server */ if (connect_to_server(sock, &server_addr) < 0) { closesocket(sock); osal_log_e("Connection failed, reconnecting in %d ms...", reconnect_delay); osal_thread_mdelay(reconnect_delay); // 指数退避重连 reconnect_count++; reconnect_delay = MIN(reconnect_delay * 2, TCP_CLIENT_MAX_RECONNECT_DELAY); continue; } osal_log_i("Connected to server!"); /* Authenticate with server */ if (!authenticate_server(sock)) { osal_log_e("Authentication failed, reconnecting in %d ms...", reconnect_delay); closesocket(sock); osal_thread_mdelay(reconnect_delay); // 指数退避重连 reconnect_count++; reconnect_delay = MIN(reconnect_delay * 2, TCP_CLIENT_MAX_RECONNECT_DELAY); continue; } // 认证成功,重置重连计数器和延迟 reconnect_count = 0; reconnect_delay = TCP_CLIENT_INIT_RECONNECT_DELAY; while (1) { /* Check Link Status */ if (!netif_is_link_up(&gnetif)) { osal_log_w("Link lost during connection"); break; } /* Send heartbeat */ if (send(sock, "Heartbeat", 9, 0) < 0) { if (errno != EWOULDBLOCK) { osal_log_e("Send error: %d", errno); break; } } /* Wait for data with timeout */ fd_set rset; struct timeval tv; FD_ZERO(&rset); FD_SET(sock, &rset); tv.tv_sec = TCP_CLIENT_HEARTBEAT_INTERVAL / 1000; tv.tv_usec = (TCP_CLIENT_HEARTBEAT_INTERVAL % 1000) * 1000; int n = select(sock + 1, &rset, NULL, NULL, &tv); if (n > 0) { bytes_received = recv(sock, recv_data, sizeof(recv_data) - 1, 0); if (bytes_received > 0) { recv_data[bytes_received] = '\0'; osal_log_i("Received: %s", recv_data); } else if (bytes_received == 0) { osal_log_w("Connection closed by server"); break; } else { if (errno != EWOULDBLOCK) { osal_log_e("Recv error: %d", errno); break; } } } else if (n < 0) { osal_log_e("Select error: %d", errno); break; } /* n == 0 is timeout, continue loop */ } closesocket(sock); osal_log_i("Connection closed, reconnecting in %d ms...", reconnect_delay); osal_thread_mdelay(reconnect_delay); // 指数退避重连 reconnect_count++; reconnect_delay = MIN(reconnect_delay * 2, TCP_CLIENT_MAX_RECONNECT_DELAY); } } /* Network Monitor Thread (DHCP & Fallback) */ static void network_monitor_entry(void *parameter) { ip4_addr_t ipaddr, netmask, gw; int dhcp_timeout = 100; /* 100 * 100ms = 10 seconds */ osal_log_i("Starting DHCP..."); dhcp_start(&gnetif); while (dhcp_timeout > 0) { if (gnetif.ip_addr.addr != 0) { osal_log_i("DHCP Success!"); break; } osal_thread_mdelay(100); dhcp_timeout--; /* Print a dot every second */ if (dhcp_timeout % 10 == 0) osal_kprintf("."); } osal_kprintf("\n"); if (gnetif.ip_addr.addr == 0) { osal_log_w("DHCP Timeout! Fallback to Static IP."); dhcp_stop(&gnetif); IP4_ADDR(&ipaddr, STATIC_IP_ADDR0, STATIC_IP_ADDR1, STATIC_IP_ADDR2, STATIC_IP_ADDR3); IP4_ADDR(&netmask, STATIC_NETMASK0, STATIC_NETMASK1, STATIC_NETMASK2, STATIC_NETMASK3); IP4_ADDR(&gw, STATIC_GW_ADDR0, STATIC_GW_ADDR1, STATIC_GW_ADDR2, STATIC_GW_ADDR3); netif_set_addr(&gnetif, &ipaddr, &netmask, &gw); netif_set_up(&gnetif); } osal_log_i("IP Address: %d.%d.%d.%d", ip4_addr1(&gnetif.ip_addr), ip4_addr2(&gnetif.ip_addr), ip4_addr3(&gnetif.ip_addr), ip4_addr4(&gnetif.ip_addr)); osal_log_i("Netmask: %d.%d.%d.%d", ip4_addr1(&gnetif.netmask), ip4_addr2(&gnetif.netmask), ip4_addr3(&gnetif.netmask), ip4_addr4(&gnetif.netmask)); osal_log_i("Gateway: %d.%d.%d.%d", ip4_addr1(&gnetif.gw), ip4_addr2(&gnetif.gw), ip4_addr3(&gnetif.gw), ip4_addr4(&gnetif.gw)); /* Notify TCP Client */ osal_sem_release(sem_ip_ready); /* Periodic Link Check */ while(1) { ethernet_link_check_state(&gnetif); osal_thread_mdelay(1000); } } int main(void) { osal_thread_t tid; /* OSAL Initialization */ osal_init(); rt_kprintf("Main: OSAL Log Level = %d\n", OSAL_LOG_LEVEL); osal_log_i("Test osal_log_i from main"); /* Initialize TCP/IP stack */ rt_kprintf("Initializing TCP/IP stack...\n"); tcpip_init(NULL, NULL); rt_kprintf("TCP/IP stack initialized.\n"); /* Initialize Network Interface */ ip4_addr_t ipaddr, netmask, gw; /* Initialize with 0.0.0.0 */ IP4_ADDR(&ipaddr, 0, 0, 0, 0); IP4_ADDR(&netmask, 0, 0, 0, 0); IP4_ADDR(&gw, 0, 0, 0, 0); /* Add Network Interface */ netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, &tcpip_input); netif_set_default(&gnetif); netif_set_up(&gnetif); sem_ip_ready = osal_sem_create("sem_ip", 0); /* Create Network Monitor Thread (DHCP) */ tid = osal_thread_create("net_mon", network_monitor_entry, NULL, 1024, 12); if (tid != NULL) { osal_thread_start(tid); rt_kprintf("Thread 'net_mon' created.\n"); } else { rt_kprintf("Failed to create thread 'net_mon'\n"); } /* Create Ethernet Input Thread */ /* Increased priority to 6 (Higher than TCPIP thread which is 10) for better responsiveness */ tid = osal_thread_create("eth_input", ethernet_input_entry, NULL, 1536, 6); if (tid != NULL) { osal_thread_start(tid); rt_kprintf("Thread 'eth_input' created.\n"); } else { rt_kprintf("Failed to create thread 'eth_input'\n"); } /* Create TCP Client Thread */ tid = osal_thread_create("tcp_client", tcp_client_entry, NULL, 2048, 15); if (tid != NULL) { osal_thread_start(tid); rt_kprintf("Thread 'tcp_client' created.\n"); } else { rt_kprintf("Failed to create thread 'tcp_client'\n"); } /* Create Blink/Status Thread */ tid = osal_thread_create("blink", blink_entry, NULL, 1024, 20); if (tid != NULL) { osal_thread_start(tid); rt_kprintf("Thread 'blink' created.\n"); } else { rt_kprintf("Failed to create thread 'blink'\n"); } rt_size_t total, used, max_used; rt_memory_info(&total, &used, &max_used); rt_kprintf("Memory Info: Total=%d, Used=%d, MaxUsed=%d\n", total, used, max_used); /* OSAL Start */ osal_start(); return 0; }