#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" #include "sht40.h" #include "tcp_server.h" #include "event_queue.h" #include "event_handler.h" #include "event_trigger.h" #include "transaction.h" #include "state_manager.h" #include "error_handler.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 /* Blink Thread */ /** * @brief LED闪烁任务入口函数 * @param parameter 任务参数(本函数中未使用) * @note 该函数初始化PA6引脚为输出模式,并在循环中翻转该引脚状态,实现LED闪烁效果 */ 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); /* 初始化为关闭状态 */ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET); while (1) { /* 检查数据上传成功标志 */ if (data_upload_success) { /* 亮LED */ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET); osal_thread_mdelay(500); /* 亮500ms */ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET); /* 重置标志 */ data_upload_success = 0; } osal_thread_mdelay(100); } } /* Ethernet Input Thread */ /** * @brief 以太网输入任务入口函数 * @param parameter 任务参数(本函数中未使用) * @note 该函数在循环中调用ethernetif_input处理接收到的以太网数据包 */ static void ethernet_input_entry(void *parameter) { while(1) { /* Block until packet received */ ethernetif_input(&gnetif); } } /** * @brief Ping配置参数 * @note 该结构体定义了Ping操作的相关参数,包括ID、数据大小、接收超时时间 */ #define PING_ID 0xAFAF #define PING_DATA_SIZE 32 #define PING_RCV_TIMEO 5000 // 5 seconds /** * @brief 准备Ping回显包 * @param iecho 指向icmp_echo_hdr结构体的指针,用于存储回显包 * @param len 回显包的总长度(包括icmp_echo_hdr头和数据) * @param seq Ping包的序列号 * @note 该函数填充icmp_echo_hdr结构体,设置类型为ICMP_ECHO,ID为PING_ID,序列号为seq, * 并填充数据部分为0到(data_len-1)的连续字节 */ 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); } /** * @brief 检查目标IP是否可达 * @param target_ip 目标IP地址字符串 * @return 如果目标IP可达,返回1;否则返回0 * @note 该函数通过发送ICMP Echo请求包到目标IP,并等待响应来检查目标IP是否可达 */ 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; } /* 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!"); /* 触发网络连接事件 */ event_trigger(EVENT_TYPE_NETWORK_CONNECTED, EVENT_PRIORITY_NORMAL, NULL, 0); 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); /* 触发网络连接事件 */ event_trigger(EVENT_TYPE_NETWORK_CONNECTED, EVENT_PRIORITY_NORMAL, NULL, 0); } 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); } } /* 事件处理函数 */ static int sensor_data_handler(event_t *event, void *user_data) { osal_log_i("Handling sensor data event"); /* 这里可以添加传感器数据处理逻辑 */ return 0; } static int network_connected_handler(event_t *event, void *user_data) { osal_log_i("Handling network connected event"); state_manager_set_network_state(NETWORK_STATE_CONNECTED); return 0; } static int network_disconnected_handler(event_t *event, void *user_data) { osal_log_i("Handling network disconnected event"); state_manager_set_network_state(NETWORK_STATE_DISCONNECTED); return 0; } static int tcp_client_connected_handler(event_t *event, void *user_data) { osal_log_i("Handling TCP client connected event"); state_manager_set_tcp_state(TCP_STATE_CONNECTED); return 0; } static int tcp_client_disconnected_handler(event_t *event, void *user_data) { osal_log_i("Handling TCP client disconnected event"); state_manager_set_tcp_state(TCP_STATE_LISTENING); return 0; } static int timer_handler(event_t *event, void *user_data) { osal_log_i("Handling timer event"); /* 这里可以添加定时任务逻辑 */ return 0; } static int error_handler(event_t *event, void *user_data) { osal_log_i("Handling error event"); error_code_t error = ERROR_UNKNOWN; if (event->data != NULL) { error = *(error_code_t *)event->data; } error_handler_process(error, user_data); return 0; } 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 event queue */ if (event_queue_init() != 0) { osal_log_e("Failed to initialize event queue"); return -1; } /* Initialize event handler */ if (event_handler_init() != 0) { osal_log_e("Failed to initialize event handler"); return -1; } /* Initialize transaction management */ if (transaction_init() != 0) { osal_log_e("Failed to initialize transaction management"); return -1; } /* Initialize state manager */ if (state_manager_init() != 0) { osal_log_e("Failed to initialize state manager"); return -1; } /* Initialize error handler */ if (error_handler_init() != 0) { osal_log_e("Failed to initialize error handler"); return -1; } /* Register event handlers */ event_handler_register(EVENT_TYPE_SENSOR_DATA, sensor_data_handler, NULL); event_handler_register(EVENT_TYPE_NETWORK_CONNECTED, network_connected_handler, NULL); event_handler_register(EVENT_TYPE_NETWORK_DISCONNECTED, network_disconnected_handler, NULL); event_handler_register(EVENT_TYPE_TCP_CLIENT_CONNECTED, tcp_client_connected_handler, NULL); event_handler_register(EVENT_TYPE_TCP_CLIENT_DISCONNECTED, tcp_client_disconnected_handler, NULL); event_handler_register(EVENT_TYPE_TIMER, timer_handler, NULL); event_handler_register(EVENT_TYPE_ERROR, error_handler, NULL); /* Create event dispatch thread */ tid = osal_thread_create("event_dispatch", event_dispatch_thread, NULL, 1024, 8); if (tid != NULL) { osal_thread_start(tid); rt_kprintf("Thread 'event_dispatch' created.\n"); } else { rt_kprintf("Failed to create thread 'event_dispatch'\n"); } /* 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"); } /* Initialize SHT40 sensor */ if (sht40_init() != 0) { osal_log_e("SHT40 sensor initialization failed"); error_code_t error = ERROR_SENSOR; event_trigger(EVENT_TYPE_ERROR, EVENT_PRIORITY_HIGH, &error, sizeof(error)); } else { osal_log_i("SHT40 sensor initialized successfully"); state_manager_set_sensor_state(SENSOR_STATE_READY); /* Use heater once during initialization for self-calibration */ osal_log_i("Performing SHT40 self-calibration using heater..."); if (sht40_heater_enable(1) == 0) // Use medium power (110mW) { osal_log_i("SHT40 self-calibration completed successfully"); } else { osal_log_e("SHT40 self-calibration failed"); error_code_t error = ERROR_SENSOR; event_trigger(EVENT_TYPE_ERROR, EVENT_PRIORITY_HIGH, &error, sizeof(error)); } } /* Create TCP Server Thread */ tid = osal_thread_create("tcp_server", tcp_server_entry, NULL, 2048, 15); if (tid != NULL) { osal_thread_start(tid); rt_kprintf("Thread 'tcp_server' created.\n"); } else { rt_kprintf("Failed to create thread 'tcp_server'\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; }