Files
DT_BR_GUI/LFP_Manager/Controls/ucCalibration.cs
2025-12-17 12:40:51 +09:00

464 lines
15 KiB
C#

using DevExpress.XtraLayout;
using LFP_Manager.DataStructure;
using LFP_Manager.Utils;
using System;
using System.Globalization;
using System.Windows.Forms;
namespace LFP_Manager.Controls
{
public partial class ucCalibration : DevExpress.XtraEditors.XtraUserControl
{
#region DELEGATE
public delegate void setCalibUpdate(object sender);
public delegate void setCalibCommand(int mode, int index, int flag, ref DeviceParamData aParm, ref DeviceCalibration aCalib);
public delegate Int32 getBattData(int item, int cno);
#endregion
#region ENUMS
private enum ControlLevel
{
User = 0,
Technician = 1,
Engineer = 2,
Master = 3
}
private enum CommandMode
{
SetCapacity = 15,
SetChargeMode = 16,
SetDateTime = 17,
SetAntiTheft = 18,
ClearAntiTheft = 19,
SetRS485Timeout = 20,
SetBalanceVoltage = 21,
SetBalanceDiff = 22
}
#endregion
#region VARIABLES
const int CALC_INDEX = 6;
CommConfig Config;
DeviceSystemData SystemData;
DeviceCalibration rCalib;
DeviceCalibration wCalib;
DeviceParamData rParam;
public event setCalibCommand OnCommand = null;
int wFlag = 0;
int dFlag;
int PasswordResult;
#endregion
#region CONSTRUCTORS
// Battery No:
// 0: No 1,3,5,7,9,11,13,15 ODD
// 1: No 2,4,6,8,10,12,14 Even
public ucCalibration()
{
InitializeComponent();
ComponentLoad();
Config = new CommConfig();
dFlag = 0;
}
private void ComponentLoad()
{
CbNewChaMode.Clear();
for (int i = 0; i < csConstData.SystemInfo.CHG_MODE.Length; i++)
{
CbNewChaMode.Properties.Items.Add(csConstData.SystemInfo.CHG_MODE[i]);
}
teNewCapacity.KeyPress += TextBox_KeyPress;
teNewSoc.KeyPress += TextBox_KeyPress;
TeCommTimeoutNew.KeyPress += TextBox_KeyPress;
TeChgModeValueNew.KeyPress += TextBox_KeyPress2;
}
#endregion
#region EXT EVENT FUNCTION
private void OnCommnadEvent(int mode, int index, int flag, ref DeviceParamData aParam, ref DeviceCalibration aCalib)
{
OnCommand?.Invoke(mode, index, flag, ref aParam, ref aCalib);
}
#endregion
#region PUBLIC FUCTIONS
public void UpdateConfig(CommConfig aConfig)
{
Config = aConfig;
}
public void UpdateData(DeviceSystemData aSystemData, DeviceCalibration aCalib)
{
SystemData = aSystemData;
rCalib = aCalib;
DisplayCalib();
UpdateNewCalib();
}
private void UpdateNewCalib()
{
if (SystemData != null)
{
if (wFlag == 0)
{
teNewCapacity.Text = teCurrCapacity.Text;
teNewSoc.Text = teCurrSoc.Text;
wFlag = 1;
}
}
}
#endregion
#region DISPLAY DATA
private void DisplayCalib()
{
if (SystemData != null)
{
teCurrCapacity.Text = string.Format("{0}", SystemData.ValueData.designedCapacity / 10);
teCurrSoc.Text = string.Format("{0}", SystemData.ValueData.rSOC / 10);
int mode = SystemData.CalibrationData.ChaMode.Mode;
int idx = MapChaModeToComboIndex(mode);
if (idx >= 0 && idx < csConstData.SystemInfo.CHG_MODE.Length)
TeChaMode.Text = csConstData.SystemInfo.CHG_MODE[idx];
else
TeChaMode.Text = string.Format(CultureInfo.InvariantCulture, "UNKNOWN({0})", mode);
TeChgModeValueCurr.Text = string.Format("{0:0.00}", Convert.ToDouble(SystemData.CalibrationData.ChaMode.Value) / 100);
TeCurrDateTime.Text = SystemData.BmsDateTime.DateTimeStr;
// Anti-Theft Data Display
if (SystemData.CalibrationData.AntiTheft.GyroScope == 0)
{
TeAntiTheftGyroCurr.Text = "DISABLE";
}
else
{
TeAntiTheftGyroCurr.Text = "ENABLE";
}
TeSensitive.Text = string.Format("{0}", SystemData.CalibrationData.AntiTheft.GyroScope);
// Anti-Theft - RS-485 Comm. Timeout
TeCommTimeout.Text = string.Format("{0}", SystemData.CalibrationData.AntiTheft.Comm);
if (dFlag == 0)
{
CbNewChaMode.SelectedIndex = 1;
CbNewChaMode.SelectedIndex = SystemData.CalibrationData.ChaMode.Mode;
TeChgModeValueNew.Text = TeChgModeValueCurr.Text;
dFlag = 1;
}
}
}
#endregion
#region BUTTON EVENT
private void TextBox_KeyPress(object sender, KeyPressEventArgs e)
{
csUtils.TypingOnlyNumber(sender, e, false, false);
}
private void TextBox_KeyPress2(object sender, KeyPressEventArgs e)
{
csUtils.TypingOnlyNumber(sender, e, true, false);
}
private void btnCapacitySet_Click(object sender, EventArgs e)
{
try
{
if (!ValidateNumericInput(teNewCapacity.Text, "Capacity") ||
!ValidateNumericInput(teNewSoc.Text, "SOC"))
{
return;
}
wCalib = rCalib.DeepCopy();
wCalib.CapCalib.DesignCapacity = Convert.ToInt32(teNewCapacity.Text) * 10;
wCalib.CapCalib.SocValue = Convert.ToInt32(teNewSoc.Text);
OnCommnadEvent((int)CommandMode.SetCapacity, CALC_INDEX, 1, ref rParam, ref wCalib);
}
catch (Exception ex)
{
ShowError($"Failed to set capacity: {ex.Message}");
}
}
private void BtnChaModeSet_Click(object sender, EventArgs e)
{
try
{
if (string.IsNullOrEmpty(CbNewChaMode.Text))
{
ShowError("Please select a charge mode");
return;
}
if (CbNewChaMode.SelectedIndex > 1 &&
!ValidateNumericInput(TeChgModeValueNew.Text, "Charge Mode Value"))
{
return;
}
wCalib = rCalib.DeepCopy();
wCalib.ChaMode.Mode = CbNewChaMode.SelectedIndex;
wCalib.ChaMode.Value = (int)(Convert.ToDouble(TeChgModeValueNew.Text) * 100);
OnCommnadEvent((int)CommandMode.SetChargeMode, CALC_INDEX, 1, ref rParam, ref wCalib);
}
catch (Exception ex)
{
ShowError($"Failed to set charge mode: {ex.Message}");
}
}
private void BtnBmsDateTimeSet_Click(object sender, EventArgs e)
{
try
{
if (string.IsNullOrEmpty(TeNewDateTime.Text))
{
ShowError("Please enter a date/time value");
return;
}
DateTime dateTime = Convert.ToDateTime(TeNewDateTime.Text);
int iDateTime = CalculateDateTimeValue(dateTime);
wCalib = rCalib.DeepCopy();
wCalib.BmsDateTime.sValue[0] = (short)(iDateTime >> 16);
wCalib.BmsDateTime.sValue[1] = (short)(iDateTime >> 0);
OnCommnadEvent((int)CommandMode.SetDateTime, CALC_INDEX, 1, ref rParam, ref wCalib);
}
catch (Exception ex)
{
ShowError($"Failed to set date/time: {ex.Message}");
}
}
private int CalculateDateTimeValue(DateTime dateTime)
{
return ((dateTime.Year - 2000) << 26)
| (dateTime.Month << 22)
| (dateTime.Day << 17)
| (dateTime.Hour << 12)
| (dateTime.Minute << 6)
| (dateTime.Second << 0);
}
private void BtnGetCurrTime_Click(object sender, EventArgs e)
{
TeNewDateTime.Text = string.Format("{0:yyyy-MM-dd HH:mm:ss}", DateTime.Now);
}
private void BtnClearAntiTheftProtect_Click(object sender, EventArgs e)
{
wCalib = rCalib.DeepCopy();
wCalib.AntiTheft.GyroScope = Config.GyroSensitive;
OnCommnadEvent(19, CALC_INDEX, 1, ref rParam, ref wCalib);
}
private void PassWordResultProc(int result)
{
PasswordResult = result;
}
private void BtnAntiTheftEnable_Click(object sender, EventArgs e)
{
wCalib = rCalib.DeepCopy();
wCalib.AntiTheft.GyroScope = Config.GyroSensitive;
OnCommnadEvent(18, CALC_INDEX, 1, ref rParam, ref wCalib);
}
private void BtnAntiTheftDisable_Click(object sender, EventArgs e)
{
wCalib = rCalib.DeepCopy();
wCalib.AntiTheft.GyroScope = 0;
OnCommnadEvent(18, CALC_INDEX, 1, ref rParam, ref wCalib);
}
private void BtnRS485TimeoutSet_Click(object sender, EventArgs e)
{
string stTimeout = TeCommTimeoutNew.Text;
int Timeout = 0;
try
{
Timeout = Convert.ToInt32(stTimeout);
}
catch (Exception)
{
MessageBox.Show("Timeout data Format Error", "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
wCalib = rCalib.DeepCopy();
wCalib.AntiTheft.Comm = Timeout;
OnCommnadEvent(20, CALC_INDEX, 1, ref rParam, ref wCalib);
}
#endregion
#region COMPONENT EVENT
private void CbNewChaMode_SelectedIndexChanged(object sender, EventArgs e)
{
switch (CbNewChaMode.SelectedIndex)
{
case 0:
TeChgModeValueNew.Enabled = false;
break;
case 1:
TeChgModeValueNew.Enabled = false;
break;
case 2:
TeChgModeValueNew.Enabled = true;
break;
case 3:
TeChgModeValueNew.Enabled = true;
break;
case 4:
TeChgModeValueNew.Enabled = true;
break;
default:
TeChgModeValueNew.Enabled = false;
break;
}
}
#endregion
#region FORM EVENT
private void ucCalibration_Load(object sender, EventArgs e)
{
CalibConfig_ReLoad();
}
private void CalibConfig_ReLoad()
{
var level = (ControlLevel)Config.ControlLevel;
btnCapacitySet.Enabled = level == ControlLevel.Master;
BtnChaModeSet.Enabled = level >= ControlLevel.Engineer;
BtnBmsDateTimeSet.Enabled = level >= ControlLevel.Engineer;
BtnClearAntiTheftProtect.Enabled = level >= ControlLevel.Technician;
BtnAntiTheftEnable.Enabled = level >= ControlLevel.Engineer;
BtnAntiTheftDisable.Enabled = level >= ControlLevel.Engineer;
BtnRS485TimeoutSet.Enabled = level >= ControlLevel.Technician;
}
#endregion
#region VALIDATION METHODS
private bool ValidateNumericInput(string input, string fieldName)
{
if (string.IsNullOrEmpty(input))
{
ShowError($"Please enter a value for {fieldName}");
return false;
}
if (!int.TryParse(input, out _))
{
ShowError($"Invalid numeric value for {fieldName}");
return false;
}
return true;
}
private void ShowError(string message)
{
MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
#endregion
#region HELPER FUNCTIONS
// Charging Mode 매핑: 콤보 인덱스 <-> ChaMode.Mode
private static bool TryMapIndexToChaMode(int comboIndex, out int mode)
{
// UI: 0=CC,1=CV,2=CC-CV(x),3=Time(x),4=Power(x) (예시)
// 장비: 0,1,2,4,8 로 매핑
switch (comboIndex)
{
case 0: mode = 0; return true;
case 1: mode = 1; return true;
case 2: mode = 2; return true;
case 3: mode = 4; return true;
case 4: mode = 8; return true;
default: mode = -1; return false;
}
}
private static int MapChaModeToComboIndex(int mode)
{
switch (mode)
{
case 0: return 0;
case 1: return 1;
case 2: return 2;
case 4: return 3;
case 8: return 4;
default: return -1;
}
}
private static bool TryParseDouble(string text, out double value)
{
return double.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out value);
}
private static string ToInvStr(double v, string fmt) =>
v.ToString(fmt, CultureInfo.InvariantCulture);
// BMS DateTime 비트 인코딩 (검증 포함)
private static bool TryEncodeBmsDateTime(DateTime dt, out short hi, out short lo, out string error)
{
error = null;
int year = dt.Year;
if (year < 2000 || year > 2063) { error = "Year must be 2000~2063"; hi = lo = 0; return false; }
int y = year - 2000;
int m = dt.Month; if (m < 1 || m > 12) { error = "Month out of range"; hi = lo = 0; return false; }
int d = dt.Day; if (d < 1 || d > 31) { error = "Day out of range"; hi = lo = 0; return false; }
int hh = dt.Hour; if (hh < 0 || hh > 23) { error = "Hour out of range"; hi = lo = 0; return false; }
int mm = dt.Minute; if (mm < 0 || mm > 59) { error = "Minute out of range"; hi = lo = 0; return false; }
int ss = dt.Second; if (ss < 0 || ss > 59) { error = "Second out of range"; hi = lo = 0; return false; }
int packed = (y << 26) | (m << 22) | (d << 17) | (hh << 12) | (mm << 6) | ss;
hi = (short)(packed >> 16);
lo = (short)(packed & 0xFFFF);
return true;
}
#endregion
}
}