diff --git a/data/msg/uPower_fcsState_st.json b/data/msg/uPower_fcsState_st.json index d23d9f2..cb8b10a 100644 --- a/data/msg/uPower_fcsState_st.json +++ b/data/msg/uPower_fcsState_st.json @@ -1,30 +1,30 @@ { "backpressure1_fp32": -1.6155215737897056e+25, "backpressure2_fp32": 1.9618178500547439e-44, - "ch4oConcent1_fp32": 3.7196912217041245e-12, - "ch4oConcent2_fp32": 1.1664828806579075e-38, - "ch4o_fp32": 1.1754855226419623e-38, - "excTemp_fp32": 1.1664828806579075e-38, - "faultCode1_uint16": 29888, - "faultCode2_uint16": 49624, + "ch4oConcent1_fp32": 1687.0, + "ch4oConcent2_fp32": 1.1726195870227251e-38, + "ch4o_fp32": 1.1753983618774813e-38, + "excTemp_fp32": 1.1726195870227251e-38, + "faultCode1_uint16": 38848, + "faultCode2_uint16": 21499, "faultCode3_uint16": 0, - "fcuCurIns_fp32": -1775767650304.0, - "fcuCurPower_fp32": 7.894814654516588e-39, + "fcuCurIns_fp32": 2.1062722967662487e+22, + "fcuCurPower_fp32": 7.9041248815135621e-39, "fcuCur_fp32": 1.7755460477889746e-38, - "fcuFaultLeve_uint8": 194, + "fcuFaultLeve_uint8": 226, "fcuOutIns_fp32": 0.0, "fcuOutPower_fp32": 2.152394441202919e-42, "fcuState_uint8": 124, "fcuVolIns_fp32": 0.0, - "fcuVolPower_fp32": 1.1664542941692352e-38, - "fcuVol_fp32": 1.1754855226419623e-38, + "fcuVolPower_fp32": 1.1725886183266636e-38, + "fcuVol_fp32": 1.1753983618774813e-38, "flameDet_uint8": 0, - "h2Concent1_fp32": 3.8200553831302386e-12, - "h2Concent2_fp32": 1.1664828806579075e-38, - "o2Concent1_fp32": 4.5144443738820428e-14, - "o2Concent2_fp32": 1.1664828806579075e-38, - "o2Level_fp32": 1.1664542941692352e-38, - "o2_fp32": -1075184933011456.0, - "powLimit_fp32": 1.166482740528061e-38, - "powerGen_fp32": -1075322371964928.0 + "h2Concent1_fp32": 1715.25, + "h2Concent2_fp32": 1.1726195870227251e-38, + "o2Concent1_fp32": 19.4140625, + "o2Concent2_fp32": 1.1726195870227251e-38, + "o2Level_fp32": 1.1725886183266636e-38, + "o2_fp32": -1.5729414295823943e+36, + "powLimit_fp32": 1.1726194468928787e-38, + "powerGen_fp32": -1.5732659481360528e+36 } \ No newline at end of file diff --git a/data/msg/uPower_liBatState_st.json b/data/msg/uPower_liBatState_st.json index 1f59671..031c1ab 100644 --- a/data/msg/uPower_liBatState_st.json +++ b/data/msg/uPower_liBatState_st.json @@ -6,16 +6,16 @@ "insBatSoc_uint8": 0, "insBatTotalElect_uint16": 2, "insChargeState_uint8": 71, - "insCurSocHold1_uint8": 41, - "insCurSocHold2_uint8": 204, - "insCurSocHold3_uint8": 4, + "insCurSocHold1_uint8": 65, + "insCurSocHold2_uint8": 221, + "insCurSocHold3_uint8": 175, "insCurrent_uint16": 0, - "insLinkVol_uint16": 52163, + "insLinkVol_uint16": 56547, "insNegRelayState_uint8": 0, - "insNegRes_uint16": 52265, - "insPackVol_uint16": 32516, + "insNegRes_uint16": 56641, + "insPackVol_uint16": 32687, "insPosRelayState_uint8": 0, - "insPosRes_uint16": 18488, + "insPosRes_uint16": 38968, "insfaultCode_uint8": 176, "powBatCurElect_uint16": 0, "powBatSoc_uint8": 0, @@ -27,12 +27,12 @@ "powCurToInsLimit1_uint8": 48, "powCurToinsLimit2_uint8": 0, "powCur_uint16": 15376, - "powLinkVol_uint16": 32516, + "powLinkVol_uint16": 32687, "powNegRelayState_uint8": 0, - "powNegRes_uint16": 32516, + "powNegRes_uint16": 32687, "powPosRelayState_uint8": 0, - "powPosRes_uint16": 52247, + "powPosRes_uint16": 56623, "powerBatLimit_uint16": 0, "powerPackVol_uint16": 0, - "powfaultCode_uint8": 68 + "powfaultCode_uint8": 148 } \ No newline at end of file diff --git a/src/pPowerManger/PowerManger.cpp b/src/pPowerManger/PowerManger.cpp index 9fcabfc..ff70386 100644 --- a/src/pPowerManger/PowerManger.cpp +++ b/src/pPowerManger/PowerManger.cpp @@ -104,8 +104,7 @@ bool PowerManger::Iterate() updateTime(); //2. 运行状态机 m_fsm.run(m_pmState,this); - cout <<"CURRENT STATE:" << m_pmState.name << " | CURRENT EVENT :" << m_pmEvent << endl; - + // cout <<"CURRENT STATE:" << m_pmState.name << " | CURRENT EVENT :" << m_pmEvent << endl; AppCastingMOOSApp::Iterate(); //3. 输出报告 buildPowerSysReport(); @@ -799,14 +798,20 @@ int PowerManger::handleInite_s1(FSM_State &fsm, void* pData) { cout << fsm.name << endl; PowerManger* pm = (PowerManger*)pData; - //1. 检查复合管控器连接 double StartTime = pm->GetAppStartTime(); while (!pm->m_connected) { + + disHighVolBusCmd a; + a.fuelCellCircuitBreaker = DIS_BREAKER_OFF; + a.propulsionMotorCircuitBreaker = DIS_BREAKER_OFF; + pm->m_udpComm.sendDisSysCmd(a); + + MOOSPause(1000); pm->updateTime(); double dft = abs(pm->m_current_time - StartTime); - if(dft > 1) + if(dft > 10) { pm->m_pmState = pm->m_Fault_s99; break; @@ -835,18 +840,19 @@ int PowerManger::handleInite_s1(FSM_State &fsm, void* pData) // 首先闭合应急电源开关 //TODO 检查并配置当前配电装置状态 disHighVolBusCmd a; - a.fuelCellCircuitBreaker = 0xAA; - a.propulsionMotorCircuitBreaker = 0xAA; + a.fuelCellCircuitBreaker = DIS_BREAKER_OFF; + a.propulsionMotorCircuitBreaker = DIS_BREAKER_OFF; pm->m_udpComm.sendDisSysCmd(a); MOOSPause(1000); - // pm->workCondition = ""; return 0; } int PowerManger::handleFault_s99(FSM_State &fsm, void* pData) { - cout << fsm.name << endl; + // cout << fsm.name << endl; + PowerManger* pm = (PowerManger*)pData; + pm->printState(fsm,"故障"); return 0; } diff --git a/src/pPowerManger/ccuUdpMsg.h b/src/pPowerManger/ccuUdpMsg.h index 20f7f47..46607ad 100644 --- a/src/pPowerManger/ccuUdpMsg.h +++ b/src/pPowerManger/ccuUdpMsg.h @@ -21,6 +21,10 @@ #define DIS_HVBUSB_CMD_ID 0x0003 #define DIS_LVBUS_CMD_ID 0x0004 +#define DIS_BREAKER_ON 0x55 +#define DIS_BREAKER_OFF 0xAA +#define DIS_FAULTOFF 0x5A + typedef unsigned int Checksum; typedef unsigned char cChecksum; diff --git a/test/model/untitled.slx b/test/model/untitled.slx new file mode 100644 index 0000000..6657b56 Binary files /dev/null and b/test/model/untitled.slx differ diff --git a/test/model/untitled.slx.original b/test/model/untitled.slx.original new file mode 100644 index 0000000..4a8ec29 Binary files /dev/null and b/test/model/untitled.slx.original differ diff --git a/test/scripts/TestGUI.py b/test/scripts/TestGUI.py new file mode 100644 index 0000000..b224d1b --- /dev/null +++ b/test/scripts/TestGUI.py @@ -0,0 +1,46 @@ +import socket +import struct +import tkinter as tk +import threading +from udpmsg import * +from datetime import datetime +from disSys import * +from logWin import * +from udpComm import * + + +# 创建UDP通信套接字 +sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +# 目标IP地址和端口号 +target_ip = 'localhost' +target_port = 5001 +server_address = (target_ip, target_port) +sock.bind(server_address) +# 要发送的消息 +# 创建主窗口 +root = tk.Tk() +root.title("能源管理系统调试") +# 创建消息显示窗口 +logFrame = tk.LabelFrame(root, text="消息显示") +logFrame.grid(row=1, columnspan=3 ,column=0, sticky='nsw') +logwin = logWin(logFrame) +logwin.grid(row=0, column=0, sticky='nesw') +# 创建配电窗口 +disSysFrame = tk.LabelFrame(root, text="配电系统") +disSysFrame.grid(row=0, column=0, sticky='ne') +disSysWin = disSys(disSysFrame) +disSysWin.grid(row=0, column=0, sticky='ne') + +# 创建并启动接收和发送消息的线程 +thread = threading.Thread(target=receive_messages, args=(sock, logwin, disSysWin)) +thread.daemon = True +thread.start() +thread2 = threading.Thread(target=send_messages, args=(sock, logwin, disSysWin)) +thread2.daemon = True +thread2.start() + + +# 运行主循环 +root.mainloop() +# 关闭套接字 +sock.close() \ No newline at end of file diff --git a/test/scripts/gui.py b/test/scripts/back/gui.py similarity index 100% rename from test/scripts/gui.py rename to test/scripts/back/gui.py diff --git a/test/scripts/guiEle.py b/test/scripts/back/guiEle.py similarity index 100% rename from test/scripts/guiEle.py rename to test/scripts/back/guiEle.py diff --git a/test/scripts/guiInput.py b/test/scripts/back/guiInput.py similarity index 100% rename from test/scripts/guiInput.py rename to test/scripts/back/guiInput.py diff --git a/test/scripts/test.py b/test/scripts/back/test.py similarity index 100% rename from test/scripts/test.py rename to test/scripts/back/test.py diff --git a/test/scripts/back/testGui.py b/test/scripts/back/testGui.py new file mode 100644 index 0000000..527f5a6 --- /dev/null +++ b/test/scripts/back/testGui.py @@ -0,0 +1,44 @@ +import socket +import struct +import tkinter as tk +import threading +from udpmsg import * +from datetime import datetime +from tkinter import font +from disSys import * +from guiEle import ElementDisplayApp +from until import * +from guiInput import InputGUI + +# 创建UDP套接字 +sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +server_address = ('localhost', 5001) +sock.bind(server_address) + +# 创建主窗口 +root = tk.Tk() +root.title("能源管理系统调试") + +disSysWin = disSys(root) +disSysWin.grid(row=0, column=0, sticky='ne') + + +# 创建一个文本框用于显示消息 +custom_font = font.Font(family="Arial", size=12, weight="normal") +text_box = tk.Text(root, height=10, width=50, font=custom_font) +text_box.grid(row=6, column=0, sticky='ne') + +# 创建并启动接收和发送消息的线程 +# thread = threading.Thread(target=receive_messages, args=(sock, text_box,eleplay)) +# thread.daemon = True +# thread.start() + +# thread2 = threading.Thread(target=send_messages, args=(sock, eleplay)) +# thread2.daemon = True +# thread2.start() + +# 运行主循环 +root.mainloop() + +# 关闭套接字 +sock.close() diff --git a/test/scripts/until.py b/test/scripts/back/until.py similarity index 100% rename from test/scripts/until.py rename to test/scripts/back/until.py diff --git a/test/scripts/ccuSys.py b/test/scripts/ccuSys.py new file mode 100644 index 0000000..ece51a8 --- /dev/null +++ b/test/scripts/ccuSys.py @@ -0,0 +1,20 @@ +import socket +import struct +import tkinter as tk +import threading +from udpmsg import * +from datetime import datetime +from tkinter import font +from guiEle import ElementDisplayApp +from until import * +from guiInput import InputGUI +from tkinter import Frame + + +class ccuSys(Frame): + def __init__(self,root): + super().__init__(root) + self.createWidgets() + + def createWidgets(self): + pass \ No newline at end of file diff --git a/test/scripts/disSys.py b/test/scripts/disSys.py new file mode 100644 index 0000000..f0ce0f6 --- /dev/null +++ b/test/scripts/disSys.py @@ -0,0 +1,502 @@ +import socket +import struct +import tkinter as tk +import threading +from udpmsg import * +from datetime import datetime +from tkinter import font +from tkinter import Frame +from tkinter.ttk import * + +class disSys(Frame): + def __init__(self,root): + super().__init__(root) + # 当前接受的消息,用于显示和更新 + self.disHVB = msg_disHighVolBusFbMsg() + self.disHVBA = msg_disHighAVolBusFbMsg() + self.disHVBB = msg_disHighBVolBusFbMsg() + self.disLVB = msg_disLowBusFbMsg() + # 初始化列框架列表 + self.col_frames = [] + + self.createWidgets() + self.root = root + self.root.after(2000, self.update_disp) + def createWidgets(self): + # 定义每组的颜色 + self.colors = ["#FFC0CB", "#ADD8E6", "#90EE90", "#FFD700"] + # 创建自定义字体 + self.custom_font = font.Font(family="Arial", size=12, weight='normal') + # 创建4个Frame来分组显示元素的值 + # 断路器的frame + title=list(['高压母线断路器','高电压A母线断路器','高电压B母线断路器','低电压母线断路器']) + self.frames = [] + for i in range(4): + frame = tk.Frame(self, bg=self.colors[i], padx=10, pady=10) + # frame.pack(padx=10, pady=10, expand=True, fill='both') + title_label = tk.Label(frame, text=title[i],bg=self.colors[i],relief='solid' ,font=("Arial", 16, "bold")) + title_label.grid(row=0, column=0, columnspan=4, pady=(2, 2), sticky="nsew") + self.frames.append(frame) + self.frames[0].grid(row=0, column=0, sticky='nsew') + self.frames[1].grid(row=0, column=1, sticky='nsew') + self.frames[2].grid(row=1, column=0, sticky='nsew') + self.frames[3].grid(row=1, column=1, sticky='nsew') +################################################故障选择######################################################### + inputFrame = tk.LabelFrame(self, bg='Azure',text='故障选择',font=self.custom_font ,padx=10, pady=10) + inputFrame.grid(row=0, column=2, columnspan=2, padx=2, pady=2, sticky="nsew") + # # 添加输入框来更新值 TODO:添加输入框,更新故障信息 + self.checkboxes = [] + self.checkboxesVar = [] + self.faultDict1 = {0:'动力母线绝缘低', + 1:'A汇流排绝缘低', + 2:'仪表电源失电', + 3:'应急电源失电', + 4:'DC/DC模块过温'} + self.faultDict2 = {0:'仪表电源失电', + 1:'应急电源失电', + 2:'浸水报警'} + self.faultDict3 = {0:'仪表电源失电', + 1:'应急电源失电', + 2:'仪表汇流排绝缘低'} + self.faultDict4 = {0:'仪表失电', + 1:'浸水报警'} + spl_linenum = 1 + for i, dictionary in enumerate([self.faultDict1, self.faultDict2, self.faultDict3, self.faultDict4]): + self.checkboxes.append([]) + self.checkboxesVar.append([]) + spl = Separator(inputFrame, orient='vertical') + spl.grid(row=0, column=spl_linenum+i*2, rowspan=5, pady=(2, 2), sticky="nsew") + for j, (key, value) in enumerate(dictionary.items()): + checkboxVar = tk.IntVar() + checkbox = tk.Checkbutton(inputFrame, text=value, variable=checkboxVar,font=self.custom_font,anchor="w", + command=lambda i=i, j=j: self.cheak_fault(i, j)) + checkbox.grid(row=j, column=i*2, padx=1, pady=1, sticky="nsew") + self.checkboxes[i].append(checkbox) + self.checkboxesVar[i].append(checkboxVar) +################################################电路状态######################################################### + dispFrame = tk.LabelFrame(self, bg='Azure',text='电路状态',font=self.custom_font ,padx=10, pady=10) + dispFrame.grid(row=1, column=2, columnspan=2, padx=2, pady=2, sticky="nsew") # 调整输入框的上下边距并居中显示 + value = '关闭' + self.labelDcDc = tk.Label(dispFrame, text=f"{'DC/DC模块'}:{value}", font=self.custom_font, relief='groove' ,anchor="w") + self.labelDcDc.grid(row=0, column=0, padx=1, pady=1, sticky="nsew") + self.DcDcbutton = tk.Button(dispFrame, text="TURN", command=self.toggle_DcDc) + self.DcDcbutton.grid(row=0, column=1, padx=1, pady=1, sticky="nsew") + + self.labelWaterInput = tk.Label(dispFrame, text=f"{'冷却水进水阀'}:{value}", font=self.custom_font, relief='groove' ,anchor="w") + self.labelWaterInput.grid(row=1, column=0, padx=1, pady=1, sticky="nsew") + self.buttonWaterInput = tk.Button(dispFrame, text="TURN", command=self.toggle_WaterInput) + self.buttonWaterInput.grid(row=1, column=1, padx=1, pady=1, sticky="nsew") + + self.labelWaterOutput = tk.Label(dispFrame, text=f"{'冷却水出水阀'}:{value}", font=self.custom_font, relief='groove' ,anchor="w") + self.labelWaterOutput.grid(row=2, column=0, padx=1, pady=1, sticky="nsew") + self.buttonWaterOutput = tk.Button(dispFrame, text="TURN", command=self.toggle_WaterOutput) + self.buttonWaterOutput.grid(row=2, column=1, padx=1, pady=1, sticky="nsew") + + self.buttonCurrenStateWin = tk.Button(dispFrame, text="显示电路状态", command=self.show_CurrentState) + self.buttonCurrenStateWin.grid(row=0, rowspan=3 , columnspan=2 , column=3,padx=10, pady=1, sticky="nsew") +################################################断路器操作######################################################### + # 定义四个字典来存储元素的值 + self.dict1={'燃料电池断路器':'闭合', + '动力锂电池断路器':'闭合', + '推进电机断路器':'闭合', + '仪表锂电池断路器':'闭合', + 'DC/DC5模块断路器':'闭合', + '艏部高压配电断路器':'闭合', + '艏部FT4/5断路器':'闭合', + '艉舵1/2断路器':'闭合', + '艉舵3/4断路器':'闭合', + 'FB预留断路器':'闭合', + 'TYZ预留断路器':'闭合', + '预留断路器':'闭合'} + self.dict2 = {'艏部FT1-3断路器':'闭合', + '启闭机构断路器':'闭合', + '桅杆舵机断路器':'闭合', + 'XCZ断路器':'闭合', + '艏舵断路器':'闭合', + '敞开电缸断路器':'闭合'} + self.dict3 = {'仪表锂电池断路器':'闭合', + '艏部低压断路器':'闭合', + 'UNIT4断路器':'闭合', + 'DC/DC1断路器':'闭合', + '预留断路器1':'闭合', + '预留断路器2':'闭合', + '艉部应急电池开关':'闭合'} + self.dict4 = {'UNIT1断路器':'闭合', + 'UNIT2断路器':'闭合', + 'UNIT3断路器':'闭合', + 'UNIT5断路器':'闭合', + '艏部抛载断路器':'闭合', + '预留断路器1':'闭合', + '预留断路器2':'断开', + '艏部应急电池开关':'闭合'} + self.labels = [] + for i, dictionary in enumerate([self.dict1, self.dict2, self.dict3, self.dict4]): + self.labels.append([]) + for j, (key, value) in enumerate(dictionary.items()): + # 根据元素的值选择颜色 + if value == "闭合": + color = "green" + else: + color = "red" + label = tk.Label(self.frames[i], text=f"{key}: {value}", fg=color, font=self.custom_font, relief='groove' ,anchor="w") + if (j%2==0): + label.grid(row=j//2 + 1, column=j%2, padx=1, pady=1,sticky="nsew") + else: + label.grid(row=j//2 + 1, column=j%2+1, padx=1, pady=1,sticky="nsew") + self.labels[i].append(label) + # 添加按钮来改变字典中的值 + button = tk.Button(self.frames[i], text="TURN", command=lambda i=i, j=j: self.toggle_value(i, j)) + if (j%2==0): + button.grid(row=j//2+1, column=j%2+1, padx=1, pady=1) + else: + button.grid(row=j//2+1, column=j%2+2, padx=1, pady=1, sticky="nsew") + self.update_disp() + + # 创建保存电流及电压信息的表格 + self.disHVBData = [] + self.disHVBAData = [] + self.disHVBBData = [] + self.disLVBData = [] + + def update_disp(self): + for i, dictionary in enumerate([self.dict1, self.dict2, self.dict3, self.dict4]): + for j, (key, value) in enumerate(dictionary.items()): + # 根据元素的值选择颜色 + if value == "闭合": + color = "green" + else: + color = "red" + self.labels[i][j].config(text=f"{key}: {value}", fg=color) + + + def toggle_value(self, i, j): + dictionary = [self.dict1, self.dict2, self.dict3, self.dict4][i] + key = list(dictionary.keys())[j] + if dictionary[key] == "闭合": + dictionary[key] = "断开" + else: + dictionary[key] = "闭合" + print(f'{key}操作') + self.update_disp() + + def toggle_DcDc(self): + if (self.labelDcDc.cget("text")[-1] == '开'): + self.labelDcDc.config(text=f"{'DC/DC模块'}:关闭") + else: + self.labelDcDc.config(text=f"{'DC/DC模块'}:打开") + print('DC/DC模块操作') + + def toggle_WaterInput(self): + if (self.labelWaterInput.cget("text")[-1] == '开'): + self.labelWaterInput.config(text=f"{'冷却水进水阀'}:关闭") + else: + self.labelWaterInput.config(text=f"{'冷却水进水阀'}:打开") + print('冷却水进水阀操作') + + def toggle_WaterOutput(self): + if (self.labelWaterOutput.cget("text")[-1] == '开'): + self.labelWaterOutput.config(text=f"{'冷却水出水阀'}:关闭") + else: + self.labelWaterOutput.config(text=f"{'冷却水出水阀'}:打开") + print('冷却水出水阀操作') + + def cheak_fault(self,i,j): + #TODO:实现故障更新和选择 + print(self.checkboxes[i][j].cget("text"),self.checkboxesVar[i][j].get()) + # print(self.checkboxesVar[i][j].get()) + + def update_currentState(self): + # 更新所有数值显示 + for struct, name, entry in self.state_entries: + entry.delete(0, tk.END) + entry.insert(0, str(getattr(struct, name))) + + print('电路状态已更新') + def _create_scrollable_column(self, parent_frame, title, data_struct, state_font): + """创建带滚动条的列""" + col_frame = tk.LabelFrame(parent_frame, text=title, font=state_font, + bd=2, relief=tk.GROOVE, padx=5, pady=5) + col_frame.grid(row=0, column=len(self.col_frames), padx=5, pady=5, sticky="nsew") + col_frame.rowconfigure(0, weight=1) + col_frame.columnconfigure(0, weight=1) + self.col_frames.append(col_frame) + + # 创建滚动条容器 + canvas = tk.Canvas(col_frame) + v_scrollbar = tk.Scrollbar(col_frame, orient="vertical", command=canvas.yview) + h_scrollbar = tk.Scrollbar(col_frame, orient="horizontal", command=canvas.xview) + + # 创建可滚动内容框架 + scrollable_frame = tk.Frame(canvas) + canvas.create_window((0, 0), window=scrollable_frame, anchor="nw") + + # 配置滚动区域 + def _configure_scrollregion(e): + canvas.configure(scrollregion=canvas.bbox("all")) + canvas.config(height=min(e.height, 600)) + canvas.yview_moveto(0) + canvas.xview_moveto(0) + + scrollable_frame.bind("", _configure_scrollregion) + + # 配置滚动条 + canvas.configure(yscrollcommand=v_scrollbar.set, xscrollcommand=h_scrollbar.set) + h_scrollbar.config(command=canvas.xview) + v_scrollbar.config(command=canvas.yview) + + # 布局 + canvas.grid(row=0, column=0, sticky="nsew") + v_scrollbar.grid(row=0, column=1, sticky="ns") + h_scrollbar.grid(row=1, column=0, sticky="ew") + + # 添加数据项 + for name, value in data_struct.__dict__.items(): + row_frame = tk.Frame(scrollable_frame) + row_frame.pack(fill=tk.X, padx=5, pady=2) + + name_label = tk.Label(row_frame, text=name, font=state_font, width=30, anchor="w") + name_label.pack(side=tk.LEFT, padx=5) + + entry = tk.Entry(row_frame, font=state_font, width=20) + entry.pack(side=tk.RIGHT, padx=5, fill=tk.X, expand=True) + entry.insert(0, str(value)) + entry.config(state='readonly') + + self.state_entries.append((data_struct, name, entry)) + + def show_CurrentState(self): + """显示当前电路状态窗口""" + # 初始化窗口 + self.currentStateWin = tk.Toplevel(self) + self.currentStateWin.title("电路状态") + self.currentStateWin.geometry("1400x800") + self.currentStateWin.minsize(1000, 600) + self.currentStateWin.protocol("WM_DELETE_WINDOW", self.on_close_currentState) + + # 创建主容器 + main_frame = tk.Frame(self.currentStateWin) + main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) + + # 配置网格布局 + for i in range(4): + main_frame.columnconfigure(i, weight=1) + + # 创建自定义字体 + state_font = font.Font(family="Arial", size=10, weight='bold') + + # 初始化状态条目列表 + self.state_entries = [] + self.col_frames = [] + + # 创建各状态列 + self._create_scrollable_column(main_frame, "高压母线", self.disHVB, state_font) + self._create_scrollable_column(main_frame, "高电压A母线", self.disHVBA, state_font) + self._create_scrollable_column(main_frame, "高电压B母线", self.disHVBB, state_font) + self._create_scrollable_column(main_frame, "低电压母线", self.disLVB, state_font) + + # 配置主框架布局权重 + main_frame.rowconfigure(1, weight=1) + + # 添加底部按钮容器 + btn_frame = tk.Frame(main_frame) + btn_frame.grid(row=2, column=0, columnspan=4, pady=10, sticky="sew") + + # 添加更新按钮 + update_btn = tk.Button(btn_frame, text="立即更新", font=state_font, + command=self.update_currentState) + update_btn.pack(fill=tk.X, padx=5, pady=5) + # update_btn.pack(side=tk.LEFT, padx=5) + + # 启动定时更新 + self.update_interval = 1000 # 5秒 + self.schedule_update() + + def on_close_currentState(self): + """窗口关闭回调""" + if hasattr(self, 'update_job'): + self.currentStateWin.after_cancel(self.update_job) + self.currentStateWin.destroy() + + def schedule_update(self): + """安排定时更新""" + self.update_currentState() + self.update_job = self.currentStateWin.after(self.update_interval, self.schedule_update) + def updata_data(self): + if (self.dict1['燃料电池断路器']=='闭合'): + self.disHVB.DCB1 = 0x55 + else: + self.disHVB.DCB1 = 0xAA + + if (self.dict1['动力锂电池断路器']=='闭合'): + self.disHVB.DCB2 = 0x55 + else: + self.disHVB.DCB2 = 0xAA + + if (self.dict1['推进电机断路器']=='闭合'): + self.disHVB.ZK1 = 0x55 + else: + self.disHVB.ZK1 = 0xAA + + if (self.dict1['仪表锂电池断路器']=='闭合'): + self.disHVB.ZK2 = 0x55 + else: + self.disHVB.ZK2 = 0xAA + + if (self.dict1['DC/DC5模块断路器']=='闭合'): + self.disHVB.ZK3 = 0x55 + else: + self.disHVB.ZK3 = 0xAA + + if (self.dict1['艏部高压配电断路器']=='闭合'): + self.disHVB.ZK4 = 0x55 + else: + self.disHVB.ZK4 = 0xAA + + if (self.dict1['艏部FT4/5断路器']=='闭合'): + self.disHVB.ZK5 = 0x55 + else: + self.disHVB.ZK5 = 0xAA + + if (self.dict1['艉舵1/2断路器']=='闭合'): + self.disHVB.ZK6 = 0x55 + else: + self.disHVB.ZK6 = 0xAA + + if (self.dict1['艉舵3/4断路器']=='闭合'): + self.disHVB.ZK7 = 0x55 + else: + self.disHVB.ZK7 = 0xAA + + if (self.dict1['FB预留断路器']=='闭合'): + self.disHVB.ZK8 = 0x55 + else: + self.disHVB.ZK8 = 0xAA + + if (self.dict1['TYZ预留断路器']=='闭合'): + self.disHVB.ZK9 = 0x55 + else: + self.disHVB.ZK9 = 0xAA + + if (self.dict1['预留断路器']=='闭合'): + self.disHVB.ZK10 = 0x55 + else: + self.disHVB.ZK10 = 0xAA + ###################################################### + if (self.dict2['艏部FT1-3断路器']=='闭合'): + self.disHVBA.bowFTDevice123CircuitBreaker = 0x55 + else: + self.disHVBA.bowFTDevice123CircuitBreaker = 0xAA + + if (self.dict2['启闭机构断路器']=='闭合'): + self.disHVBA.actuatorCircuitBreaker = 0x55 + else: + self.disHVBA.actuatorCircuitBreaker = 0xAA + + if (self.dict2['桅杆舵机断路器']=='闭合'): + self.disHVBA.mastSteeringGearControlBoxCircuitBreaker = 0x55 + else: + self.disHVBA.mastSteeringGearControlBoxCircuitBreaker = 0xAA + + if (self.dict2['XCZ断路器']=='闭合'): + self.disHVBA.xczCircuitBreaker = 0x55 + else: + self.disHVBA.xczCircuitBreaker = 0xAA + + if (self.dict2['艏舵断路器']=='闭合'): + self.disHVBA.bowRudderControlBoxCircuitBreaker = 0x55 + else: + self.disHVBA.bowRudderControlBoxCircuitBreaker = 0xAA + + if (self.dict2['敞开电缸断路器']=='闭合'): + self.disHVBA.openWaterCoverStartCylinderCircuitBreaker = 0x55 + else: + self.disHVBA.openWaterCoverStartCylinderCircuitBreaker = 0xAA + + #################################################################### + if (self.dict3['仪表锂电池断路器']=='闭合'): + self.disHVBB.lithiumBatteryGroupInstrumentCircuitBreaker = 0x55 + else: + self.disHVBB.lithiumBatteryGroupInstrumentCircuitBreaker = 0xAA + + if (self.dict3['艏部低压断路器']=='闭合'): + self.disHVBB.bowLowVoltageDistributionCircuitBreaker = 0x55 + else: + self.disHVBB.bowLowVoltageDistributionCircuitBreaker = 0xAA + + if (self.dict3['UNIT4断路器']=='闭合'): + self.disHVBB.unit4CircuitBreaker = 0x55 + else: + self.disHVBB.unit4CircuitBreaker = 0xAA + + if (self.dict3['DC/DC1断路器']=='闭合'): + self.disHVBB.dcdc1CircuitBreaker = 0x55 + else: + self.disHVBB.dcdc1CircuitBreaker = 0xAA + + if (self.dict3['预留断路器1']=='闭合'): + self.disHVBB.reservedCircuitBreaker1 = 0x55 + else: + self.disHVBB.reservedCircuitBreaker1 = 0xAA + + if (self.dict3['预留断路器2']=='闭合'): + self.disHVBB.reservedCircuitBreaker2 = 0x55 + else: + self.disHVBB.reservedCircuitBreaker2 = 0xAA + + if (self.dict3['艉部应急电池开关']=='闭合'): + self.disHVBB.emergencyLithiumBatteryGroup2CircuitBreaker = 0x55 + else: + self.disHVBB.emergencyLithiumBatteryGroup2CircuitBreaker = 0xAA + + ###################################################################### + if (self.dict4['UNIT1断路器']=='闭合'): + self.disLVB.unit1CircuitBreaker = 0x55 + else: + self.disLVB.unit1CircuitBreaker = 0xAA + + if (self.dict4['UNIT2断路器']=='闭合'): + self.disLVB.unit2CircuitBreaker = 0x55 + else: + self.disLVB.unit2CircuitBreaker = 0xAA + + if (self.dict4['UNIT3断路器']=='闭合'): + self.disLVB.unit3CircuitBreaker = 0x55 + else: + self.disLVB.unit3CircuitBreaker = 0xAA + + if (self.dict4['UNIT5断路器']=='闭合'): + self.disLVB.unit5CircuitBreaker = 0x55 + else: + self.disLVB.unit5CircuitBreaker = 0xAA + + if (self.dict4['预留断路器1']=='闭合'): + self.disLVB.reservedCircuitBreaker1 = 0x55 + else: + self.disLVB.reservedCircuitBreaker1 = 0xAA + + if (self.dict4['预留断路器2']=='闭合'): + self.disLVB.reservedCircuitBreaker2 = 0x55 + else: + self.disLVB.reservedCircuitBreaker2 = 0xAA + + if (self.dict4['艏部抛载断路器']=='闭合'): + self.disLVB.bowPZDeviceCircuitBreaker = 0x55 + else: + self.disLVB.bowPZDeviceCircuitBreaker = 0xAA + + if (self.dict4['艏部应急电池开关']=='闭合'): + self.disLVB.emergencyLithiumBatteryGroup1CircuitBreaker = 0x55 + else: + self.disLVB.emergencyLithiumBatteryGroup1CircuitBreaker = 0xAA + + a = self.disHVB.pack() + b = self.disHVBA.pack() + c = self.disHVBB.pack() + d = self.disLVB.pack() + return a,b,c,d + +if __name__ == "__main__": + root = tk.Tk() + app = disSys(root) + app.pack() + root.mainloop() diff --git a/test/scripts/logWin.py b/test/scripts/logWin.py new file mode 100644 index 0000000..122ac58 --- /dev/null +++ b/test/scripts/logWin.py @@ -0,0 +1,78 @@ +import socket +import struct +import tkinter as tk +import threading +from udpmsg import * +from datetime import datetime +from tkinter import font, filedialog +from tkinter import Frame +from tkinter.ttk import * + +class logWin(Frame): + def __init__(self, root): + super().__init__(root) + self.root = root + custom_font = font.Font(family="Arial", size=12, weight="normal") + + # 设置 state 为 tk.DISABLED 禁用编辑功能 + self.text_box = tk.Text(root, height=10, width=50, font=custom_font, state=tk.DISABLED) + self.text_box.grid(row=0, column=0, columnspan=2, sticky='nsew') + + # 创建垂直滚动条 + scrollbar = tk.Scrollbar(root, command=self.text_box.yview) + scrollbar.grid(row=0, column=2, sticky='ns') + + # 将滚动条与 Text 组件关联 + self.text_box.config(yscrollcommand=scrollbar.set) + + # 创建保存按钮 + save_button = tk.Button(root, text="保存日志", command=self.save_log) + save_button.grid(row=1, column=0, sticky='ew') + + # 创建清空按钮 + clear_button = tk.Button(root, text="清空日志", command=self.clear_log) + clear_button.grid(row=1, column=1, sticky='ew') + + # 配置行和列的权重,使组件能够随窗口大小变化而调整 + root.grid_rowconfigure(0, weight=1) + root.grid_columnconfigure(0, weight=1) + root.grid_columnconfigure(1, weight=1) + + def display_log(self, log_message): + # 启用编辑功能 + self.text_box.config(state=tk.NORMAL) + # 将日志信息添加到 Text 组件中 + self.text_box.insert(tk.END, log_message + "\n") + # 滚动到 Text 组件的底部,以显示最新的日志信息 + self.text_box.see(tk.END) + # 禁用编辑功能 + self.text_box.config(state=tk.DISABLED) + + def save_log(self): + # 打开文件选择对话框 + file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")]) + if file_path: + # 获取文本框中的内容 + log_content = self.text_box.get("1.0", tk.END) + # 将内容写入文件 + with open(file_path, "w") as file: + file.write(log_content) + # 显示保存成功的提示 + tk.messagebox.showinfo("保存成功", "日志已成功保存到文件。") + + def clear_log(self): + # 启用编辑功能 + self.text_box.config(state=tk.NORMAL) + # 清空 Text 组件中的内容 + self.text_box.delete("1.0", tk.END) + # 禁用编辑功能 + self.text_box.config(state=tk.DISABLED) + +if __name__ == "__main__": + root = tk.Tk() + root.title("能源管理系统调试") + log_win = logWin(root) + # 假设您有一个日志消息需要显示 + for i in range(100): + log_win.display_log("这是一条日志信息" + str(i)) + root.mainloop() \ No newline at end of file diff --git a/test/scripts/udpComm.py b/test/scripts/udpComm.py new file mode 100644 index 0000000..fdf1463 --- /dev/null +++ b/test/scripts/udpComm.py @@ -0,0 +1,106 @@ +import socket +import struct +import tkinter as tk +import threading +from udpmsg import * +from datetime import datetime +from tkinter import font +import threading +from disSys import * +from logWin import * + +target_ip = '127.0.0.1' +target_port = 5000 + +def receive_messages(sock, logwin:logWin, disSysWin:disSys): + while True: + current_time = datetime.now() + formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S") + data, address = sock.recvfrom(4096) + headBuf = data[:6] + header = struct.unpack('接收到来自 {address} | 高压母线配电指令:\n") + logWin.display_log(logwin,f"{formatted_time}->接收到来自 {address} | 高压母线配电指令:") + if(msg.fuelCellCircuitBreaker==0x55): + disSysWin.dict1['燃料电池断路器']='闭合' + elif(msg.fuelCellCircuitBreaker==0xAA): + disSysWin.dict1['燃料电池断路器']='断开' + + if(msg.powerLithiumBatteryCircuitBreaker==0x55): + disSysWin.dict1['动力锂电池断路器']='闭合' + elif(msg.powerLithiumBatteryCircuitBreaker==0xAA): + disSysWin.dict1['动力锂电池断路器']='断开' + + if(msg.propulsionMotorCircuitBreaker==0x55): + disSysWin.dict1['推进电机断路器']='闭合' + elif(msg.propulsionMotorCircuitBreaker==0xAA): + disSysWin.dict1['推进电机断路器']='断开' + + if(msg.lithiumBatteryGroupInstrumentCircuitBreaker==0x55): + disSysWin.dict1['仪表锂电池断路器']='闭合' + elif(msg.lithiumBatteryGroupInstrumentCircuitBreaker==0xAA): + disSysWin.dict1['仪表锂电池断路器']='断开' + + if(msg.dcDc5ModuleCircuitBreaker==0x55): + disSysWin.dict1['DC/DC5模块断路器']='闭合' + elif(msg.dcDc5ModuleCircuitBreaker==0xAA): + disSysWin.dict1['DC/DC5模块断路器']='断开' + + if(msg.bowHighVoltageDistributionBoxCircuitBreaker==0x55): + disSysWin.dict1['艏部高压配电断路器']='闭合' + elif(msg.bowHighVoltageDistributionBoxCircuitBreaker==0xAA): + disSysWin.dict1['艏部高压配电断路器']='断开' + + if(msg.sternFTDevice45CircuitBreaker==0x55): + disSysWin.dict1['艏部FT4/5断路器']='闭合' + elif(msg.sternFTDevice45CircuitBreaker==0xAA): + disSysWin.dict1['艏部FT4/5断路器']='断开' + + if(msg.sternRudderSwitch1CircuitBreaker==0x55): + disSysWin.dict1['艉舵1/2断路器']='闭合' + elif(msg.sternRudderSwitch1CircuitBreaker==0xAA): + disSysWin.dict1['艉舵1/2断路器']='断开' + + if(msg.sternRudderSwitch2CircuitBreaker==0x55): + disSysWin.dict1['艉舵3/4断路器']='闭合' + elif(msg.sternRudderSwitch2CircuitBreaker==0xAA): + disSysWin.dict1['艉舵3/4断路器']='断开' + + if(msg.fbReservedCircuitBreaker==0x55): + disSysWin.dict1['FB预留断路器']='闭合' + elif(msg.fbReservedCircuitBreaker==0xAA): + disSysWin.dict1['FB预留断路器']='断开' + + if(msg.tyzReservedCircuitBreaker==0x55): + disSysWin.dict1['TYZ预留断路器']='闭合' + elif(msg.tyzReservedCircuitBreaker==0xAA): + disSysWin.dict1['TYZ预留断路器']='断开' + + if(msg.reservedCircuitBreaker==0x55): + disSysWin.dict1['预留断路器']='闭合' + elif(msg.reservedCircuitBreaker==0xAA): + disSysWin.dict1['预留断路器']='断开' + disSysWin.update_disp() + + +def send_messages(sock, logwin:logWin, disSysWin:disSys): + while True: + # 配电消息反馈 + a,b,c,d = disSysWin.updata_data() + sock.sendto(a, (target_ip, target_port)) + sock.sendto(b, (target_ip, target_port)) + sock.sendto(c, (target_ip, target_port)) + sock.sendto(d, (target_ip, target_port)) + + #TODO复合管控消息反馈 + + + threading.Event().wait(1) # 每隔1秒发送一次消息