using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Linq; using System.Windows.Forms; using DevExpress.XtraEditors; using LFP_Manager.Forms; using LFP_Manager.Controls; using LFP_Manager.DataStructure; using LFP_Manager.Function; using LFP_Manager.Threads; using LFP_Manager.Utils; using DevExpress.Utils.Drawing.Helpers; using System.Threading.Tasks; using static LFP_Manager.Threads.csDbThread; namespace LFP_Manager.Forms { public partial class fmxMain : DevExpress.XtraEditors.XtraForm { #region VARIABLES // Child form private fmxInventoryConfig InventoryConfig = null; private fmxModuleDetail ModuleDetailForm = null; private fmxFwUpdate FwUpdateForm = null; private fmxHistory HistoryForm = null; // Static Variables private CommConfig Config = new CommConfig(); private CsDeviceData DeviceData = new CsDeviceData(); // Thread Variables private csUartThread uartThread = null; private CsUartThreadSB rs485Thread = null; private CsSnmpThread snmpThread = null; private csDbThread dbThread = null; private ucMainStatus MainStatus = null; private ucShelfStatus ShelfStatus = null; private int ModuleID = 1; bool Active = false; #endregion #region CONSTRUCTORS public fmxMain() { InitializeComponent(); IniLoad(ref Config); uTarget.OnConfig += ConfigButtonClick; uTarget.OnStart += StartButtonClick; uDataLog.OnUpdate += LogStatusUpdate; DisplaySystemFwVerModule(); } private void IniLoad(ref CommConfig aConfig) { csIniControlFunction.IniLoad(Application.ExecutablePath, ref aConfig); uTarget.UpdateConfig(ref aConfig); TypeChangedUpdate(ref aConfig); } #endregion #region BUTTON EVENT private void ConfigButtonClick(object sender, EventArgs e) { foreach (Form frm in Application.OpenForms) { if (frm.Name == "fmxCommConfig") { frm.Activate(); return; } } fmxCommConfig CommConfigForm = new fmxCommConfig { Owner = this }; CommConfigForm.OnUpdate += UpdateConfig; CommConfigForm.Show(); } private void StartButtonClick(object sender, EventArgs e) { if (Active) { DeviceData.Reset(); switch (Config.CommType) { case csConstData.CommType.COMM_UART: if (uartThread != null) { StopUart(); // 내부에서 UnwireUart → Dispose 순서 수행 edModuleID.Enabled = true; chbPolling.Enabled = true; } break; case csConstData.CommType.COMM_RS485: // DELTA Protocol if (rs485Thread != null) { StopRS485(); // 내부에서 UnwireRs485 → Dispose 순서 수행 edModuleID.Enabled = true; chbPolling.Enabled = true; } break; case csConstData.CommType.COMM_SNMP: break; default: break; } if (snmpThread != null) { snmpThread.disposeThread(); snmpThread = null; UpdateSnmpData(this, ref DeviceData.ModuleData[0]); } if (dbThread != null) { //dbThread.Stop(); dbThread.OnUpdateAlarmHistory -= UpdateAlarmHistory; dbThread.OnPrint -= ErrorOnPrint; dbThread.Dispose(); dbThread = null; } Active = false; } else { try { ModuleID = Convert.ToInt16(edModuleID.Text); } catch (Exception) { MessageBox.Show("Wrong Module ID - Please check module ID", "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } switch (Config.CommType) { case csConstData.CommType.COMM_UART: // UART MODE - RS-232 CommUARTStart(); break; case csConstData.CommType.COMM_RS485: // UART MODE - RS-485 CommRS485Start(); break; case csConstData.CommType.COMM_SNMP: StartProcessSNMP(); break; } } uTarget.UpdateStatus(Active); uDataLog.UpdateActiveStatus(Active, Config, ref DeviceData); uEventLog.UpdateConfig(Config); DisplayCommStatus(); } private void UartRecvData(byte[] data) { if (this.InvokeRequired) { this.Invoke(new MethodInvoker(delegate () { FwUpdateForm?.RecvData(data); HistoryForm?.RecvUardData(data); })); } else { FwUpdateForm?.RecvData(data); HistoryForm?.RecvUardData(data); } } private void CommUARTStart() { try { int mId = string.IsNullOrEmpty(edModuleID.Text) ? 0 : Convert.ToInt32(edModuleID.Text); if (mId == 0) { throw new Exception("System ID is zero."); } // 혹시 기존 인스턴스가 남아 있다면 먼저 해제 StopUart(); if (dbThread != null) { dbThread.OnUpdateAlarmHistory -= UpdateAlarmHistory; dbThread.OnPrint -= ErrorOnPrint; dbThread.Dispose(); dbThread = null; } uartThread = new csUartThread(mId, Config, this, DeviceData.ModuleData[0]); WireUart(uartThread); // ← 구독은 Start 전에 uartThread.SetPolling(chbPolling.Checked, mId, ref DeviceData.ModuleData[0]); if (uartThread.Start(ref Config, mId, chbPolling.Checked)) { Active = true; chbPolling.Enabled = true; edModuleID.Enabled = !chbPolling.Checked; ShelfStatus?.UpdateSystemId(mId); dbThread = new csDbThread(Config, this, DeviceData); dbThread.OnUpdateAlarmHistory += UpdateAlarmHistory; dbThread.OnPrint += ErrorOnPrint; dbThread.Start(Config); } else { StopUart(); if (dbThread != null) { dbThread.OnUpdateAlarmHistory -= UpdateAlarmHistory; dbThread.OnPrint -= ErrorOnPrint; dbThread.Dispose(); dbThread = null; } } } catch (Exception ex) { // 예외 시에도 반드시 해제 + Dispose StopUart(); dbThread?.Dispose(); dbThread = null; MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void StopUart() { if (uartThread != null) { UnwireUart(); // 1) 구독 해제 uartThread.Dispose(); // 2) 스레드/포트 정리(Stop 포함) uartThread = null; } } private void CommRS485Start() { try { int mId = string.IsNullOrEmpty(edModuleID.Text) ? 0 : Convert.ToInt32(edModuleID.Text); if (mId == 0) { throw new Exception("System ID is zero."); } StopRS485(); rs485Thread = new CsUartThreadSB(mId, Config, this, DeviceData.ModuleData); WireRs485(rs485Thread); // ← 구독 rs485Thread.SetPolling(chbPolling.Checked, mId, ref DeviceData.ModuleData); if (rs485Thread.Start(ref Config, ModuleID, chbPolling.Checked)) { Active = true; chbPolling.Enabled = true; edModuleID.Enabled = !chbPolling.Checked; //if (Config.ModuleQty > 1) // MainStatus?.Start(Config, DeviceData); //else // ShelfStatus?.UpdateSystemId(ModuleID); dbThread = new csDbThread(Config, this, DeviceData); dbThread.OnUpdateAlarmHistory += UpdateAlarmHistory; dbThread.OnPrint += ErrorOnPrint; dbThread.Start(Config); } else { StopRS485(); if (dbThread != null) { dbThread.OnUpdateAlarmHistory -= UpdateAlarmHistory; dbThread.OnPrint -= ErrorOnPrint; dbThread.Dispose(); dbThread = null; } } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); if (rs485Thread != null) { rs485Thread.Dispose(); rs485Thread = null; } if (dbThread != null) { dbThread.Dispose(); dbThread = null; } } } private void StopRS485() { if (rs485Thread != null) { UnwireRs485(); // 1) 구독 해제 rs485Thread.Dispose(); // 2) 스레드/포트 정리(Stop 포함) rs485Thread = null; } } private void StartProcessSNMP() { try { snmpThread = new CsSnmpThread(Config, ref DeviceData.ModuleData[ModuleID - 1]); snmpThread.OnUpdate += UpdateSnmpData; snmpThread.OnSetResult += SnmpRecvData; snmpThread.Start(Config.SnmpIP, chbPolling.Checked); Active = true; dbThread = new csDbThread(Config, this, DeviceData); dbThread.OnUpdateAlarmHistory += UpdateAlarmHistory; dbThread.OnPrint += ErrorOnPrint; dbThread.Start(Config); } catch (Exception) { if (snmpThread == null) { snmpThread.disposeThread(); snmpThread = null; } if (dbThread != null) { dbThread.OnUpdateAlarmHistory -= UpdateAlarmHistory; dbThread.OnPrint -= ErrorOnPrint; dbThread.Dispose(); dbThread = null; } } } #endregion #region UPDATE FUNCTIONS private void TypeChangeUpdateUart(ref CommConfig aConfig) { tabStatus.TabPages[0].PageVisible = true; for (int i = 1; i < tabStatus.TabPages.Count; i++) { tabStatus.TabPages[i].PageVisible = false; } tabStatus.TabPages[0].Text = String.Format("LFP Module [{0}.{1}.{2}.{3}]" , 0 , 0 , 0 , 0 ); ShelfStatus = new ucShelfStatus(); ShelfStatus.OnCommand += SetCmdEvent; ShelfStatus.Dock = DockStyle.Fill; tabStatus.TabPages[0].PageVisible = true; tabStatus.TabPages[0].Controls.Add(ShelfStatus); ShelfStatus.Start(Convert.ToInt32(edModuleID.Text), ref aConfig, ref DeviceData.ModuleData); edModuleID.Enabled = true; chbPolling.Enabled = true; } private void TypeChangeUpdateRS485(ref CommConfig aConfig) { // Display Screen Delete if (MainStatus != null) { MainStatus.Dispose(); MainStatus = null; } if (ShelfStatus != null) { ShelfStatus.Dispose(); ShelfStatus = null; } if (aConfig.ModuleQty > 1) { // All disable first for (int i = 0; i < tabStatus.TabPages.Count; i++) { tabStatus.TabPages[i].PageVisible = false; } MainStatus = new ucMainStatus(); MainStatus.OnCommand += SetCmdEvent; tabStatus.TabPages[0].Text = string.Format("LFP System"); tabStatus.TabPages[0].PageVisible = true; tabStatus.TabPages[0].Controls.Add(MainStatus); MainStatus.Dock = DockStyle.Fill; MainStatus.UpdateMainConfig(Config, DeviceData); MainStatus.Start(aConfig, DeviceData); edModuleID.Enabled = false; chbPolling.Enabled = false; } else { tabStatus.TabPages[0].PageVisible = true; for (int i = 1; i < tabStatus.TabPages.Count; i++) { tabStatus.TabPages[i].PageVisible = false; } tabStatus.TabPages[0].Text = String.Format("LFP Module [{0}.{1}.{2}.{3}]" , 0 , 0 , 0 , 0 ); ShelfStatus = new ucShelfStatus(); ShelfStatus.OnCommand += SetCmdEvent; ShelfStatus.OnSendUartData += SetWriteData; ShelfStatus.Dock = DockStyle.Fill; tabStatus.TabPages[0].PageVisible = true; tabStatus.TabPages[0].Controls.Add(ShelfStatus); ShelfStatus.Start(ModuleID, ref aConfig, ref DeviceData.ModuleData); edModuleID.Enabled = true; chbPolling.Enabled = true; } } private void TypeChangeUpdateSnmp(ref CommConfig aConfig) { tabStatus.TabPages[0].PageVisible = true; for (int i = 1; i < tabStatus.TabPages.Count; i++) { tabStatus.TabPages[i].PageVisible = false; } tabStatus.TabPages[0].Text = String.Format("LFP Module [{0}.{1}.{2}.{3}]" , 0 , 0 , 0 , 0 ); ShelfStatus = new ucShelfStatus(); ShelfStatus.OnCommand += SetCmdEvent; ShelfStatus.Dock = DockStyle.Fill; tabStatus.TabPages[0].PageVisible = true; tabStatus.TabPages[0].Controls.Add(ShelfStatus); ShelfStatus.Start(ModuleID, ref aConfig, ref DeviceData.ModuleData); edModuleID.Enabled = false; chbPolling.Enabled = true; } private void TypeChangedUpdate(ref CommConfig aConfig) { tabStatus.TabPages[0].Controls.Clear(); // Display Screen Deletes if (ShelfStatus != null) { ShelfStatus.Dispose(); ShelfStatus = null; } SetCellTempQty(aConfig, ref DeviceData.ModuleData); try { ModuleID = Convert.ToInt16(edModuleID.Text); } catch (Exception) { ModuleID = 1; } switch (aConfig.CommType) { case csConstData.CommType.COMM_UART: TypeChangeUpdateUart(ref aConfig); historyToolStripMenuItem.Visible = true; inventoryViewToolStripMenuItem.Visible = true; updateToolStripMenuItem.Visible = false; break; case csConstData.CommType.COMM_RS485: TypeChangeUpdateRS485(ref aConfig); historyToolStripMenuItem.Visible = true; inventoryViewToolStripMenuItem.Visible = false; updateToolStripMenuItem.Visible = true; break; case csConstData.CommType.COMM_SNMP: TypeChangeUpdateSnmp(ref aConfig); historyToolStripMenuItem.Visible = true; inventoryViewToolStripMenuItem.Visible = false; updateToolStripMenuItem.Visible = false; break; default: break; } //DisplayCommStatus(); } private void SetCellTempQty(CommConfig aConfig, ref CsDeviceData.DeviceModuleData[] mData) { switch (aConfig.CommType) { case csConstData.CommType.COMM_UART: case csConstData.CommType.COMM_RS485: switch (aConfig.UartModelIndex) { case csConstData.UART_MODEL_INDEX.LFPM_48100D: case csConstData.UART_MODEL_INDEX.LFPM_48150D: case csConstData.UART_MODEL_INDEX.LFPM_48200D: case csConstData.UART_MODEL_INDEX.LFPM_48250D: case csConstData.UART_MODEL_INDEX.LFPM_48300D: for (int i = 0; i < mData.Length; i++) { mData[i].cellQty = 15; mData[i].tempQty = 4; } break; case csConstData.UART_MODEL_INDEX.LFPM_124050D: for (int i = 0; i < mData.Length; i++) { mData[i].cellQty = csConstData.SystemInfo.MAX_MODULE_CELL_SIZE; mData[i].tempQty = csConstData.SystemInfo.MAX_MODULE_TEMP_SIZE; } break; default: break; } break; case csConstData.CommType.COMM_SNMP: switch (aConfig.SnmpModelIndex) { case csConstData.UART_MODEL_INDEX.LFPM_48100D: case csConstData.UART_MODEL_INDEX.LFPM_48150D: case csConstData.UART_MODEL_INDEX.LFPM_48200D: case csConstData.UART_MODEL_INDEX.LFPM_48250D: case csConstData.UART_MODEL_INDEX.LFPM_48300D: for (int i = 0; i < mData.Length; i++) { mData[i].cellQty = 15; mData[i].tempQty = 4; } break; case csConstData.UART_MODEL_INDEX.LFPM_124050D: for (int i = 0; i < mData.Length; i++) { mData[i].cellQty = csConstData.SystemInfo.MAX_MODULE_CELL_SIZE; mData[i].tempQty = csConstData.SystemInfo.MAX_MODULE_TEMP_SIZE; } break; default: break; } break; default: for (int i = 0; i < mData.Length; i++) { mData[i].cellQty = 15; mData[i].tempQty = 4; } break; } } private void DisplaySystemFwVerModule() { switch (Config.ControlLevel) { case 0: // User Level inventoryViewToolStripMenuItem.Visible = false; break; case 1: // Technician Level inventoryViewToolStripMenuItem.Visible = false; break; case 2: // Engineer Level inventoryViewToolStripMenuItem.Visible = false; break; case 3: // Master Level inventoryViewToolStripMenuItem.Visible = true; break; default: // User Level inventoryViewToolStripMenuItem.Visible = false; break; } switch (Config.ControlLevel) { case 0: // User Level this.Text = String.Format("LFP SYSTEM [{0}] -- SB - User Level", Application.ProductVersion); break; case 1: // Technician Level this.Text = String.Format("LFP SYSTEM [{0}] -- SB - Technician Level", Application.ProductVersion); break; case 2: // Engineer Level this.Text = String.Format("LFP SYSTEM [{0}] -- SB - Engineer Level", Application.ProductVersion); break; case 3: // Master Level this.Text = String.Format("LFP SYSTEM [{0}] -- SB - Master Level", Application.ProductVersion); break; default: this.Text = String.Format("LFP SYSTEM [{0}] -- SB - User Level", Application.ProductVersion); break; } if (this.InvokeRequired) { this.Invoke(new MethodInvoker(delegate () { if (DeviceData.ModuleData[0].ValueData.fw_ver[0] != 0x00) { byte[] sn = new byte[33]; for (int i = 0; i < 32; i++) sn[i] = DeviceData.ModuleData[0].Information.BMS_SN[i]; sn[32] = 0; tabStatus.TabPages[0].Text = String.Format("{0} [{1}] - {2}", "LFP MODULE" , Encoding.UTF8.GetString(DeviceData.ModuleData[0].ValueData.fw_ver) , Encoding.Default.GetString(sn).Trim('\0') ); } else { tabStatus.TabPages[0].Text = String.Format("LFP MODULE"); } })); } else { if (DeviceData.ModuleData[0].ValueData.fw_ver[0] != 0x00) { byte[] sn = new byte[17]; for (int i = 0; i < 16; i++) sn[i] = DeviceData.ModuleData[0].Information.BMS_SN[i]; //22.06.30 Byul 32->16 sn[16] = 0; tabStatus.TabPages[0].Text = String.Format("{0} [{1}] - {2}", "LFP MODULE" , Encoding.UTF8.GetString(DeviceData.ModuleData[0].ValueData.fw_ver).Trim('\0') , Encoding.Default.GetString(sn).Trim('\0') ); } else { tabStatus.TabPages[0].Text = String.Format("LFP MODULE"); } } } private void UpdateSnmpData(object sender, ref CsDeviceData.DeviceModuleData mData) { DeviceData.ModuleData[0] = mData; uDataLog.UpdateData(DeviceData); } private void UpdateConfig(object aConfig) { Config = (CommConfig)aConfig; IniLoad(ref Config); } #endregion #region MENU EVENT private void commConfigToolStripMenuItem_Click(object sender, EventArgs e) { ConfigButtonClick(sender, e); } private void exitToolStripMenuItem_Click(object sender, EventArgs e) { Close(); } private void testSendToolStripMenuItem_Click(object sender, EventArgs e) { csHistoryFunction.DbCreate(System.IO.Path.GetDirectoryName(Application.ExecutablePath)); } private void firmwareUpdateToolStripMenuItem_Click(object sender, EventArgs e) { if (rs485Thread == null) return; FwUpdateForm = new fmxFwUpdate(rs485Thread.ModuleID); FwUpdateForm.OnAutoTxSet += SetAutoTx; FwUpdateForm.OnSendUartData += SetWriteData; FwUpdateForm.ShowDialog(); } private void historyViewToolStripMenuItem_Click(object sender, EventArgs e) { foreach (Form frm in Application.OpenForms) { if (frm.Name == "fmxHistory") { frm.Activate(); return; } } HistoryForm = new fmxHistory(Config, ModuleID); HistoryForm.OnSendUartData += SetWriteData; HistoryForm.ShowDialog(); } private void inventoryViewToolStripMenuItem_Click(object sender, EventArgs e) { foreach (Form frm in Application.OpenForms) { if (frm.Name == "fmxInventoryConfig") { frm.Activate(); return; } } InventoryConfig = new fmxInventoryConfig(ModuleID, ref Config, ref DeviceData.ModuleData[ModuleID - 1]); InventoryConfig.OnSendUartData += SetWriteData; InventoryConfig.Show(); } #endregion #region FORM EVENT private void fmxMain_FormClosing(object sender, FormClosingEventArgs e) { if (uartThread != null) { uartThread.Dispose(); uartThread = null; } if (rs485Thread != null) { rs485Thread.Dispose(); rs485Thread = null; } if (snmpThread != null) { snmpThread.disposeThread(); snmpThread = null; } if (dbThread != null) { dbThread.Dispose(); dbThread = null; } } #endregion #region STATUS BAR EVENT void DisplayCommStatus() { if (Active == true) CommStatusBar.Text = "Comm: On"; else CommStatusBar.Text = "Comm: Off"; } void DisplayCommStatus(string msg) { if (msg != "") CommStatusBar.Text = String.Format("Comm: {0}", msg); } void LogStatusUpdate(object sender, string msg, bool active, int aLogTime) { LogStatusBar.Text = msg; } #endregion #region COMMAND AND SET private void CommDataPrint(object sender, int id, string msg) { if (msg != "") { uEventLog.EventUpdate(id, msg + "\r\n"); } } private void SetWriteData(ushort WriteAddr, byte[] WriteData, bool RelyFlag, int type) { uartThread?.SetWriteReg(WriteAddr, WriteData, RelyFlag, type); rs485Thread?.SetWriteReg(WriteAddr, WriteData, RelyFlag, type); } private void SetCmdEvent(int sId, int cmd, int index, int flag, ref CsDeviceData.DeviceModuleData.DeviceParamData aParam, ref CsDeviceData.DeviceModuleData.DeviceCalibration aCalib) { if (MainStatus != null) { switch (cmd) { case 1: // Module quatity set break; case 2: CreateModuleDetailForm(sId); break; } } uartThread?.SendProcessFromApp(sId, cmd, index, flag, ref aParam, ref aCalib); } private void CreateModuleDetailForm(int sID) { foreach (Form frm in Application.OpenForms) { if (frm.Name == "fmxModuleDetail") { ((fmxModuleDetail)frm).SetModuleID(sID); frm.Activate(); return; } } ModuleDetailForm = new fmxModuleDetail(sID, ref Config, ref DeviceData.ModuleData); //ModuleDetailForm.OnAutoTxCanSet += SetAutoTxCan; //ModuleDetailForm.OnSendDataCan += SendDataToCan; ModuleDetailForm.Show(); } private void chbPolling_CheckedChanged(object sender, EventArgs e) { if (edModuleID.Text != "") { ModuleID = Convert.ToInt32(edModuleID.Text); if (uartThread != null) { uartThread.SetPolling(chbPolling.Checked, ModuleID, ref DeviceData.ModuleData[ModuleID - 1]); ShelfStatus?.UpdateSystemId(ModuleID); } if (rs485Thread != null) { rs485Thread.SetPolling(chbPolling.Checked, ModuleID, ref DeviceData.ModuleData); ShelfStatus?.UpdateSystemId(ModuleID); } snmpThread?.SetAutoTx(chbPolling.Checked); uDataLog.UpdateActiveStatus(Active, Config, ref DeviceData); edModuleID.Enabled = !chbPolling.Checked; } } private void SnmpRecvData(string result, bool error) { if (result != "") { uEventLog.EventUpdate(0, result + "\r\n"); } } private void SetAutoTx(bool autoTx) { uartThread?.SetAutoTx(autoTx); } #endregion #region KEYBOARD HOOK private void edSystemId_KeyPress(object sender, KeyPressEventArgs e) { csUtils.TypingOnlyNumber(sender, e, false, false); } #endregion #region MENU COMMAND private void inventoryControlToolStripMenuItem_Click(object sender, EventArgs e) { foreach (Form frm in Application.OpenForms) { if (frm.Name == "fmxInventoryConfig") { frm.Activate(); return; } } InventoryConfig = new fmxInventoryConfig(0, ref Config, ref DeviceData.ModuleData[0]); InventoryConfig.OnUpdate += UpdateInformation; InventoryConfig.OnCommand += InvDataSetCmd; //InventoryConfig.OnCommandBySnmp += SetInvEventBySnmp; InventoryConfig.Show(); } private void InvDataSetCmd(int sId, int mode, int index, int flag, ref CsDeviceData.DeviceModuleData.DeviceInforation aInvData) { DeviceData.ModuleData[0].Information = aInvData; //OnCommand?.Invoke(sId, mode, index, flag, ref DeviceData.ModuleData[0].ParamData, ref DeviceData.ModuleData[0].CalibriationData); //SetCmdToCan(sId, mode, index, flag, ref DeviceData.ModuleData[0].ParamData, ref DeviceData.ModuleData[0].CalibriationData); } private void UpdateInformation(object sendor) { ((fmxInventoryConfig)sendor).UpdateData(ref DeviceData.ModuleData[0]); } private void checkDBToolStripMenuItem_Click(object sender, EventArgs e) { foreach (Form frm in Application.OpenForms) { if (frm.Name == "fmxExcelFile") { frm.Activate(); return; } } fmxExcelFile DbControl = new fmxExcelFile(Config); DbControl.Show(); } private void levelConfigToolStripMenuItem_Click(object sender, EventArgs e) { } private void changeLeToolStripMenuItem_Click(object sender, EventArgs e) { foreach (Form frm in Application.OpenForms) { if (frm.Name == "FmxLevelConfig") { frm.Activate(); return; } } FmxLevelConfig LevelControl = new FmxLevelConfig(Config); LevelControl.ShowDialog(); } private void changePasswordToolStripMenuItem_Click(object sender, EventArgs e) { foreach (Form frm in Application.OpenForms) { if (frm.Name == "FmxPasswordChange") { frm.Activate(); return; } } FmxPasswordChange ChangePassword = new FmxPasswordChange(Config); ChangePassword.ShowDialog(); } #endregion #region TIMER EVENT private void tmrDisplay_Tick(object sender, EventArgs e) { uTarget.UpdateStatus(Active); DisplaySystemFwVerModule(); } #endregion #region MAKE TOTAL DATA private void MakeTotalDataAndStatus() { if (Config.CommType == csConstData.CommType.COMM_RS485) { MakeTotalDataRS485(); MakeTotalStatusRS485(); MakeTotalAlarmRS485(); } } private void MakeTotalDataRS485() { int j = 0; int vsum, csum, ssum, hsum, tsum; int mQty = csUtils.GetModuleQty(Config); vsum = csum = ssum = hsum = tsum = 0; for (int i = 0; i < mQty; i++) { if (DeviceData.ModuleData[i].ShelfCommFail == false) { vsum += DeviceData.ModuleData[i].ValueData.voltage; csum += DeviceData.ModuleData[i].ValueData.current; ssum += DeviceData.ModuleData[i].ValueData.SOC; hsum += DeviceData.ModuleData[i].ValueData.SOH; tsum += DeviceData.ModuleData[i].AvgData.avgTemp; j++; } } if (j > 0) { DeviceData.TotalData.ValueData.TotalVoltage = (short)(vsum / j); DeviceData.TotalData.ValueData.TotalCurrent = (short)(csum); DeviceData.TotalData.ValueData.TotalSOC = (short)(ssum / j); DeviceData.TotalData.ValueData.TotalSOH = (short)(hsum / j); DeviceData.TotalData.ValueData.TotalTemp = (short)(tsum / j); } else { DeviceData.TotalData.ValueData.TotalVoltage = 0; DeviceData.TotalData.ValueData.TotalCurrent = 0; DeviceData.TotalData.ValueData.TotalSOC = 0; DeviceData.TotalData.ValueData.TotalSOH = 0; DeviceData.TotalData.ValueData.TotalTemp = 0; } } private void MakeTotalStatusRS485() { int mQty = csUtils.GetModuleQty(Config); switch (DeviceData.TotalData.StatusData.status) { case 0: // Standby if (DeviceData.TotalData.ValueData.TotalCurrent > 50) // Discharging 5.0A { DeviceData.TotalData.StatusData.status = 2; // Discharging } else if (DeviceData.TotalData.ValueData.TotalCurrent < -50) // Charging -5.0A { DeviceData.TotalData.StatusData.status = 1; // Charging } else { bool flag = true; for (int i = 0; i < mQty; i++) { if (DeviceData.ModuleData[i].StatusData.status != 3) { flag = false; break; } } if (flag == true) { DeviceData.TotalData.StatusData.status = 3; // Floating } } break; case 1: // Charging if (DeviceData.TotalData.ValueData.TotalCurrent > 50) // Discharge -5.0A { DeviceData.TotalData.StatusData.status = 2; // Discharging } else if (DeviceData.TotalData.ValueData.TotalCurrent > -30) // Charging > -3.0A { DeviceData.TotalData.StatusData.status = 0; // Standby } else { bool flag = true; for (int i = 0; i < mQty; i++) { if (DeviceData.ModuleData[i].StatusData.status != 3) { flag = false; break; } } if (flag == true) { DeviceData.TotalData.StatusData.status = 3; // Floating } } break; case 2: // Discharging if (DeviceData.TotalData.ValueData.TotalCurrent < -50) // Charging -5.0A { DeviceData.TotalData.StatusData.status = 1; // Charging } else if (DeviceData.TotalData.ValueData.TotalCurrent < 30) // Discharge 3.0A { DeviceData.TotalData.StatusData.status = 0; // Standby } else { bool flag = true; for (int i = 0; i < mQty; i++) { if (DeviceData.ModuleData[i].StatusData.status != 3) { flag = false; break; } } if (flag == true) { DeviceData.TotalData.StatusData.status = 3; // Floating } } break; case 3: // Floating if (DeviceData.TotalData.ValueData.TotalCurrent < -50) // Charging -5.0A { DeviceData.TotalData.StatusData.status = 1; // Charging } else if (DeviceData.TotalData.ValueData.TotalCurrent > 50) // Discharge 5.0A { DeviceData.TotalData.StatusData.status = 2; // Discharge } else { bool flag = true; for (int i = 0; i < mQty; i++) { if (DeviceData.ModuleData[i].StatusData.status != 3) { flag = false; break; } } if (flag == false) { DeviceData.TotalData.StatusData.status = 0; // Standby } } break; } } private void MakeTotalAlarmRS485() { int mQty = csUtils.GetModuleQty(Config); bool aTrip, aWarning; aTrip = aWarning = false; for (int i = 0; i < mQty; i++) { if (DeviceData.ModuleData[i].StatusData.batteryStatus == 2) { aTrip = true; } else if ((DeviceData.ModuleData[i].StatusData.batteryStatus == 1) || (DeviceData.ModuleData[i].ShelfCommFail)) { aWarning = true; } } if (aTrip) { DeviceData.TotalData.StatusData.batteryStatus = 2; } else if (aWarning) { DeviceData.TotalData.StatusData.batteryStatus = 1; } else { DeviceData.TotalData.StatusData.batteryStatus = 0; } } #endregion #region EVENT CONNECT AND DISCONNECT // UART 이벤트 연결/해제 private void WireUart(csUartThread t) { if (t == null) return; t.OnUpdate += UpdateDataUart; // EventHandler t.OnDataRecv += UartRecvData; // EventHandler t.OnPrint += CommDataPrint; // EventHandler } private void UnwireUart() { if (uartThread == null) return; uartThread.OnUpdate -= UpdateDataUart; uartThread.OnDataRecv -= UartRecvData; uartThread.OnPrint -= CommDataPrint; } // RS485(Delta) 이벤트 연결/해제 private void WireRs485(CsUartThreadSB t) { if (t == null) return; t.OnUpdate += UpdateDataRS485; // EventHandler t.OnDataRecv += UartRecvData; // EventHandler t.OnPrint += CommDataPrint; // EventHandler } private void UnwireRs485() { if (rs485Thread == null) return; rs485Thread.OnUpdate -= UpdateDataRS485; rs485Thread.OnDataRecv -= UartRecvData; rs485Thread.OnPrint -= CommDataPrint; } #endregion #region EVENT HANDLER private void UpdateDataUart(object sender, csUartThread.ModuleDataEventArgs e) { // 필요시 깊은 복사(바인딩 대상이 스레드 모두에서 변경될 여지가 있으면) // var snapshot = e.Modules.Select(m => m.DeepCopy()).ToArray(); // DeviceData.ModuleData = snapshot; DeviceData.ModuleData[0] = e.Module; // 참조 재할당만으로 충분하면 이대로 // ref 제거: UpdateData 시그니처도 ref 없이 받도록 변경 권장 ShelfStatus?.UpdateData(DeviceData.ModuleData); uDataLog.UpdateData(DeviceData); } private void UpdateDataRS485(object sender, CsUartThreadSB.ModuleDataEventArgs e) { // 필요시 깊은 복사(바인딩 대상이 스레드 모두에서 변경될 여지가 있으면) // var snapshot = e.Modules.Select(m => m.DeepCopy()).ToArray(); // DeviceData.ModuleData = snapshot; DeviceData.ModuleData = e.Modules; // 참조 재할당만으로 충분하면 이대로 // ref 제거: UpdateData 시그니처도 ref 없이 받도록 변경 권장 ShelfStatus?.UpdateData(DeviceData.ModuleData); MakeTotalDataAndStatus(); MainStatus?.UpdateData(DeviceData); uDataLog.UpdateData(DeviceData); } // 핸들러 (대응되는 형태) private void UartRecvData(object sender, DataRecvEventArgs e) { // e.Data 사용 FwUpdateForm?.RecvData(e.Data); //HistoryForm?.RecvUartData(e.Data); // 메서드명 확인 (오타 주의) } // 핸들러 (대응되는 형태) private void CommDataPrint(object sender, PrintEventArgs e) { var id = e.Id; var msg = e.Message; if (!string.IsNullOrEmpty(msg)) uEventLog.EventUpdate(id, msg + "\r\n"); } private void ErrorOnPrint(object sender, PrintEventArgs e) { var id = e.Id; var msg = e.Message; if (!string.IsNullOrEmpty(e.Message)) uEventLog.ErrorUpdate(id, msg + "\r\n"); } #endregion #region EVENT DB COMMAND TO THREAD private void UpdateAlarmHistory(DataTable aAlarmHistory) { uEventLog.AlarmHistoryUpdate1(aAlarmHistory); } #endregion } }