V1.0.1.8 -- 2025/12/20
* BMS History Function Improved
This commit is contained in:
@@ -180,7 +180,7 @@ namespace LFP_Manager.Controls
|
|||||||
SaveFileDialog sDialog = new SaveFileDialog();
|
SaveFileDialog sDialog = new SaveFileDialog();
|
||||||
sDialog.Title = "Select save file";
|
sDialog.Title = "Select save file";
|
||||||
sDialog.DefaultExt = "xlsx";
|
sDialog.DefaultExt = "xlsx";
|
||||||
sDialog.Filter = "Excel files 2003 (*.xls)|*.xls|All files (*.*)|*.*";
|
sDialog.Filter = "Excel files (*.xlsx)|*.xlsx|All files (*.*)|*.*";
|
||||||
|
|
||||||
if (sDialog.ShowDialog() == DialogResult.OK)
|
if (sDialog.ShowDialog() == DialogResult.OK)
|
||||||
{
|
{
|
||||||
@@ -188,7 +188,9 @@ namespace LFP_Manager.Controls
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
csExcelExport.ExportToExcelExt(dtHistory, filename);
|
DataTable[] export = new DataTable[1];
|
||||||
|
export[0] = dtHistory;
|
||||||
|
csExcelFunction.ExportDgvWithClosedXml(filename, export);
|
||||||
|
|
||||||
MessageBox.Show("Complete Export Excel File", "Result", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
MessageBox.Show("Complete Export Excel File", "Result", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
}
|
}
|
||||||
|
|||||||
25
LFP_Manager/Forms/fmxHistory.Designer.cs
generated
25
LFP_Manager/Forms/fmxHistory.Designer.cs
generated
@@ -79,7 +79,7 @@
|
|||||||
this.layoutControlGroup3 = new DevExpress.XtraLayout.LayoutControlGroup();
|
this.layoutControlGroup3 = new DevExpress.XtraLayout.LayoutControlGroup();
|
||||||
this.emptySpaceItem1 = new DevExpress.XtraLayout.EmptySpaceItem();
|
this.emptySpaceItem1 = new DevExpress.XtraLayout.EmptySpaceItem();
|
||||||
this.layoutControlItem5 = new DevExpress.XtraLayout.LayoutControlItem();
|
this.layoutControlItem5 = new DevExpress.XtraLayout.LayoutControlItem();
|
||||||
this.layoutControlGroup4 = new DevExpress.XtraLayout.LayoutControlGroup();
|
this.LcGrResult = new DevExpress.XtraLayout.LayoutControlGroup();
|
||||||
this.layoutControlItem4 = new DevExpress.XtraLayout.LayoutControlItem();
|
this.layoutControlItem4 = new DevExpress.XtraLayout.LayoutControlItem();
|
||||||
this.layoutControlItem6 = new DevExpress.XtraLayout.LayoutControlItem();
|
this.layoutControlItem6 = new DevExpress.XtraLayout.LayoutControlItem();
|
||||||
this.emptySpaceItem2 = new DevExpress.XtraLayout.EmptySpaceItem();
|
this.emptySpaceItem2 = new DevExpress.XtraLayout.EmptySpaceItem();
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
((System.ComponentModel.ISupportInitialize)(this.layoutControlGroup3)).BeginInit();
|
((System.ComponentModel.ISupportInitialize)(this.layoutControlGroup3)).BeginInit();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.emptySpaceItem1)).BeginInit();
|
((System.ComponentModel.ISupportInitialize)(this.emptySpaceItem1)).BeginInit();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.layoutControlItem5)).BeginInit();
|
((System.ComponentModel.ISupportInitialize)(this.layoutControlItem5)).BeginInit();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.layoutControlGroup4)).BeginInit();
|
((System.ComponentModel.ISupportInitialize)(this.LcGrResult)).BeginInit();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.layoutControlItem4)).BeginInit();
|
((System.ComponentModel.ISupportInitialize)(this.layoutControlItem4)).BeginInit();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.layoutControlItem6)).BeginInit();
|
((System.ComponentModel.ISupportInitialize)(this.layoutControlItem6)).BeginInit();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.emptySpaceItem2)).BeginInit();
|
((System.ComponentModel.ISupportInitialize)(this.emptySpaceItem2)).BeginInit();
|
||||||
@@ -712,7 +712,7 @@
|
|||||||
this.layoutControlGroup2.GroupBordersVisible = false;
|
this.layoutControlGroup2.GroupBordersVisible = false;
|
||||||
this.layoutControlGroup2.Items.AddRange(new DevExpress.XtraLayout.BaseLayoutItem[] {
|
this.layoutControlGroup2.Items.AddRange(new DevExpress.XtraLayout.BaseLayoutItem[] {
|
||||||
this.layoutControlGroup3,
|
this.layoutControlGroup3,
|
||||||
this.layoutControlGroup4});
|
this.LcGrResult});
|
||||||
this.layoutControlGroup2.Name = "Root";
|
this.layoutControlGroup2.Name = "Root";
|
||||||
this.layoutControlGroup2.Padding = new DevExpress.XtraLayout.Utils.Padding(2, 2, 2, 2);
|
this.layoutControlGroup2.Padding = new DevExpress.XtraLayout.Utils.Padding(2, 2, 2, 2);
|
||||||
this.layoutControlGroup2.Size = new System.Drawing.Size(903, 526);
|
this.layoutControlGroup2.Size = new System.Drawing.Size(903, 526);
|
||||||
@@ -748,17 +748,17 @@
|
|||||||
this.layoutControlItem5.TextSize = new System.Drawing.Size(0, 0);
|
this.layoutControlItem5.TextSize = new System.Drawing.Size(0, 0);
|
||||||
this.layoutControlItem5.TextVisible = false;
|
this.layoutControlItem5.TextVisible = false;
|
||||||
//
|
//
|
||||||
// layoutControlGroup4
|
// LcGrResult
|
||||||
//
|
//
|
||||||
this.layoutControlGroup4.Items.AddRange(new DevExpress.XtraLayout.BaseLayoutItem[] {
|
this.LcGrResult.Items.AddRange(new DevExpress.XtraLayout.BaseLayoutItem[] {
|
||||||
this.layoutControlItem4,
|
this.layoutControlItem4,
|
||||||
this.layoutControlItem6,
|
this.layoutControlItem6,
|
||||||
this.emptySpaceItem2});
|
this.emptySpaceItem2});
|
||||||
this.layoutControlGroup4.Location = new System.Drawing.Point(0, 64);
|
this.LcGrResult.Location = new System.Drawing.Point(0, 64);
|
||||||
this.layoutControlGroup4.Name = "layoutControlGroup4";
|
this.LcGrResult.Name = "LcGrResult";
|
||||||
this.layoutControlGroup4.Padding = new DevExpress.XtraLayout.Utils.Padding(1, 1, 1, 1);
|
this.LcGrResult.Padding = new DevExpress.XtraLayout.Utils.Padding(1, 1, 1, 1);
|
||||||
this.layoutControlGroup4.Size = new System.Drawing.Size(899, 458);
|
this.LcGrResult.Size = new System.Drawing.Size(899, 458);
|
||||||
this.layoutControlGroup4.Text = "Result";
|
this.LcGrResult.Text = "Result";
|
||||||
//
|
//
|
||||||
// layoutControlItem4
|
// layoutControlItem4
|
||||||
//
|
//
|
||||||
@@ -850,6 +850,7 @@
|
|||||||
this.Name = "fmxHistory";
|
this.Name = "fmxHistory";
|
||||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||||
this.Text = "History";
|
this.Text = "History";
|
||||||
|
this.Load += new System.EventHandler(this.fmxHistory_Load);
|
||||||
((System.ComponentModel.ISupportInitialize)(this.layoutControl1)).EndInit();
|
((System.ComponentModel.ISupportInitialize)(this.layoutControl1)).EndInit();
|
||||||
this.layoutControl1.ResumeLayout(false);
|
this.layoutControl1.ResumeLayout(false);
|
||||||
((System.ComponentModel.ISupportInitialize)(this.tabHistory)).EndInit();
|
((System.ComponentModel.ISupportInitialize)(this.tabHistory)).EndInit();
|
||||||
@@ -868,7 +869,7 @@
|
|||||||
((System.ComponentModel.ISupportInitialize)(this.layoutControlGroup3)).EndInit();
|
((System.ComponentModel.ISupportInitialize)(this.layoutControlGroup3)).EndInit();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.emptySpaceItem1)).EndInit();
|
((System.ComponentModel.ISupportInitialize)(this.emptySpaceItem1)).EndInit();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.layoutControlItem5)).EndInit();
|
((System.ComponentModel.ISupportInitialize)(this.layoutControlItem5)).EndInit();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.layoutControlGroup4)).EndInit();
|
((System.ComponentModel.ISupportInitialize)(this.LcGrResult)).EndInit();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.layoutControlItem4)).EndInit();
|
((System.ComponentModel.ISupportInitialize)(this.layoutControlItem4)).EndInit();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.layoutControlItem6)).EndInit();
|
((System.ComponentModel.ISupportInitialize)(this.layoutControlItem6)).EndInit();
|
||||||
((System.ComponentModel.ISupportInitialize)(this.emptySpaceItem2)).EndInit();
|
((System.ComponentModel.ISupportInitialize)(this.emptySpaceItem2)).EndInit();
|
||||||
@@ -902,7 +903,7 @@
|
|||||||
private DevExpress.XtraLayout.LayoutControlItem layoutControlItem5;
|
private DevExpress.XtraLayout.LayoutControlItem layoutControlItem5;
|
||||||
private DevExpress.XtraLayout.EmptySpaceItem emptySpaceItem1;
|
private DevExpress.XtraLayout.EmptySpaceItem emptySpaceItem1;
|
||||||
private DevExpress.XtraLayout.LayoutControlGroup layoutControlGroup3;
|
private DevExpress.XtraLayout.LayoutControlGroup layoutControlGroup3;
|
||||||
private DevExpress.XtraLayout.LayoutControlGroup layoutControlGroup4;
|
private DevExpress.XtraLayout.LayoutControlGroup LcGrResult;
|
||||||
private DevExpress.XtraGrid.Columns.GridColumn gcHistDateTime;
|
private DevExpress.XtraGrid.Columns.GridColumn gcHistDateTime;
|
||||||
private DevExpress.XtraGrid.Columns.GridColumn gcStatus;
|
private DevExpress.XtraGrid.Columns.GridColumn gcStatus;
|
||||||
private DevExpress.XtraGrid.Columns.GridColumn gcWarning;
|
private DevExpress.XtraGrid.Columns.GridColumn gcWarning;
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
using LFP_Manager.DataStructure;
|
using DevExpress.Utils;
|
||||||
|
using DevExpress.XtraEditors.Repository;
|
||||||
|
using DevExpress.XtraGrid;
|
||||||
|
using DevExpress.XtraGrid.Columns;
|
||||||
|
using DevExpress.XtraGrid.Views.Grid;
|
||||||
|
|
||||||
|
using LFP_Manager.DataStructure;
|
||||||
using LFP_Manager.Function;
|
using LFP_Manager.Function;
|
||||||
|
using LFP_Manager.Utils;
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
@@ -15,9 +23,16 @@ namespace LFP_Manager.Forms
|
|||||||
|
|
||||||
private byte[] rData = null;
|
private byte[] rData = null;
|
||||||
private ushort curr_addr = 0;
|
private ushort curr_addr = 0;
|
||||||
|
private int recv_data_len = 0;
|
||||||
|
|
||||||
private int hist_no = 0;
|
private int hist_no = 0;
|
||||||
private bool stopReq = true;
|
private bool stopReq = true;
|
||||||
|
|
||||||
|
private int cell_qty = 16;
|
||||||
|
private int temp_qty = 4;
|
||||||
|
|
||||||
|
private int req_timeoutCount = 0;
|
||||||
|
|
||||||
private DateTime ReqDateTime;
|
private DateTime ReqDateTime;
|
||||||
|
|
||||||
private DataTable BmsHistoryTable = null;
|
private DataTable BmsHistoryTable = null;
|
||||||
@@ -28,21 +43,34 @@ namespace LFP_Manager.Forms
|
|||||||
|
|
||||||
#region CONTRUCTORS
|
#region CONTRUCTORS
|
||||||
|
|
||||||
//public fmxHistory()
|
|
||||||
//{
|
|
||||||
// InitializeComponent();
|
|
||||||
//}
|
|
||||||
|
|
||||||
public fmxHistory(CommConfig aConfig, int systemId)
|
public fmxHistory(CommConfig aConfig, int systemId)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Config = aConfig;
|
Config = aConfig;
|
||||||
|
|
||||||
|
switch (Config.UartModelIndex)
|
||||||
|
{
|
||||||
|
case csConstData.MODEL_INDEX.LFPM_124050D:
|
||||||
|
recv_data_len = 112;
|
||||||
|
cell_qty = 39;
|
||||||
|
temp_qty = 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
recv_data_len = 58;
|
||||||
|
cell_qty = 16;
|
||||||
|
temp_qty = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ucHistroy1.SetCommCofig(Config);
|
ucHistroy1.SetCommCofig(Config);
|
||||||
SystemId = systemId;
|
SystemId = systemId;
|
||||||
|
|
||||||
CreateHistoryColomn(ref BmsHistoryTable);
|
CreateHistoryColumn(ref BmsHistoryTable);
|
||||||
|
BuildHistoryGridColumns(gcBmsHistory, gvBmsHistory, BmsHistoryTable);
|
||||||
|
|
||||||
|
gvBmsHistory.Appearance.HeaderPanel.TextOptions.HAlignment = HorzAlignment.Center;
|
||||||
|
gvBmsHistory.Appearance.HeaderPanel.TextOptions.VAlignment = VertAlignment.Center;
|
||||||
|
|
||||||
switch (Config.CommType)
|
switch (Config.CommType)
|
||||||
{
|
{
|
||||||
@@ -67,7 +95,7 @@ namespace LFP_Manager.Forms
|
|||||||
|
|
||||||
#region INITIALIZE COMPONENT
|
#region INITIALIZE COMPONENT
|
||||||
|
|
||||||
private void CreateHistoryColomn(ref DataTable hDT)
|
private void CreateHistoryColumn(ref DataTable hDT)
|
||||||
{
|
{
|
||||||
hDT = new DataTable();
|
hDT = new DataTable();
|
||||||
|
|
||||||
@@ -78,52 +106,223 @@ namespace LFP_Manager.Forms
|
|||||||
hDT.Columns.Add("protect", typeof(string));
|
hDT.Columns.Add("protect", typeof(string));
|
||||||
hDT.Columns.Add("error", typeof(string));
|
hDT.Columns.Add("error", typeof(string));
|
||||||
|
|
||||||
hDT.Columns.Add("voltage", typeof(float));
|
hDT.Columns.Add("voltage", typeof(decimal));
|
||||||
hDT.Columns.Add("current", typeof(float));
|
hDT.Columns.Add("current", typeof(decimal));
|
||||||
hDT.Columns.Add("SOC", typeof(float));
|
hDT.Columns.Add("SOC", typeof(decimal));
|
||||||
hDT.Columns.Add("SOH", typeof(float));
|
|
||||||
|
|
||||||
for (int i = 0; i < 6; i++)
|
hDT.Columns.Add("pcb_t", typeof(decimal));
|
||||||
|
hDT.Columns.Add("amb_t", typeof(decimal));
|
||||||
|
|
||||||
|
for (int i = 0; i < temp_qty; i++)
|
||||||
{
|
{
|
||||||
hDT.Columns.Add(string.Format("temp_{0:00}", i + 1), typeof(float));
|
hDT.Columns.Add(string.Format("temp_{0:00}", i + 1), typeof(decimal));
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 16; i++)
|
for (int i = 0; i < cell_qty; i++)
|
||||||
{
|
{
|
||||||
hDT.Columns.Add(string.Format("cell_v_{0:00}", i + 1), typeof(float));
|
hDT.Columns.Add(string.Format("cell_v_{0:00}", i + 1), typeof(decimal));
|
||||||
}
|
}
|
||||||
gcBmsHistory.DataSource = hDT;
|
gcBmsHistory.DataSource = hDT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void BuildHistoryGridColumns(GridControl grid, GridView view, DataTable dt)
|
||||||
|
{
|
||||||
|
grid.BeginUpdate();
|
||||||
|
view.BeginUpdate();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 1️⃣ DataSource 바인딩
|
||||||
|
grid.DataSource = dt;
|
||||||
|
|
||||||
|
// 2️⃣ 기존 컬럼 제거
|
||||||
|
view.Columns.Clear();
|
||||||
|
|
||||||
|
// 3️⃣ RepositoryItems 준비
|
||||||
|
|
||||||
|
RepositoryItemTextEdit repoText = new RepositoryItemTextEdit
|
||||||
|
{
|
||||||
|
ReadOnly = true
|
||||||
|
};
|
||||||
|
|
||||||
|
RepositoryItemSpinEdit repoInt = new RepositoryItemSpinEdit
|
||||||
|
{
|
||||||
|
IsFloatValue = false,
|
||||||
|
Mask = { EditMask = "N0", UseMaskAsDisplayFormat = true }
|
||||||
|
};
|
||||||
|
|
||||||
|
RepositoryItemSpinEdit repoF1 = new RepositoryItemSpinEdit
|
||||||
|
{
|
||||||
|
IsFloatValue = true,
|
||||||
|
Mask = { EditMask = "F1", UseMaskAsDisplayFormat = true }
|
||||||
|
};
|
||||||
|
|
||||||
|
RepositoryItemSpinEdit repoF2 = new RepositoryItemSpinEdit
|
||||||
|
{
|
||||||
|
IsFloatValue = true,
|
||||||
|
Mask = { EditMask = "F2", UseMaskAsDisplayFormat = true }
|
||||||
|
};
|
||||||
|
|
||||||
|
RepositoryItemSpinEdit repoF3 = new RepositoryItemSpinEdit
|
||||||
|
{
|
||||||
|
IsFloatValue = true,
|
||||||
|
Mask = { EditMask = "F3", UseMaskAsDisplayFormat = true }
|
||||||
|
};
|
||||||
|
|
||||||
|
RepositoryItemDateEdit repoDate = new RepositoryItemDateEdit
|
||||||
|
{
|
||||||
|
Mask = { EditMask = "yyyy-MM-dd HH:mm:ss", UseMaskAsDisplayFormat = true }
|
||||||
|
};
|
||||||
|
|
||||||
|
grid.RepositoryItems.AddRange(new RepositoryItem[]
|
||||||
|
{
|
||||||
|
repoText, repoInt, repoF1, repoF2, repoF3, repoDate
|
||||||
|
});
|
||||||
|
|
||||||
|
int visibleIndex = 0;
|
||||||
|
|
||||||
|
// 4️⃣ DataTable 컬럼 기준 GridColumn 생성
|
||||||
|
foreach (DataColumn dc in dt.Columns)
|
||||||
|
{
|
||||||
|
GridColumn col = new GridColumn
|
||||||
|
{
|
||||||
|
FieldName = dc.ColumnName,
|
||||||
|
Name = "gc_" + dc.ColumnName,
|
||||||
|
Caption = GetHistoryColumnCaption(dc.ColumnName), // ⭐ 헤더 변경
|
||||||
|
Visible = true,
|
||||||
|
VisibleIndex = visibleIndex++
|
||||||
|
};
|
||||||
|
|
||||||
|
string name = dc.ColumnName.ToLower();
|
||||||
|
|
||||||
|
// ───── 타입/이름 기준 포맷 규칙 ─────
|
||||||
|
|
||||||
|
if (name == "no")
|
||||||
|
{
|
||||||
|
col.ColumnEdit = repoInt;
|
||||||
|
col.DisplayFormat.FormatType = FormatType.Numeric;
|
||||||
|
col.DisplayFormat.FormatString = "N0";
|
||||||
|
col.AppearanceCell.TextOptions.HAlignment = HorzAlignment.Center;
|
||||||
|
}
|
||||||
|
else if (name == "datetime")
|
||||||
|
{
|
||||||
|
col.ColumnEdit = repoDate;
|
||||||
|
col.DisplayFormat.FormatType = FormatType.DateTime;
|
||||||
|
col.DisplayFormat.FormatString = "yyyy-MM-dd HH:mm:ss";
|
||||||
|
}
|
||||||
|
else if (name == "status")
|
||||||
|
{
|
||||||
|
col.ColumnEdit = repoText;
|
||||||
|
// ✅ status는 표시가 문자열이므로 가운데 정렬 강제
|
||||||
|
col.AppearanceCell.Options.UseTextOptions = true; // ⭐⭐⭐ 핵심 ⭐⭐⭐
|
||||||
|
col.AppearanceCell.TextOptions.HAlignment = HorzAlignment.Center;
|
||||||
|
|
||||||
|
// (선택) 숫자 표시 포맷/에디터 굳이 필요 없으면 빼도 됨
|
||||||
|
// col.ColumnEdit = repoInt;
|
||||||
|
}
|
||||||
|
else if (name == "voltage" || name == "current" || name == "soc")
|
||||||
|
{
|
||||||
|
col.ColumnEdit = repoF2;
|
||||||
|
col.DisplayFormat.FormatType = FormatType.Numeric;
|
||||||
|
col.DisplayFormat.FormatString = "0.00";
|
||||||
|
}
|
||||||
|
else if (name == "pcb_t" || name == "amb_t" || name.StartsWith("temp_"))
|
||||||
|
{
|
||||||
|
col.ColumnEdit = repoF1;
|
||||||
|
col.DisplayFormat.FormatType = FormatType.Numeric;
|
||||||
|
col.DisplayFormat.FormatString = "0.0";
|
||||||
|
}
|
||||||
|
else if (name.StartsWith("cell_v_"))
|
||||||
|
{
|
||||||
|
col.ColumnEdit = repoF3;
|
||||||
|
col.DisplayFormat.FormatType = FormatType.Numeric;
|
||||||
|
col.DisplayFormat.FormatString = "0.000";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// warning / protect / error (string)
|
||||||
|
col.ColumnEdit = repoText;
|
||||||
|
col.AppearanceCell.Options.UseTextOptions = true; // ⭐⭐⭐ 핵심 ⭐⭐⭐
|
||||||
|
col.AppearanceCell.TextOptions.HAlignment = HorzAlignment.Center;
|
||||||
|
}
|
||||||
|
|
||||||
|
view.Columns.Add(col);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5️⃣ 전체 헤더 가운데 정렬 (요청하신 설정)
|
||||||
|
view.Appearance.HeaderPanel.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Center;
|
||||||
|
view.Appearance.HeaderPanel.TextOptions.VAlignment = DevExpress.Utils.VertAlignment.Center;
|
||||||
|
|
||||||
|
// 6️⃣ Grid 기본 옵션
|
||||||
|
view.OptionsView.ColumnAutoWidth = false;
|
||||||
|
view.OptionsView.ShowGroupPanel = false;
|
||||||
|
view.OptionsBehavior.Editable = false; // History Grid → 읽기 전용 권장
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
view.EndUpdate();
|
||||||
|
grid.EndUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetHistoryColumnCaption(string fieldName)
|
||||||
|
{
|
||||||
|
string name = fieldName.ToLower();
|
||||||
|
|
||||||
|
if (name == "no") return "No";
|
||||||
|
if (name == "datetime") return "Date / Time";
|
||||||
|
if (name == "status") return "Status";
|
||||||
|
|
||||||
|
if (name == "warning") return "Warning Flags";
|
||||||
|
if (name == "protect") return "Protect Flags";
|
||||||
|
if (name == "error") return "Error Flags";
|
||||||
|
|
||||||
|
if (name == "voltage") return "Pack Voltage (V)";
|
||||||
|
if (name == "current") return "Pack Current (A)";
|
||||||
|
if (name == "soc") return "SOC (%)";
|
||||||
|
|
||||||
|
if (name == "pcb_t") return "PCB Temp (°C)";
|
||||||
|
if (name == "amb_t") return "Ambient Temp (°C)";
|
||||||
|
|
||||||
|
if (name.StartsWith("temp_"))
|
||||||
|
{
|
||||||
|
int idx = int.Parse(name.Substring(5));
|
||||||
|
return $"Temp {idx} (°C)";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name.StartsWith("cell_v_"))
|
||||||
|
{
|
||||||
|
int idx = int.Parse(name.Substring(7));
|
||||||
|
return $"Cell {idx} Voltage (V)";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 기본: 컬럼명 그대로 (Fallback)
|
||||||
|
return fieldName;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region PUBLIC FUNCTIONS
|
#region PUBLIC FUNCTIONS
|
||||||
private short[] ByteArrTo2Short(byte[] bytes)
|
public void RecvUartData(byte[] data)
|
||||||
{
|
{
|
||||||
short[] result = null;
|
if (InvokeRequired)
|
||||||
|
|
||||||
if (bytes != null)
|
|
||||||
{
|
{
|
||||||
int len = bytes[2];
|
BeginInvoke(new Action(() => RecvUartData(data)));
|
||||||
result = new short[len / 2];
|
return;
|
||||||
|
|
||||||
for (int i = 0; i < result.Length; i++)
|
|
||||||
{
|
|
||||||
result[i] = (short)((bytes[3 + (i * 2) + 0] << 8) + bytes[3 + (i * 2) + 1]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
|
||||||
public void RecvUardData(byte[] data)
|
|
||||||
{
|
|
||||||
rData = data;
|
rData = data;
|
||||||
|
|
||||||
if ((rData != null) && (rData.Length > 58))
|
LcGrResult.Text = $"Result ({rData.Length})";
|
||||||
|
|
||||||
|
if ((rData != null) && (rData.Length == recv_data_len))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
req_timeoutCount = 0;
|
||||||
|
|
||||||
DataRow hRow = BmsHistoryTable.NewRow();
|
DataRow hRow = BmsHistoryTable.NewRow();
|
||||||
|
|
||||||
short[] shorts = ByteArrTo2Short(data);
|
short[] shorts = csUtils.ByteArrTo2ShortSafe(data);
|
||||||
|
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
int yy, MM, dd, HH, mm, ss;
|
int yy, MM, dd, HH, mm, ss;
|
||||||
@@ -146,7 +345,13 @@ namespace LFP_Manager.Forms
|
|||||||
, ss
|
, ss
|
||||||
);
|
);
|
||||||
|
|
||||||
DateTime aDateTime = Convert.ToDateTime(stDateTime);
|
DateTime aDateTime;
|
||||||
|
|
||||||
|
if (MM < 1 || MM > 12 || dd < 1 || dd > 31 || HH > 23 || mm > 59 || ss > 59)
|
||||||
|
aDateTime = DateTime.MinValue; // 또는 DateTime.MinValue 넣기
|
||||||
|
else
|
||||||
|
aDateTime = Convert.ToDateTime(stDateTime);
|
||||||
|
|
||||||
hRow["datetime"] = aDateTime;
|
hRow["datetime"] = aDateTime;
|
||||||
|
|
||||||
pos = 2;
|
pos = 2;
|
||||||
@@ -154,22 +359,26 @@ namespace LFP_Manager.Forms
|
|||||||
hRow["warning"] = string.Format("{0:X4}", shorts[pos++]);
|
hRow["warning"] = string.Format("{0:X4}", shorts[pos++]);
|
||||||
hRow["protect"] = string.Format("{0:X4}", shorts[pos++]);
|
hRow["protect"] = string.Format("{0:X4}", shorts[pos++]);
|
||||||
hRow["error"] = string.Format("{0:X4}", shorts[pos++]);
|
hRow["error"] = string.Format("{0:X4}", shorts[pos++]);
|
||||||
hRow["voltage"] = string.Format("{0:0.00}", Convert.ToDouble(shorts[pos++]) / 100);
|
hRow["voltage"] = shorts[pos++] / 100m;
|
||||||
hRow["current"] = string.Format("{0:0.00}", Convert.ToDouble(shorts[pos++]) / 100);
|
hRow["current"] = shorts[pos++] / 100m;
|
||||||
hRow["SOC"] = string.Format("{0:0.0}", Convert.ToDouble(shorts[pos++]) / 1);
|
hRow["SOC"] = shorts[pos++] / 1m;
|
||||||
|
|
||||||
|
hRow["pcb_t"] = (byte)(shorts[pos] >> 8) / 1m;
|
||||||
|
hRow["amb_t"] = (byte)(shorts[pos] >> 0) / 1m;
|
||||||
|
pos++;
|
||||||
|
|
||||||
// Temperature
|
// Temperature
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < (temp_qty / 2); i++)
|
||||||
{
|
{
|
||||||
hRow[string.Format("temp_{0:00}", (i * 2) + 1)] = Convert.ToDouble((byte)(shorts[pos] >> 8));
|
hRow[string.Format("temp_{0:00}", (i * 2) + 1)] = Convert.ToDouble((byte)(shorts[pos] >> 8));
|
||||||
hRow[string.Format("temp_{0:00}", (i * 2) + 2)] = Convert.ToDouble((byte)(shorts[pos++] >> 0));
|
hRow[string.Format("temp_{0:00}", (i * 2) + 2)] = Convert.ToDouble((byte)(shorts[pos++] >> 0));
|
||||||
}
|
}
|
||||||
// Cell Voltage
|
// Cell Voltage
|
||||||
for (int i = 0; i < 16; i++)
|
for (int i = 0; i < cell_qty; i++)
|
||||||
{
|
{
|
||||||
hRow[string.Format("cell_v_{0:00}", i + 1)] = Convert.ToDouble(shorts[pos++]) / 1000;
|
hRow[string.Format("cell_v_{0:00}", i + 1)] = Convert.ToDecimal(shorts[pos++]) / 1000m;
|
||||||
}
|
}
|
||||||
hRow["SOH"] = string.Format("{0:0.0}", Convert.ToDouble(shorts[pos++]) / 1);
|
//hRow["SOH"] = shorts[pos++] / 1m;
|
||||||
|
|
||||||
BmsHistoryTable.Rows.Add(hRow);
|
BmsHistoryTable.Rows.Add(hRow);
|
||||||
}
|
}
|
||||||
@@ -178,8 +387,6 @@ namespace LFP_Manager.Forms
|
|||||||
MessageBox.Show(e.Message);
|
MessageBox.Show(e.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gvBmsHistory.BestFitColumns();
|
|
||||||
gvBmsHistory.ClearSelection();
|
|
||||||
|
|
||||||
hist_no++;
|
hist_no++;
|
||||||
curr_addr += 0x20;
|
curr_addr += 0x20;
|
||||||
@@ -212,9 +419,7 @@ namespace LFP_Manager.Forms
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stopReq = true;
|
StopAndFinish("User Stop Request");
|
||||||
//btnBmsHistoryReq.Text = "Request";
|
|
||||||
//TmrCheckReq.Enabled = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,7 +435,7 @@ namespace LFP_Manager.Forms
|
|||||||
sdata[2] = (byte)(addr >> 8); // Address H
|
sdata[2] = (byte)(addr >> 8); // Address H
|
||||||
sdata[3] = (byte)(addr >> 0); // Address L
|
sdata[3] = (byte)(addr >> 0); // Address L
|
||||||
sdata[4] = 0x00; // Number of Register H
|
sdata[4] = 0x00; // Number of Register H
|
||||||
sdata[5] = 0x1D; // Number of Register L
|
sdata[5] = 0x35; // Number of Register L
|
||||||
|
|
||||||
crc = csSerialCommFunction.GetCRC(sdata, 6);
|
crc = csSerialCommFunction.GetCRC(sdata, 6);
|
||||||
|
|
||||||
@@ -244,12 +449,29 @@ namespace LFP_Manager.Forms
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void StopAndFinish(string reason = null)
|
||||||
|
{
|
||||||
|
stopReq = true;
|
||||||
|
TmrCheckReq.Enabled = false;
|
||||||
|
btnBmsHistoryReq.Text = "Request";
|
||||||
|
|
||||||
|
req_timeoutCount = 0;
|
||||||
|
|
||||||
|
gvBmsHistory.BestFitColumns();
|
||||||
|
gvBmsHistory.ClearSelection();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(reason))
|
||||||
|
MessageBox.Show($"Finished: {reason}");
|
||||||
|
else
|
||||||
|
MessageBox.Show("Finished BMS History Read");
|
||||||
|
}
|
||||||
|
|
||||||
private void btnExportExcel_Click(object sender, EventArgs e)
|
private void btnExportExcel_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SaveFileDialog sDialog = new SaveFileDialog();
|
SaveFileDialog sDialog = new SaveFileDialog();
|
||||||
sDialog.Title = "Select save file";
|
sDialog.Title = "Select save file";
|
||||||
sDialog.DefaultExt = "xlsx";
|
sDialog.DefaultExt = "xlsx";
|
||||||
sDialog.Filter = "Excel files 2003 (*.xls)|*.xls|All files (*.*)|*.*";
|
sDialog.Filter = "Excel files (*.xlsx)|*.xlsx|All files (*.*)|*.*";
|
||||||
|
|
||||||
if (sDialog.ShowDialog() == DialogResult.OK)
|
if (sDialog.ShowDialog() == DialogResult.OK)
|
||||||
{
|
{
|
||||||
@@ -257,7 +479,10 @@ namespace LFP_Manager.Forms
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
csExcelExport.ExportToExcelExt(BmsHistoryTable, filename);
|
//csExcelExport.ExportToExcelExt(BmsHistoryTable, filename);
|
||||||
|
DataTable[] export = new DataTable[1];
|
||||||
|
export[0] = BmsHistoryTable;
|
||||||
|
csExcelFunction.ExportDgvWithClosedXml(filename, export);
|
||||||
|
|
||||||
MessageBox.Show("Complete Export Excel File", "Result", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
MessageBox.Show("Complete Export Excel File", "Result", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
}
|
}
|
||||||
@@ -308,14 +533,23 @@ namespace LFP_Manager.Forms
|
|||||||
{
|
{
|
||||||
DateTime nDateTime = ReqDateTime.AddSeconds(1);
|
DateTime nDateTime = ReqDateTime.AddSeconds(1);
|
||||||
|
|
||||||
if (nDateTime < DateTime.Now)
|
if (DateTime.Now - ReqDateTime > TimeSpan.FromSeconds(1))
|
||||||
{
|
{
|
||||||
TmrCheckReq.Enabled = false;
|
req_timeoutCount++;
|
||||||
|
|
||||||
MessageBox.Show("Finished BMS History Read", "Result", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
if (req_timeoutCount >= 3)
|
||||||
btnBmsHistoryReq.Text = "Request";
|
{
|
||||||
|
StopAndFinish("Read Finished");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region FORM EVENT
|
||||||
|
private void fmxHistory_Load(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
//SetGridColumnFormat();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,28 +124,28 @@
|
|||||||
<data name="fmxHistory.IconOptions.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
<data name="fmxHistory.IconOptions.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
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
|
||||||
YII=
|
YAAAAABJRU5ErkJggg==
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -274,13 +274,13 @@ namespace LFP_Manager.Forms
|
|||||||
this.Invoke(new MethodInvoker(delegate ()
|
this.Invoke(new MethodInvoker(delegate ()
|
||||||
{
|
{
|
||||||
FwUpdateForm?.RecvData(data);
|
FwUpdateForm?.RecvData(data);
|
||||||
HistoryForm?.RecvUardData(data);
|
HistoryForm?.RecvUartData(data);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FwUpdateForm?.RecvData(data);
|
FwUpdateForm?.RecvData(data);
|
||||||
HistoryForm?.RecvUardData(data);
|
HistoryForm?.RecvUartData(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
using System;
|
using ClosedXML.Excel;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.OleDb;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Data;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
using System.Data.OleDb;
|
|
||||||
|
|
||||||
namespace LFP_Manager.Function
|
namespace LFP_Manager.Function
|
||||||
{
|
{
|
||||||
public class csExcelFunction
|
public class csExcelFunction
|
||||||
{
|
{
|
||||||
|
#region EXCEL IMPORT / EXPORT
|
||||||
public static DataTable[] ExcelImport(string Ps_FileName, string[] sheetName)
|
public static DataTable[] ExcelImport(string Ps_FileName, string[] sheetName)
|
||||||
{
|
{
|
||||||
DataTable[] result = null;
|
DataTable[] result = null;
|
||||||
@@ -141,5 +144,209 @@ namespace LFP_Manager.Function
|
|||||||
connection.Dispose();
|
connection.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region EXCEL CLOSED XML IMPORT / EXPORT
|
||||||
|
|
||||||
|
private static readonly string[] IsoDateFormats = new string[]
|
||||||
|
{
|
||||||
|
"yyyy-MM-dd HH:mm:ss",
|
||||||
|
"yyyy-MM-ddTHH:mm:ss",
|
||||||
|
"yyyy-MM-ddTHH:mm:ss.fff",
|
||||||
|
"yyyy-MM-ddTHH:mm:ssZ",
|
||||||
|
"yyyy-MM-ddTHH:mm:ss.fffZ",
|
||||||
|
"yyyy-MM-dd"
|
||||||
|
};
|
||||||
|
|
||||||
|
public static bool ExportDgvWithClosedXml(string filePath, DataTable[] dt, bool overwiteFile = true)
|
||||||
|
{
|
||||||
|
if (dt == null || dt.Length == 0) return false;
|
||||||
|
|
||||||
|
// .xls로 들어오면 .xlsx로 변환하여 저장 경로 결정
|
||||||
|
var outputPath = EnsureXlsxPath(filePath);
|
||||||
|
|
||||||
|
// 저장 경로 폴더 보장
|
||||||
|
var dir = Path.GetDirectoryName(outputPath);
|
||||||
|
if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
|
||||||
|
Directory.CreateDirectory(dir);
|
||||||
|
|
||||||
|
if (File.Exists(outputPath))
|
||||||
|
{
|
||||||
|
if (overwiteFile) File.Delete(outputPath);
|
||||||
|
else throw new IOException("File already exists: " + outputPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var wb = new XLWorkbook()) // C# 7.3 호환
|
||||||
|
{
|
||||||
|
var nameCount = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
for (int i = 0; i < dt.Length; i++)
|
||||||
|
{
|
||||||
|
var table = dt[i];
|
||||||
|
if (table == null) continue;
|
||||||
|
|
||||||
|
string baseName = !string.IsNullOrWhiteSpace(table.TableName) ? table.TableName : ("Sheet" + (i + 1));
|
||||||
|
string sheetName = SanitizeSheetName(baseName);
|
||||||
|
|
||||||
|
// 중복 시트명 처리: _2, _3...
|
||||||
|
int dup;
|
||||||
|
if (nameCount.TryGetValue(sheetName, out dup))
|
||||||
|
{
|
||||||
|
dup++;
|
||||||
|
nameCount[sheetName] = dup;
|
||||||
|
string prefix = sheetName.Length > 28 ? sheetName.Substring(0, 28) : sheetName; // "_n" 자리 고려
|
||||||
|
sheetName = prefix + "_" + dup;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nameCount[sheetName] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataTable 전체를 시트로 추가 (헤더 포함)
|
||||||
|
var ws = wb.Worksheets.Add(table, sheetName);
|
||||||
|
|
||||||
|
// 자동 필터
|
||||||
|
var tbl = ws.Tables.FirstOrDefault();
|
||||||
|
if (tbl != null) tbl.ShowAutoFilter = true;
|
||||||
|
|
||||||
|
// ====== [추가] 문자열 날짜 → 진짜 DateTime으로 변환 ======
|
||||||
|
// 1) 날짜 컬럼 후보 탐지 (타입/컬럼명/샘플링)
|
||||||
|
bool[] isDateCol = new bool[table.Columns.Count];
|
||||||
|
for (int c = 0; c < table.Columns.Count; c++)
|
||||||
|
{
|
||||||
|
var colType = table.Columns[c].DataType;
|
||||||
|
if (colType == typeof(DateTime)) { isDateCol[c] = true; continue; }
|
||||||
|
|
||||||
|
if (colType == typeof(string))
|
||||||
|
{
|
||||||
|
string colName = table.Columns[c].ColumnName ?? "";
|
||||||
|
// 컬럼명 힌트
|
||||||
|
if (colName.IndexOf("date", StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
colName.IndexOf("time", StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
colName.EndsWith("_at", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
isDateCol[c] = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 값 샘플링 (최대 20개)
|
||||||
|
int seen = 0, hits = 0;
|
||||||
|
for (int r = 0; r < table.Rows.Count && seen < 20; r++)
|
||||||
|
{
|
||||||
|
var obj = table.Rows[r][c];
|
||||||
|
if (obj == null || obj == DBNull.Value) continue;
|
||||||
|
var s = obj.ToString();
|
||||||
|
if (string.IsNullOrWhiteSpace(s)) continue;
|
||||||
|
seen++;
|
||||||
|
DateTime tmp;
|
||||||
|
if (TryParseIsoDate(s, out tmp)) hits++;
|
||||||
|
}
|
||||||
|
if (seen > 0 && (hits * 1.0 / seen) >= 0.6) isDateCol[c] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) 열 서식 지정 + 각 셀 값 DateTime으로 재설정
|
||||||
|
for (int c = 0; c < table.Columns.Count; c++)
|
||||||
|
{
|
||||||
|
var col = ws.Column(c + 1);
|
||||||
|
Type t = table.Columns[c].DataType;
|
||||||
|
|
||||||
|
if (isDateCol[c])
|
||||||
|
{
|
||||||
|
// 열 서식(표시): 날짜/시간
|
||||||
|
col.Style.DateFormat.Format = "yyyy-MM-dd HH:mm:ss";
|
||||||
|
|
||||||
|
// 데이터 행(2행부터) 변환
|
||||||
|
int rowCount = table.Rows.Count;
|
||||||
|
for (int r = 0; r < rowCount; r++)
|
||||||
|
{
|
||||||
|
var cell = ws.Cell(r + 2, c + 1);
|
||||||
|
|
||||||
|
// 이미 DateTime 셀은 스킵
|
||||||
|
if (cell.DataType == ClosedXML.Excel.XLDataType.DateTime)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var s = cell.GetString();
|
||||||
|
if (string.IsNullOrWhiteSpace(s)) continue;
|
||||||
|
|
||||||
|
DateTime dtv;
|
||||||
|
if (TryParseIsoDate(s, out dtv))
|
||||||
|
{
|
||||||
|
cell.Value = dtv; // ✅ 진짜 날짜로 저장 (엑셀 DateTime)
|
||||||
|
// cell.Style.DateFormat.Format = "yyyy-MM-dd HH:mm:ss"; // per-cell 필요시
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 기존 숫자/텍스트 서식 유지
|
||||||
|
if (t == typeof(DateTime))
|
||||||
|
col.Style.DateFormat.Format = "yyyy-MM-dd HH:mm:ss";
|
||||||
|
else if (t == typeof(int) || t == typeof(long) || t == typeof(short) || t == typeof(byte))
|
||||||
|
col.Style.NumberFormat.Format = "0"; // 정수
|
||||||
|
else if (t == typeof(decimal) || t == typeof(float) || t == typeof(double))
|
||||||
|
col.Style.NumberFormat.Format = "General"; // 일반 숫자
|
||||||
|
else
|
||||||
|
col.Style.NumberFormat.Format = "@"; // 텍스트
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====== [추가 끝] ======
|
||||||
|
|
||||||
|
// 열 너비 자동 조정
|
||||||
|
ws.Columns().AdjustToContents();
|
||||||
|
}
|
||||||
|
wb.SaveAs(outputPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// 필요 시 로깅 추가
|
||||||
|
throw new Exception(ex.Message);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string EnsureXlsxPath(string filePath)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(filePath)) throw new ArgumentNullException(nameof(filePath));
|
||||||
|
var ext = Path.GetExtension(filePath);
|
||||||
|
if (!string.IsNullOrEmpty(ext) && ext.Equals(".xls", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return Path.ChangeExtension(filePath, ".xlsx");
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string SanitizeSheetName(string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(name)) return "Sheet1";
|
||||||
|
// Excel 금지문자: : \ / ? * [ ]
|
||||||
|
char[] invalid = { ':', '\\', '/', '?', '*', '[', ']' };
|
||||||
|
var arr = name.ToCharArray();
|
||||||
|
for (int i = 0; i < arr.Length; i++)
|
||||||
|
for (int j = 0; j < invalid.Length; j++)
|
||||||
|
if (arr[i] == invalid[j]) { arr[i] = '_'; break; }
|
||||||
|
|
||||||
|
var sanitized = new string(arr);
|
||||||
|
if (sanitized.Length > 31) sanitized = sanitized.Substring(0, 31);
|
||||||
|
if (string.IsNullOrWhiteSpace(sanitized)) sanitized = "Sheet1";
|
||||||
|
return sanitized;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryParseIsoDate(string s, out DateTime dt)
|
||||||
|
{
|
||||||
|
// 로컬 시간 가정(오프셋 보정 없음). DB 문자열이 UTC라면 AdjustToUniversal로 변경하세요.
|
||||||
|
return DateTime.TryParseExact(
|
||||||
|
s, IsoDateFormats,
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
|
DateTimeStyles.AssumeLocal,
|
||||||
|
out dt)
|
||||||
|
|| DateTime.TryParse(
|
||||||
|
s, CultureInfo.InvariantCulture,
|
||||||
|
DateTimeStyles.AssumeLocal,
|
||||||
|
out dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,12 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Accessibility" />
|
<Reference Include="Accessibility" />
|
||||||
|
<Reference Include="ClosedXML, Version=0.105.0.0, Culture=neutral, PublicKeyToken=fd1eb21b62ae805b, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\ClosedXML.0.105.0\lib\netstandard2.0\ClosedXML.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="ClosedXML.Parser, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1d5f7376574c51ec, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\ClosedXML.Parser.2.0.0\lib\netstandard2.0\ClosedXML.Parser.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="DevExpress.Charts.v22.2.Core, Version=22.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a">
|
<Reference Include="DevExpress.Charts.v22.2.Core, Version=22.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a">
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
@@ -119,12 +125,21 @@
|
|||||||
<Reference Include="DevExpress.XtraTreeList.v22.2, Version=22.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" />
|
<Reference Include="DevExpress.XtraTreeList.v22.2, Version=22.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" />
|
||||||
<Reference Include="DevExpress.XtraTreeMap.v22.2.UI, Version=22.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
|
<Reference Include="DevExpress.XtraTreeMap.v22.2.UI, Version=22.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
|
||||||
<Reference Include="DevExpress.XtraTreeMap.v22.2, Version=22.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
|
<Reference Include="DevExpress.XtraTreeMap.v22.2, Version=22.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
|
||||||
|
<Reference Include="DocumentFormat.OpenXml, Version=3.1.1.0, Culture=neutral, PublicKeyToken=8fb06cb64d019a17, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\DocumentFormat.OpenXml.3.1.1\lib\net46\DocumentFormat.OpenXml.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="DocumentFormat.OpenXml.Framework, Version=3.1.1.0, Culture=neutral, PublicKeyToken=8fb06cb64d019a17, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\DocumentFormat.OpenXml.Framework.3.1.1\lib\net46\DocumentFormat.OpenXml.Framework.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
<Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\EntityFramework.6.5.1\lib\net45\EntityFramework.dll</HintPath>
|
<HintPath>..\packages\EntityFramework.6.5.1\lib\net45\EntityFramework.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
<Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\EntityFramework.6.5.1\lib\net45\EntityFramework.SqlServer.dll</HintPath>
|
<HintPath>..\packages\EntityFramework.6.5.1\lib\net45\EntityFramework.SqlServer.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="ExcelNumberFormat, Version=1.1.0.0, Culture=neutral, PublicKeyToken=23c6f5d73be07eca, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\ExcelNumberFormat.1.1.0\lib\net20\ExcelNumberFormat.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="IPAddressControlLib">
|
<Reference Include="IPAddressControlLib">
|
||||||
<HintPath>dll\IPAddressControlLib.dll</HintPath>
|
<HintPath>dll\IPAddressControlLib.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
@@ -134,6 +149,9 @@
|
|||||||
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.5, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.5, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.9.0.5\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
|
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.9.0.5\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Bcl.HashCode, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Microsoft.Bcl.HashCode.1.1.1\lib\net461\Microsoft.Bcl.HashCode.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="Microsoft.Extensions.Configuration, Version=9.0.0.5, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
<Reference Include="Microsoft.Extensions.Configuration, Version=9.0.0.5, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\Microsoft.Extensions.Configuration.9.0.5\lib\net462\Microsoft.Extensions.Configuration.dll</HintPath>
|
<HintPath>..\packages\Microsoft.Extensions.Configuration.9.0.5\lib\net462\Microsoft.Extensions.Configuration.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
@@ -173,6 +191,12 @@
|
|||||||
<Reference Include="Microsoft.Extensions.Primitives, Version=9.0.0.5, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
<Reference Include="Microsoft.Extensions.Primitives, Version=9.0.0.5, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\Microsoft.Extensions.Primitives.9.0.5\lib\net462\Microsoft.Extensions.Primitives.dll</HintPath>
|
<HintPath>..\packages\Microsoft.Extensions.Primitives.9.0.5\lib\net462\Microsoft.Extensions.Primitives.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="RBush, Version=4.0.0.0, Culture=neutral, PublicKeyToken=c77e27b81f4d0187, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\RBush.Signed.4.0.0\lib\net47\RBush.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="SixLabors.Fonts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d998eea7b14cab13, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\SixLabors.Fonts.1.0.0\lib\netstandard2.0\SixLabors.Fonts.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="SnmpSharpNet, Version=0.9.4.0, Culture=neutral, PublicKeyToken=b2181aa3b9571feb, processorArchitecture=MSIL">
|
<Reference Include="SnmpSharpNet, Version=0.9.4.0, Culture=neutral, PublicKeyToken=b2181aa3b9571feb, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>dll\SnmpSharpNet.dll</HintPath>
|
<HintPath>dll\SnmpSharpNet.dll</HintPath>
|
||||||
@@ -242,6 +266,7 @@
|
|||||||
<Reference Include="Tftp.Net">
|
<Reference Include="Tftp.Net">
|
||||||
<HintPath>dll\Tftp.Net.dll</HintPath>
|
<HintPath>dll\Tftp.Net.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="WindowsBase" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Controls\UcAntiTheftControl.cs">
|
<Compile Include="Controls\UcAntiTheftControl.cs">
|
||||||
|
|||||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
|||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("1.0.1.7")]
|
[assembly: AssemblyVersion("1.0.1.8")]
|
||||||
[assembly: AssemblyFileVersion("1.0.1.7")]
|
[assembly: AssemblyFileVersion("1.0.1.8")]
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.IO.Ports;
|
using System.IO.Ports;
|
||||||
using System.Windows.Forms;
|
|
||||||
using LFP_Manager.DataStructure;
|
using LFP_Manager.DataStructure;
|
||||||
using LFP_Manager.Function;
|
using LFP_Manager.Function;
|
||||||
using LFP_Manager.Utils;
|
using LFP_Manager.Utils;
|
||||||
@@ -460,10 +461,11 @@ namespace LFP_Manager.Threads
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: // Firmware update packet
|
case 2: // Firmware update packet
|
||||||
if (OnPrint != null)
|
SafeRaiseOnPrint(csLog.trx_data_print(_readBuffer, _readPosition, 1));
|
||||||
{
|
//if (OnPrint != null)
|
||||||
OnPrint(this, csLog.trx_data_print(_readBuffer, _readPosition, 1));
|
//{
|
||||||
}
|
// OnPrint(this, csLog.trx_data_print(_readBuffer, _readPosition, 1));
|
||||||
|
//}
|
||||||
_timeoutCount = 0;
|
_timeoutCount = 0;
|
||||||
ProcessFirmwareResponse();
|
ProcessFirmwareResponse();
|
||||||
break;
|
break;
|
||||||
@@ -702,5 +704,22 @@ namespace LFP_Manager.Threads
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region SAFE CALLS
|
||||||
|
private void SafeRaiseOnPrint(string msg)
|
||||||
|
{
|
||||||
|
var handler = OnPrint; // 복사
|
||||||
|
if (handler == null) return;
|
||||||
|
|
||||||
|
// 비차단 + 예외격리: 핸들러를 ThreadPool에서 실행
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
try { handler.Invoke(this, msg); }
|
||||||
|
catch (Exception ex) { /* 내부 로깅 */ }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,11 +34,6 @@ namespace LFP_Manager.Threads
|
|||||||
|
|
||||||
private ushort ExtReqRegAddr = 0x0000;
|
private ushort ExtReqRegAddr = 0x0000;
|
||||||
|
|
||||||
private ushort WriteRegAddr = 0x0000; //Byul Init 0x0000
|
|
||||||
private short WriteCoilRegData = 0;
|
|
||||||
private byte[] WriteRegData;
|
|
||||||
private short WriteParamRegData;
|
|
||||||
|
|
||||||
private TUartTxBuff UartTxBuff;
|
private TUartTxBuff UartTxBuff;
|
||||||
|
|
||||||
public event UartDataUpdateRS485 OnUpdate = null;
|
public event UartDataUpdateRS485 OnUpdate = null;
|
||||||
@@ -139,13 +134,13 @@ namespace LFP_Manager.Threads
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// 무시하지 말고 로그 출력
|
// 무시하지 말고 로그 출력
|
||||||
OnPrint?.Invoke(this, $"DataRecv Error: {ex.Message}");
|
SafeRaiseOnPrint($"DataRecv Error: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sErrorReceived(object sender, System.IO.Ports.SerialErrorReceivedEventArgs e)
|
private void sErrorReceived(object sender, System.IO.Ports.SerialErrorReceivedEventArgs e)
|
||||||
{
|
{
|
||||||
OnPrint?.Invoke(this, $"Serial Error: {e.EventType}");
|
SafeRaiseOnPrint($"Serial Error: {e.EventType}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sPinChanged(object sender, System.IO.Ports.SerialPinChangedEventArgs e)
|
private void sPinChanged(object sender, System.IO.Ports.SerialPinChangedEventArgs e)
|
||||||
@@ -186,7 +181,8 @@ namespace LFP_Manager.Threads
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
OnPrint?.Invoke(this, $"Error Open - {ex.Message}");
|
SafeRaiseOnPrint($"Error Open - {ex.Message}");
|
||||||
|
|
||||||
if (sPort != null)
|
if (sPort != null)
|
||||||
{
|
{
|
||||||
try { sPort.Dispose(); } catch { }
|
try { sPort.Dispose(); } catch { }
|
||||||
@@ -220,7 +216,7 @@ namespace LFP_Manager.Threads
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
OnPrint?.Invoke(this, $"Port Close Fail: {ex.Message}");
|
SafeRaiseOnPrint($"Port Close Fail: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,8 +241,6 @@ namespace LFP_Manager.Threads
|
|||||||
|
|
||||||
public void SetWriteReg(ushort WriteAddr, byte[] WriteData, bool ReplyFlag, int type)
|
public void SetWriteReg(ushort WriteAddr, byte[] WriteData, bool ReplyFlag, int type)
|
||||||
{
|
{
|
||||||
WriteRegAddr = WriteAddr;
|
|
||||||
|
|
||||||
var uartTRxData = new TUartTRxData
|
var uartTRxData = new TUartTRxData
|
||||||
{
|
{
|
||||||
type = type,
|
type = type,
|
||||||
@@ -448,7 +442,7 @@ namespace LFP_Manager.Threads
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
OnPrint?.Invoke(this, $"uartCommThread Start");
|
SafeRaiseOnPrint($"uartCommThread Start");
|
||||||
|
|
||||||
int RecvTimeout = (Config != null) ? Config.RecvWaitTime : 1500;
|
int RecvTimeout = (Config != null) ? Config.RecvWaitTime : 1500;
|
||||||
int getData = 0;
|
int getData = 0;
|
||||||
@@ -472,11 +466,11 @@ namespace LFP_Manager.Threads
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
sPort.Write(txData, 0, txData.Length);
|
sPort.Write(txData, 0, txData.Length);
|
||||||
OnPrint?.Invoke(this, csLog.trx_data_print(txData, txData.Length, 0));
|
SafeRaiseOnPrint(csLog.trx_data_print(txData, txData.Length, 0));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
OnPrint?.Invoke(this, $"Write error: {ex.Message}");
|
SafeRaiseOnPrint($"Write error: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -519,7 +513,7 @@ namespace LFP_Manager.Threads
|
|||||||
case 0: // Need more data
|
case 0: // Need more data
|
||||||
break;
|
break;
|
||||||
case 1: // Packet OK, no error
|
case 1: // Packet OK, no error
|
||||||
OnPrint?.Invoke(this, csLog.trx_data_print(ReadBuf, rPosition, 1));
|
SafeRaiseOnPrint(csLog.trx_data_print(ReadBuf, rPosition, 1));
|
||||||
|
|
||||||
TimeOutCount[ModuleID - 1] = 0;
|
TimeOutCount[ModuleID - 1] = 0;
|
||||||
|
|
||||||
@@ -535,7 +529,7 @@ namespace LFP_Manager.Threads
|
|||||||
Thread.Sleep(5);
|
Thread.Sleep(5);
|
||||||
goto StartSend;
|
goto StartSend;
|
||||||
case 2: // Fw Update Packet OK
|
case 2: // Fw Update Packet OK
|
||||||
OnPrint?.Invoke(this, csLog.trx_data_print(ReadBuf, rPosition, 1));
|
SafeRaiseOnPrint(csLog.trx_data_print(ReadBuf, rPosition, 1));
|
||||||
|
|
||||||
TimeOutCount[ModuleID - 1] = 0;
|
TimeOutCount[ModuleID - 1] = 0;
|
||||||
rFlag = false;
|
rFlag = false;
|
||||||
@@ -564,7 +558,8 @@ namespace LFP_Manager.Threads
|
|||||||
|
|
||||||
if (rPosition > 0)
|
if (rPosition > 0)
|
||||||
{
|
{
|
||||||
OnPrint?.Invoke(this, csLog.trx_data_print(ReadBuf, rPosition, 1));
|
SafeRaiseOnPrint(csLog.trx_data_print(ReadBuf, rPosition, 1));
|
||||||
|
|
||||||
Thread.Sleep(1);
|
Thread.Sleep(1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -595,15 +590,31 @@ namespace LFP_Manager.Threads
|
|||||||
catch (OperationCanceledException) { }
|
catch (OperationCanceledException) { }
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
OnPrint?.Invoke(this, $"Comm thread error: {ex.Message}");
|
SafeRaiseOnPrint($"Comm thread error: {ex.Message}");
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
SerialPortThreadEnd = true;
|
SerialPortThreadEnd = true;
|
||||||
OnPrint?.Invoke(this, $"uartCommThread End");
|
SafeRaiseOnPrint($"uartCommThread End");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region SAFE CALLS
|
||||||
|
private void SafeRaiseOnPrint(string msg)
|
||||||
|
{
|
||||||
|
var handler = OnPrint; // 복사
|
||||||
|
if (handler == null) return;
|
||||||
|
|
||||||
|
// 비차단 + 예외격리: 핸들러를 ThreadPool에서 실행
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
try { handler.Invoke(this, msg); }
|
||||||
|
catch (Exception ex) { /* 내부 로깅 */ }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -208,6 +208,29 @@ namespace LFP_Manager.Utils
|
|||||||
byte[] StrByte = Encoding.UTF8.GetBytes(str); return StrByte;
|
byte[] StrByte = Encoding.UTF8.GetBytes(str); return StrByte;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static short[] ByteArrTo2ShortSafe(byte[] bytes)
|
||||||
|
{
|
||||||
|
if (bytes == null || bytes.Length < 5) return null; // addr+func+len+crc 최소
|
||||||
|
int byteCount = bytes[2];
|
||||||
|
|
||||||
|
// byteCount가 짝수인지 확인(레지스터는 2바이트 단위)
|
||||||
|
if ((byteCount % 2) != 0) return null;
|
||||||
|
|
||||||
|
// 데이터 영역 + CRC(2byte)까지 길이 확인
|
||||||
|
int minLen = 3 + byteCount + 2;
|
||||||
|
if (bytes.Length < minLen) return null;
|
||||||
|
|
||||||
|
int regCount = byteCount / 2;
|
||||||
|
var result = new short[regCount];
|
||||||
|
|
||||||
|
for (int i = 0; i < regCount; i++)
|
||||||
|
{
|
||||||
|
int idx = 3 + i * 2;
|
||||||
|
result[i] = (short)((bytes[idx] << 8) | bytes[idx + 1]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
#region OPERATING WARNING FUCTION
|
#region OPERATING WARNING FUCTION
|
||||||
|
|
||||||
public static bool BitCheck(short rData, int pos)
|
public static bool BitCheck(short rData, int pos)
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
|
<package id="ClosedXML" version="0.105.0" targetFramework="net48" />
|
||||||
|
<package id="ClosedXML.Parser" version="2.0.0" targetFramework="net48" />
|
||||||
|
<package id="DocumentFormat.OpenXml" version="3.1.1" targetFramework="net48" />
|
||||||
|
<package id="DocumentFormat.OpenXml.Framework" version="3.1.1" targetFramework="net48" />
|
||||||
<package id="EntityFramework" version="6.5.1" targetFramework="net48" />
|
<package id="EntityFramework" version="6.5.1" targetFramework="net48" />
|
||||||
|
<package id="ExcelNumberFormat" version="1.1.0" targetFramework="net48" />
|
||||||
<package id="Microsoft.Bcl.AsyncInterfaces" version="9.0.5" targetFramework="net48" />
|
<package id="Microsoft.Bcl.AsyncInterfaces" version="9.0.5" targetFramework="net48" />
|
||||||
|
<package id="Microsoft.Bcl.HashCode" version="1.1.1" targetFramework="net48" />
|
||||||
<package id="Microsoft.Extensions.Configuration" version="9.0.5" targetFramework="net48" />
|
<package id="Microsoft.Extensions.Configuration" version="9.0.5" targetFramework="net48" />
|
||||||
<package id="Microsoft.Extensions.Configuration.Abstractions" version="9.0.5" targetFramework="net48" />
|
<package id="Microsoft.Extensions.Configuration.Abstractions" version="9.0.5" targetFramework="net48" />
|
||||||
<package id="Microsoft.Extensions.Configuration.Binder" version="9.0.5" targetFramework="net48" />
|
<package id="Microsoft.Extensions.Configuration.Binder" version="9.0.5" targetFramework="net48" />
|
||||||
@@ -15,6 +21,8 @@
|
|||||||
<package id="Microsoft.Extensions.Options" version="9.0.5" targetFramework="net48" />
|
<package id="Microsoft.Extensions.Options" version="9.0.5" targetFramework="net48" />
|
||||||
<package id="Microsoft.Extensions.Options.ConfigurationExtensions" version="9.0.5" targetFramework="net48" />
|
<package id="Microsoft.Extensions.Options.ConfigurationExtensions" version="9.0.5" targetFramework="net48" />
|
||||||
<package id="Microsoft.Extensions.Primitives" version="9.0.5" targetFramework="net48" />
|
<package id="Microsoft.Extensions.Primitives" version="9.0.5" targetFramework="net48" />
|
||||||
|
<package id="RBush.Signed" version="4.0.0" targetFramework="net48" />
|
||||||
|
<package id="SixLabors.Fonts" version="1.0.0" targetFramework="net48" />
|
||||||
<package id="SQLite" version="3.13.0" targetFramework="net48" />
|
<package id="SQLite" version="3.13.0" targetFramework="net48" />
|
||||||
<package id="Stub.System.Data.SQLite.Core.NetFramework" version="1.0.119.0" targetFramework="net48" />
|
<package id="Stub.System.Data.SQLite.Core.NetFramework" version="1.0.119.0" targetFramework="net48" />
|
||||||
<package id="System.Buffers" version="4.6.1" targetFramework="net48" />
|
<package id="System.Buffers" version="4.6.1" targetFramework="net48" />
|
||||||
|
|||||||
Reference in New Issue
Block a user