#include "http_server.h" // HTML页面模板 #include "html_files.h" // 解析HTTP请求 static void parse_http_request(uint8_t* buffer, uint16_t length, http_request* req) { char* method = strtok((char*)buffer, " "); char* uri = strtok(NULL, " "); if(strcmp(method, "GET") == 0) { req->method = HTTP_GET; } else if(strcmp(method, "POST") == 0) { req->method = HTTP_POST; } else { req->method = HTTP_UNKNOWN; } strncpy(req->uri, uri, MAX_URI_SIZE); // 如果是POST请求,查找请求体 if(req->method == HTTP_POST) { char* body = strstr((char*)buffer, "\r\n\r\n"); if(body) { body += 4; req->body = (uint8_t*)body; req->body_length = length - (body - (char*)buffer); } } } // 发送HTTP响应 static int send_all(uint8_t sn, const uint8_t* data, uint16_t length) { int total_sent = 0; while (total_sent < length) { int sent = send(sn, data + total_sent, length - total_sent); if (sent <= 0) { return -1; // 发送错误 } total_sent += sent; } return total_sent; } static void send_chunked_response_header(uint8_t sn) { const char* header = "HTTP/1.1 200 OK\r\n" "Content-Type: text/html\r\n" "Transfer-Encoding: chunked\r\n" "\r\n"; send_all(sn, (uint8_t*)header, strlen(header)); } static void send_chunk(uint8_t sn, const char* data, uint16_t length) { char chunk_header[10]; sprintf(chunk_header, "%X\r\n", length); send_all(sn, (uint8_t*)chunk_header, strlen(chunk_header)); send_all(sn, (uint8_t*)data, length); send_all(sn, (uint8_t*)"\r\n", 2); } static void send_chunk_end(uint8_t sn) { send_all(sn, (uint8_t*)"0\r\n\r\n", 5); } #define CHUNK_SIZE 512 // 处理配置页面请求 static void handle_config_page(uint8_t sn) { char buffer[CHUNK_SIZE]; // 先将完整的HTML内容格式化到一个临时缓冲区 char full_page[1024*15]; // 确保足够大 int total_len = sprintf(full_page, index_html,0, gWIZNETINFO.mac[0], gWIZNETINFO.mac[1], gWIZNETINFO.mac[2], gWIZNETINFO.mac[3], gWIZNETINFO.mac[4], gWIZNETINFO.mac[5], gWIZNETINFO.ip[0], gWIZNETINFO.ip[1], gWIZNETINFO.ip[2], gWIZNETINFO.ip[3], gWIZNETINFO.sn[0], gWIZNETINFO.sn[1], gWIZNETINFO.sn[2], gWIZNETINFO.sn[3], gWIZNETINFO.gw[0], gWIZNETINFO.gw[1], gWIZNETINFO.gw[2], gWIZNETINFO.gw[3]); // 发送响应头 send_chunked_response_header(sn); // 分块发送内容 int sent = 0; while (sent < total_len) { int chunk_len = (total_len - sent) > CHUNK_SIZE ? CHUNK_SIZE : (total_len - sent); memcpy(buffer, full_page + sent, chunk_len); send_chunk(sn, buffer, chunk_len); sent += chunk_len; } // 发送结束块 send_chunk_end(sn); } // 解析并更新网络配置 static void update_network_config(const char* body) { char mac[18], ip[16], subnet[16], gateway[16]; uint32_t mac_values[6], ip_values[4], subnet_values[4], gateway_values[4]; if(sscanf(body, "mac=%02X%%3A%02X%%3A%02X%%3A%02X%%3A%02X%%3A%02X&" "ip=%d.%d.%d.%d&" "subnet=%d.%d.%d.%d&" "gateway=%d.%d.%d.%d", &mac_values[0], &mac_values[1], &mac_values[2], &mac_values[3], &mac_values[4], &mac_values[5], &ip_values[0], &ip_values[1], &ip_values[2], &ip_values[3], &subnet_values[0], &subnet_values[1], &subnet_values[2], &subnet_values[3], &gateway_values[0], &gateway_values[1], &gateway_values[2], &gateway_values[3]) == 18) { // 更新MAC地址 for(int i = 0; i < 6; i++) { gWIZNETINFO.mac[i] = (uint8_t)mac_values[i]; } // 更新IP地址 for(int i = 0; i < 4; i++) { gWIZNETINFO.ip[i] = (uint8_t)ip_values[i]; gWIZNETINFO.sn[i] = (uint8_t)subnet_values[i]; gWIZNETINFO.gw[i] = (uint8_t)gateway_values[i]; } // 应用新的网络配置 wizchip_setnetinfo(&gWIZNETINFO); } } void http_server_init(void) { // 创建服务器socket socket(HTTP_SERVER_SOCKET, Sn_MR_TCP, HTTP_SERVER_PORT, 0); listen(HTTP_SERVER_SOCKET); } // 三通阀结构体 typedef struct { uint8_t angle1; // 阀门1角度 (120/210) uint8_t angle2; // 阀门2角度 (120/210) } ValveStatus; // 泵结构体 typedef struct { uint8_t status1; // 泵1运行状态 (停止/顺时针/逆时针) uint8_t status2; // 泵2运行状态 (停止/顺时针/逆时针) uint8_t speed1; // 泵1速度百分比 (0-100) uint8_t speed2; // 泵2速度百分比 (0-100) } PumpStatus; // 设备状态结构体 // 1.下挂设备在位状态,在位为1,否则为0,当前为气泡感应器,1个字节 // 2.两个三通阀实时角度,每个角度占用1个字节,只能为210或120 // 3.泵状态,1表示泵顺时针转动中,2表示泵逆时针转动中,0表示停止,两个泵共2个字节 // 4.泵速度,2个字节,每个泵的速度占用一个字节,表示当前泵设定的速度百分比 // 5.气泡感应器读值,1表示监测到气泡,0表示没有气泡,共1个字节 // 6.急停按键状态,1个字节,1为按下,0为正常。 // 7.错误码1个字节,用于监控当前系统总体状态,如通信异常、控制异常等等,具体错误码待定 // 8.初始化状态,1个字节, 0表示初始化执行中,1表示初始化执行成功,2表示初始化执行失败。 typedef struct { uint8_t deviceStatus; // 下挂设备状态 ValveStatus valves; // 两个三通阀状态 PumpStatus pumps; // 两个泵状态 uint8_t bubbleStatus; // 气泡状态 uint8_t stopStatus; // 急停状态 uint8_t errorCode; // 错误码 uint8_t initStatus; // 初始化状态 } DeviceStatus; DeviceStatus deviceStatus={ .deviceStatus=1, .valves={ .angle1=0, .angle2=0 }, .pumps={ .status1=0, .status2=0, .speed1=60, .speed2=70 }, .bubbleStatus=0, .stopStatus=0, .errorCode=0, .initStatus=1 }; // 发送JSON响应头 static void send_json_response_header(uint8_t sn) { const char* header = "HTTP/1.1 200 OK\r\n" "Content-Type: application/json\r\n" "Access-Control-Allow-Origin: *\r\n" "Connection: close\r\n" // 明确指示关闭连接 "Cache-Control: no-cache, no-store\r\n" // 禁止缓存 "\r\n"; send_all(sn, (uint8_t*)header, strlen(header)); } // 处理状态请求 static void handle_status_request(uint8_t sn) { char json_buffer[512]; // DeviceStatus deviceStatus; // 确保能访问到deviceStatus变量 // 构建JSON响应 int len = sprintf(json_buffer, "{" "\"deviceStatus\":%d," "\"valves\":{" "\"angle1\":%d," "\"angle2\":%d" "}," "\"pumps\":{" "\"status1\":%d," "\"status2\":%d," "\"speed1\":%d," "\"speed2\":%d" "}," "\"bubbleStatus\":%d," "\"stopStatus\":%d," "\"errorCode\":%d," "\"initStatus\":%d" "}", deviceStatus.deviceStatus, deviceStatus.valves.angle1, deviceStatus.valves.angle2, deviceStatus.pumps.status1, deviceStatus.pumps.status2, deviceStatus.pumps.speed1, deviceStatus.pumps.speed2, deviceStatus.bubbleStatus, deviceStatus.stopStatus, deviceStatus.errorCode, deviceStatus.initStatus ); // 发送响应 send_json_response_header(sn); send_all(sn, (uint8_t*)json_buffer, len); // 发送完成后主动关闭连接 disconnect(sn); printf("send status success!\r\n"); } // 处理网络配置请求 static void handle_netconfig_request(uint8_t sn) { char json_buffer[256]; // 构建JSON响应 int len = sprintf(json_buffer, "{" "\"mac\":[%d,%d,%d,%d,%d,%d]," "\"ip\":[%d,%d,%d,%d]," "\"sn\":[%d,%d,%d,%d]," "\"gw\":[%d,%d,%d,%d]" "}", gWIZNETINFO.mac[0], gWIZNETINFO.mac[1], gWIZNETINFO.mac[2], gWIZNETINFO.mac[3], gWIZNETINFO.mac[4], gWIZNETINFO.mac[5], gWIZNETINFO.ip[0], gWIZNETINFO.ip[1], gWIZNETINFO.ip[2], gWIZNETINFO.ip[3], gWIZNETINFO.sn[0], gWIZNETINFO.sn[1], gWIZNETINFO.sn[2], gWIZNETINFO.sn[3], gWIZNETINFO.gw[0], gWIZNETINFO.gw[1], gWIZNETINFO.gw[2], gWIZNETINFO.gw[3] ); // 发送响应 send_json_response_header(sn); send_all(sn, (uint8_t*)json_buffer, len); // 发送完成后主动关闭连接 disconnect(sn); } void http_server_task(void) { uint8_t buffer[2048]; uint16_t size; uint8_t status = getSn_SR(HTTP_SERVER_SOCKET); switch(status) { case SOCK_INIT: listen(HTTP_SERVER_SOCKET); break; case SOCK_LISTEN: // 等待连接 break; case SOCK_ESTABLISHED: { if((size = getSn_RX_RSR(HTTP_SERVER_SOCKET)) > 0) { size = recv(HTTP_SERVER_SOCKET, buffer, sizeof(buffer)); if(size > 0) { http_request req; parse_http_request(buffer, size, &req); if(req.method == HTTP_GET) { if(strcmp(req.uri, "/status") == 0) { handle_status_request(HTTP_SERVER_SOCKET); } else if(strcmp(req.uri, "/netconfig") == 0) { handle_netconfig_request(HTTP_SERVER_SOCKET); } else { handle_config_page(HTTP_SERVER_SOCKET); } } else if(req.method == HTTP_POST && strcmp(req.uri, "/config") == 0) { update_network_config((char*)req.body); send_chunked_response_header(HTTP_SERVER_SOCKET); send_chunk(HTTP_SERVER_SOCKET, "
", strlen("")); send_chunk_end(HTTP_SERVER_SOCKET); } } } break; } case SOCK_CLOSE_WAIT: disconnect(HTTP_SERVER_SOCKET); break; case SOCK_CLOSED: socket(HTTP_SERVER_SOCKET, Sn_MR_TCP, HTTP_SERVER_PORT, 0); break; } }