#include "GUI_tjc_hmi.h" #include #include #include #include #include "proto_modbus_lib.h" #include "bsp_Flash.h" // 添加Flash操作 #include "bsp_uart.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_ASCII_RX_DELINITER (0xAA)/*接收分隔符*/ #define HMI_PROTO_ASCII_TX_DELINITER (0xFF)/*发送分隔符*/ #define HMI_PROTO_ASCII_TX_DELINITER_NUM (3)/*发送分隔符数量*/ static void gui_tjc_hmi_init(void); static void gui_tjc_hmi_communication_data_analysis(u8 *p_data, u16 len, void *rx_uart); /*串口发送缓冲区*/ 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; } /*发送接口*/ 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); } } /*设置对应的控件 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++; } 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],"%s",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; u8 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],"%s",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; u8 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; } /* 计算全局区域索引: 全局索引 = 主界面页码 * 4 + 相对索引 - 1 */ region_idx = p_tjc_hmi->page.main_index * 4 + (relative_region_idx - 1); /* 检查区域索引是否有效 */ if (region_idx >= leakage.region_num) { /* 区域索引越界,尝试显示第一个区域 */ region_idx = 0; } /* 判断是否切换了区域 */ 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; } /* 发送数据到HMI屏幕 */ if (len > 0) { 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中存储的密码,只存储密码*/ { }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中*/ { }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) { u16 len = 0,i; if(HMI_PROTO_CMD_GET == cmd)/*获取数据*/ { switch(opa) { case 0x01:/*读取历史报警信息,历史报警信息应该存储在flash中,显示区域名,设备ID,设备名称,报警类型,开始时间(年月日时分),结束时间*/ { }break; case 0x03:/*翻页功能,每页15条历史报警数据*/ { }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; 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; if(HMI_PROTO_CMD_GET == cmd)/*获取数据*/ { switch(opa) { case 0x01:/*读取网络配置信息,p_data[0]=0x01为读取设置的网络配置,02为读取默认的,网络IP,子网掩码,网关,DNS服务器*/ { }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*/ { }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) { u16 len = 0,i; if(HMI_PROTO_CMD_GET == cmd)/*获取数据*/ { switch(opa) { case 0x01:/*读取已存在的设备,显示区域,端口,设备ID,设备名,*/ { }break; case 0x03:/*翻页功能,每页显示8个设备*/ { }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中*/ { }break; case 0x02:/*删除设备,将设备信息从flash中删除*/ { }break; default:return; } len = strlen((char *)hmi_tx_buffer); gui_tjc_hmi_data_send(hmi_tx_buffer,len); } } /*屏幕指令解析*/ 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_main_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; } }