#include "GUI_tjc_hmi.h" #include #include #include #include #include #include "proto_modbus_lib.h" #include "bsp_w25q.h" // 添加Flash操作 #include "bsp_W5500.h" #include "bsp_uart.h" #include "bsp_DS1302.h" #include "app_leakage.h" /*串口发送缓冲区*/ #define HMI_TX_BUFFER_NUM (2048) /*字符发送拼接 缓冲区*/ #define GUI_TJC_HMI_TEXT_BUFFER_NUM (256) /*帧头*/ #define HMI_PROTO_FRAME_HEADER1 (0xAA) #define HMI_PROTO_FRAME_HEADER2 (0x55) /*操作*/ #define HMI_PROTO_CMD_GET (0x03) /*获取数据数据*/ #define HMI_PROTO_CMD_SET (0x10) /*设置信息*/ /*界面*/ #define HMI_PROTO_GUI_MAIN (0x10)/*主界面 */ #define HMI_PROTO_GUI_CURR_ALARM (0x11)/*实时报警界面 */ #define HMI_PROTO_GUI_DETAIL_MAIN (0x12)/*主界面_详细信息 */ #define HMI_PROTO_GUI_LOGIN (0x13)/*登录界面 */ #define HMI_PROTO_GUI_HISTORY_ALARM (0x14)/*历史报警界面 */ #define HMI_PROTO_GUI_TCP_CONFIG (0x15)/*网络配置界面 */ #define HMI_PROTO_GUI_DEVICE_CONFIG (0x16)/*设备配置界面 */ #define HMI_PROTO_GUI_HELP (0x17)/*帮助界面 */ #define HMI_PROTO_GUI_TIME (0x18)/*时间设置界面*/ #define HMI_PROTO_ASCII_RX_DELINITER (0xAA)/*接收分隔符*/ #define HMI_PROTO_ASCII_TX_DELINITER (0xFF)/*发送分隔符*/ #define HMI_PROTO_ASCII_TX_DELINITER_NUM (3)/*发送分隔符数量*/ #define W25Q32_PASSWORD_ADDR (W25Q32_USER_DATA_ADDR)/*密码存储地址*/ static void gui_tjc_hmi_init(void); static void gui_tjc_hmi_communication_data_analysis(u8 *p_data, u16 len, void *rx_uart); static void gui_tjc_hmi_read_device_info_from_w25q(void); /*串口发送缓冲区*/ static u8 hmi_tx_buffer[HMI_TX_BUFFER_NUM]; /*字符发送拼接 缓冲区*/ static char gui_tjc_hmi_text_buffer[GUI_TJC_HMI_TEXT_BUFFER_NUM]; /*字符名称 端口号*/ static char *hmi_proto_string_com[] = { "COM1", "COM2", "COM3", "COM4" }; /*字符名称 波特率*/ static char *hmi_proto_string_baudrate[] = { "4800", "9600", "19200", "57600", "115200", }; static bsp_uart_t * p_rx_uart = NULL; gui_tjc_hmi_t tjc_hmi = { .init = gui_tjc_hmi_init, }; gui_tjc_hmi_t *p_tjc_hmi = &tjc_hmi; /*屏幕协议初始化*/ static void gui_tjc_hmi_init(void) { com_uart1.rx_data_analysis = gui_tjc_hmi_communication_data_analysis; gui_tjc_hmi_read_device_info_from_w25q(); history.init_history(); } /*发送接口*/ static void gui_tjc_hmi_data_send(u8 *p_data,u16 len) { if(p_rx_uart != NULL) { p_rx_uart->send(p_rx_uart,p_data,len); } } static void gui_tjc_hmi_read_password_from_w25q(void) { /*直接读取4字节密码*/ w25q32.read(W25Q32_PASSWORD_ADDR, p_tjc_hmi->password, 4); /*检查数据有效性,如果全部为0xFF,说明是首次使用,清空密码*/ if(p_tjc_hmi->password[0] == 0xFF && p_tjc_hmi->password[1] == 0xFF && p_tjc_hmi->password[2] == 0xFF && p_tjc_hmi->password[3] == 0xFF) { memset(p_tjc_hmi->password, 0, 4); } } /*将密码保存到W25Q32*/ static void gui_tjc_hmi_save_password_to_w25q(void) { /*将4字节密码写入W25Q32*/ w25q32.write(W25Q32_PASSWORD_ADDR, p_tjc_hmi->password, 4); } /* 从W25Q32读取设备信息到app_leakage */ static void gui_tjc_hmi_read_device_info_from_w25q(void) { /* 创建一个临时缓冲区 */ app_leakage_sub_device_flash_data_t temp_buffer[APP_LEAKAGE_SUB_DEVICE_NUM]; /* 一次性读取所有设备信息 */ w25q32.read(W25Q32_DEVICE_INFO_ADDR, (uint8_t*)temp_buffer, DEVICE_INFO_STORAGE_SIZE); /* 检查数据有效性 */ uint8_t data_valid = 1; for(int i = 0; i < APP_LEAKAGE_SUB_DEVICE_NUM; i++) { /* 如果所有字段都是0xFF,说明是空数据 */ if(temp_buffer[i].state == 0xFF && temp_buffer[i].com_port == 0xFF && temp_buffer[i].modbus_id == 0xFF) { data_valid = 0; break; } } if(data_valid) { /* 复制到app_leakage结构体中 */ for(int i = 0; i < APP_LEAKAGE_SUB_DEVICE_NUM; i++) { p_leakage->sub_device_data[i].flash_data = temp_buffer[i]; } } else { /* Flash为空,初始化设备信息为默认值 */ for(int i = 0; i < APP_LEAKAGE_SUB_DEVICE_NUM; i++) { memset(&p_leakage->sub_device_data[i].flash_data, 0, sizeof(app_leakage_sub_device_flash_data_t)); p_leakage->sub_device_data[i].flash_data.state = DISABLE; } } /* 重新分类区域 */ app_leakage_region_classify(); } /* 将设备信息从app_leakage保存到W25Q32 */ static void gui_tjc_hmi_save_device_info_to_w25q(void) { /* 创建一个临时缓冲区 */ app_leakage_sub_device_flash_data_t temp_buffer[APP_LEAKAGE_SUB_DEVICE_NUM]; /* 从app_leakage结构体复制到临时缓冲区 */ for(int i = 0; i < APP_LEAKAGE_SUB_DEVICE_NUM; i++) { temp_buffer[i] = p_leakage->sub_device_data[i].flash_data; } /* 添加Flash擦除操作 - 必须擦除后才能写入 */ uint32_t erase_addr = W25Q32_DEVICE_INFO_ADDR; /* 确保地址是4K对齐(W25Q32_SECTOR_SIZE = 4096) */ erase_addr &= ~(W25Q32_SECTOR_SIZE - 1); /* 擦除整个扇区 */ w25q32_sector_erase(erase_addr); /* 一次性写入所有设备信息 */ w25q32.write(W25Q32_DEVICE_INFO_ADDR, (uint8_t*)temp_buffer, DEVICE_INFO_STORAGE_SIZE); } /*设置对应的控件 x:第几行 y:第几个 buffer:写入的buffer format:格式化输入 ...:不定长 */ static u16 gui_tjc_hmi_tx_text_display(u16 x,u16 y,char *buffer,const char *format,...) { u16 i,len; s16 state; va_list arg; /*清空缓冲区*/ memset(gui_tjc_hmi_text_buffer,0,sizeof(gui_tjc_hmi_text_buffer)); va_start(arg,format); /*格式化转成字符串*/ state = vsnprintf(gui_tjc_hmi_text_buffer,GUI_TJC_HMI_TEXT_BUFFER_NUM,format,arg); if(-1 == state || state > GUI_TJC_HMI_TEXT_BUFFER_NUM) { va_end(arg); printf("Length REEOR"); return 0; } /*拼接字符串*/ sprintf(buffer,"t%d_%d.txt=\"%s\"",x,y,gui_tjc_hmi_text_buffer); len = strlen(buffer); for(i=0;i 0) { page_num++; } char time[20]; sprintf(time,"20%d-%02d-%02d %02d:%02d", DS1302.Time.Year, DS1302.Time.Month, DS1302.Time.Day, DS1302.Time.Hour, DS1302.Time.Minute); len += gui_tjc_hmi_tx_text_display(0,0,(char *)&hmi_tx_buffer[len],"%s",time); if(HMI_PROTO_CMD_GET == cmd)/*获取数据*/ { switch(opa) { case 0x01:/*读取区域信息*/ { if(p_tjc_hmi->page.main_index == page_num - 1 && remain_region_num >0)/*显示剩余区域*/ { for(j=0;jpage.main_index * MAIN_PAGE_SUB_DEVICE_NUM + j; x = j; /*名称*/ y = 0; len += gui_tjc_hmi_tx_text_display(x+1,y+1,(char *)&hmi_tx_buffer[len],"%s",leakage.region_data[index].name); /*区域内设备总数量*/ y = 1; len += gui_tjc_hmi_tx_text_display(x+1,y+1,(char *)&hmi_tx_buffer[len],"%d",leakage.region_data[index].sub_device_num); /*漏液数量*/ y = 2; len += gui_tjc_hmi_tx_text_display(x+1,y+1,(char *)&hmi_tx_buffer[len],"%d",leakage.region_data[index].leakage_num); /*断带*/ y = 3; len += gui_tjc_hmi_tx_text_display(x+1,y+1,(char *)&hmi_tx_buffer[len],"%d",leakage.region_data[index].open_num); /*通讯*/ y = 4; len += gui_tjc_hmi_tx_text_display(x+1,y+1,(char *)&hmi_tx_buffer[len],"%d",leakage.region_data[index].time_out_num); } } else { for(j=0;jpage.main_index*MAIN_PAGE_SUB_DEVICE_NUM + j; x = j; /*名称*/ y = 0; len = gui_tjc_hmi_tx_text_display(x+1,y+1,(char *)&hmi_tx_buffer[len],"%s",leakage.region_data[index].name); /*区域内设备总数量*/ y = 1; len = gui_tjc_hmi_tx_text_display(x+1,y+1,(char *)&hmi_tx_buffer[len],"%d",leakage.region_data[index].sub_device_num); /*漏液数量*/ y = 2; len = gui_tjc_hmi_tx_text_display(x+1,y+1,(char *)&hmi_tx_buffer[len],"%d",leakage.region_data[index].leakage_num); /*断带*/ y = 3; len = gui_tjc_hmi_tx_text_display(x+1,y+1,(char *)&hmi_tx_buffer[len],"%d",leakage.region_data[index].open_num); /*通讯*/ y = 4; len = gui_tjc_hmi_tx_text_display(x+1,y+1,(char *)&hmi_tx_buffer[len],"%d",leakage.region_data[index].time_out_num); } } }break; case 0x03:/*翻页*/ { if(0x01 == p_data[5]) { if(page_num - 1 <= p_tjc_hmi->page.main_index) { p_tjc_hmi->page.main_index = 0; } else { p_tjc_hmi->page.main_index++; } } else { if(0 == p_tjc_hmi->page.main_index) { p_tjc_hmi->page.main_index = page_num - 1; } else { p_tjc_hmi->page.main_index--; } } } default:return; } len = strlen((char *)hmi_tx_buffer); gui_tjc_hmi_data_send(hmi_tx_buffer,len); } else if(HMI_PROTO_CMD_SET == cmd)/*设置*/ { switch(opa) { case 0x01:/*蜂鸣器开关*/ { if(0x01 == p_data[0]) { /*01打开蜂鸣器*/ } else { /*00关闭蜂鸣器*/ } } default:return; } len = strlen((char *)hmi_tx_buffer); gui_tjc_hmi_data_send(hmi_tx_buffer,len); } } /*实时报警响应*/ static void gui_tjc_hmi_curr_alarm_send(u8 cmd,u8 opa,u8 *p_data) { /*每页显示的报警设备数量*/ #define REAL_ALARM_PAGE_NUM (4) u16 len = 0,i,j,x,y,device_index,ch,index; u8 page_num,remain_alrm_device_num,display_count; u8 alarm_device_count; u8 alarm_device_index[APP_LEAKAGE_SUB_DEVICE_NUM]; memset(hmi_tx_buffer,0,sizeof(hmi_tx_buffer)); /*计算报警设备数量*/ alarm_device_count = 0; for(i = 0;i 0) { page_num++; } if(HMI_PROTO_CMD_GET == cmd)/*获取数据*/ { switch(opa) { case 0x01:/*获取实时报警信息*/ { if(p_tjc_hmi->page.real_alarm_index == page_num - 1 && remain_alrm_device_num > 0) { for(j=0;jpage.real_alarm_index * REAL_ALARM_PAGE_NUM + j; device_index = alarm_device_index[index]; x = j; /*区域名称*/ y = 0; len += gui_tjc_hmi_tx_text_display(x+1,y+1,(char *)&hmi_tx_buffer[len],"%s",leakage.sub_device_data[index].flash_data.region_name); /*设备ID*/ y = 1; len += gui_tjc_hmi_tx_text_display(x+1,y+1,(char *)&hmi_tx_buffer[len],"%d",leakage.sub_device_data[index].flash_data.modbus_id); /*设备名称*/ y = 2; len += gui_tjc_hmi_tx_text_display(x+1,y+1,(char *)&hmi_tx_buffer[len],"%s",leakage.sub_device_data[index].flash_data.device_name); /*通讯状态*/ y =3; u16 comm_state = 0; for(ch=0;chpage.real_alarm_index * REAL_ALARM_PAGE_NUM + j; device_index = alarm_device_index[index]; x = j; /*区域名称*/ y = 0; len += gui_tjc_hmi_tx_text_display(x+1,y+1,(char *)&hmi_tx_buffer[len],"%s",leakage.sub_device_data[device_index].flash_data.region_name); /*设备ID*/ y = 1; len += gui_tjc_hmi_tx_text_display(x+1,y+1,(char *)&hmi_tx_buffer[len],"%d",leakage.sub_device_data[index].flash_data.modbus_id); /*设备名称*/ y = 2; len += gui_tjc_hmi_tx_text_display(x+1,y+1,(char *)&hmi_tx_buffer[len],"%s",leakage.sub_device_data[index].flash_data.device_name); /*通讯状态*/ y =3; u16 comm_state = 0; for(ch=0;chpage.real_alarm_index) { p_tjc_hmi->page.real_alarm_index = 0; } else { p_tjc_hmi->page.real_alarm_index++; } } else { if(0 == p_tjc_hmi->page.real_alarm_index) { p_tjc_hmi->page.real_alarm_index = page_num - 1; } else { p_tjc_hmi->page.real_alarm_index--; } } } default:return; } len = strlen((char *)hmi_tx_buffer); gui_tjc_hmi_data_send(hmi_tx_buffer,len); } else if(HMI_PROTO_CMD_SET == cmd)/*设置*/ { switch(opa) { case 0x01: { }break; case 0x02: { }break; default:return; } len = strlen((char *)hmi_tx_buffer); gui_tjc_hmi_data_send(hmi_tx_buffer,len); } } /*主界面详情*/ static void gui_tjc_hmi_detail_main_send(u8 cmd, u8 opa, u8 *p_data) { #define DETAIL_MAIN_NUM (4) /* 每页显示4个设备 */ u16 len = 0, i, sub_device_index, ch, x, y, index; u8 page_num, remain_device_num, display_count; u8 region_idx; /* 区域索引 */ app_leakage_region_data_class_t *region_data; memset(hmi_tx_buffer, 0, sizeof(hmi_tx_buffer)); /* 计算详情页面数量:每页显示4个设备 */ page_num = region_data->sub_device_num / DETAIL_MAIN_NUM; remain_device_num = region_data->sub_device_num % DETAIL_MAIN_NUM; if (remain_device_num > 0) { page_num++; } if (HMI_PROTO_CMD_GET == cmd) /* 获取数据 */ { switch (opa) { case 0x01: /* 获取设备详情信息 */ { /* 从指令中获取区域索引 (p_data[0] = 相对区域索引,从1开始,对应当前主界面的1-4) */ u8 relative_region_idx = p_data[0]; if (relative_region_idx < 1 || relative_region_idx > 4) { /* 相对区域索引无效,默认显示第一个 */ // relative_region_idx = 1; return; } /* 计算全局区域索引: 全局索引 = 主界面页码 * 4 + 相对索引 - 1 */ region_idx = p_tjc_hmi->page.main_index * 4 + (relative_region_idx - 1); /* 检查区域索引是否有效 */ if (region_idx >= leakage.region_num) { /* 区域索引越界,尝试显示第一个区域 */ // region_idx = 0; return; } /* 判断是否切换了区域 */ if (region_idx != p_tjc_hmi->page.deliniter_main_index) { p_tjc_hmi->page.detail_main_index = 0; } /* 保存当前区域索引和主界面页码,翻页时使用 */ p_tjc_hmi->page.deliniter_main_index = region_idx; /* 获取区域数据 */ region_data = &leakage.region_data[region_idx]; /* 获取当前详情页面的设备数据 */ u8 start_index = p_tjc_hmi->page.detail_main_index * DETAIL_MAIN_NUM; if (p_tjc_hmi->page.detail_main_index == page_num - 1 && remain_device_num > 0) { display_count = remain_device_num; } else { display_count = DETAIL_MAIN_NUM; } for (i = 0; i < display_count; i++) { index = start_index + i; if (index >= region_data->sub_device_num) break; /* 获取设备的全局索引 */ sub_device_index = region_data->sub_device_index[index]; x = i; /* 0-3表示当前详情页面的4个设备位置 */ /* 设备ID: t(x+1)_1 */ y = 0; len += gui_tjc_hmi_tx_text_display(x+1, y+1, (char *)&hmi_tx_buffer[len], "%d", leakage.sub_device_data[sub_device_index].flash_data.modbus_id); /* 设备名称: t(x+1)_2 */ y = 1; len += gui_tjc_hmi_tx_text_display(x+1, y+1, (char *)&hmi_tx_buffer[len], "%s", leakage.sub_device_data[sub_device_index].flash_data.device_name); /* 通讯状态: t(x+1)_3 */ y = 2; u8 comm_state = 0; for (ch = 0; ch < APP_LEAKAGE_SUB_DEVICE_CH_NUM; ch++) { if (leakage.sub_device_data[sub_device_index].ch_data[ch].state & APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT) { comm_state = 1; break; } } if (comm_state) { len += gui_tjc_hmi_tx_text_display(x+1, y+1, (char *)&hmi_tx_buffer[len], "超时"); } else { len += gui_tjc_hmi_tx_text_display(x+1, y+1, (char *)&hmi_tx_buffer[len], "正常"); } /* 通道1-4状态 */ for (ch = 0; ch < APP_LEAKAGE_SUB_DEVICE_CH_NUM; ch++) { u16 ch_state = leakage.sub_device_data[sub_device_index].ch_data[ch].state; u16 ch_distance = leakage.sub_device_data[sub_device_index].ch_data[ch].distance; /* 漏液状态 */ y = 3 + (ch * 3); if (ch_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE) { len += gui_tjc_hmi_tx_text_display(x+1, y+1, (char *)&hmi_tx_buffer[len], "漏液"); } else { len += gui_tjc_hmi_tx_text_display(x+1, y+1, (char *)&hmi_tx_buffer[len], "正常"); } /* 断带状态 */ y = 4 + (ch * 3); if (ch_state & APP_LEAKAGE_SUB_DEVICE_STATE_OPEN) { len += gui_tjc_hmi_tx_text_display(x+1, y+1, (char *)&hmi_tx_buffer[len], "断带"); } else { len += gui_tjc_hmi_tx_text_display(x+1, y+1, (char *)&hmi_tx_buffer[len], "正常"); } /* 漏液位置 */ y = 5 + (ch * 3); if (ch_state & APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE) { len += gui_tjc_hmi_tx_text_display(x+1, y+1, (char *)&hmi_tx_buffer[len], "%d", ch_distance); } else { len += gui_tjc_hmi_tx_text_display(x+1, y+1, (char *)&hmi_tx_buffer[len], "0"); } } } } break; case 0x03: /* 翻页 */ { /* 使用之前保存的全局区域索引 */ region_idx = p_tjc_hmi->page.deliniter_main_index; /* 检查区域索引是否有效 */ if (region_idx >= leakage.region_num) { return; /* 区域索引越界 */ } /* 获取区域数据 */ region_data = &leakage.region_data[region_idx]; if(0x01 == p_data[0]) /* 下一页 */ { if(page_num - 1 <= p_tjc_hmi->page.detail_main_index) { p_tjc_hmi->page.detail_main_index = 0; } else { p_tjc_hmi->page.detail_main_index++; } } else /* 上一页 */ { if(0 == p_tjc_hmi->page.detail_main_index) { p_tjc_hmi->page.detail_main_index = page_num - 1; } else { p_tjc_hmi->page.detail_main_index--; } } return; } break; default: return; } len = strlen((char *)hmi_tx_buffer); gui_tjc_hmi_data_send(hmi_tx_buffer,len); } else if (HMI_PROTO_CMD_SET == cmd) /* 设置命令 */ { switch (opa) { case 0x01: /* */ { } break; default: return; } } } /*登录界面*/ static void gui_tjc_hmi_login_send(u8 cmd,u8 opa,u8 *p_data) { u16 len = 0,i; if(HMI_PROTO_CMD_GET == cmd)/*获取数据*/ { switch(opa) { case 0x01:/*读取flash中存储的密码*/ { memset(hmi_tx_buffer,0,sizeof(hmi_tx_buffer)); len = gui_tjc_hmi_tx_text_display(1,1,(char *)hmi_tx_buffer,"%02X%02X%02X%02X", p_tjc_hmi->password[0], p_tjc_hmi->password[1], p_tjc_hmi->password[2], p_tjc_hmi->password[3]); gui_tjc_hmi_data_send(hmi_tx_buffer,len); }break; case 0x02:/*无*/ { }break; default:return; } len = strlen((char *)hmi_tx_buffer); gui_tjc_hmi_data_send(hmi_tx_buffer,len); } else if(HMI_PROTO_CMD_SET == cmd)/*设置*/ { switch(opa) { case 0x01:/*将密码存入flash中*/ { for(i=0; i<4; i++) { p_tjc_hmi->password[i] = p_data[i]; } /*保存到W25Q32*/ gui_tjc_hmi_save_password_to_w25q(); }break; case 0x02:/*无*/ { }break; default:return; } len = strlen((char *)hmi_tx_buffer); gui_tjc_hmi_data_send(hmi_tx_buffer,len); } } /*历史报警界面*/ static void gui_tjc_hmi_history_alarm_send(u8 cmd,u8 opa,u8 *p_data) { #define HISTORY_ALARM_PER_PAGE (15) /* 每页15条历史报警数据 */ u16 len = 0, i, j; u8 page_num, remain_records, display_count; u32 total_records, start_index, record_index; app_leakage_history_alarm_t history_record; char time_str[20]; char alarm_type_str[20]; /* 获取总记录数 */ total_records = leakage.history_metadata.total_records; if(total_records == 0) { return; } /* 计算页面数量 */ page_num = total_records / HISTORY_ALARM_PER_PAGE; remain_records = total_records % HISTORY_ALARM_PER_PAGE; if(remain_records > 0) { page_num++; } if(HMI_PROTO_CMD_GET == cmd) /* 获取数据 */ { switch(opa) { case 0x01: /* 读取历史报警信息 */ { /* 获取当前页码对应的记录 */ u8 current_page = p_tjc_hmi->page.history_alarm_index; /* 计算起始记录索引(按时间倒序显示,最新的在前面) */ start_index = current_page * HISTORY_ALARM_PER_PAGE; /* 计算本页显示记录数 */ if(current_page == page_num - 1 && remain_records > 0) { display_count = remain_records; } else { display_count = HISTORY_ALARM_PER_PAGE; } /* 显示历史报警记录 */ for(i = 0; i < display_count; i++) { /* 计算记录索引(从最新的开始) */ if(total_records > start_index + i) { record_index = total_records - 1 - (start_index + i); } else { break; } /* 读取历史报警记录 */ if(history.read_history(record_index, &history_record)) { /* 区域名: t(i+1)_1 */ len += gui_tjc_hmi_tx_text_display(i+1, 1, (char *)&hmi_tx_buffer[len], "%s", history_record.region_name); /* 设备ID: t(i+1)_2 */ len += gui_tjc_hmi_tx_text_display(i+1, 2, (char *)&hmi_tx_buffer[len], "%d", history_record.device_id); /* 设备名称: t(i+1)_3 */ len += gui_tjc_hmi_tx_text_display(i+1, 3, (char *)&hmi_tx_buffer[len], "%s", history_record.device_name); /* 报警类型: t(i+1)_4 */ alarm_type_str[0] = '\0'; if(history_record.alarm_type == APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE) strcat(alarm_type_str, "漏液"); else if(history_record.alarm_type == APP_LEAKAGE_SUB_DEVICE_STATE_OPEN) strcat(alarm_type_str, "断带"); else if(history_record.alarm_type == APP_LEAKAGE_SUB_DEVICE_STATE_TIME_OUT) strcat(alarm_type_str, "通讯超时"); len += gui_tjc_hmi_tx_text_display(i+1, 4, (char *)&hmi_tx_buffer[len], "%s", alarm_type_str); /* 开始时间: t(i+1)_5 */ uint16_t year = (history_record.start_time[0] << 8) | history_record.start_time[1]; sprintf(time_str, "%04d-%02d-%02d %02d:%02d", year, history_record.start_time[2], history_record.start_time[3], history_record.start_time[4], history_record.start_time[5]); len += gui_tjc_hmi_tx_text_display(i+1, 5, (char *)&hmi_tx_buffer[len], "%s", time_str); /* 漏液距离: t(i+1)_6 (如果是漏液报警才显示) */ if(history_record.alarm_type == APP_LEAKAGE_SUB_DEVICE_STATE_LEAKAGE) { len += gui_tjc_hmi_tx_text_display(i+1, 6, (char *)&hmi_tx_buffer[len], "%d", history_record.leak_distance); } else { len += gui_tjc_hmi_tx_text_display(i+1, 6, (char *)&hmi_tx_buffer[len], "0"); } } else { /* 读取失败,显示空 */ len += gui_tjc_hmi_tx_text_display(i+1, 1, (char *)&hmi_tx_buffer[len], ""); len += gui_tjc_hmi_tx_text_display(i+1, 2, (char *)&hmi_tx_buffer[len], ""); len += gui_tjc_hmi_tx_text_display(i+1, 3, (char *)&hmi_tx_buffer[len], ""); len += gui_tjc_hmi_tx_text_display(i+1, 4, (char *)&hmi_tx_buffer[len], ""); len += gui_tjc_hmi_tx_text_display(i+1, 5, (char *)&hmi_tx_buffer[len], ""); len += gui_tjc_hmi_tx_text_display(i+1, 6, (char *)&hmi_tx_buffer[len], ""); } } /* 如果本页不足15条记录,清空剩余行 */ for(; i < HISTORY_ALARM_PER_PAGE; i++) { len += gui_tjc_hmi_tx_text_display(i+1, 1, (char *)&hmi_tx_buffer[len], ""); len += gui_tjc_hmi_tx_text_display(i+1, 2, (char *)&hmi_tx_buffer[len], ""); len += gui_tjc_hmi_tx_text_display(i+1, 3, (char *)&hmi_tx_buffer[len], ""); len += gui_tjc_hmi_tx_text_display(i+1, 4, (char *)&hmi_tx_buffer[len], ""); len += gui_tjc_hmi_tx_text_display(i+1, 5, (char *)&hmi_tx_buffer[len], ""); len += gui_tjc_hmi_tx_text_display(i+1, 6, (char *)&hmi_tx_buffer[len], ""); } len = strlen((char *)hmi_tx_buffer); gui_tjc_hmi_data_send(hmi_tx_buffer, len); } break; case 0x03: /* 翻页 */ { if(0x01 == p_data[0]) /* 下一页 */ { if(p_tjc_hmi->page.history_alarm_index >= page_num - 1) { p_tjc_hmi->page.history_alarm_index = 0; } else { p_tjc_hmi->page.history_alarm_index++; } } else /* 上一页 */ { if(p_tjc_hmi->page.history_alarm_index == 0) { p_tjc_hmi->page.history_alarm_index = page_num - 1; } else { p_tjc_hmi->page.history_alarm_index--; } } } break; default:return; } len = strlen((char *)hmi_tx_buffer); gui_tjc_hmi_data_send(hmi_tx_buffer,len); } else if(HMI_PROTO_CMD_SET == cmd)/*设置*/ { switch(opa) { case 0x01:/*清空*/ { history.clean_history(); }break; case 0x02:/*无*/ { }break; default:return; } len = strlen((char *)hmi_tx_buffer); gui_tjc_hmi_data_send(hmi_tx_buffer,len); } } /*网络配置界面*/ static void gui_tjc_hmi_tcp_config_send(u8 cmd,u8 opa,u8 *p_data) { u16 len = 0,i; memset(hmi_tx_buffer,0,sizeof(hmi_tx_buffer)); if(HMI_PROTO_CMD_GET == cmd)/*获取数据*/ { switch(opa) { case 0x01:/*读取网络配置信息,p_data[0]=0x01为读取设置的网络配置,00为读取默认的,网络IP,子网掩码,网关,DNS服务器*/ { if(p_data[0] == 0x01) { len += gui_tjc_hmi_tx_text_display(1,1,(char *)&hmi_tx_buffer[len], "%d.%d.%d.%d", W5500.IP_Addr[0], W5500.IP_Addr[1], W5500.IP_Addr[2], W5500.IP_Addr[3]); len += gui_tjc_hmi_tx_text_display(1,2,(char *)&hmi_tx_buffer[len], "%d.%d.%d.%d", W5500.Sub_Mask[0], W5500.Sub_Mask[1], W5500.Sub_Mask[2], W5500.Sub_Mask[3]); len += gui_tjc_hmi_tx_text_display(1,3,(char *)&hmi_tx_buffer[len], "%d.%d.%d.%d", W5500.Gateway_IP[0], W5500.Gateway_IP[1], W5500.Gateway_IP[2], W5500.Gateway_IP[3]); len += gui_tjc_hmi_tx_text_display(1,4,(char *)&hmi_tx_buffer[len],"%s","114.114.114.114"); }else if(p_data[0] == 0x00) { len += gui_tjc_hmi_tx_text_display(1,1,(char *)&hmi_tx_buffer[len],"%s","192.168.100.100"); len += gui_tjc_hmi_tx_text_display(1,2,(char *)&hmi_tx_buffer[len],"%s","255.255.255.0"); len += gui_tjc_hmi_tx_text_display(1,3,(char *)&hmi_tx_buffer[len],"%s","192.168.50.1"); len += gui_tjc_hmi_tx_text_display(1,4,(char *)&hmi_tx_buffer[len],"%s","114.114.114.114"); } }break; case 0x02:/*无*/ { }break; default:return; } len = strlen((char *)hmi_tx_buffer); gui_tjc_hmi_data_send(hmi_tx_buffer,len); } else if(HMI_PROTO_CMD_SET == cmd)/*设置*/ { switch(opa) { case 0x01:/*添加网络配置,并将网络配置信息存入flash*/ { u8 field_count = 0; u8 *current_pos = p_data; /*解析IP地址*/ for(i=0; i<16; i++) { if(current_pos[i] == HMI_PROTO_ASCII_RX_DELINITER) { memcpy(W5500.IP_Addr, current_pos, i); current_pos += (i + 1); field_count++; break; } } /*解析子网掩码*/ for(i=0; i<16; i++) { if(current_pos[i] == HMI_PROTO_ASCII_RX_DELINITER) { memcpy(W5500.Sub_Mask, current_pos, i); current_pos += (i + 1); field_count++; break; } } /*解析网关*/ for(i=0; i<16; i++) { if(current_pos[i] == HMI_PROTO_ASCII_RX_DELINITER) { memcpy(W5500.Gateway_IP, current_pos, i); current_pos += (i + 1); field_count++; break; } } /*解析DNS服务器*/ for(i=0; i<16; i++) { if(current_pos[i] == HMI_PROTO_ASCII_RX_DELINITER) { // memcpy(p_tjc_hmi->network_config.dns, current_pos, i); // p_tjc_hmi->network_config.dns[i] = '\0'; field_count++; break; } } }break; case 0x02:/*无*/ { }break; default:return; } len = strlen((char *)hmi_tx_buffer); gui_tjc_hmi_data_send(hmi_tx_buffer,len); } } /*设备配置界面 */ static void gui_tjc_hmi_device_config_send(u8 cmd,u8 opa,u8 *p_data) { #define DEVICES_PER_PAGE (8) u16 len = 0,i,j; u8 found_empty_slot = 0,enabled_device_count,field_count,page_num,remain_region_num; u8 empty_slot_index = 0; u8 *current_pos = NULL; app_leakage_sub_device_flash_data_t new_device; memset(hmi_tx_buffer,0,sizeof(hmi_tx_buffer)); /*计算总页数*/ page_num = enabled_device_count / DEVICES_PER_PAGE; remain_region_num = enabled_device_count % DEVICES_PER_PAGE; if(remain_region_num > 0) { page_num++; } /*确保页码在有效范围内*/ if(p_tjc_hmi->page.device_config_index >= page_num) { p_tjc_hmi->page.device_config_index = 0; } if(HMI_PROTO_CMD_GET == cmd)/*获取数据*/ { switch(opa) { case 0x01:/*读取已存在的设备,显示区域,端口,设备ID,设备名,*/ { u8 page_device_indices[DEVICES_PER_PAGE] = {0}; /*存储当前页8个设备在app_leakage中的索引*/ u8 page_device_count = 0; /*当前页实际启用的设备数量*/ u8 current_enabled_index = 0; /*当前是第几个启用的设备*/ u8 device_index; /*计算启用的设备数量*/ enabled_device_count = 0; for(i = 0; i < APP_LEAKAGE_SUB_DEVICE_NUM; i++) { if(p_leakage->sub_device_data[i].flash_data.state == ENABLE) { enabled_device_count++; } } if(enabled_device_count == 0) { return; } /*获取当前页的设备索引*/ for(i = 0; i < APP_LEAKAGE_SUB_DEVICE_NUM && page_device_count < DEVICES_PER_PAGE; i++) { if(p_leakage->sub_device_data[i].flash_data.state == ENABLE) { current_enabled_index++; /*判断这个设备是否在当前页*/ u8 device_page = (current_enabled_index - 1) / DEVICES_PER_PAGE; if(device_page == p_tjc_hmi->page.device_config_index) { page_device_indices[page_device_count] = i; page_device_count++; } } } if(page_device_count == 0) { /*当前页没有设备,发送空数据*/ len = strlen((char *)hmi_tx_buffer); gui_tjc_hmi_data_send(hmi_tx_buffer,len); return; } /*显示当前页的设备信息*/ for(i = 0; i < page_device_count; i++) { device_index = page_device_indices[i]; /*区域名: t(i+1)_1 */ len += gui_tjc_hmi_tx_text_display(i+1, 1, (char *)&hmi_tx_buffer[len], "%s", p_leakage->sub_device_data[device_index].flash_data.region_name); /*端口号: t(i+1)_2 */ u8 com_port = p_leakage->sub_device_data[device_index].flash_data.com_port; if(com_port < 4) /*确保端口号在有效范围内*/ { len += gui_tjc_hmi_tx_text_display(i+1, 2, (char *)&hmi_tx_buffer[len], "%s", hmi_proto_string_com[com_port]); } else { len += gui_tjc_hmi_tx_text_display(i+1, 2, (char *)&hmi_tx_buffer[len], "未知"); } /*设备ID: t(i+1)_3 */ len += gui_tjc_hmi_tx_text_display(i+1, 3, (char *)&hmi_tx_buffer[len], "%d", p_leakage->sub_device_data[device_index].flash_data.modbus_id); /*设备名称: t(i+1)_4 */ len += gui_tjc_hmi_tx_text_display(i+1, 4, (char *)&hmi_tx_buffer[len], "%s", p_leakage->sub_device_data[device_index].flash_data.device_name); } /*如果当前页不足8个设备,清空剩余的设备显示位置*/ if(page_device_count < DEVICES_PER_PAGE) { for(i = page_device_count; i < DEVICES_PER_PAGE; i++) { /*清空区域名*/ len += gui_tjc_hmi_tx_text_display(i+1, 1, (char *)&hmi_tx_buffer[len], ""); /*清空端口号*/ len += gui_tjc_hmi_tx_text_display(i+1, 2, (char *)&hmi_tx_buffer[len], ""); /*清空设备ID*/ len += gui_tjc_hmi_tx_text_display(i+1, 3, (char *)&hmi_tx_buffer[len], ""); /*清空设备名称*/ len += gui_tjc_hmi_tx_text_display(i+1, 4, (char *)&hmi_tx_buffer[len], ""); } } }break; case 0x03:/*翻页功能,每页显示8个设备*/ { if(0x01 == p_data[0]) /*下一页*/ { if(page_num - 1 <= p_tjc_hmi->page.device_config_index) { p_tjc_hmi->page.device_config_index = 0; } else { p_tjc_hmi->page.device_config_index++; } } else /*上一页*/ { if(0 == p_tjc_hmi->page.device_config_index) { p_tjc_hmi->page.device_config_index = page_num - 1; } else { p_tjc_hmi->page.device_config_index--; } } /*翻页后需要重新获取数据并显示,这里不直接发送数据*/ return; }break; default:return; } len = strlen((char *)hmi_tx_buffer); gui_tjc_hmi_data_send(hmi_tx_buffer,len); } else if(HMI_PROTO_CMD_SET == cmd)/*设置*/ { switch(opa) { case 0x01: { found_empty_slot = 0; for(i = 0; i < APP_LEAKAGE_SUB_DEVICE_NUM; i++) { if(p_leakage->sub_device_data[i].flash_data.state == DISABLE) { found_empty_slot = 1; empty_slot_index = i; break; } } if(!found_empty_slot) { /*设备数量已满*/ return; } field_count = 0; current_pos = p_data; memset(&new_device, 0, sizeof(new_device)); /*解析端口号*/ for(i = 0; i < 10; i++) { if(current_pos[i] == HMI_PROTO_ASCII_RX_DELINITER) { if(i == 0) { /*端口号不能为空*/ return; } char port_str[10] = {0}; memcpy(port_str, current_pos, i); port_str[i] = '\0'; /*将字符串端口号转换为数值*/ if(strcmp(port_str, "COM1") == 0) { new_device.com_port = 0; } else if(strcmp(port_str, "COM2") == 0) { new_device.com_port = 1; } else if(strcmp(port_str, "COM3") == 0) { new_device.com_port = 2; } else if(strcmp(port_str, "COM4") == 0) { new_device.com_port = 3; } current_pos += (i + 1); field_count++; break; } } /*解析区域名*/ for(i = 0; i < APP_LEAKAGE_STRING_NANE_LEN; i++) { if(current_pos[i] == HMI_PROTO_ASCII_RX_DELINITER) { memcpy(new_device.region_name, current_pos, i); new_device.region_name[i] = '\0'; current_pos += (i + 1); field_count++; break; } } /*解析设备ID */ for(i = 0; i < 10; i++) { if(current_pos[i] == HMI_PROTO_ASCII_RX_DELINITER) { if(i == 0) { /*设备ID不能为空*/ return; } /*设备ID是数字字符串,转换为数值*/ char id_str[10] = {0}; memcpy(id_str, current_pos, i); id_str[i] = '\0'; new_device.modbus_id = atoi(id_str); current_pos += (i + 1); field_count++; break; } } /*解析设备名称*/ for(i = 0; i < APP_LEAKAGE_STRING_NANE_LEN; i++) { if(current_pos[i] == HMI_PROTO_ASCII_RX_DELINITER) { memcpy(new_device.device_name, current_pos, i); new_device.device_name[i] = '\0'; field_count++; break; } } /*相同id时覆盖之前的*/ if(field_count == 4) { for(u8 x = 0; x < APP_LEAKAGE_SUB_DEVICE_NUM; x++) { if (p_leakage->sub_device_data[x].flash_data.modbus_id == new_device.modbus_id) { new_device.state = ENABLE; p_leakage->sub_device_data[x].flash_data = new_device; gui_tjc_hmi_save_device_info_to_w25q(); app_leakage_region_classify(); field_count++; } } } /*添加到设备列表*/ if(field_count == 4) { /*设置默认状态为启用*/ new_device.state = ENABLE; /*添加到app_leakage的设备列表中*/ p_leakage->sub_device_data[empty_slot_index].flash_data = new_device; /*保存到W25Q32*/ gui_tjc_hmi_save_device_info_to_w25q(); /*重新分类区域*/ app_leakage_region_classify(); } else { /*发送错误响应*/ return; } }break; case 0x02:/*删除设备,将设备信息从w25q中删除*/ { u8 page_device_indices[8] = {0}; /*存储当前页8个设备在app_leakage中的索引*/ u8 page_device_count = 0; /*当前页实际启用的设备数量*/ u8 current_enabled_index = 0; /*当前是第几个启用的设备*/ for(i = 0; i < APP_LEAKAGE_SUB_DEVICE_NUM && page_device_count < DEVICES_PER_PAGE; i++) { if(p_leakage->sub_device_data[i].flash_data.state == ENABLE) { current_enabled_index++; /*判断这个设备是否在当前页*/ u8 device_page = (current_enabled_index - 1) / DEVICES_PER_PAGE; if(device_page == p_tjc_hmi->page.device_config_index) { page_device_indices[page_device_count] = i; page_device_count++; } } } if(page_device_count == 0) { /*当前页没有设备*/ return; } /*遍历8个选中框字节,删除被选中的设备*/ u8 deleted_count = 0; /*记录删除的设备数量*/ u8 shift_offset = 0; /*偏移量,用于处理删除后设备索引的变化*/ for(i = 0; i < 8; i++) { /*只处理当前页实际存在的设备*/ if(i >= page_device_count) { break; } /*检查设备是否被选中删除*/ if(p_data[i] == 0x01) { /*计算实际要删除的设备在app_leakage中的索引*/ u8 actual_index = page_device_indices[i] - shift_offset; /*直接删除设备:将后面的设备向前移动*/ for(j = actual_index; j < APP_LEAKAGE_SUB_DEVICE_NUM - 1; j++) { p_leakage->sub_device_data[j].flash_data = p_leakage->sub_device_data[j + 1].flash_data; } /*最后一个设备清空*/ memset(&p_leakage->sub_device_data[APP_LEAKAGE_SUB_DEVICE_NUM - 1].flash_data, 0, sizeof(app_leakage_sub_device_flash_data_t)); p_leakage->sub_device_data[APP_LEAKAGE_SUB_DEVICE_NUM - 1].flash_data.state = DISABLE; /*删除设备后,后面的设备索引会变化,更新偏移量*/ shift_offset++; deleted_count++; /*重新计算当前页的设备索引,设备前移*/ for(u8 k = i + 1; k < page_device_count; k++) { page_device_indices[k]--; } } } if(deleted_count > 0) { /*保存到W25Q32*/ gui_tjc_hmi_save_device_info_to_w25q(); /*重新分类区域*/ app_leakage_region_classify(); /*发送确认响应*/ } else { /*没有选中任何设备*/ return; } }break; default:return; } len = strlen((char *)hmi_tx_buffer); gui_tjc_hmi_data_send(hmi_tx_buffer,len); } } /*设置时间界面*/ static void gui_tjc_hmi_time_set_send(u8 cmd,u8 opa,u8 *p_data) { u16 i, len = 0; char temp_buf[5]; bsp_DS1302_Time_t new_time; if(HMI_PROTO_CMD_SET == cmd) /* 设置命令 */ { switch(opa) { case 0x01: /* 设置时间 */ { /* 检查数据长度 */ if(p_data[4] != 0xAA || /* 年后的分隔符 */ p_data[7] != 0xAA || /* 月后的分隔符 */ p_data[10] != 0xAA || /* 日后的分隔符 */ p_data[13] != 0xAA) /* 时后的分隔符 */ { return; } /* 解析年份 (4个字节ASCII码) */ memcpy(temp_buf, &p_data[0], 4); temp_buf[4] = '\0'; /* 添加结束符 */ new_time.Year = atoi(temp_buf)%2000; /* 解析月份 (2个字节ASCII码) */ memcpy(temp_buf, &p_data[5], 2); temp_buf[2] = '\0'; /* 添加结束符 */ new_time.Month = atoi(temp_buf); /* 解析日期 (2个字节ASCII码) */ memcpy(temp_buf, &p_data[8], 2); temp_buf[2] = '\0'; /* 添加结束符 */ new_time.Day = atoi(temp_buf); /* 解析小时 (2个字节ASCII码) */ memcpy(temp_buf, &p_data[11], 2); temp_buf[2] = '\0'; /* 添加结束符 */ new_time.Hour = atoi(temp_buf); /* 解析分钟 (2个字节ASCII码) */ memcpy(temp_buf, &p_data[14], 2); temp_buf[2] = '\0'; /* 添加结束符 */ new_time.Minute = atoi(temp_buf); DS1302.Set(&new_time); } break; default: break; } } } /*屏幕指令解析*/ static void gui_tjc_hmi_communication_data_analysis(u8 *p_data, u16 len, void *rx_uart) { u8 cmd,data,gui_id,opa,*p_offset_data; u16 i,modbus_crc16,check_crc16; /*长度不足*/ if(len < 5) { return ; } /*检测帧头*/ if(p_data[0] != HMI_PROTO_FRAME_HEADER1 || p_data[1] != HMI_PROTO_FRAME_HEADER2) { return ; } /*校验位*/ check_crc16 = p_data[len-2] << 8 | p_data[len-1]; modbus_crc16 = modbus_lib_crc16(p_data,len-2); modbus_crc16 = (modbus_crc16 >> 8) | (modbus_crc16 << 8); if(modbus_crc16 != check_crc16) { return ; } /*CMD*/ cmd = p_data[2]; if(cmd != HMI_PROTO_CMD_GET && cmd != HMI_PROTO_CMD_SET) { return ; } gui_id = p_data[3]; /*gui_id*/ opa = p_data[4]; /*操作码*/ p_offset_data = &p_data[5]; /*附带数据*/ p_rx_uart = (bsp_uart_t *)rx_uart; /*串口指针*/ switch(gui_id) { case HMI_PROTO_GUI_MAIN : { gui_tjc_hmi_main_send(cmd,opa,p_offset_data); }break; case HMI_PROTO_GUI_CURR_ALARM : { gui_tjc_hmi_curr_alarm_send(cmd,opa,p_offset_data); }break; case HMI_PROTO_GUI_DETAIL_MAIN : { gui_tjc_hmi_detail_main_send(cmd,opa,p_offset_data); }break; case HMI_PROTO_GUI_LOGIN : { gui_tjc_hmi_login_send(cmd,opa,p_offset_data); }break; case HMI_PROTO_GUI_HISTORY_ALARM : { gui_tjc_hmi_history_alarm_send(cmd,opa,p_offset_data); }break; case HMI_PROTO_GUI_TCP_CONFIG : { gui_tjc_hmi_tcp_config_send(cmd,opa,p_offset_data); }break; case HMI_PROTO_GUI_DEVICE_CONFIG : { gui_tjc_hmi_device_config_send(cmd,opa,p_offset_data); }break; case HMI_PROTO_GUI_HELP : { //gui_tjc_hmi_help_send(cmd,opa,p_offset_data); }break; case HMI_PROTO_GUI_TIME : { gui_tjc_hmi_time_set_send(cmd,opa,p_offset_data); } } }