2078 lines
88 KiB
C#
2078 lines
88 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Data;
|
|
using System.Drawing;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
using Logic.ProductionToProductMapper.Cordonel;
|
|
using Logic.ProductionToProductMapper.Files.Fw;
|
|
using Newtonsoft.Json;
|
|
using NLog;
|
|
using Xylem.Common.CommonCore.Consts;
|
|
using Xylem.Common.CommonCore.ThreadWatcher;
|
|
using Xylem.Common.Cryptology.Security;
|
|
using Xylem.Common.Utils.AssemblyLoader;
|
|
using Xylem.Common.Utils.Crc16Ccitt;
|
|
using Xylem.Common.Utils.Logging;
|
|
using Xylem.Common.Utils.DateTimeServer;
|
|
using Xylem.Common.Utils.FileIo;
|
|
using Xylem.Common.Utils.UiLanguageControl;
|
|
using Xylem.Common.Utils.UiInvoker;
|
|
using Xylem.ServiceFwUpdate.Common.FwUpdateConfig.Consts;
|
|
using Xylem.ServiceFwUpdate.Common.FwUpdateDb;
|
|
using Xylem.ServiceFwUpdate.Common.FwUpdateSafe;
|
|
using Xylem.ServiceFwUpdate.Common.FwUpdateSafe.Consts;
|
|
using Xylem.ServiceFwUpdate.Ui.FwUpdateLoader.Const;
|
|
using Xylem.ServiceFwUpdate.Ui.FwUpdateLoader.Properties;
|
|
|
|
namespace Xylem.ServiceFwUpdate.Ui.FwUpdateLoader
|
|
{
|
|
/// <summary>
|
|
/// Service firmware update loader main form.
|
|
/// </summary>
|
|
/// <remarks date="2020-Nov-30" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
[Serializable]
|
|
public partial class FrmFwUpdateLoader : Form
|
|
{
|
|
#region ------------------------------------------ Variables --------------------------------------------------
|
|
|
|
//private static readonly Color ColorDefault = Color.Black;
|
|
private static readonly Color ColorSuccess = Color.Green;
|
|
private static readonly Color ColorProcessFailed = Color.Red;
|
|
private static readonly Color ColorProcessRequired = Color.Blue;
|
|
private static readonly Color ColorOngoingProcess = Color.Blue;
|
|
private static readonly Color ColorUnknownStatus = Color.Gray;
|
|
private const String SuccessSign = @"✔";
|
|
private const String FailedSign = @"✘";
|
|
private const String WebApiTimeout = "Web API Timeout";
|
|
|
|
private readonly CancellationTokenSource _processToken = new CancellationTokenSource();
|
|
private readonly Thread _fwUpdateLoaderThread;
|
|
private AssemblyLoader _asmLoader;
|
|
private DataTable _dataTablePcbIds;
|
|
private String _backupSafeNameForLanguageChange;
|
|
|
|
// actual process state
|
|
private ProcessState _processState;
|
|
|
|
// locker to avoid repeated state execution
|
|
private ProcessState _lastProcessState;
|
|
|
|
// reminder for state change to execute e.g. error messaging
|
|
private ProcessState _invokerProcessState;
|
|
|
|
/// <summary>
|
|
/// DB connection trial timer
|
|
/// </summary>
|
|
private const Int32 DbConnectionRetryDelayMs = 30000;
|
|
|
|
/// <summary>
|
|
/// DB connection trial timer
|
|
/// </summary>
|
|
private const Int32 DbConnectionTimeoutMs = 9000;
|
|
|
|
private Int32 _dbAccessDelayCtrMs;
|
|
|
|
/// <summary>
|
|
/// Avoid DB connection trial on ongoing DB access, FW-Update procedure or registration
|
|
/// </summary>
|
|
private Boolean _dbAccessIsLocked;
|
|
|
|
/// <summary>
|
|
/// Check date time to enable FW update button.
|
|
/// </summary>
|
|
private Boolean _fwUpdateEnabled;
|
|
|
|
/// <summary>
|
|
/// List for upload app list versions.
|
|
/// </summary>
|
|
private readonly List<FwUpdateAppVersionDb> _fwUpdateAppVersions = new List<FwUpdateAppVersionDb>();
|
|
|
|
/// <summary>
|
|
/// List for upload reports.
|
|
/// </summary>
|
|
private readonly List<FwUpdateReportDb> _fwUpdateReportFiles = new List<FwUpdateReportDb>();
|
|
|
|
/// <summary>
|
|
/// Project name for the DLL to load:
|
|
/// This is the base for the source folder, the destination folder, the namespace and the form
|
|
/// </summary>
|
|
private const String FwUpdateProjectName = "ServiceFwUpdateSw";
|
|
|
|
/// <summary>
|
|
/// Name of the file which contains the meter file names that can be erased before the FW-Update
|
|
/// to free disk space and have to be restored after the FW-Update
|
|
/// </summary>
|
|
private readonly String _meterFilesConfigPathName;
|
|
|
|
/// <summary>
|
|
/// DB access
|
|
/// </summary>
|
|
private readonly FwUpdateDb _fwUpdateDbAccess = new FwUpdateDb();
|
|
|
|
/// <summary>
|
|
/// Name for firmware update software including the namespace
|
|
/// </summary>
|
|
private const String FwUpdateSwFullName = "Xylem.ServiceFwUpdate.Ui." + FwUpdateProjectName;
|
|
|
|
/// <summary>
|
|
/// Name for firmware update dll
|
|
/// </summary>
|
|
private const String FwUpdateSwDll = FwUpdateSwFullName + ".dll";
|
|
|
|
/// <summary>
|
|
/// Name for firmware update form
|
|
/// </summary>
|
|
private const String FormFwUpdateSw = FwUpdateSwFullName + ".Frm" + FwUpdateProjectName;
|
|
|
|
/// <summary>
|
|
/// FW-Update SW interface for data exchange
|
|
/// </summary>
|
|
private const String FwUpdateSwDataExchangeInterface = "SetDataContainerJson";
|
|
|
|
|
|
/// <summary>
|
|
/// Path to firmware update software DLL
|
|
/// </summary>
|
|
private readonly String _fwUpdateSwDestinationPath;
|
|
|
|
/// <summary>
|
|
/// Object reference of FW-Update SW
|
|
/// </summary>
|
|
private Object _fwUpdateObject;
|
|
|
|
#if (USE_APP_DOMAIN)
|
|
/// <summary>
|
|
/// FW-Update SW application domain
|
|
/// </summary>
|
|
private const String AppDomainName = "AppDomain" + FwUpdateProjectName;
|
|
|
|
/// <summary>
|
|
/// App domain for FW-Update SW
|
|
/// </summary>
|
|
private AppDomain _fwUpdateSwAppDomain;
|
|
#endif
|
|
/// <summary>
|
|
/// Logger of messages
|
|
/// </summary>
|
|
private readonly ILogger _logger;
|
|
|
|
/// <summary>
|
|
/// Separator string used for logger and history window
|
|
/// </summary>
|
|
private const String StrSeparator = "-----------------------------------------------------" +
|
|
"-----------------------------------------------------";
|
|
|
|
/// <summary>
|
|
/// remind manually changed culture setting
|
|
/// </summary>
|
|
private CultureInfo _cultureInfo;
|
|
|
|
/// <summary>
|
|
/// remind software version
|
|
/// </summary>
|
|
private readonly Version _version;
|
|
|
|
/// <summary>
|
|
/// FW-Update Safe
|
|
/// </summary>
|
|
private FwUpdateSafe _fwUpdateSafe;
|
|
|
|
/// <summary>
|
|
/// File name of FW-Update safe without extension (CustomerName_FwUpdateOrderNumber)
|
|
/// </summary>
|
|
private String _customerAndOrderInfo;
|
|
|
|
/// <summary>
|
|
/// Registered user information read from registration file.
|
|
/// </summary>
|
|
private UserInformation _regUser;
|
|
|
|
/// <summary>
|
|
/// Path to application configuration ../[user]/AppData/Roaming/Genesis/
|
|
/// </summary>
|
|
private static readonly String ApplicationConfigPath = Path.Combine(Environment.GetFolderPath(
|
|
Environment.SpecialFolder.ApplicationData), ProgramConfig.GenesisBaseFolder);
|
|
|
|
/// <summary>
|
|
/// Destination directory and file name for serial port configuration file
|
|
/// </summary>
|
|
private static readonly String PortConfigPathName = Path.Combine(ApplicationConfigPath,
|
|
ProgramConfig.SerialConfigFileName);
|
|
|
|
/// <summary>
|
|
/// Path and file user registration
|
|
/// </summary>
|
|
private static readonly String UserRegistrationPathFile = Path.Combine(ApplicationConfigPath,
|
|
FwUpdateConfig.UserRegistrationFileName);
|
|
|
|
/// <summary>
|
|
/// Path and file user NLog configuration
|
|
/// </summary>
|
|
private static readonly String NLogConfigurationDestPathFile = Path.Combine(ApplicationConfigPath,
|
|
ProgramConfig.NlogConfig);
|
|
|
|
/// <summary>
|
|
/// Path for FW-Update safes
|
|
/// </summary>
|
|
private static readonly String FwUpdateSafePath = Path.Combine(Environment.GetFolderPath(
|
|
Environment.SpecialFolder.UserProfile), FwUpdateConfig.DefaultFwUpdateSafePath);
|
|
|
|
/// <summary>
|
|
/// Path for FW-Update safes
|
|
/// </summary>
|
|
private static readonly String FwUpdateSafeInfoBackupPath = Path.Combine(Environment.GetFolderPath(
|
|
Environment.SpecialFolder.UserProfile), FwUpdateConfig.FwUpdateSafeInfoBackupPath);
|
|
|
|
/// <summary>
|
|
/// Path and name of FW-Update safe
|
|
/// </summary>
|
|
private static String _fwUpdateSafePathName;
|
|
|
|
/// <summary>
|
|
/// Timer for cyclic status update
|
|
/// </summary>
|
|
private System.Windows.Forms.Timer _tmrLoaderCyclicStatus = new System.Windows.Forms.Timer();
|
|
|
|
#endregion --------------------------------------- Variables --------------------------------------------------
|
|
|
|
#region ------------------------------------------ State Machine ----------------------------------------------
|
|
|
|
/// <summary>
|
|
/// State machine for FW update builder:
|
|
/// Will be executed in an endless loop from the "Service FW-Update Thread" until exit. State will be executed
|
|
/// once and then locked for repeated execution. A state change is the reason for reentry.
|
|
/// NOTE:
|
|
/// Change the state immediately before calling any routine to avoid repeated execution of routine!
|
|
/// </summary>
|
|
/// <remarks date="2021-Mar-23" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-29" author="Thomas Wiedebusch">
|
|
/// - Upload report files,
|
|
/// - Upload app list version,
|
|
/// - Download FW-Update Safes.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Jun-08" author="Roland Drabesch">
|
|
/// - Sleep on equal process state to force suspend of actual thread.
|
|
/// </remarks>
|
|
private void FwUpdateLoaderStateMachine()
|
|
{
|
|
while (!_processToken.IsCancellationRequested)
|
|
{
|
|
if (_lastProcessState == _processState)
|
|
{
|
|
Thread.Sleep(1);
|
|
// do nothing until state changed
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
_lastProcessState = _processState;
|
|
switch (_processState)
|
|
{
|
|
case ProcessState.Init:
|
|
_processState = ProcessState.Idle;
|
|
break;
|
|
|
|
case ProcessState.Idle:
|
|
// nothing to do than to wait for state change
|
|
break;
|
|
|
|
case ProcessState.Stop:
|
|
// stop clears all status's and ongoing processes
|
|
StopProcesses();
|
|
break;
|
|
|
|
case ProcessState.Error:
|
|
// stop clears all status's and ongoing processes
|
|
ErrorProcesses();
|
|
break;
|
|
|
|
//case ProcessState.ConnectDb:
|
|
// EstablishDbConnectionTask();
|
|
// break;
|
|
|
|
case ProcessState.UploadReportFiles:
|
|
UploadReportFilesToDbTask();
|
|
break;
|
|
|
|
case ProcessState.DownloadFwUpdateSafe:
|
|
DownloadFwUpdateSafesFromDbTask();
|
|
break;
|
|
|
|
case ProcessState.LoadFwUpdateSafe:
|
|
LoadFwUpdateSafe();
|
|
break;
|
|
|
|
case ProcessState.FwUpdateProcess:
|
|
StartFwUpdateProcess();
|
|
break;
|
|
|
|
case ProcessState.CheckPcbIdProcessState:
|
|
// catch the state but do nothing as this is a separate task,
|
|
// state is going to be handled by the timer
|
|
break;
|
|
|
|
default:
|
|
_processState = ProcessState.Idle;
|
|
break;
|
|
}
|
|
|
|
}
|
|
catch (ThreadAbortException)
|
|
{
|
|
throw;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
if (_fwUpdateLoaderThread.ThreadState == ThreadState.Aborted
|
|
|| _fwUpdateLoaderThread.ThreadState == ThreadState.AbortRequested)
|
|
{
|
|
MessageBoxShow(e.ToString(), Resources.StrError, MessageBoxButtons.OK,
|
|
MessageBoxIcon.Error);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
//finally
|
|
//{
|
|
//}
|
|
}
|
|
} // state locked against repeated execution
|
|
}
|
|
|
|
#endregion --------------------------------------- State Machine ----------------------------------------------
|
|
|
|
#region ------------------------------------------ Timer Controls ---------------------------------------------
|
|
|
|
/// <summary>
|
|
/// Check the DB connection.
|
|
/// </summary>
|
|
/// <remarks date="2021-Feb-16" author="Thomas Wiedebusch">
|
|
/// - Initial.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
|
|
/// - Implemented state machine.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-28" author="Thomas Wiedebusch">
|
|
/// - Fill data grid with pcb id infos.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mai-07" author="Thomas Wiedebusch">
|
|
/// - Check register exported to separate function to avoid registration before check of FwUpdateSafes
|
|
/// availability on DB.
|
|
/// </remarks>
|
|
private void TmrLoaderCyclicStatus_Tick(Object sender, EventArgs e)
|
|
{
|
|
Thread.CurrentThread.CurrentUICulture = _cultureInfo;
|
|
Thread.CurrentThread.CurrentCulture = _cultureInfo;
|
|
|
|
_dbAccessDelayCtrMs += _tmrLoaderCyclicStatus.Interval;
|
|
|
|
switch (_processState)
|
|
{
|
|
case ProcessState.Idle:
|
|
CheckDbConnectivity();
|
|
CheckFwUpdateSafeExistence();
|
|
CheckReportStatus();
|
|
CheckRegisterState();
|
|
break;
|
|
case ProcessState.UploadReportFiles:
|
|
case ProcessState.DownloadFwUpdateSafe:
|
|
CheckDbConnectionTimeout();
|
|
SetStatusProgressBar(ProgressBarStatus.Value + 1 > 100 ? 0 : ProgressBarStatus.Value + 1);
|
|
break;
|
|
case ProcessState.CheckPcbIdProcessState:
|
|
FillDataGridWithPcbIdInfos();
|
|
_processState = ProcessState.Idle;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion --------------------------------------- Timer Controls ---------------------------------------------
|
|
|
|
#region ------------------------------------------ User Interaction -------------------------------------------
|
|
|
|
/// <summary>
|
|
/// Start of FW-Update SW.
|
|
/// </summary>
|
|
/// <remarks date="2020-Nov-30" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-26" author="Thomas Wiedebusch">
|
|
/// - Exported functionality to StartFwUpdateProcess.
|
|
/// </remarks>
|
|
private void BtnFwUpdate_Click(Object sender, EventArgs e)
|
|
{
|
|
if (_fwUpdateSafe == null) return;
|
|
|
|
_tmrLoaderCyclicStatus.Tick -= TmrLoaderCyclicStatus_Tick;
|
|
_tmrLoaderCyclicStatus.Enabled = false;
|
|
_dbAccessIsLocked = true;
|
|
_processState = ProcessState.FwUpdateProcess;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Register user at DB Laatzen. This can only be done if the network is connected.
|
|
/// </summary>
|
|
/// <remarks date="2020-Nov-27" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2021-Feb-04" author="Thomas Wiedebusch">
|
|
/// - Register to DB.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-15" author="Thomas Wiedebusch">
|
|
/// - Reg user information will be sent the registration form.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-16" author="Thomas Wiedebusch">
|
|
/// - Locked DB access during registration.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-25" author="Thomas Wiedebusch">
|
|
/// - _fwUpdateDbAccess added,
|
|
/// - new process state added.
|
|
/// </remarks>
|
|
private void BtnRegister_Click(Object sender, EventArgs e)
|
|
{
|
|
// The user registration file needs to be created if it doesn't exists,
|
|
// therefore the registration form has to be started.
|
|
if (string.IsNullOrEmpty(UserRegistrationPathFile)) return;
|
|
|
|
_processState = ProcessState.UserRegistration;
|
|
_dbAccessIsLocked = true;
|
|
var frmRegister = new FrmRegister(UserRegistrationPathFile,
|
|
SystemControl.FilesExistingInPath(FwUpdateSafePath), _regUser, _fwUpdateDbAccess);
|
|
DisableControls();
|
|
frmRegister.Show();
|
|
frmRegister.Closed += FormRegister_Closed;
|
|
Hide();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Open FW-Update safe and decrypt it.
|
|
/// </summary>
|
|
/// <remarks date="2021-Feb-05" author="Thomas Wiedebusch">
|
|
/// - Initial.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-26" author="Thomas Wiedebusch">
|
|
/// - Exported functionality to LoadFwUpdateSafe.
|
|
/// </remarks>
|
|
private void btnLoadFwUpdSafe_Click(Object sender, EventArgs e)
|
|
{
|
|
_dbAccessIsLocked = true;
|
|
_processState = ProcessState.LoadFwUpdateSafe;
|
|
}
|
|
|
|
#endregion --------------------------------------- User Interaction -------------------------------------------
|
|
|
|
#region ------------------------------------------ Form Load Unload -------------------------------------------
|
|
|
|
/// <summary>
|
|
/// Ctor
|
|
/// </summary>
|
|
/// <remarks date="2020-Nov-30" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2021-Feb-05" author="Thomas Wiedebusch">
|
|
/// - Moved all paths and file setups to this function.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-15" author="Thomas Wiedebusch">
|
|
/// - Moved FW-Update SW directory directly to the FW-Update Loader directory,
|
|
/// - Check for ../[user]/AppData/Roaming/Genesis/ folder existence and create it,
|
|
/// - Copy needed files from execution directory to this directory.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-16" author="Thomas Wiedebusch">
|
|
/// - DB offline message added.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
|
|
/// - Thread added.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Jun-08" author="Thomas Wiedebusch">
|
|
/// - Library added to NLogConfig source path, as this is the release source, copy files only if not
|
|
/// identical.
|
|
/// </remarks>
|
|
public FrmFwUpdateLoader()
|
|
{
|
|
var fwUpdateLoaderExePath = AppDomain.CurrentDomain.BaseDirectory;
|
|
var fwUpdateLoaderConfigPath = Path.Combine(fwUpdateLoaderExePath, FwUpdateConfig.ConfigSubFolderName);
|
|
|
|
// Set the FW-Update SW destination folder to the FW-Update Loader exe path
|
|
_fwUpdateSwDestinationPath = Path.Combine(fwUpdateLoaderExePath, FwUpdateProjectName);
|
|
|
|
// files for erase before FW-Update and restore after
|
|
_meterFilesConfigPathName = Path.Combine(_fwUpdateSwDestinationPath,
|
|
FwUpdateConfig.MeterFilesEraseRestoreConfigFileName);
|
|
|
|
var nLogConfigSourcePathName = Path.Combine(fwUpdateLoaderConfigPath, ProgramConfig.NlogConfig);
|
|
|
|
// Build the configuration directory and copy at least the NLog config to it
|
|
try
|
|
{
|
|
if (!Directory.Exists(ApplicationConfigPath))
|
|
{
|
|
Directory.CreateDirectory(ApplicationConfigPath);
|
|
}
|
|
|
|
// Check for the file in the application exe path and the application configuration path
|
|
if (File.Exists(nLogConfigSourcePathName) && !File.Exists(NLogConfigurationDestPathFile))
|
|
SystemControl.CopyFile(nLogConfigSourcePathName, NLogConfigurationDestPathFile);
|
|
|
|
// create the location for the FW-Update safes as they may be loaded from the DB if online
|
|
if (!Directory.Exists(FwUpdateSafePath))
|
|
{
|
|
Directory.CreateDirectory(FwUpdateSafePath);
|
|
}
|
|
|
|
if (!Directory.Exists(FwUpdateConfig.ReportedPath))
|
|
{
|
|
Directory.CreateDirectory(FwUpdateConfig.ReportedPath);
|
|
}
|
|
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// nothing to do
|
|
}
|
|
|
|
_logger = NLogHelper.CreateOrGetLogger("ServiceFwUpdateLoader");
|
|
_version = Assembly.GetExecutingAssembly().GetName().Version;
|
|
_logger.Info(StrSeparator);
|
|
_logger.Info($"Service FW-Update Loader Version: {_version.Major}.{_version.Minor}.{_version.Build}.{_version.Revision}");
|
|
_logger.Info(StrSeparator);
|
|
|
|
InitializeComponent();
|
|
|
|
_cultureInfo = Thread.CurrentThread.CurrentCulture;
|
|
radioBtnEnglishLanguage.Checked = true;
|
|
if (_cultureInfo.IetfLanguageTag == "de-DE")
|
|
{
|
|
radioBtnGermanLanguage.Checked = true;
|
|
}
|
|
|
|
lblFwUpdateInfo.Text = $@"Version: {_version.Major}.{_version.Minor}.{_version.Build}";
|
|
|
|
DisableControls();
|
|
CheckUserRegistration();
|
|
CheckFwUpdateSafeExistence();
|
|
CheckReportStatus();
|
|
_dbAccessDelayCtrMs = DbConnectionRetryDelayMs;
|
|
_dbAccessIsLocked = false;
|
|
//_userAccessLocked = true;
|
|
|
|
// set locked repeat initially different from process state to unlock first entry to state machine
|
|
_lastProcessState = ProcessState.Unspecified;
|
|
_invokerProcessState = ProcessState.Unspecified;
|
|
_processState = ProcessState.Init;
|
|
|
|
_fwUpdateLoaderThread = new Thread(FwUpdateLoaderStateMachine);
|
|
if (!string.IsNullOrEmpty(_fwUpdateLoaderThread.Name))
|
|
_fwUpdateLoaderThread.Name = "State Machine Service FW-Update Loader thread";
|
|
ThreadWatcher.Instance.Start(_fwUpdateLoaderThread);
|
|
|
|
_tmrLoaderCyclicStatus.Interval = 200;
|
|
_tmrLoaderCyclicStatus.Tick += TmrLoaderCyclicStatus_Tick;
|
|
_tmrLoaderCyclicStatus.Enabled = true;
|
|
|
|
lblPcName.ForeColor = ColorSuccess;
|
|
lblPcName.Text = @"PC Name: " + CryptInformation.GetSysPcName();
|
|
lblCustomerName.Text = "";
|
|
lblSafeValidDate.Text = "";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Exit of Registration Form.
|
|
/// </summary>
|
|
/// <remarks date="2021-Feb-04" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2021-Apr-28" author="Thomas Wiedebusch">
|
|
/// - Fill data grid PCB IDs.
|
|
/// </remarks>
|
|
private void FormRegister_Closed(Object sender, EventArgs e)
|
|
{
|
|
Show();
|
|
Update();
|
|
CheckUserRegistration();
|
|
CheckFwUpdateSafeExistence();
|
|
CheckReportStatus();
|
|
FillDataGridWithPcbIdInfos();
|
|
_dbAccessIsLocked = false;
|
|
_processState = ProcessState.CheckPcbIdProcessState;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Exit of FW-Update SW.
|
|
/// </summary>
|
|
/// <remarks date="2020-Nov-30" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-23" author="Thomas Wiedebusch">
|
|
/// - Avoid second start of FW-Update SW and loading of FW-Update Safe!
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-26" author="Thomas Wiedebusch">
|
|
/// - Avoid second start of FW-Update SW and loading of FW-Update Safe but do not exit!
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-27" author="Thomas Wiedebusch">
|
|
/// - Process state at exit to idle.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-29" author="Thomas Wiedebusch">
|
|
/// - Do not delete the FW-Update SW as this may be used with a restart in single app domain,
|
|
/// in multiple app domain these files are unlocked and should be erased.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Apr-28" author="Thomas Wiedebusch">
|
|
/// - Fill data grid PCB IDs.
|
|
/// </remarks>
|
|
private void FormFwUpdate_Closed(Object sender, EventArgs e)
|
|
{
|
|
#if (USE_APP_DOMAIN)
|
|
|
|
if (_fwUpdateSwAppDomain != null ) AppDomain.Unload(_fwUpdateSwAppDomain);
|
|
try
|
|
{
|
|
// erase DLLs and remove directory if empty
|
|
SystemControl.RemoveDirectory(_fwUpdateSwDestinationPath);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBoxShow(ex.ToString(), Resources.StrError, MessageBoxButtons.OK,
|
|
MessageBoxIcon.Error);
|
|
throw;
|
|
}
|
|
#endif
|
|
_tmrLoaderCyclicStatus.Tick += TmrLoaderCyclicStatus_Tick;
|
|
_tmrLoaderCyclicStatus.Enabled = true;
|
|
|
|
Show();
|
|
Update();
|
|
CheckUserRegistration();
|
|
CheckFwUpdateSafeExistence();
|
|
CheckReportStatus();
|
|
_dbAccessIsLocked = false;
|
|
_processState = ProcessState.CheckPcbIdProcessState;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove all files which are not locked from HDD
|
|
/// </summary>
|
|
/// <remarks date="2020-Nov-30" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
|
|
/// - Cancellation request added.
|
|
/// </remarks>
|
|
private void FrmFwUpdateLoader_FormClosed(Object sender, FormClosedEventArgs e)
|
|
{
|
|
#if (USE_APP_DOMAIN)
|
|
if (_fwUpdateSwAppDomain != null) AppDomain.Unload(_fwUpdateSwAppDomain);
|
|
#endif
|
|
_processToken?.Cancel();
|
|
try
|
|
{
|
|
// erase DLLs and remove directory if empty
|
|
SystemControl.RemoveDirectory(_fwUpdateSwDestinationPath);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBoxShow(ex.ToString(), Resources.StrError, MessageBoxButtons.OK,
|
|
MessageBoxIcon.Error);
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
_tmrLoaderCyclicStatus?.Dispose();
|
|
Dispose();
|
|
}
|
|
}
|
|
|
|
#endregion --------------------------------------- Form Load Unload -------------------------------------------
|
|
|
|
#region ------------------------------------------ Checks -----------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// The loader version needs to be checked to avoid an incompatible Software to Loader version as the Loader
|
|
/// release contains some dlls to keep the FwUpdateSafe as small as possible.
|
|
/// </summary>
|
|
/// <returns>true if version is accepted</returns>
|
|
private Boolean CrosscheckLoaderVersion()
|
|
{
|
|
if (_fwUpdateSafe?.License != null &&
|
|
_version.Major == _fwUpdateSafe.License.Major &&
|
|
_version.Minor == _fwUpdateSafe.License.Minor &&
|
|
_version.Build == _fwUpdateSafe.License.Build )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
/// <summary>
|
|
/// Check validation date and if safe is loaded.
|
|
/// </summary>
|
|
/// <remarks date="2023-Oct-23" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
void CheckFwUpdateEnabled()
|
|
{
|
|
if (_fwUpdateSafe?.SafeInfo != null)
|
|
{
|
|
Color color;
|
|
// check valid date
|
|
if (DateTime.Compare(_fwUpdateSafe.SafeInfo.FwUpdateValidDate, DateTime.Now) >= 1)
|
|
|
|
{
|
|
_fwUpdateEnabled = true;
|
|
color = ColorSuccess;
|
|
}
|
|
else
|
|
{
|
|
_fwUpdateEnabled = false;
|
|
color = ColorProcessFailed;
|
|
}
|
|
|
|
UiInvoker.ControlInvoker(lblLoadedSafe, color, _customerAndOrderInfo);
|
|
UiInvoker.ControlInvoker(lblCustomerName, color, _fwUpdateSafe.SafeInfo.CustomerName);
|
|
UiInvoker.ControlInvoker(lblSafeValidDate, color, Resources.StrSafeValidDate +
|
|
$@" {_fwUpdateSafe.SafeInfo.FwUpdateValidDate:dddd, dd-MMM-yyyy HH:mm:ss} UTC");
|
|
}
|
|
else
|
|
{
|
|
UiInvoker.ControlInvoker(lblLoadedSafe, ColorSuccess, _customerAndOrderInfo);
|
|
UiInvoker.ControlInvoker(lblCustomerName, ColorSuccess);
|
|
UiInvoker.ControlInvoker(lblSafeValidDate, ColorSuccess);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Search "Firmware is up to date!" string in file to guarantee the successful execution of the update
|
|
/// process. Get success string for all language settings!
|
|
/// </summary>
|
|
/// <remarks date="2021-Oct-15" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
private Boolean IsSuccessStringInFile(String fileNamePath)
|
|
{
|
|
try
|
|
{
|
|
// Get search strings from resources StrFwUpToDateMessage from ServiceFwUpdateSw
|
|
var fileLines = File.ReadAllLines(fileNamePath);
|
|
var fwIsUpToDate = false;
|
|
foreach (var searchString in FwUpdateConfig.FirmwareUpToDateSearchStrings)
|
|
{
|
|
if (fileLines.Any(line => line.Contains(searchString))) fwIsUpToDate = true;
|
|
}
|
|
|
|
return fwIsUpToDate;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Search for report files
|
|
/// </summary>
|
|
/// <remarks date="2021-Apr-28" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2021-Oct-15" author="Thomas Wiedebusch">
|
|
/// - Check file content for "success" string to mark exclusively the validated updates.
|
|
/// - Check order number to enable more than one update for a specific pcbId.
|
|
/// </remarks>
|
|
private Boolean IsPcbIdProcessed(String pcbId, String orderNo)
|
|
{
|
|
try
|
|
{
|
|
// If this directory is existent and contains files, these files have to be checked
|
|
if (SystemControl.FilesExistingInPath(FwUpdateConfig.UnreportedPath))
|
|
{
|
|
var fileList = new List<String>();
|
|
SystemControl.GetFilesOfDirectoryAndSubDirectory(FwUpdateConfig.UnreportedPath, fileList,
|
|
$"*{FwUpdateConfig.ReportFileExtension}");
|
|
if (fileList.Any(file => file.Contains(pcbId) && file.Contains(orderNo)
|
|
&& IsSuccessStringInFile(file))) return true;
|
|
}
|
|
// If this directory is existent and contains files, these files have to be checked
|
|
if (SystemControl.FilesExistingInPath(FwUpdateConfig.ReportedPath))
|
|
{
|
|
var fileList = new List<String>();
|
|
SystemControl.GetFilesOfDirectoryAndSubDirectory(FwUpdateConfig.ReportedPath, fileList,
|
|
$"*{FwUpdateConfig.ReportFileExtension}");
|
|
if (fileList.Any(file => file.Contains(pcbId) && file.Contains(orderNo)
|
|
&& IsSuccessStringInFile(file))) return true;
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check the status of the report files:
|
|
/// - If any file is in the c:/GenesisLog/Unreported folder, these have to be uploaded to the DB with the next
|
|
/// established DB connection.
|
|
/// </summary>
|
|
/// <remarks date="2021-Mar-16" author="Thomas Wiedebusch">
|
|
/// - Initial.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-20" author="Thomas Wiedebusch">
|
|
/// - Changed logic.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-30" author="Thomas Wiedebusch">
|
|
/// - Build report and app version file lists.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Apr-12" author="Thomas Wiedebusch">
|
|
/// - Added number of upload reports.
|
|
/// - Split order number as it contains an e.g. "1234567890-10".
|
|
/// </remarks>
|
|
public void CheckReportStatus()
|
|
{
|
|
if (_regUser == null) return;
|
|
if (_fwUpdateReportFiles.Count > 0) _fwUpdateReportFiles.Clear();
|
|
if (_fwUpdateAppVersions.Count > 0) _fwUpdateAppVersions.Clear();
|
|
|
|
// If this directory is existent and contains files, these files have to be reported
|
|
if (SystemControl.FilesExistingInPath(FwUpdateConfig.UnreportedPath))
|
|
{
|
|
try
|
|
{
|
|
var fileList = new List<String>();
|
|
SystemControl.GetFilesOfDirectoryAndSubDirectory(FwUpdateConfig.UnreportedPath, fileList,
|
|
$"*{FwUpdateConfig.ReportFileExtension}");
|
|
foreach (var f in fileList)
|
|
{
|
|
// the naming is c:\\...\\PcbID_CustomerName_OrderNumber-Position.report
|
|
var fileName = Path.GetFileNameWithoutExtension(f);
|
|
var split = fileName.Split(FwUpdateConfig.FwUpdateFileFieldSeparator);
|
|
split[0] = Regex.Replace(split[0], "[^0-9]", "");
|
|
|
|
var orderSplit = split[2].Split('-');
|
|
orderSplit[0] = Regex.Replace(orderSplit[0], "[^0-9]", "");
|
|
orderSplit[1] = Regex.Replace(orderSplit[1], "[^0-9]", "");
|
|
|
|
var reportFile = new FwUpdateReportDb
|
|
{
|
|
UserId = _regUser.Id,
|
|
FileName = Path.GetFileName(f),
|
|
PcbId = Convert.ToInt64(string.IsNullOrEmpty(split[0]) ? "0" : split[0]),
|
|
OrderNr = Convert.ToInt64(string.IsNullOrEmpty(orderSplit[0]) ? "0" : orderSplit[0]),
|
|
OrderPos = Convert.ToInt64(string.IsNullOrEmpty(orderSplit[1]) ? "0" : orderSplit[1]),
|
|
Content = File.ReadAllText(f)
|
|
};
|
|
_fwUpdateReportFiles.Add(reportFile);
|
|
}
|
|
|
|
fileList.Clear();
|
|
SystemControl.GetFilesOfDirectoryAndSubDirectory(FwUpdateConfig.UnreportedPath, fileList,
|
|
$"*{FwUpdateConfig.AppVersionFileExtension}");
|
|
|
|
foreach (var f in fileList)
|
|
{
|
|
// the naming is c:\\...\\PcbID_CustomerName_OrderNumber-Position.applist
|
|
var fileName = Path.GetFileNameWithoutExtension(f);
|
|
var split = fileName.Split(FwUpdateConfig.FwUpdateFileFieldSeparator);
|
|
split[0] = Regex.Replace(split[0], "[^0-9]", "");
|
|
|
|
var orderSplit = split[2].Split('-');
|
|
orderSplit[0] = Regex.Replace(orderSplit[0], "[^0-9]", "");
|
|
orderSplit[1] = Regex.Replace(orderSplit[1], "[^0-9]", "");
|
|
|
|
var appVersionFile = new FwUpdateAppVersionDb
|
|
{
|
|
UserId = _regUser.Id,
|
|
FileName = Path.GetFileName(f),
|
|
PcbId = Convert.ToInt64(string.IsNullOrEmpty(split[0]) ? "0" : split[0]),
|
|
OrderNr = Convert.ToInt64(string.IsNullOrEmpty(orderSplit[0]) ? "0" : orderSplit[0]),
|
|
OrderPos = Convert.ToInt64(string.IsNullOrEmpty(orderSplit[1]) ? "0" : orderSplit[1]),
|
|
AppVersionList = new List<CordonelAppVersion>()
|
|
};
|
|
var fileContent = File.ReadAllText(f);
|
|
appVersionFile.AppVersionList = JsonConvert.DeserializeObject<List<CordonelAppVersion>>(fileContent);
|
|
_fwUpdateAppVersions.Add(appVersionFile);
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
UiInvoker.ControlInvoker(lblReportUploadStatus, ColorProcessRequired, visible: false);
|
|
return;
|
|
}
|
|
|
|
if (_fwUpdateReportFiles.Count > 0 || _fwUpdateAppVersions.Count > 0)
|
|
{
|
|
UiInvoker.ControlInvoker(lblReportUploadStatus, ColorProcessRequired,
|
|
$"{Resources.StrReportsUploadNeeded} " +
|
|
$"{SystemControl.NumberOfFilesInPath(FwUpdateConfig.UnreportedPath)}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UiInvoker.ControlInvoker(lblReportUploadStatus, ColorProcessRequired, visible: false);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check the user registration from ../[user]/AppData/Roaming/Genesis//UserInformation.register
|
|
/// and compare it with the system user information.
|
|
/// </summary>
|
|
/// <remarks date="2021-Feb-05" author="Thomas Wiedebusch">
|
|
/// - Initial.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-16" author="Thomas Wiedebusch">
|
|
/// - Moved registration file handling to <see cref="CryptInformation"/>,
|
|
/// - Take the validation date for temporary decoding if system password hash has been changed.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
|
|
/// - UiInvoker.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-30" author="Thomas Wiedebusch">
|
|
/// - Message corrected if HW changed.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Apr-04" author="Thomas Wiedebusch">
|
|
/// - Moved lblRegistrationStatus from ToolSTrip to normal label.
|
|
/// </remarks>
|
|
public void CheckUserRegistration()
|
|
{
|
|
// Case 1: User is not locally registered -> Exit as it cannot be solved without registration,
|
|
// The cyclic DB connection detection will enable the [Registration] button!
|
|
// Check if user is locally registered in the "UserRegistration.register" file and fill _regUser
|
|
if (!CryptInformation.ReadUserRegistration(UserRegistrationPathFile, out _regUser) || _regUser == null ||
|
|
string.IsNullOrEmpty(_regUser.FullName))
|
|
{
|
|
UiInvoker.ControlEnableInvoker(btnFwUpdate, false);
|
|
UiInvoker.ControlEnableInvoker(btnLoadFwUpdSafe, false);
|
|
UiInvoker.ControlInvoker(lblRegistrationStatus, ColorProcessFailed, Resources.StrUserNotRegistered);
|
|
return;
|
|
}
|
|
|
|
// Case 2: User is locally registered -> check if decoding is possible
|
|
// If the system user isn't identical to the registered user, this has to be fixed as a decoding
|
|
// is not feasible! The registration file is the "OFFLINE" information of the user info stored
|
|
// to the DB and therefore used by the FW-Update Builder for encryption!
|
|
// This may occur if the validation has outdated, the password hash or the HW has changed.
|
|
if (!CryptInformation.IsDecodingPossible(_regUser))
|
|
{
|
|
UiInvoker.ControlInvoker(lblRegistrationStatus, ColorProcessFailed, _regUser.FullName +
|
|
Resources.StrUserRegistrationExpired);
|
|
return;
|
|
}
|
|
|
|
// Case 3: User is locally registered and pwd hash has changed
|
|
// After changing the password, this shall be updated to the DB as well as to the registration file.
|
|
var date = DateTimeServer.GetDateStringFromDateTimeOffset(_regUser.ValidDate, _cultureInfo);
|
|
if (_regUser.PasswordHash != CryptInformation.GetSysUserPasswordHash(_regUser))
|
|
{
|
|
//TODO THW avoid automatic registration until all FW-Update Safes have been processed
|
|
UiInvoker.ControlInvoker(lblRegistrationStatus, ColorProcessRequired,
|
|
_regUser.FullName + @" " + Resources.StrUserRegistrationValid + @" " + date);
|
|
return;
|
|
}
|
|
|
|
// Case 4: User is locally registered and identical to the system user information
|
|
UiInvoker.ControlInvoker(lblRegistrationStatus, ColorSuccess,
|
|
_regUser.FullName + @" " + Resources.StrUserRegistrationValid + @" " + date);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Check DB connection timeout during connectivity check
|
|
/// </summary>
|
|
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
private void CheckDbConnectionTimeout()
|
|
{
|
|
if (_dbAccessDelayCtrMs <= DbConnectionTimeoutMs) return;
|
|
|
|
_dbAccessDelayCtrMs = 0;
|
|
SetStatusProgressBar(0, false);
|
|
_processState = ProcessState.Idle;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check DB connectivity.
|
|
/// </summary>
|
|
/// <remarks date="2021-Mar-25" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-29" author="Thomas Wiedebusch">
|
|
/// - Lock user access during download of FW-Update Safes and/or report uploads.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Apr-04" author="Thomas Wiedebusch">
|
|
/// - Process state set to idle if DB is connected.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Apr-08" author="Thomas Wiedebusch">
|
|
/// - Check DB connection always, even if it was connected.
|
|
/// </remarks>
|
|
/// <remarks date="2021-May-07" author="Thomas Wiedebusch">
|
|
/// - Check register exported to separate function to avoid registration before check of FwUpdateSafes
|
|
/// availability on DB.
|
|
/// </remarks>
|
|
private void CheckDbConnectivity()
|
|
{
|
|
if (_dbAccessIsLocked) return;
|
|
|
|
if (_fwUpdateDbAccess.DbIsConnected)
|
|
{
|
|
if (ProgressBarStatus.Visible) ProgressBarStatus.Visible = false;
|
|
|
|
if (lblStatusDbConnect.Text != Resources.StrConnectedToDb)
|
|
{
|
|
lblStatusDbConnect.ForeColor = ColorSuccess;
|
|
lblStatusDbConnect.Text = Resources.StrConnectedToDb;
|
|
}
|
|
|
|
//#if (!DEBUG)
|
|
if ((_fwUpdateReportFiles != null && _fwUpdateReportFiles.Count > 0) ||
|
|
(_fwUpdateAppVersions != null && _fwUpdateAppVersions.Count > 0))
|
|
{
|
|
UiInvoker.ToolStripLabelInvoker(lblStatusDbConnect, ColorSuccess, Resources.StrUploadingReports);
|
|
SetStatusProgressBar();
|
|
_processState = ProcessState.UploadReportFiles;
|
|
return;
|
|
}
|
|
//#endif
|
|
|
|
}
|
|
else
|
|
{
|
|
if (ProgressBarStatus.Visible) ProgressBarStatus.Visible = false;
|
|
|
|
if (lblStatusDbConnect.Text != Resources.StrNotConnectedToDb)
|
|
{
|
|
lblStatusDbConnect.ForeColor = ColorOngoingProcess;
|
|
lblStatusDbConnect.Text = Resources.StrNotConnectedToDb;
|
|
}
|
|
|
|
if (btnRegister.Enabled) btnRegister.Enabled = false;
|
|
|
|
}
|
|
|
|
if (_dbAccessDelayCtrMs <= DbConnectionRetryDelayMs || _dbAccessIsLocked) return;
|
|
// kick off new connectivity check
|
|
if (btnRegister.Enabled) btnRegister.Enabled = false;
|
|
lblStatusDbConnect.ForeColor = ColorOngoingProcess;
|
|
lblStatusDbConnect.Text = Resources.StrConnectingToDb;
|
|
SetStatusProgressBar();
|
|
_dbAccessDelayCtrMs = 0;
|
|
_processState = ProcessState.DownloadFwUpdateSafe;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check register exported to separate function to avoid registration before check of FwUpdateSafes
|
|
/// availability on DB.
|
|
/// </summary>
|
|
/// <remarks date="2021-May-07" author="Thomas Wiedebusch">
|
|
/// Initial
|
|
/// </remarks>
|
|
private void CheckRegisterState()
|
|
{
|
|
if (_dbAccessIsLocked) return;
|
|
if (_fwUpdateDbAccess.DbIsConnected)
|
|
{
|
|
if (!btnRegister.Enabled) btnRegister.Enabled = true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enable update.
|
|
/// </summary>
|
|
/// <remarks date="2021-Feb-16" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-20" author="Thomas Wiedebusch">
|
|
/// - FW-Update safe load button enabled if any FwUpdateSafe exists.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
|
|
/// - UiInvoker.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Apr-04" author="Thomas Wiedebusch">
|
|
/// - Extended messages.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Apr-12" author="Thomas Wiedebusch">
|
|
/// - Added number of update safes.
|
|
/// </remarks>
|
|
private void CheckFwUpdateSafeExistence()
|
|
{
|
|
UiInvoker.ControlEnableInvoker(btnFwUpdate, _fwUpdateSafe != null && _fwUpdateEnabled);
|
|
|
|
if (SystemControl.FilesExistingInPath(FwUpdateSafePath))
|
|
{
|
|
UiInvoker.ControlInvoker(lblLocalSafesStatus, ColorSuccess,
|
|
$"{Resources.StrFwUpdateSafesLocallyExisting} " +
|
|
$"{SystemControl.NumberOfFilesInPath(FwUpdateSafePath)}");
|
|
}
|
|
else
|
|
{
|
|
UiInvoker.ControlInvoker(lblLocalSafesStatus, ColorProcessFailed,
|
|
Resources.StrFwUpdateSafesLocallyMissing);
|
|
|
|
}
|
|
UiInvoker.ControlEnableInvoker(btnLoadFwUpdSafe, SystemControl.FilesExistingInPath(FwUpdateSafePath));
|
|
}
|
|
#endregion --------------------------------------- Checks -----------------------------------------------------
|
|
|
|
#region ------------------------------------------ Tools ------------------------------------------------------
|
|
/// <summary>
|
|
/// Download FW update safes from DB task.
|
|
/// </summary>
|
|
/// <remarks date="2021-Apr-28" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2021-Jun-01" author="Thomas Wiedebusch">
|
|
/// - Web API timeout message.
|
|
/// </remarks>
|
|
private void DownloadFwUpdateSafesFromDbTask()
|
|
{
|
|
_invokerProcessState = _processState;
|
|
Task.Factory.StartNew(() =>
|
|
{
|
|
Thread.CurrentThread.CurrentUICulture = _cultureInfo;
|
|
Thread.CurrentThread.CurrentCulture = _cultureInfo;
|
|
try
|
|
{
|
|
_dbAccessIsLocked = true;
|
|
// check DB connection in advance to overcome the timing issues for DB service startup
|
|
if (!_fwUpdateDbAccess.CheckDbConnection()) LogText(WebApiTimeout);
|
|
DownloadFwUpdateSafesFromDb();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
_processState = ProcessState.Error;
|
|
}
|
|
}).ContinueWith(delegate
|
|
{
|
|
_dbAccessIsLocked = false;
|
|
_processState = ProcessState.Idle;
|
|
});
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Download FW update safes from DB task.
|
|
/// </summary>
|
|
/// <remarks date="2021-Apr-28" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2021-Jun-01" author="Thomas Wiedebusch">
|
|
/// - Web API timeout message.
|
|
/// </remarks>
|
|
private void DownloadFwUpdateSafesFromDb()
|
|
{
|
|
if (_fwUpdateDbAccess == null || _regUser == null || !_fwUpdateDbAccess.DbIsConnected) return;
|
|
try
|
|
{
|
|
|
|
if (!Directory.Exists(FwUpdateSafeInfoBackupPath))
|
|
{
|
|
Directory.CreateDirectory(FwUpdateSafeInfoBackupPath);
|
|
}
|
|
|
|
if (!Directory.Exists(FwUpdateSafePath))
|
|
{
|
|
Directory.CreateDirectory(FwUpdateSafePath);
|
|
}
|
|
|
|
// Check in special folder for accessed safes. if this directory is existent and contains files,
|
|
// these files have to be checked.
|
|
var backupSafeNames = new List<String>();
|
|
var safesToBackupName = new List<String>();
|
|
if (SystemControl.FilesExistingInPath(FwUpdateSafeInfoBackupPath))
|
|
{
|
|
var backupSafeNamesPath = new List<String>();
|
|
SystemControl.GetFilesOfDirectoryAndSubDirectory(FwUpdateSafeInfoBackupPath, backupSafeNamesPath,
|
|
$"*{FwUpdateConfig.LoadedSafesBackupFileExtension}");
|
|
backupSafeNames = backupSafeNamesPath.Select(Path.GetFileNameWithoutExtension).ToList();
|
|
}
|
|
|
|
// load the safe information from DB
|
|
if (_fwUpdateDbAccess != null && _fwUpdateDbAccess.ListAllFwUpdateSafesOfUserFromDb(_regUser.Id,
|
|
out var userFwUpdateSafes))
|
|
{
|
|
foreach (var safe in userFwUpdateSafes)
|
|
{
|
|
if (backupSafeNames.All(x => x != Path.GetFileNameWithoutExtension(safe.Name)))
|
|
{
|
|
// it is only one safe (even if it is a list!)
|
|
var fwUpdateSafes = _fwUpdateDbAccess.DownloadFwUpdateSafeFromDb(safe.ContainerId);
|
|
// store to file if it not already exists
|
|
if (fwUpdateSafes != null && fwUpdateSafes.Count > 0)
|
|
{
|
|
if (Directory.Exists(FwUpdateSafePath))
|
|
{
|
|
var sourceFile = Path.Combine(FwUpdateSafePath, fwUpdateSafes[0].Name);
|
|
if (File.Exists(sourceFile)) continue;
|
|
|
|
var fs = File.Open(sourceFile, FileMode.Create);
|
|
fs.Write(fwUpdateSafes[0].Content, 0, fwUpdateSafes[0].Content.Length);
|
|
fs.Close();
|
|
safesToBackupName.Add(Path.GetFileNameWithoutExtension(fwUpdateSafes[0].Name) +
|
|
FwUpdateConfig.LoadedSafesBackupFileExtension);
|
|
}
|
|
}
|
|
if (!_fwUpdateDbAccess.DbIsConnected) LogText(WebApiTimeout);
|
|
}
|
|
}
|
|
// copy backup information of downloaded safes to special folder to exclude these on next trial
|
|
foreach (var s in safesToBackupName)
|
|
{
|
|
if (Directory.Exists(FwUpdateSafeInfoBackupPath))
|
|
{
|
|
var sourceFile = Path.Combine(FwUpdateSafeInfoBackupPath, s);
|
|
var fs = File.Open(sourceFile, FileMode.Create);
|
|
fs.Close();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogText(WebApiTimeout);
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// nothing to do
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Upload report files to DB task.
|
|
/// </summary>
|
|
/// <remarks date="2021-Apr-08" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2021-Jun-01" author="Thomas Wiedebusch">
|
|
/// - Web API timeout message.
|
|
/// </remarks>
|
|
private void UploadReportFilesToDbTask()
|
|
{
|
|
_invokerProcessState = _processState;
|
|
Task.Factory.StartNew(() =>
|
|
{
|
|
Thread.CurrentThread.CurrentUICulture = _cultureInfo;
|
|
Thread.CurrentThread.CurrentCulture = _cultureInfo;
|
|
try
|
|
{
|
|
_dbAccessIsLocked = true;
|
|
// check DB connection in advance to overcome the timing issues for DB service startup
|
|
if (!_fwUpdateDbAccess.CheckDbConnection()) LogText(WebApiTimeout);
|
|
UploadReportFilesToDb();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
_processState = ProcessState.Error;
|
|
}
|
|
}).ContinueWith(delegate
|
|
{
|
|
_dbAccessIsLocked = false;
|
|
_processState = ProcessState.Idle;
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Upload report files to DB.
|
|
/// </summary>
|
|
/// <remarks date="2021-Apr-08" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2021-Jun-01" author="Thomas Wiedebusch">
|
|
/// - Web API timeout message.
|
|
/// </remarks>
|
|
private void UploadReportFilesToDb()
|
|
{
|
|
if (_fwUpdateDbAccess == null || !_fwUpdateDbAccess.DbIsConnected) return;
|
|
foreach (var appVersionFile in _fwUpdateAppVersions)
|
|
{
|
|
if (_fwUpdateDbAccess.UploadCordonelAppVersionsToDb(appVersionFile.PcbId,
|
|
appVersionFile.AppVersionList))
|
|
{
|
|
var sourceFilePathName = Path.Combine(FwUpdateConfig.UnreportedPath + appVersionFile.FileName);
|
|
var destinationFilePathName = Path.Combine(FwUpdateConfig.ReportedPath + appVersionFile.FileName);
|
|
if (SystemControl.CopyFile(sourceFilePathName, destinationFilePathName))
|
|
{
|
|
File.Delete(sourceFilePathName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogText(WebApiTimeout);
|
|
}
|
|
}
|
|
foreach (var reportFile in _fwUpdateReportFiles)
|
|
{
|
|
if (_fwUpdateDbAccess.UploadFwUpdateReportToDb(reportFile))
|
|
{
|
|
var sourceFilePathName = Path.Combine(FwUpdateConfig.UnreportedPath + reportFile.FileName);
|
|
var destinationFilePathName = Path.Combine(FwUpdateConfig.ReportedPath + reportFile.FileName);
|
|
if (SystemControl.CopyFile(sourceFilePathName, destinationFilePathName))
|
|
{
|
|
File.Delete(sourceFilePathName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogText(WebApiTimeout);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Error processes.
|
|
/// </summary>
|
|
/// <remarks date="2021-Apr-06" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
private void ErrorProcesses()
|
|
{
|
|
// take the invoker of the error state to generate the message and / or popup window
|
|
switch (_invokerProcessState)
|
|
{
|
|
default:
|
|
_processState = ProcessState.Idle;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stop all ongoing processes.
|
|
/// </summary>
|
|
/// <remarks date="2021-Apr-06" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
private void StopProcesses()
|
|
{
|
|
// take the invoker of the error state to generate the message and / or popup window
|
|
switch (_invokerProcessState)
|
|
{
|
|
default:
|
|
_processState = ProcessState.Idle;
|
|
break;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Common message window.
|
|
/// </summary>
|
|
/// <remarks date="2021-Mar-29" author="Thomas Wiedebusch">
|
|
/// - Forcing message box being modal and on top.
|
|
/// </remarks>
|
|
private static void MessageBoxShow(String text, String caption, MessageBoxButtons buttons, MessageBoxIcon icon)
|
|
{
|
|
MessageBox.Show(text, caption, buttons, icon, MessageBoxDefaultButton.Button1,
|
|
MessageBoxOptions.ServiceNotification);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Extract the FW-Update SW from FW-Update Safe.
|
|
/// </summary>
|
|
/// <remarks date="2021-Mar-23" author="Thomas Wiedebusch">
|
|
/// - Initial.
|
|
/// </remarks>
|
|
public Boolean ExtractFwUpdateSw()
|
|
{
|
|
try
|
|
{
|
|
var files = new List<FilePart>();
|
|
if (_fwUpdateSafe?.Software?.SoftwareDynLinkLibs == null ||
|
|
_fwUpdateSafe.Software.SoftwareDynLinkLibs.Count == 0) return false;
|
|
foreach (var fp in _fwUpdateSafe.Software.SoftwareDynLinkLibs.Where(f => f.FileName.EndsWith(".dll")))
|
|
{
|
|
if (fp.FileContentLength == fp.FileContent.Length &&
|
|
fp.FileContentCrc16CcittMsb == Crc16Ccitt.CalculateMsb1021(fp.FileContent))
|
|
{
|
|
files.Add(fp);
|
|
}
|
|
}
|
|
if (_fwUpdateSafe?.Software?.MeterFilesEraseRestore == null) return false;
|
|
var file = _fwUpdateSafe.Software.MeterFilesEraseRestore;
|
|
if (file.FileContentLength == file.FileContent.Length &&
|
|
file.FileContentCrc16CcittMsb == Crc16Ccitt.CalculateMsb1021(file.FileContent))
|
|
{
|
|
files.Add(file);
|
|
}
|
|
if (_fwUpdateSafe?.Software?.SoftwareSetupFile == null) return false;
|
|
file = _fwUpdateSafe.Software.SoftwareSetupFile;
|
|
if (file.FileContentLength == file.FileContent.Length &&
|
|
file.FileContentCrc16CcittMsb == Crc16Ccitt.CalculateMsb1021(file.FileContent))
|
|
{
|
|
files.Add(file);
|
|
}
|
|
if (_fwUpdateSafe?.Software?.RegisterDefinitionFile == null) return false;
|
|
file = _fwUpdateSafe.Software.RegisterDefinitionFile;
|
|
if (file.FileContentLength == file.FileContent.Length &&
|
|
file.FileContentCrc16CcittMsb == Crc16Ccitt.CalculateMsb1021(file.FileContent))
|
|
{
|
|
files.Add(file);
|
|
}
|
|
|
|
foreach (var f in files)
|
|
{
|
|
var destinationPath = _fwUpdateSwDestinationPath;
|
|
if (!string.IsNullOrEmpty(f.SubDirectory))
|
|
{
|
|
destinationPath = Path.Combine(_fwUpdateSwDestinationPath, f.SubDirectory);
|
|
}
|
|
if (!Directory.Exists(destinationPath))
|
|
{
|
|
Directory.CreateDirectory(destinationPath);
|
|
}
|
|
|
|
if (Directory.Exists(destinationPath))
|
|
{
|
|
var sourceFile = Path.Combine(destinationPath, f.FileName);
|
|
var fs = File.Open(sourceFile, FileMode.Create);
|
|
fs.Write(f.FileContent, 0, f.FileContent.Length);
|
|
fs.Close();
|
|
}
|
|
// if one path cannot be created, exit
|
|
else return false;
|
|
}
|
|
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Open FW-Update safe and decrypt it.
|
|
/// </summary>
|
|
/// <remarks date="2021-Feb-05" author="Thomas Wiedebusch">
|
|
/// - Initial.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-09" author="Thomas Wiedebusch">
|
|
/// - Extracted FW-Update safe name as this represents the customer name and FW-Update order number.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-20" author="Thomas Wiedebusch">
|
|
/// - Logging info.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
|
|
/// - FW-Update safe loaded marked to stop DB connection trials.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-26" author="Thomas Wiedebusch">
|
|
/// - Exported from button click.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-27" author="Thomas Wiedebusch">
|
|
/// - Process state at exit to idle.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Apr-04" author="Thomas Wiedebusch">
|
|
/// - Removed Boundary Castle decoding error message.
|
|
/// - Process state set to idle and removed DB access lock on abort of open, exception or exit.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Apr-28" author="Thomas Wiedebusch">
|
|
/// - Changed exit status to force fill data grid with pcb ids,
|
|
/// - Log detected pcb ids of safe.
|
|
/// </remarks>
|
|
/// <remarks date="2023-Oct-23" author="Thomas Wiedebusch">
|
|
/// - Output extended to customer name and valid date and colored based on valid date.
|
|
/// </remarks>
|
|
/// <remarks date="2024-Jun-06" author="Thomas Wiedebusch">
|
|
/// - Crosscheck Loader version.
|
|
/// </remarks>
|
|
private void LoadFwUpdateSafe()
|
|
{
|
|
Byte[] encryptedStream = null;
|
|
try
|
|
{
|
|
Invoke(new Action(() =>
|
|
{
|
|
dlgOpenFwUpdateSafe.InitialDirectory = FwUpdateSafePath;
|
|
var fileExtension = FwUpdateConfig.FwUpdateFileExtension;
|
|
dlgOpenFwUpdateSafe.Filter = $@"FW-Update Safe (*{fileExtension})|*{fileExtension}";
|
|
if (dlgOpenFwUpdateSafe.ShowDialog() != DialogResult.OK)
|
|
{
|
|
MessageBoxShow(Resources.StrLoadingFwUpdateSafeFailed, Resources.StrError,
|
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
_dbAccessIsLocked = false;
|
|
_processState = ProcessState.Idle;
|
|
return;
|
|
}
|
|
|
|
_fwUpdateSafePathName = dlgOpenFwUpdateSafe.FileName;
|
|
|
|
_customerAndOrderInfo = "";
|
|
if (File.Exists(_fwUpdateSafePathName))
|
|
{
|
|
encryptedStream = File.ReadAllBytes(_fwUpdateSafePathName);
|
|
// extract _customerAndOrderInfo from FW-Update safe name
|
|
_customerAndOrderInfo = Path.GetFileNameWithoutExtension(_fwUpdateSafePathName);
|
|
}
|
|
else
|
|
{
|
|
LogText(Resources.StrLoadingFwUpdateSafeFailed + " " + _customerAndOrderInfo);
|
|
MessageBoxShow(Resources.StrLoadingFwUpdateSafeFailed, Resources.StrError,
|
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
_dbAccessIsLocked = false;
|
|
_processState = ProcessState.Idle;
|
|
}
|
|
}));
|
|
|
|
}
|
|
catch (Exception)
|
|
{
|
|
LogText(Resources.StrLoadingFwUpdateSafeFailed + " " + _customerAndOrderInfo);
|
|
//MessageBoxShow(e.ToString(), Resources.StrError, MessageBoxButtons.OK,
|
|
// MessageBoxIcon.Error);
|
|
MessageBoxShow(Resources.StrLoadingFwUpdateSafeFailed, Resources.StrError, MessageBoxButtons.OK,
|
|
MessageBoxIcon.Error);
|
|
_processState = ProcessState.Idle;
|
|
}
|
|
|
|
if (encryptedStream == null) return;
|
|
|
|
try
|
|
{
|
|
var primaryKey = FwUpdateCrypt.BuildPrimaryKey(_regUser.HardwareId, _regUser.Domain,
|
|
_regUser.LogInName, _regUser.PasswordHash);
|
|
var decryptedStream = FwUpdateCrypt.Decrypt(encryptedStream, primaryKey);
|
|
var decryptedData = Encoding.UTF8.GetString(decryptedStream, 0, decryptedStream.Length);
|
|
_fwUpdateSafe = JsonConvert.DeserializeObject<FwUpdateSafe>(decryptedData);
|
|
LogText(Resources.StrDecryptFwUpdateSafeSuccess + " " + _customerAndOrderInfo);
|
|
if (_fwUpdateSafe?.Updates?.CordonelDeviceInfos != null)
|
|
{
|
|
foreach (var cordonel in _fwUpdateSafe.Updates.CordonelDeviceInfos)
|
|
{
|
|
LogText($@"{Resources.StrTableCordonelPcbId}: {cordonel.PcbId}");
|
|
}
|
|
}
|
|
|
|
Thread.CurrentThread.CurrentUICulture = _cultureInfo;
|
|
Thread.CurrentThread.CurrentCulture = _cultureInfo;
|
|
// The loader version needs to be checked to avoid an incompatible Software to Loader version
|
|
if (CrosscheckLoaderVersion())
|
|
{
|
|
CheckFwUpdateEnabled();
|
|
_dbAccessIsLocked = false;
|
|
_processState = ProcessState.CheckPcbIdProcessState;
|
|
}
|
|
else
|
|
{
|
|
var versionMajor = "?";
|
|
var versionMinor = "?";
|
|
var versionBuild = "?";
|
|
if (_fwUpdateSafe?.License != null)
|
|
{
|
|
versionMajor = _fwUpdateSafe.License.Major.ToString();
|
|
versionMinor = _fwUpdateSafe.License.Minor.ToString();
|
|
versionBuild = _fwUpdateSafe.License.Build.ToString();
|
|
}
|
|
var msg = Resources.StrSoftwareVersionExpired +
|
|
$@" Version: {versionMajor}.{versionMinor}.{versionBuild}";
|
|
LogText(msg);
|
|
MessageBoxShow(msg, Resources.StrError,
|
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
_dbAccessIsLocked = false;
|
|
_processState = ProcessState.Idle;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogText(ex.Message);
|
|
LogText(Resources.StrDecryptFwUpdateSafeFailed + " " + _customerAndOrderInfo);
|
|
//MessageBoxShow(e.ToString(), Resources.StrError, MessageBoxButtons.OK,
|
|
// MessageBoxIcon.Error);
|
|
MessageBoxShow(Resources.StrDecryptFwUpdateSafeFailed, Resources.StrError, MessageBoxButtons.OK,
|
|
MessageBoxIcon.Error);
|
|
_dbAccessIsLocked = false;
|
|
_processState = ProcessState.Idle;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Start of FW-Update SW.
|
|
/// </summary>
|
|
/// <remarks date="2020-Nov-30" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2021-Jan-29" author="Thomas Wiedebusch">
|
|
/// - Removed test and use real data.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-09" author="Thomas Wiedebusch">
|
|
/// - Added customer name and FW-Update order number.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-16" author="Thomas Wiedebusch">
|
|
/// - Locked DB access during FW-Update.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-18" author="Thomas Wiedebusch">
|
|
/// - load configuration.json to the AppDomain "FwUpdateLoader" as it cannot be accessed if stored in the
|
|
/// subdirectory "ServiceFwUpdateSw". ALl other files can remain there.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-20" author="Thomas Wiedebusch">
|
|
/// - Logging info.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-22" author="Thomas Wiedebusch">
|
|
/// - FW-Update SW taken from FW-Update Safe.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
|
|
/// - FW-Update process marked to stop DB connection trials.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-26" author="Thomas Wiedebusch">
|
|
/// - FW-Update SW loaded to new app domain.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-27" author="Thomas Wiedebusch">
|
|
/// - FW-Update SW loaded to new app domain [optional],
|
|
/// - Avoid loading of assembly if already done.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-29" author="Thomas Wiedebusch">
|
|
/// - If files are already loaded, skip the ExtractFwUpdateSw process in single domain mode, as the assembly
|
|
/// is loaded and these files are locked for processing.
|
|
/// </remarks>
|
|
/// <remarks date="2023-Oct-23" author="Thomas Wiedebusch">
|
|
/// - Send safe information.
|
|
/// </remarks>
|
|
private void StartFwUpdateProcess()
|
|
{
|
|
if (_fwUpdateSafe == null) return;
|
|
try
|
|
{
|
|
#if (USE_APP_DOMAIN)
|
|
// create and copy all DLLs to this temporary working directory, copy register definition
|
|
// file to current AppDomain
|
|
if (ExtractFwUpdateSw())
|
|
{
|
|
{
|
|
// Copy the actual setup
|
|
var domainSetup = AppDomain.CurrentDomain.SetupInformation;
|
|
domainSetup.PrivateBinPath = _fwUpdateSwDestinationPath;
|
|
var appDomainEvidence = AppDomain.CurrentDomain.Evidence;
|
|
_fwUpdateSwAppDomain = AppDomain.CreateDomain(AppDomainName, appDomainEvidence, domainSetup);
|
|
|
|
_asmLoader = (AssemblyLoader)_fwUpdateSwAppDomain.CreateInstanceAndUnwrap(
|
|
typeof(AssemblyLoader).Assembly.FullName, typeof(AssemblyLoader).FullName ?? string.Empty);
|
|
|
|
_fwUpdateObject = _asmLoader.LoadAssemblyGetClassObject(_fwUpdateSwDestinationPath, FwUpdateSwDll,
|
|
FormFwUpdateSw);
|
|
if (_fwUpdateObject == null) return;
|
|
}
|
|
#else
|
|
// If files are already loaded, skip the ExtractFwUpdateSw process in single domain mode, as the assembly
|
|
// is loaded and these files are locked for processing!
|
|
if (_asmLoader != null || ExtractFwUpdateSw())
|
|
{
|
|
{
|
|
// avoid loading of assembly if already done
|
|
if (_asmLoader == null)
|
|
{
|
|
_asmLoader = new AssemblyLoader();
|
|
// loading the FwUpdateSw DLL from HDD
|
|
if (!_asmLoader.LoadAssembly(_fwUpdateSwDestinationPath, FwUpdateSwDll)) return;
|
|
}
|
|
// retrieving the address of a specific assembly
|
|
_fwUpdateObject = _asmLoader.GetAssemblyFnObject(FormFwUpdateSw, null, null);
|
|
}
|
|
#endif
|
|
// inform the FW-Update SW where to find the setups
|
|
// relative to C:\[user]\AppData\Roaming\ which is here \Genesis
|
|
var basePaths = new FwUpdatePaths
|
|
{
|
|
PortConfigFilePathName = PortConfigPathName,
|
|
MeterFilesConfigFilePathName = _meterFilesConfigPathName,
|
|
FwUpdateSwPathName = _fwUpdateSwDestinationPath,
|
|
CustomerAndOrderNumber = _customerAndOrderInfo
|
|
};
|
|
SendDataToFwUpdateSw(basePaths);
|
|
|
|
// send CordonelFirmware to FW-Update SW
|
|
if (_fwUpdateSafe.Updates.CordonelFwPackage != null)
|
|
{
|
|
SendDataToFwUpdateSw(_fwUpdateSafe.Updates.CordonelFwPackage);
|
|
}
|
|
|
|
// send Cordonel device information
|
|
foreach (var di in _fwUpdateSafe.Updates.CordonelDeviceInfos)
|
|
{
|
|
SendDataToFwUpdateSw(di);
|
|
}
|
|
|
|
// send safe information
|
|
if (_fwUpdateSafe.SafeInfo != null)
|
|
{
|
|
SendDataToFwUpdateSw(_fwUpdateSafe.SafeInfo);
|
|
}
|
|
|
|
if (!(_fwUpdateObject is Form formFwUpdate)) return;
|
|
|
|
LogText(Resources.StrLoadingFwUpdateSwSuccess);
|
|
DisableControls();
|
|
|
|
formFwUpdate.Closed += FormFwUpdate_Closed;
|
|
|
|
Invoke(new Action(() =>
|
|
{
|
|
formFwUpdate.Show();
|
|
Hide();
|
|
}));
|
|
|
|
SendDataToFwUpdateSw(_fwUpdateSafe.License);
|
|
}// build and copy entire FwUpdateSw directory and register definition file
|
|
else
|
|
{
|
|
LogText(Resources.StrLoadingFwUpdateSwFailed);
|
|
MessageBoxShow(Resources.StrLoadingFwUpdateSwFailed, Resources.StrError, MessageBoxButtons.OK,
|
|
MessageBoxIcon.Error);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
LogText(Resources.StrLoadingFwUpdateSwFailed);
|
|
MessageBoxShow(e.ToString(), Resources.StrError, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
// erase DLLs and remove directory if empty
|
|
// SystemControl.RemoveDirectory(_fwUpdateSwDestinationPath);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Process bar.
|
|
/// </summary>
|
|
/// <remarks date="2021-Feb-25" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-25" author="Thomas Wiedebusch">
|
|
/// - Avoid repeated execution on invisible progress bar.
|
|
/// </remarks>
|
|
private void SetStatusProgressBar(Int32 value = 0, Boolean visible = true)
|
|
{
|
|
if (ProgressBarStatus == null || (!ProgressBarStatus.Visible && !visible)) return;
|
|
if (ProgressBarStatus.Visible && visible && ProgressBarStatus.Value == value) return;
|
|
ProgressBarStatus.Value = value;
|
|
ProgressBarStatus.Visible = visible;
|
|
}
|
|
|
|
///// <summary>
|
|
///// Establish the DB connection.
|
|
///// </summary>
|
|
///// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
|
|
///// - Initial
|
|
///// </remarks>
|
|
//private void EstablishDbConnectionTask()
|
|
//{
|
|
// Task.Factory.StartNew(() =>
|
|
// {
|
|
// Thread.CurrentThread.CurrentUICulture = _cultureInfo;
|
|
// Thread.CurrentThread.CurrentCulture = _cultureInfo;
|
|
// try
|
|
// {
|
|
// // check DB connection in advance to overcome the timing issues for DB service startup
|
|
// _fwUpdateDbAccess?.CheckDbConnection();
|
|
// }
|
|
// catch (Exception)
|
|
// {
|
|
// _processState = ProcessState.Idle;
|
|
// }
|
|
// }).ContinueWith(delegate
|
|
// {
|
|
// if (_processState == ProcessState.ConnectDb) _processState = ProcessState.Idle;
|
|
// });
|
|
//}
|
|
|
|
/// <summary>
|
|
/// Output exclusively to user update remarks text window.
|
|
/// </summary>
|
|
private void LogText(String txtHistory)
|
|
{
|
|
Invoke(new Action(() =>
|
|
{
|
|
_logger.Info(txtHistory);
|
|
}));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Neutral information to label, user text box and logger.
|
|
/// </summary>
|
|
private void InfoStatusUnknown(Control label, String msg, Boolean userTextOutput = false)
|
|
{
|
|
if (userTextOutput) LogText(msg);
|
|
UiInvoker.ControlInvoker(label, ColorUnknownStatus, msg);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Success information to label, user text box and logger.
|
|
/// </summary>
|
|
private void InfoProcessActive(Control label, String msg, Boolean log = true)
|
|
{
|
|
if (log) LogText(msg);
|
|
UiInvoker.ControlInvoker(label, ColorOngoingProcess, msg);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Success information to label, user text box and logger.
|
|
/// </summary>
|
|
private void InfoProcessSuccess(Control label, String msg, Boolean log = true)
|
|
{
|
|
if (log) LogText(msg);
|
|
UiInvoker.ControlInvoker(label, ColorSuccess, $@"{SuccessSign} {msg}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Failed information to label, user text box and logger.
|
|
/// </summary>
|
|
private void InfoProcessFailed(Control label, String msg, Boolean log = true)
|
|
{
|
|
if (log)
|
|
{
|
|
LogText(StrSeparator);
|
|
LogText(msg);
|
|
LogText(StrSeparator);
|
|
}
|
|
|
|
UiInvoker.ControlInvoker(label, ColorProcessFailed, $@"{FailedSign} {msg}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Common routine for disable all controls.
|
|
/// </summary>
|
|
/// <remarks date="2021-Mar-16" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
|
|
/// - UiInvoker.
|
|
/// </remarks>
|
|
private void DisableControls()
|
|
{
|
|
UiInvoker.ControlEnableInvoker(btnFwUpdate, false);
|
|
UiInvoker.ControlEnableInvoker(btnLoadFwUpdSafe, false);
|
|
UiInvoker.ControlEnableInvoker(btnRegister, false);
|
|
}
|
|
|
|
#endregion --------------------------------------- Tools ------------------------------------------------------
|
|
|
|
#region ------------------------------------------ Data Grid PCB ID -------------------------------------------
|
|
/// <summary>
|
|
/// Build data grid for PCB ID
|
|
/// </summary>
|
|
/// <remarks date="2021-Apr-28" author="Thomas Wiedebusch">
|
|
/// - Initial.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Oct-15" author="Thomas Wiedebusch">
|
|
/// - Added order number to search for successfully updated device in linked to this safe.
|
|
/// </remarks>
|
|
/// <remarks date="2023-Oct-12" author="Thomas Wiedebusch">
|
|
/// - Added customer serial number in overview.
|
|
/// </remarks>
|
|
private void FillDataGridWithPcbIdInfos()
|
|
{
|
|
if (_fwUpdateSafe?.Updates?.CordonelDeviceInfos == null) return;
|
|
|
|
grpLanguageSelection.Enabled = false;
|
|
|
|
_dataTablePcbIds?.Dispose();
|
|
Thread.CurrentThread.CurrentUICulture = _cultureInfo;
|
|
Thread.CurrentThread.CurrentCulture = _cultureInfo;
|
|
_dataTablePcbIds = new DataTable();
|
|
|
|
_dataTablePcbIds.Columns.Add(Resources.StrTableUpdated, typeof(Boolean));
|
|
_dataTablePcbIds.Columns.Add(Resources.StrTableCordonelPcbId, typeof(String));
|
|
_dataTablePcbIds.Columns.Add(Resources.StrTableCustomerSerialNumber, typeof(String));
|
|
|
|
try
|
|
{
|
|
foreach (var cordSearch in _fwUpdateSafe.Updates.CordonelDeviceInfos)
|
|
{
|
|
var row = _dataTablePcbIds.NewRow();
|
|
row[Resources.StrTableUpdated] = IsPcbIdProcessed(cordSearch.PcbId, _customerAndOrderInfo);
|
|
row[Resources.StrTableCordonelPcbId] = cordSearch.PcbId ?? Constants.StrUnknown;
|
|
row[Resources.StrTableCustomerSerialNumber] = cordSearch.CustomerSerialNumber ?? Constants.StrUnknown;
|
|
|
|
_dataTablePcbIds.Rows.Add(row);
|
|
}
|
|
|
|
gridViewPcbIds.DataSource = _dataTablePcbIds;
|
|
|
|
foreach (DataGridViewColumn column in gridViewPcbIds.Columns)
|
|
{
|
|
column.SortMode = DataGridViewColumnSortMode.Automatic;
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
_processState = ProcessState.Error;
|
|
}
|
|
finally
|
|
{
|
|
grpLanguageSelection.Enabled = true;
|
|
}
|
|
}
|
|
#endregion --------------------------------------- Data Grid PCB ID -------------------------------------------
|
|
|
|
#region ------------------------------------------ Interfaces -------------------------------------------------
|
|
/// <summary>
|
|
/// Send data as json stream to FW-Update SW.
|
|
/// </summary>
|
|
/// <param name="data"></param>
|
|
/// <returns>true if succeeded</returns>
|
|
/// <remarks date="2020-Dec-14" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2023-Oct-23" author="Thomas Wiedebusch">
|
|
/// - Added FW update safe information for report
|
|
/// </remarks>
|
|
private Boolean SendDataToFwUpdateSw(Object data)
|
|
{
|
|
if (_fwUpdateObject == null) return false;
|
|
var parameters = new Object[2];
|
|
|
|
// As a complex field cannot be passed between a dynamic loaded assembly due to
|
|
// the unknown signature or assembly version, a simple data type will be passed and
|
|
// then converted to the complex type.
|
|
switch (data)
|
|
{
|
|
case FwUpdateSafeInfo _:
|
|
parameters[0] = (Int32)DataContainerName.FwUpdateSafeInfo;
|
|
break;
|
|
|
|
case CordonelDeviceInfo _:
|
|
parameters[0] = (Int32)DataContainerName.CordonelDeviceInfo;
|
|
break;
|
|
|
|
case SoftwareLicense _:
|
|
parameters[0] = (Int32)DataContainerName.SoftwareLicense;
|
|
break;
|
|
|
|
case FwUpdatePaths _:
|
|
parameters[0] = (Int32)DataContainerName.UpdatePackageBasePath;
|
|
break;
|
|
|
|
case CordonelFirmware _:
|
|
parameters[0] = (Int32)DataContainerName.UpdatePackage;
|
|
break;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
parameters[1] = JsonConvert.SerializeObject(data);
|
|
#if (USE_APP_DOMAIN)
|
|
return _asmLoader.InvokeMember(FormFwUpdateSw, FwUpdateSwDataExchangeInterface, parameters);
|
|
#else
|
|
return (Boolean)_fwUpdateObject.GetType().InvokeMember(FwUpdateSwDataExchangeInterface,
|
|
BindingFlags.InvokeMethod, null, _fwUpdateObject, parameters);
|
|
#endif
|
|
}
|
|
#endregion --------------------------------------- Interfaces -------------------------------------------------
|
|
|
|
#region ------------------------------------------ Language ---------------------------------------------------
|
|
/// <summary>
|
|
/// Select language at runtime: English
|
|
/// </summary>
|
|
/// <remarks date="2020-Nov-27" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2021-Feb-23" author="Thomas Wiedebusch">
|
|
/// - Change menu.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Feb-26" author="Thomas Wiedebusch">
|
|
/// - Avoid repetition if current culture is equal to the required one.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Apr-28" author="Thomas Wiedebusch">
|
|
/// - Backup safe name for language change.
|
|
/// </remarks>
|
|
private void RadioBtnEnglishLanguage_Click(Object sender, EventArgs e)
|
|
{
|
|
if (Thread.CurrentThread.CurrentCulture.Name == "en-GB") return;
|
|
_cultureInfo = new CultureInfo("en-GB");
|
|
_backupSafeNameForLanguageChange = lblLoadedSafe.Text;
|
|
ChangeLanguageControls();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Select language at runtime: German
|
|
/// </summary>
|
|
/// <remarks date="2020-Nov-27" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2021-Feb-23" author="Thomas Wiedebusch">
|
|
/// - Change menu.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Feb-26" author="Thomas Wiedebusch">
|
|
/// - Avoid repetition if current culture is equal to required.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Apr-28" author="Thomas Wiedebusch">
|
|
/// - Backup safe name for language change.
|
|
/// </remarks>
|
|
private void RadioBtnGermanLanguage_Click(Object sender, EventArgs e)
|
|
{
|
|
if (Thread.CurrentThread.CurrentCulture.Name == "de-DE") return;
|
|
_cultureInfo = new CultureInfo("de-DE");
|
|
_backupSafeNameForLanguageChange = lblLoadedSafe.Text;
|
|
ChangeLanguageControls();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Change language at runtime
|
|
/// </summary>
|
|
/// <remarks date="2021-Feb-23" author="Thomas Wiedebusch">
|
|
/// - Initial based on code example
|
|
/// https://stackoverflow.com/questions/52178064/winforms-localization-how-to-change-the-language-of-a-menu.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Apr-06" author="Thomas Wiedebusch">
|
|
/// - Check user registration added.
|
|
/// </remarks>
|
|
/// <remarks date="2021-Apr-28" author="Thomas Wiedebusch">
|
|
/// - Restore safe name after language change.
|
|
/// </remarks>
|
|
private void ChangeLanguageControls()
|
|
{
|
|
Thread.CurrentThread.CurrentUICulture = _cultureInfo;
|
|
Thread.CurrentThread.CurrentCulture = _cultureInfo;
|
|
var resources = new ComponentResourceManager(typeof(FrmFwUpdateLoader));
|
|
resources.ApplyResources(this, "$this");
|
|
ControlExtensions.ChangeControlText(resources, Controls);
|
|
|
|
var rm = new ComponentResourceManager(this.GetType());
|
|
foreach (var control in this.AllControls())
|
|
{
|
|
if (control is ToolStrip)
|
|
{
|
|
var items = ((ToolStrip)control).AllItems().ToList();
|
|
foreach (var item in items)
|
|
rm.ApplyResources(item, item.Name);
|
|
}
|
|
rm.ApplyResources(control, control.Name);
|
|
}
|
|
|
|
if (!_fwUpdateDbAccess.DbIsConnected)
|
|
{
|
|
lblStatusDbConnect.Text = Resources.StrNotConnectedToDb;
|
|
lblStatusDbConnect.ForeColor = ColorProcessRequired;
|
|
}
|
|
else
|
|
{
|
|
lblStatusDbConnect.Text = Resources.StrConnectedToDb;
|
|
lblStatusDbConnect.ForeColor = ColorSuccess;
|
|
}
|
|
|
|
lblFwUpdateInfo.Text = $@"Version: {_version.Major}.{_version.Minor}.{_version.Build}";
|
|
lblPcName.Text = @"PC Name: " + CryptInformation.GetSysPcName();
|
|
lblCustomerName.Text = "";
|
|
lblSafeValidDate.Text = "";
|
|
|
|
CheckReportStatus();
|
|
CheckUserRegistration();
|
|
CheckFwUpdateSafeExistence();
|
|
if (_fwUpdateSafe?.SafeInfo != null)
|
|
{
|
|
lblLoadedSafe.Text = _backupSafeNameForLanguageChange;
|
|
lblCustomerName.Text = _fwUpdateSafe.SafeInfo.CustomerName;
|
|
lblSafeValidDate.Text = Resources.StrSafeValidDate +
|
|
$@" {_fwUpdateSafe.SafeInfo.FwUpdateValidDate:dddd, dd-MMM-yyyy HH:mm:ss} UTC";
|
|
}
|
|
FillDataGridWithPcbIdInfos();
|
|
}
|
|
|
|
#endregion --------------------------------------- Language ---------------------------------------------------
|
|
}
|
|
}
|
|
|