laatzen/ServiceFwUpdate/Ui/ServiceFwUpdateBuilder/FrmFwUpdateBuilder.cs

4808 lines
217 KiB
C#

using Logic.ProductionToProductMapper.Files.Fw;
using Newtonsoft.Json;
using NLog;
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 Xylem.Common.CommonCore.Consts;
using Xylem.Common.CommonCore.ThreadWatcher;
using Xylem.Common.Cryptology.Security;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile;
using Xylem.Common.Utils.DateTimeServer;
using Xylem.Common.Utils.Logging;
using Xylem.Common.Utils.UiInvoker;
using Xylem.Common.Utils.UiLanguageControl;
using Xylem.Common.Utils.FileIo;
using Xylem.ServiceFwUpdate.Common.FwUpdateConfig.Consts;
using Xylem.ServiceFwUpdate.Common.FwUpdateDb;
using Xylem.ServiceFwUpdate.Common.FwUpdateSafe;
using Xylem.ServiceFwUpdate.Ui.FwUpdateBuilder.Const;
using Xylem.ServiceFwUpdate.Ui.FwUpdateBuilder.Properties;
using Xylem.Common.Utils.Crc16Ccitt;
namespace Xylem.ServiceFwUpdate.Ui.FwUpdateBuilder
{
/// <summary>
/// FW update builder
/// </summary>
public partial class FrmFwUpdateBuilder : Form
{
#region ------------------------------------------ Variables --------------------------------------------------
private static readonly Color ColorBackGround = Color.White;
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 ColorOngoingProcess = Color.Blue;
//private static readonly Color ColorUnknownStatus = Color.Gray;
private static readonly Color ColorBkMissing = Color.LightCoral;
private static readonly Color ColorBkValid = Color.LightGreen;
//private const String SuccessSign = @"✔";
//private const String FailedSign = @"✘";
private readonly CancellationTokenSource _processToken = new CancellationTokenSource();
private readonly Thread _fwUpdateBuilderThread;
// 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>
/// remind manually changed culture setting
/// </summary>
private CultureInfo _cultureInfo;
private readonly Version _version;
private readonly String _versionString;
private readonly AssemblyName _assemblyName;
private Boolean _licenseUnchecked;
private DateTimeOffset _licenseValidDateTimeOffset;
private const Int32 DbLicenseRefreshTimeoutMs = 60000;
private Int32 _dbLicenseRefreshDelayCtrMs;
private readonly ILogger _logger;
private const String StrSeparator = "-----------------------------------------------------" +
"-----------------------------------------------------";
/// <summary>
/// Registered user information read from registration file.
/// </summary>
private readonly UserInformation _regUser = new UserInformation();
//data grid styles
private readonly DataGridViewCellStyle _styleValid = new DataGridViewCellStyle();
private readonly DataGridViewCellStyle _styleInvalid = new DataGridViewCellStyle();
private readonly DataGridViewCellStyle _styleUnknown = new DataGridViewCellStyle();
private readonly DataGridViewCellStyle _styleInstallationApproved = new DataGridViewCellStyle();
private readonly DataGridViewCellStyle _styleInstallationDenied = new DataGridViewCellStyle();
private readonly DataGridViewCellStyle _styleInstallationUserApproval = new DataGridViewCellStyle();
private readonly DataGridViewCellStyle _styleInstallationRemoved = new DataGridViewCellStyle();
private DataTable _dataTableFwPackages;
private DataTable _dataTableSummary;
private DataTable _dataTableCordonels;
private DataTable _dataTableUpdateOperators;
private DataTable _dataTableCustomers;
///<summary>
/// Collection of software needed for the FW-Update safe!
/// </summary>
private SoftwareContainer _fwUpdateSwContainer;
///<summary>
/// All customer specific production order numbers to search mask from the DB!
/// This information will only be used by the FW Update Builder!
/// </summary>
private readonly List<CordonelCustomerOrderDb> _cordonelCustomerOrdersSearch =
new List<CordonelCustomerOrderDb>();
///<summary>
/// All information acquired from the DB! This information will only be used by the FW Update Builder
/// as search!
/// </summary>
private readonly List<CordonelProductionInfosDb> _cordonelProductionSearchInfos =
new List<CordonelProductionInfosDb>();
///<summary>
/// All information acquired from the DB! This information will only be used by the FW Update Builder
/// as pre-selection!
/// </summary>
private readonly List<CordonelProductionInfosDb> _cordonelProductionPreSelectInfos =
new List<CordonelProductionInfosDb>();
///<summary>
/// The Cordonel device info is all needed information for the FW-Update SW to login, install the password file
/// and select the required release version to collect it out of the FW-Update packages!
/// This is the list of already selected Cordonels for the update process! This information will be installed
/// in the FW-Update Safe and therefore passed to the FW-Update SW.
/// </summary>
private readonly List<CordonelDeviceInfo> _cordonelUpdateList = new List<CordonelDeviceInfo>();
private String _fwPackageCordonelPcbId;
///<summary>
/// The FW-Update package is a collection of all needed applications and settings to install into the Cordonel!
/// This information will be passed to the FW-Update SW if any Cordonel requires this package.
/// </summary>
private readonly List<CordonelFirmware> _fwUpdatePackages = new List<CordonelFirmware>();
///<summary>
/// All Cordonel FW package information needed to select the right package for installation! This is going to be
/// filled with information from the read packages from DB.
/// This information will only be used by the FW Update Builder!
/// </summary>
private readonly List<CordonelFwPackageInfo> _cordonelFwPackageInfoSearch = new List<CordonelFwPackageInfo>();
private readonly List<String> _metrologySearchItems = new List<String>();
private readonly List<String> _coreSearchItems = new List<String>();
private readonly List<String> _regionSearchItems = new List<String>();
private readonly List<String> _radioSearchItems = new List<String>();
private readonly List<String> _sizeSearchItems = new List<String>();
///<summary>
/// The FW-Update update capability is internally used to check core revision, metrology, region, frequency a.s.o.
/// This information will only be used by the FW Update Builder!
/// </summary>
private readonly List<FwUpdateCapability> _fwUpdateCapability = new List<FwUpdateCapability>();
private readonly FwUpdateDb _fwUpdateDbAccess = new FwUpdateDb();
// private readonly UserInformation _userInfo;
private Byte[] _primaryKey;
private readonly DateTimePicker _datePicker = new DateTimePicker();
private readonly ComboBox _cbxFwReleaseSelection = new ComboBox();
private Boolean _enableFwSafeUpload;
private String _fwUpdateSafeName;
private FwUpdateSafeDb _fwUpdateSafeDb;
private Int32 _updateOperatorId;
private readonly List<MeterFwUpdateRuler> _meterFwUpdateRuler = new List<MeterFwUpdateRuler>();
/// <summary>
/// Reminder to avoid repeated reading of DB contents and reset of selection if item has already been assigned
/// Values have to be preset to avoid a null at first check!!!!!!
/// </summary>
private String _customerNumberBeforeLastCordonelDbSearch = "";
/// <summary>
/// Feedback from any task that an update of all tables is required
/// </summary>
private Boolean _fwUpdateOperatorsPropertyChanged;
private Boolean _customersPropertyChanged;
private Boolean _cordonelsPropertyChanged;
private Boolean _fwPackagePropertyChanged;
private Boolean _fwReportFilesPropertyChanged;
private Boolean _fwUpdateSafesPropertyChanged;
private Boolean _preBuildSummaryPropertyChanged;
/// <summary>
/// DB connection retry timer if DB is not connected
/// </summary>
private const Int32 DbConnectionRetryDelayMs = 6000;
/// <summary>
/// DB connection timeout on active DB connectivity test
/// </summary>
private const Int32 DbConnectionTimeoutMs = 5000;
private Int32 _dbAccessDelayCtrMs;
/// <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 for firmware update software including the namespace
/// </summary>
public const String FwUpdateSwFullName = "Xylem.ServiceFwUpdate.Ui." + FwUpdateProjectName;
/// <summary>
/// Path for FW-Update safes
/// </summary>
private static readonly String FwUpdateSafePath = Path.Combine(Environment.GetFolderPath(
Environment.SpecialFolder.UserProfile), FwUpdateConfig.DefaultFwUpdateSafePath);
/// <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>
/// Path and file user NLog configuration
/// </summary>
private static readonly String NLogConfigurationDestPathFile = Path.Combine(ApplicationConfigPath,
ProgramConfig.NlogConfig);
/// <summary>
/// Source folder of software package if taken from local [user]/downloads/ServiceFwUpdateSw
/// </summary>
private static readonly String FwUpdateSwSourcePath = Path.Combine(Environment.GetFolderPath(
Environment.SpecialFolder.UserProfile), FwUpdateConfig.DefaultFwUpdateSwSourcePath);
#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-Jun-08" author="Roland Drabesch">
/// - Sleep on equal process state to force suspend of actual thread.
/// </remarks>
/// <remarks date="2021-Oct-28" author="Thomas Wiedebusch">
/// - Added report files and FW-Update safes load from DB.
/// </remarks>
private void FwUpdateBuilderStateMachine()
{
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:
// Process state change catcher to leave state as is
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.GetCustomersFromDb:
LoadDbCordonelCustomersTask();
break;
case ProcessState.GetReportFilesFromDb:
LoadDbReportFilesTask();
break;
case ProcessState.GetFwUpdateSafesFromDb:
LoadDbOutstandingFwUpdateSafesTask();
break;
case ProcessState.GetFwUpdateOperatorsFromDb:
LoadDbFwUpdateOperatorsTask();
break;
case ProcessState.ValidateSoftware:
CheckLicenseTask();
break;
case ProcessState.BuildFwUpdateSafe:
BuildFwUpdateSafeTask();
break;
case ProcessState.UploadFwUpdateSafeToDb:
UploadFwUpdateSafeTask();
break;
case ProcessState.GetCordonelProductionOrdersFromDb:
LoadDbCordonelProductionOrdersTask();
break;
case ProcessState.GetCordonelSerialNumbersFromDb:
LoadDbCordonelSerialNumbersTask();
break;
case ProcessState.GetFwPackagesFromDb:
LoadDbCordonelFwPackagesTask();
break;
case ProcessState.DbAccessLocked:
// Process state change catcher to leave state as is
break;
case ProcessState.UserRegistration:
// Process state change catcher to leave state as is
break;
default:
_processState = ProcessState.Idle;
break;
}
}
catch (ThreadAbortException)
{
throw;
}
catch (Exception e)
{
_processState = ProcessState.Error;
if (_fwUpdateBuilderThread.ThreadState == ThreadState.Aborted
|| _fwUpdateBuilderThread.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>
/// The timer for progress bar.
/// </summary>
/// <remarks date="2021-Feb-25" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2021-Mar-23" author="Thomas Wiedebusch">
/// - Changed logic
/// </remarks>
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
/// - Checks exported
/// </remarks>
/// <remarks date="2021-Oct-28" author="Thomas Wiedebusch">
/// - Added checks for FW-update safes and report files.
/// </remarks>
private void TmrProgressUpdate_Tick(Object sender, EventArgs e)
{
Thread.CurrentThread.CurrentUICulture = _cultureInfo;
Thread.CurrentThread.CurrentCulture = _cultureInfo;
_dbAccessDelayCtrMs += TmrDbAccess.Interval;
_dbLicenseRefreshDelayCtrMs += TmrDbAccess.Interval;
switch (_processState)
{
case ProcessState.DbAccessLocked:
CheckDbConnectivity();
break;
case ProcessState.Idle:
CheckDbConnectivity();
CheckDataCollectionStatus();
CheckUpdateOperatorAccountChange();
CheckCustomerChange();
CheckCordonelChange();
CheckFwPackageChange();
CheckFwUpdateSafesChange();
CheckReportFilesChange();
break;
case ProcessState.BuildFwUpdateSafe:
SetStatusProgressBar(ProgressBarStatus.Value + 1 > 100 ? 0 : ProgressBarStatus.Value + 1);
break;
case ProcessState.ConnectDb:
case ProcessState.GetFwUpdateOperatorsFromDb:
case ProcessState.GetCordonelProductionOrdersFromDb:
case ProcessState.GetCustomersFromDb:
case ProcessState.GetFwPackagesFromDb:
case ProcessState.GetCordonelSerialNumbersFromDb:
case ProcessState.GetFwUpdateSafesFromDb:
case ProcessState.GetReportFilesFromDb:
case ProcessState.UploadFwUpdateSafeToDb:
CheckDbConnectionTimeout();
SetStatusProgressBar(ProgressBarStatus.Value + 1 > 100 ? 0 : ProgressBarStatus.Value + 1);
break;
}
}
#endregion --------------------------------------- Timer Controls ---------------------------------------------
#region ------------------------------------------ User Interaction -------------------------------------------
/// <summary>
/// Select all content for quick change
/// </summary>
/// <remarks date="2021-Apr-15" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void tbxCordonelProductionOrdersSearch_Enter(Object sender, EventArgs e)
{
tbxCordonelProductionOrdersSearch.Select(0, tbxCordonelProductionOrdersSearch.Text.Length);
}
/// <summary>
/// Select all content for quick change
/// </summary>
/// <remarks date="2021-Apr-15" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void tbxCordonelProductionOrdersSearch_MouseClick(Object sender, MouseEventArgs e)
{
tbxCordonelProductionOrdersSearch.Select(0, tbxCordonelProductionOrdersSearch.Text.Length);
}
/// <summary>
/// Validate input
/// </summary>
/// <remarks date="2021-Apr-13" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void tbxOrderNumber_TextChanged(Object sender, EventArgs e)
{
tbxOrderNumber.Text = Regex.Match(tbxOrderNumber.Text, "[0-9]+").Groups[0].Value;
}
/// <summary>
/// Validate input
/// </summary>
/// <remarks date="2021-Apr-13" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void tbxOrderPosition_TextChanged(Object sender, EventArgs e)
{
tbxOrderPosition.Text = Regex.Match(tbxOrderPosition.Text, "[0-9]+").Groups[0].Value;
}
/// <summary>
/// Display Info
/// </summary>
/// <remarks date="2021-Apr-09" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void infoToolStripMenuItem_Click(Object sender, EventArgs e)
{
_processState = ProcessState.UserRegistration;
var frmRegister = new FrmRegister(_regUser);
DisableAllControlsInvoked();
frmRegister.Show();
frmRegister.Closed += FormRegister_Closed;
Hide();
}
/// <summary>
/// Exit of Registration Form.
/// </summary>
/// <remarks date="2021-Feb-04" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void FormRegister_Closed(Object sender, EventArgs e)
{
Show();
Update();
CheckUserRegistration();
}
/// <summary>
/// Exit the program
/// </summary>
/// <remarks date="2021-Apr-07" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void exitToolStripMenuItem_Click(Object sender, EventArgs e)
{
Close();
}
/// <summary>
/// Kick off customer search on key [Enter] pressed
/// </summary>
/// <remarks date="2021-Apr-07" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void tbxCustomerSearchMask_KeyDown(Object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
btnSearchCustomer_Click(this, null);
}
}
/// <summary>
/// Kick off Cordonel search on key [Enter] pressed
/// </summary>
/// <remarks date="2021-Apr-15" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void tbxCordonelProductionOrdersSearch_KeyDown(Object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
// Check if the searched serial number is in the download list if ALL have been loaded
if (!string.IsNullOrEmpty(tbxCordonelProductionOrdersSearch.Text) &&
_cordonelProductionSearchInfos.Count != 0 &&
_cordonelProductionSearchInfos.Any(x =>
x.CustomerSerialNumber.Contains(tbxCordonelProductionOrdersSearch.Text)) &&
cbxCordonelProductionOrdersSearch.Text == @"*")
{
_cordonelsPropertyChanged = true;
return;
}
btnCordonelSearch_Click(this, null);
}
}
/// <summary>
/// Kick off Cordonel search referenced by order number
/// </summary>
/// <remarks date="2021-Apr-04" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Apr-06" author="Thomas Wiedebusch">
/// - Removed DB access delay.
/// </remarks>
private void btnCordonelSearch_Click(Object sender, EventArgs e)
{
// reading if customer is selected
if (string.IsNullOrEmpty(lblCustomerNumber.Text) ||
string.IsNullOrEmpty(cbxCordonelProductionOrdersSearch.Text) ||
_fwUpdateDbAccess?.DbCordonelCustomerOrders == null) return;
try
{
// leave all original orders list intact to keep this information for the next search
// and clear the search list which will contain the user selected order numbers
_cordonelCustomerOrdersSearch.Clear();
// as the production info is going to fill the grid table view it has to be cleared on every new search
_cordonelProductionSearchInfos.Clear();
// remove unselected devices, avoid adding of already included devices
if (cbxCordonelProductionOrdersSearch?.SelectedItem == null ||
cbxCordonelProductionOrdersSearch.SelectedItem.ToString() == @"*")
{
_cordonelCustomerOrdersSearch.AddRange(_fwUpdateDbAccess.DbCordonelCustomerOrders);
}
else
{
// format is orderNumber-position e.g. 12345678-10
var orderText = cbxCordonelProductionOrdersSearch.SelectedItem.ToString().Split('-');
if (Int64.TryParse(orderText[0], out var orderNumber) &&
Int64.TryParse(orderText[1], out var orderPosition))
{
foreach (var order in _fwUpdateDbAccess.DbCordonelCustomerOrders.Where(order =>
order.CustomerOrderNumber == orderNumber &&
order.CustomerOrderPos == orderPosition))
{
_cordonelCustomerOrdersSearch.Add(order);
break;
}
}
}
DisableAllControlsInvoked();
UiInvoker.ToolStripLabelInvoker(lblStatusDbConnect, ColorSuccess, Resources.StrReadingCordonels);
SetStatusProgressBar();
_dbAccessDelayCtrMs = 0;
_processState = ProcessState.GetCordonelSerialNumbersFromDb;
}
catch (Exception)
{
//nothing to do
}
}
/// <summary>
/// Kick off customer search.
/// </summary>
/// <remarks date="2021-Apr-04" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Apr-07" author="Thomas Wiedebusch">
/// - Clear last search result.
/// </remarks>
private void btnSearchCustomer_Click(Object sender, EventArgs e)
{
// clear last search result
_dataTableCustomers?.Rows.Clear();
_dataTableCustomers?.Columns.Clear();
DisableAllControlsInvoked();
UiInvoker.ToolStripLabelInvoker(lblStatusDbConnect, ColorSuccess, Resources.StrReadingCustomers);
SetStatusProgressBar();
_dbAccessDelayCtrMs = 0;
_processState = ProcessState.GetCustomersFromDb;
}
/// <summary>
/// Select DEBUG Cordonels.
/// </summary>
/// <remarks date="2021-Apr-02" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void cbxAddDebugCordonels_Click(Object sender, EventArgs e)
{
//DebugDeviceAndFwPackageSelection();
}
/// <summary>
/// Kick off FW-Update package search.
/// </summary>
/// <remarks date="2021-Apr-13" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void btnFwPackageSearch_Click(Object sender, EventArgs e)
{
// Load fw packages only if not selected indicated in count
if (_fwUpdatePackages.Count > 0) return;
DisableAllControlsInvoked();
_dataTableFwPackages?.Clear();
UiInvoker.ToolStripLabelInvoker(lblStatusDbConnect, ColorSuccess, Resources.StrReadingFwPackages);
SetStatusProgressBar();
_dbAccessDelayCtrMs = 0;
_processState = ProcessState.GetFwPackagesFromDb;
}
/// <summary>
/// Mask already loaded FW-Update packages.
/// </summary>
/// <remarks date="2021-Apr-13" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void allFwPackageSearch_Event(Object sender, EventArgs e)
{
_fwPackagePropertyChanged = true;
}
/// <summary>
/// Tab page selection event (replaced of tabPage_Enter event of a selected tab page as this
/// fires on all data sets copied to it).
/// </summary>
/// <remarks date="2021-Apr-01" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Apr-13" author="Thomas Wiedebusch">
/// - FW update package selection.
/// </remarks>
/// <remarks date="2021-Apr-14" author="Thomas Wiedebusch">
/// - Enable retry if DB connection lost.
/// </remarks>
/// <remarks date="2021-Apr-30" author="Thomas Wiedebusch">
/// - FW packages not loaded if already done on page change.
/// </remarks>
private void tabControlSelection_Selected(Object sender, TabControlEventArgs e)
{
if (e.TabPage == tabPageFwUpdateSafes)
{
DisableAllControlsInvoked();
UiInvoker.ToolStripLabelInvoker(lblStatusDbConnect, ColorSuccess, Resources.StrReadingFwUpdateSafes);
SetStatusProgressBar();
_dbAccessDelayCtrMs = 0;
_processState = ProcessState.GetFwUpdateSafesFromDb;
}
if (e.TabPage == tabPageReports)
{
DisableAllControlsInvoked();
UiInvoker.ToolStripLabelInvoker(lblStatusDbConnect, ColorSuccess, Resources.StrReadingReportFiles);
SetStatusProgressBar();
_dbAccessDelayCtrMs = 0;
_processState = ProcessState.GetReportFilesFromDb;
}
if (e.TabPage == tabPageCordonelSelection)
{
// avoid reading of DB contents and reset of selection if customer remains identical
if (!_fwUpdateDbAccess.DbIsConnected) _customerNumberBeforeLastCordonelDbSearch = "";
if (string.IsNullOrEmpty(lblCustomerNumber.Text) ||
_customerNumberBeforeLastCordonelDbSearch == lblCustomerNumber.Text) return;
_customerNumberBeforeLastCordonelDbSearch = lblCustomerNumber.Text;
DisableAllControlsInvoked();
UiInvoker.ToolStripLabelInvoker(lblStatusDbConnect, ColorSuccess, Resources.StrReadingOrderNumbers);
SetStatusProgressBar();
_dbAccessDelayCtrMs = 0;
_processState = ProcessState.GetCordonelProductionOrdersFromDb;
}
if (e.TabPage == tabPageCustomerSelection)
{
}
if (e.TabPage == tabPagePreBuildSummary)
{
_preBuildSummaryPropertyChanged = true;
}
if (e.TabPage == tabPageFwPackageSelection)
{
// Load fw packages only if not selected indicated in count
if (_fwUpdatePackages.Count > 0 ||
_cordonelFwPackageInfoSearch != null && _cordonelFwPackageInfoSearch.Count > 0) return;
DisableAllControlsInvoked();
_dataTableFwPackages?.Clear();
UiInvoker.ToolStripLabelInvoker(lblStatusDbConnect, ColorSuccess, Resources.StrReadingFwPackages);
SetStatusProgressBar();
_dbAccessDelayCtrMs = 0;
_processState = ProcessState.GetFwPackagesFromDb;
}
if (e.TabPage == tabPageUpdateOperator)
{
// Avoid reading of DB contents and reset of selection if an update operator has already been assigned.
// If not, an update of the update operators may be sufficient, as the builder operator may call the
// update operator and require a new registration, so the update may immediately show the new registered
// or refreshed update operator without program exit and restart
if (!string.IsNullOrEmpty(lblUpdateOperator.Text)) return;
DisableAllControlsInvoked();
UiInvoker.ToolStripLabelInvoker(lblStatusDbConnect, ColorSuccess, Resources.StrReadingUpdateOperators);
SetStatusProgressBar();
_dbAccessDelayCtrMs = 0;
_processState = ProcessState.GetFwUpdateOperatorsFromDb;
}
}
/// <summary>
/// Upload FW-Update Safe to DB.
/// </summary>
/// <remarks date="2021-Apr-27" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void btnUploadSafeToDb_Click(Object sender, EventArgs e)
{
UiInvoker.ToolStripLabelInvoker(lblStatusDbConnect, ColorSuccess, Resources.StrFwUpdateSafeUploading);
SetStatusProgressBar();
_dbAccessDelayCtrMs = 0;
_processState = ProcessState.UploadFwUpdateSafeToDb;
}
/// <summary>
/// License the actual FW-Update Builder which is this product!
/// </summary>
/// <remarks date="2021-Mar-22" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Jun-30" author="Thomas Wiedebusch">
/// - Add 10 years for valid date.
/// </remarks>
private void btnLicenseFwUpdateBuilder_Click(Object sender, EventArgs e)
{
GetFwUpdateSwLicenseFromDb(_assemblyName.Name, out var fwUpdateBuilderLicenseRead);
BuildSwLicense(_assemblyName.Name, out var fwUpdateBuilderLicense);
fwUpdateBuilderLicense.ValidTo = DateTime.Now.AddYears(10);
SetFwUpdateSwLicenseToDb(fwUpdateBuilderLicense);
GetFwUpdateSwLicenseFromDb(_assemblyName.Name, out fwUpdateBuilderLicenseRead);
if (fwUpdateBuilderLicenseRead.Major == fwUpdateBuilderLicense.Major &&
fwUpdateBuilderLicenseRead.Minor == fwUpdateBuilderLicense.Minor &&
fwUpdateBuilderLicenseRead.Build == fwUpdateBuilderLicense.Build)
{
var msg = "FW-Update Builder Version: " +
$"{_version.Major}.{_version.Minor}.{_version.Build} {Resources.StrRegistrationSuccess}";
MessageBoxShow(msg, Resources.StrSuccess);
}
else
{
var msg = $"FW-Update Builder {Resources.StrRegisteredFailed}";
MessageBoxShow(msg, Resources.StrError);
}
}
/// <summary>
/// License the actual FW-Update SW.
/// </summary>
/// <remarks date="2021-Mar-22" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void btnLicenseFwUpdateSw_Click(Object sender, EventArgs e)
{
GetFwUpdateSwLicenseFromDb(FwUpdateSwFullName, out var fwUpdateSwLicenseRead);
BuildSwLicense(FwUpdateSwFullName, out var fwUpdateSwLicense);
SetFwUpdateSwLicenseToDb(fwUpdateSwLicense);
GetFwUpdateSwLicenseFromDb(FwUpdateSwFullName, out fwUpdateSwLicenseRead);
String msg;
if (fwUpdateSwLicenseRead != null)
{
if (fwUpdateSwLicenseRead.Major == fwUpdateSwLicense.Major &&
fwUpdateSwLicenseRead.Minor == fwUpdateSwLicense.Minor &&
fwUpdateSwLicenseRead.Build == fwUpdateSwLicense.Build)
{
msg = "FW-Update Software Version: " +
$"{_version.Major}.{_version.Minor}.{_version.Build} {Resources.StrRegistrationSuccess}";
MessageBoxShow(msg, Resources.StrSuccess);
}
return;
}
msg = $"FW-Update Software {Resources.StrRegisteredFailed}";
MessageBoxShow(msg, Resources.StrError);
}
/// <summary>
/// Build the update safe.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2021-Feb-24" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Apr-23" author="Thomas Wiedebusch">
/// - Clear content of FW package to force reload and output of loaded package on rebuild of safe.
/// </remarks>
private void btnBuildFwUpdateSafe_Click(Object sender, EventArgs e)
{
SetStatusProgressBar();
_dbAccessDelayCtrMs = 0;
// clear FW packages content to force reload from data base and therefore report generation,
// this is essential for rebuilding of a safe
foreach (var package in _fwUpdatePackages)
{
package?.BinaryApplicationFiles?.Clear();
}
rtbReport.Clear();
rtbReport.ForeColor = ColorDefault;
lblStatusDbConnect.Text = Resources.StrFwUpdateSafeBuilding;
_processState = ProcessState.BuildFwUpdateSafe;
}
/// <summary>
/// Close the date picker for the FW-Update validation date.
/// </summary>
/// <remarks date="2021-Feb-25" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void datePickerFwUpdateValidationDate_CloseUp(Object sender, EventArgs e)
{
// change text two times to include the culture info
var dateTimeOffset = DateTimeServer.GetDateTimeOffsetFromDateString(_datePicker.Text);
lblFwUpdateDutyDate.Text = DateTimeServer.GetDateStringFromDateTimeOffset(dateTimeOffset, _cultureInfo);
HideDatePicker();
}
/// <summary>
/// Close the date picker for the user validation date.
/// </summary>
/// <remarks date="2021-Feb-25" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void datePickerUserValidationDate_CloseUp(Object sender, EventArgs e)
{
//_userInfo.ValidDate = DateTimeServer.GetDateTimeOffsetFromDateString(_datePicker.Text);
_fwUpdateOperatorsPropertyChanged = true;
HideDatePicker();
}
/// <summary>
/// Activate date time picker.
/// </summary>
/// <remarks date="2021-Feb-25" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void lblFwUpdateDutyDate_Click(Object sender, EventArgs e)
{
if (_datePicker.Visible)
{
HideDatePicker();
}
// hide the label, only with this the date picker can be seen !!!!
lblFwUpdateDutyDate.Visible = false;
var cell = tblPanelSafeInfo.GetCellPosition(lblFwUpdateDutyDate);
// Adding DateTimePicker control into cell x, y
tblPanelSafeInfo.Controls.Add(_datePicker, cell.Column, cell.Row);
// The final selection of the date
_datePicker.CloseUp += datePickerFwUpdateValidationDate_CloseUp;
// Now make it visible
_datePicker.Visible = true;
}
#endregion --------------------------------------- User Interaction -------------------------------------------
#region ------------------------------------------ Form Load Unload -------------------------------------------
/// <summary>
/// Ctor
/// </summary>
/// <remarks date="2020-Nov-30" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
/// - Invisible progress bar at start.
/// </remarks>
/// <remarks date="2021-Mar-25" author="Thomas Wiedebusch">
/// - Directory for FW-Update Safes created.
/// </remarks>
/// <remarks date="2021-Apr-12" author="Thomas Wiedebusch">
/// - Grid color for update capability checks.
/// </remarks>
/// <remarks date="2021-Apr-13" author="Thomas Wiedebusch">
/// - Pre-filled FW-Update package search lists.
/// </remarks>
/// <remarks date="2021-Apr-30" author="Thomas Wiedebusch">
/// - MeterFwUpdateRuler.json class changed to nullable DateTime.
/// </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 FrmFwUpdateBuilder()
{
var fwUpdateBuilderExePath = AppDomain.CurrentDomain.BaseDirectory;
var fwUpdateBuilderLibraryPath = Path.Combine(fwUpdateBuilderExePath, "Library");
var fwUpdateBuilderConfigPath = Path.Combine(fwUpdateBuilderExePath, "Config");
var nLogConfigSourcePathName = Path.Combine(fwUpdateBuilderConfigPath, ProgramConfig.NlogConfig);
// Build the configuration directory and copy at least the NLog config to it
try
{
if (!Directory.Exists(ApplicationConfigPath))
{
Directory.CreateDirectory(ApplicationConfigPath);
}
if (!Directory.Exists(FwUpdateSafePath))
{
Directory.CreateDirectory(FwUpdateSafePath);
}
// 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);
var rulerPathName = Path.Combine(fwUpdateBuilderLibraryPath,
FwUpdateConfig.MeterFwUpdateRulerConfigFileName);
if (!File.Exists(rulerPathName)) rulerPathName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
FwUpdateConfig.MeterFwUpdateRulerConfigFileName);
if (File.Exists(rulerPathName))
{
var rulerFile = File.ReadAllText(rulerPathName, Encoding.UTF8);
_meterFwUpdateRuler = JsonConvert.DeserializeObject<List<MeterFwUpdateRuler>>(rulerFile);
}
}
catch (Exception)
{
// nothing to do
}
_logger = NLogHelper.CreateOrGetLogger("ServiceFwUpdateBuilder");
_assemblyName = Assembly.GetExecutingAssembly().GetName();
_version = _assemblyName.Version;
_versionString = $"{_assemblyName.Name} Version: {_version.Major}.{_version.Minor}.{_version.Build}";
_logger.Info(StrSeparator);
_logger.Info(_versionString);
_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}";
lblStatusDbConnect.ForeColor = ColorDefault;
DateTimeServer.SetValidationDate(FwUpdateConfig.ValidDays);
var dateTime = DateTimeServer.SetValidationDate(FwUpdateConfig.ValidDays).DateTime;
_datePicker.Format = DateTimePickerFormat.Short;
_datePicker.Value = dateTime;
lblFwUpdateDutyDate.Text = _datePicker.Value.ToShortDateString();
_styleValid.BackColor = ColorBackGround;
_styleValid.ForeColor = ColorSuccess;
_styleInvalid.BackColor = ColorBackGround;
_styleInvalid.ForeColor = ColorProcessFailed;
_styleUnknown.BackColor = ColorBackGround;
_styleUnknown.ForeColor = ColorDefault;
_styleInstallationApproved.BackColor = Color.LightGreen;
_styleInstallationApproved.ForeColor = Color.Black;
_styleInstallationDenied.BackColor = Color.LightCoral;
_styleInstallationDenied.ForeColor = Color.Black;
_styleInstallationUserApproval.BackColor = Color.Orange;
_styleInstallationUserApproval.ForeColor = Color.Black;
_styleInstallationRemoved.BackColor = Color.LightGray;
_styleInstallationRemoved.ForeColor = Color.Gray;
// start immediately the connection check
_dbAccessDelayCtrMs = DbConnectionRetryDelayMs;
// validate software license as soon as possible
_dbLicenseRefreshDelayCtrMs = DbLicenseRefreshTimeoutMs;
lblUpdateOperator.Text = "";
btnBuildFwUpdateSafe.Enabled = false;
btnUploadSafeToDb.Enabled = false;
if (System.Diagnostics.Debugger.IsAttached)
{
btnLicenseFwUpdateSw.Visible = true;
btnLicenseFwUpdateBuilder.Visible = true;
//cbxAddDebugCordonels.Visible = true;
}
cbxAddDebugCordonels.Checked = false;
btnLicenseFwUpdateSw.Enabled = false;
btnLicenseFwUpdateBuilder.Enabled = false;
tbxCustomerName.Text = "";
lblCustomerNumber.Text = "";
tbxOrderNumber.Text = @"1234567890";
tbxOrderPosition.Text = @"10";
var tabControlImages = new ImageList { ColorDepth = ColorDepth.Depth24Bit };
tabControlImages.Images.Add(Resources.ImageMissingInput);
tabControlImages.Images.Add(Resources.ImageValidInput);
tabControlSelection.ImageList = tabControlImages;
// set locked repeat initially different from process state to unlock first entry to state machine
_lastProcessState = ProcessState.Unspecified;
_processState = ProcessState.Init;
_invokerProcessState = _processState;
// disable all actions until license has been verified
DisableControlsExceptLanguageInvoked();
_licenseUnchecked = true;
//assign a thread name to observe this
if (string.IsNullOrEmpty(Thread.CurrentThread.Name))
Thread.CurrentThread.Name = "Form Service FW-Update Builder thread";
//assign thread to loop and start thread
_fwUpdateBuilderThread = new Thread(FwUpdateBuilderStateMachine);
if (!string.IsNullOrEmpty(_fwUpdateBuilderThread.Name))
_fwUpdateBuilderThread.Name = "State Machine Service FW-Update Builder thread";
ThreadWatcher.Instance.Start(_fwUpdateBuilderThread);
}
/// <summary>
/// Exit
/// </summary>
/// <remarks date="2021-Mar-23" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void FrmFwUpdateBuilder_FormClosing(Object sender, FormClosingEventArgs e)
{
_datePicker?.Dispose();
_cbxFwReleaseSelection?.Dispose();
_processToken?.Cancel();
}
#endregion --------------------------------------- Form Load Unload -------------------------------------------
#region ------------------------------------------ Build FW-Update Safe ---------------------------------------
/// <summary>
/// Build the firmware update safe and stores it to a file and to the DB.
/// </summary>
/// <remarks date="2021-Jan-27" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Mar-20" author="Thomas Wiedebusch">
/// - Logging added.
/// </remarks>
/// <remarks date="2021-Mar-23" author="Thomas Wiedebusch">
/// - FW-Update SW container added.
/// </remarks>
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
/// - Order number and customer text added added,
/// - Disable all controls during FW-UpdateSafe build.
/// </remarks>
/// <remarks date="2021-Mar-26" author="Thomas Wiedebusch">
/// - Additional logging.
/// </remarks>
/// <remarks date="2021-Mar-30" author="Thomas Wiedebusch">
/// - Output short file name.
/// </remarks>
/// <remarks date="2021-Apr-02" author="Thomas Wiedebusch">
/// - Action on missing FwUpdateSw.
/// </remarks>
/// <remarks date="2021-Apr-06" author="Thomas Wiedebusch">
/// - Error process state introduced.
/// </remarks>
/// <remarks date="2021-Apr-08" author="Thomas Wiedebusch">
/// - Replaced _userInfo by lblUpdateOperator.
/// </remarks>
/// <remarks date="2021-Apr-15" author="Thomas Wiedebusch">
/// - Taking FW-Update SW license from DB.
/// </remarks>
/// <remarks date="2021-Apr-27" author="Thomas Wiedebusch">
/// - Added FwUpdateSafeDb preparation
/// </remarks>
/// <remarks date="2021-Oct-27" author="Thomas Wiedebusch">
/// - Added BuildFwUpdateSwContainerFromDb, not longer taken from locally file system!
/// </remarks>
public Boolean BuildFwUpdateSafe()
{
if (string.IsNullOrEmpty(lblUpdateOperator.Text)) return false;
DisableAllControlsInvoked();
Invoke(new Action(() =>
{
tabControlSelection.SelectTab(tabPageSafeBuildReport);
tabControlSelection.Refresh();
}));
try
{
var fwUpdateSafe = new FwUpdateSafe
{
//License = new SoftwareLicense(),
Software = new SoftwareContainer(),
Updates = new UpdateContainer()
};
// check DB connection in advance to overcome the timing issues for DB service startup
_fwUpdateDbAccess.CheckDbConnection();
LogText(StrSeparator);
LogText(Resources.StrCustomerName + @" " + tbxCustomerName.Text);
LogText(Resources.StrCustomerNumber + @" " + lblCustomerNumber.Text);
LogText($@"{Resources.StrOrderNumber} {tbxOrderNumber.Text}-{tbxOrderPosition.Text}");
LogText(Resources.StrBuilderOperator + @" " + _regUser.FullName);
LogText(Resources.StrUpdateOperator + @" " + lblUpdateOperator.Text);
LogText(Resources.StrValidDate + @" " + lblFwUpdateDutyDate.Text);
LogText(StrSeparator);
// Should never occur as [Build FW-Update Safe] is locked if no device is selected
if (_cordonelUpdateList.Count == 0)
{
LogErrorText(Resources.StrCordonelsMissing);
MessageBoxShow(Resources.StrCordonelsMissing, Resources.StrError, MessageBoxButtons.OK,
MessageBoxIcon.Error);
_processState = ProcessState.Error;
return false;
}
GetFwUpdateSwLicenseFromDb(FwUpdateSwFullName, out fwUpdateSafe.License);
if (fwUpdateSafe.License == null)
{
LogErrorText(Resources.StrSwLicenseMissing);
MessageBoxShow(Resources.StrSwLicenseMissing, Resources.StrError, MessageBoxButtons.OK,
MessageBoxIcon.Error);
_processState = ProcessState.Error;
return false;
}
// overwrite license validation date as operator has selected this
fwUpdateSafe.License.ValidTo =
DateTimeServer.GetDateTimeFromDateString(lblFwUpdateDutyDate.Text + " 23:59:59", _cultureInfo);
LogSuccessText($@"{Resources.StrSwLicenseLoadedSuccessfully} {FwUpdateProjectName}" +
$" {fwUpdateSafe.License.Major}.{fwUpdateSafe.License.Minor}.{fwUpdateSafe.License.Build}");
// local files: if (!BuildFwUpdateSwContainer(fwUpdateSafe.License) ||
if (!BuildFwUpdateSwContainerFromDb(fwUpdateSafe.License) ||
_fwUpdateSwContainer?.RegisterDefinitionFile == null ||
_fwUpdateSwContainer.SoftwareSetupFile == null ||
_fwUpdateSwContainer.MeterFilesEraseRestore == null ||
string.IsNullOrEmpty(_fwUpdateSwContainer.RegisterDefinitionFile.FileName) ||
string.IsNullOrEmpty(_fwUpdateSwContainer.SoftwareSetupFile.FileName) ||
string.IsNullOrEmpty(_fwUpdateSwContainer.MeterFilesEraseRestore.FileName) ||
_fwUpdateSwContainer.SoftwareDynLinkLibs == null ||
_fwUpdateSwContainer.SoftwareDynLinkLibs.Count == 0)
{
LogErrorText(Resources.StrSwContainerCollectionFailed);
MessageBoxShow(Resources.StrSwContainerCollectionFailed, Resources.StrError, MessageBoxButtons.OK,
MessageBoxIcon.Error);
_processState = ProcessState.Error;
return false;
}
fwUpdateSafe.Software = _fwUpdateSwContainer;
LogSuccessText(Resources.StrSwContainerCollectionSuccess);
CompleteCordonelDeviceInfos();
if (_cordonelUpdateList.Count == 0)
{
LogErrorText(Resources.StrCordonelsMissing);
MessageBoxShow(Resources.StrCordonelsMissing, Resources.StrError, MessageBoxButtons.OK,
MessageBoxIcon.Error);
_processState = ProcessState.Error;
return false;
}
if (_fwUpdateCapability.All(x => x.ReleaseContainerLoaded == false))
{
_processState = ProcessState.Error;
return false;
}
fwUpdateSafe.Updates = new UpdateContainer
{
CordonelFwPackages = new List<CordonelFirmware>(),
CordonelDeviceInfos = new List<CordonelDeviceInfo>()
};
fwUpdateSafe.Updates.CordonelFwPackages = _fwUpdatePackages;
fwUpdateSafe.Updates.CordonelDeviceInfos = _cordonelUpdateList;
var serializedData = JsonConvert.SerializeObject(fwUpdateSafe);
var asciiStream = Encoding.ASCII.GetBytes(serializedData);
// the build primary key
BuildPrimaryKey(lblUpdateOperator.Text);
if (_primaryKey == null)
{
LogErrorText(Resources.StrUserInformationMissing);
MessageBoxShow(Resources.StrUserInformationMissing, Resources.StrError, MessageBoxButtons.OK,
MessageBoxIcon.Error);
_processState = ProcessState.Error;
return false;
}
var encryptedStream = FwUpdateCrypt.Encrypt(asciiStream, _primaryKey);
// first replace the underlines as these are used for the file name and later to separate for customer and order number
var fileName = tbxCustomerName.Text.Replace(FwUpdateConfig.FwUpdateFileFieldSeparator.ToString(), "");
// leave all word characters (including the umlaut in for multilingual support), numbers the "-" and the white space in
fileName = Regex.Replace(fileName, @"[^\w\d\-\s]", "");
// The safe shall look like "Thames Water_01234567890-10.safe"
_fwUpdateSafeName = $@"{fileName}{FwUpdateConfig.FwUpdateFileFieldSeparator}" +
$@"{tbxOrderNumber.Text}-{tbxOrderPosition.Text}" +
FwUpdateConfig.FwUpdateFileExtension;
// prepare FwUpdateSafeDb
if (string.IsNullOrEmpty(_regUser.FullName)) _regUser.FullName = "";
_fwUpdateSafeDb = new FwUpdateSafeDb
{
OperatorNameBuilder = _regUser.FullName,
Name = _fwUpdateSafeName,
UserId = _updateOperatorId,
Content = encryptedStream,
ValidDate = new DateTimeOffset(fwUpdateSafe.License.ValidTo)
};
//assign FW update safe
var fwUpdateSafeFile = Path.Combine(FwUpdateSafePath, _fwUpdateSafeName);
File.WriteAllBytes(fwUpdateSafeFile, encryptedStream);
return true;
}
catch (Exception e)
{
LogErrorText(Resources.StrFwUpdateSafeBuildFailed);
MessageBoxShow(e.ToString(), Resources.StrError, MessageBoxButtons.OK,
MessageBoxIcon.Error);
_processState = ProcessState.Error;
return false;
}
}
/// <summary>
/// Collect cordonel device info, the user has to input the required pcbIds and release versions in advance!
/// </summary>
/// <remarks date="2021-Jan-27" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Feb-02" author="Thomas Wiedebusch">
/// - Load from DB.
/// </remarks>
/// <remarks date="2021-Mar-23" author="Thomas Wiedebusch">
/// - Kick off DB connection with dummy request.
/// </remarks>
/// <remarks date="2021-Apr-01" author="Thomas Wiedebusch">
/// - Password container directly assigned.
/// </remarks>
public void CompleteCordonelDeviceInfos()
{
// establish DB connection with dummy request
_fwUpdateDbAccess?.DownloadCordonelPwdFromDb("0", out _);
_fwUpdateDbAccess?.DownloadCordonelPwdFromDb("0", out _);
// get the real passwords
foreach (var cordonelDeviceInfo in _cordonelUpdateList)
{
var fwUpdateCapability = new FwUpdateCapability
{
PcbId = cordonelDeviceInfo.PcbId,
PasswordContainerLoaded = GetPwdFromDb(cordonelDeviceInfo)
};
// stop collection of data if the password container cannot be loaded
if (!fwUpdateCapability.PasswordContainerLoaded)
{
continue;
}
// load a single release if not already done
fwUpdateCapability.ReleaseContainerLoaded = GetFwPackageFromDb(cordonelDeviceInfo.RequiredRelease);
_fwUpdateCapability.Add(fwUpdateCapability);
}
}
#endregion --------------------------------------- Build FW-Update Safe ---------------------------------------
#region ------------------------------------------ Checks -----------------------------------------------------
/// <summary>
/// Check the user registration from DB.
/// </summary>
/// <remarks date="2021-Apr-13" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void CheckUserRegistration()
{
if (_fwUpdateDbAccess == null || _regUser == null) return;
_regUser.Domain = CryptInformation.GetSysDomain();
_regUser.LogInName = CryptInformation.GetSysUserLoginName();
_fwUpdateDbAccess.GetAllBuilderOperatorsFromDb();
// If the connection to the DB cannot be established
if (!_fwUpdateDbAccess.GetAllBuilderOperatorsFromDb() ||
_fwUpdateDbAccess.DbAllBuilderOperators == null ||
_fwUpdateDbAccess.DbAllBuilderOperators.Count == 0) return;
// search for this system user specified by Domain and LogInName
foreach (var user in _fwUpdateDbAccess.DbAllBuilderOperators.Where(user => user.Domain == _regUser.Domain &&
user.LogInName == _regUser.LogInName))
{
_regUser.AccountActive = user.AccountActive;
_regUser.FullName = user.FullName;
break;
}
if (_regUser.AccountActive)
{
EnableInputsInvoked();
_processState = ProcessState.Idle;
return;
}
DisableControlsExceptLanguageInvoked();
_processState = ProcessState.DbAccessLocked;
}
/// <summary>
/// Check the update capability of all selected Cordonels
/// </summary>
/// <remarks date="2021-Mar-26" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void CheckUpdateCapability()
{
var success = true;
foreach (var cordonel in _cordonelProductionPreSelectInfos)
{
// load the actual installed app versions
// check metrology
// check core revision
// check radio frequency
if (success)
{
LogSuccessText(Resources.StrCordonelUpdateCapabilityCheckSuccess + " " + cordonel.PcbId);
return;
}
var msg = Resources.StrCordonelUpdateCapabilityCheckFailed + @" " + cordonel.PcbId;
LogErrorText(msg);
MessageBoxShow(msg, Resources.StrError, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// Check DB connection timeout during connectivity check
/// </summary>
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2021-Apr-09" author="Thomas Wiedebusch">
/// - Avoid interruption if DB is connected.
/// </remarks>
private void CheckDbConnectionTimeout()
{
// stop connectivity test after response timeout
if (_fwUpdateDbAccess == null || _fwUpdateDbAccess.DbIsConnected ||
_dbAccessDelayCtrMs <= DbConnectionTimeoutMs) return;
EnableInputsInvoked();
_dbAccessDelayCtrMs = 0;
SetStatusProgressBar(0, false);
_processState = ProcessState.Idle;
}
/// <summary>
/// Check DB license refresh.
/// </summary>
/// <remarks date="2021-Apr-14" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void RefreshLicense()
{
if (DateTimeOffset.Compare(_licenseValidDateTimeOffset, DateTimeOffset.Now) < 0)
_licenseUnchecked = true;
}
/// <summary>
/// Check DB connectivity.
/// </summary>
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2021-Mar-26" author="Thomas Wiedebusch">
/// - Progress bar off if connection lost.
/// </remarks>
/// <remarks date="2021-Apr-02" author="Thomas Wiedebusch">
/// - On initialized DB connection fire the tabControl event to update user view,
/// - dbAccessLocked introduced.
/// </remarks>
/// <remarks date="2021-Apr-04" author="Thomas Wiedebusch">
/// - Disabled: On initialized DB connection fire the tabControl event to update user view.
/// </remarks>
/// <remarks date="2021-Apr-14" author="Thomas Wiedebusch">
/// - Check for license.
/// </remarks>
private void CheckDbConnectivity()
{
if (_fwUpdateDbAccess.DbIsConnected)
{
// DB is free to use
if (_dbLicenseRefreshDelayCtrMs > DbLicenseRefreshTimeoutMs)
{
_dbLicenseRefreshDelayCtrMs = 0;
RefreshLicense();
if (_licenseUnchecked) _processState = ProcessState.ValidateSoftware;
}
// If the progress bar is visible, the DB connection status has just changed from NOT connected
if (!ProgressBarStatus.Visible && lblStatusDbConnect.Text != Resources.StrNotConnectedToDb) return;
// Stop connection test
SetStatusProgressBar(0, false);
UiInvoker.ToolStripLabelInvoker(lblStatusDbConnect, ColorSuccess, Resources.StrConnectedToDb);
// enable controls only if software license has been checked
EnableInputsInvoked();
}
else
{
UiInvoker.ToolStripLabelInvoker(lblStatusDbConnect, ColorProcessFailed, Resources.StrNotConnectedToDb);
if (ProgressBarStatus.Visible) SetStatusProgressBar(0, false);
// kick off new connectivity check if retry delay exceeded and DB is NOT connected
if (_dbAccessDelayCtrMs <= DbConnectionRetryDelayMs) return;
DisableAllControlsInvoked();
UiInvoker.ToolStripLabelInvoker(lblStatusDbConnect, ColorSuccess, Resources.StrConnectingToDb);
SetStatusProgressBar();
_dbAccessDelayCtrMs = 0;
_processState = ProcessState.ConnectDb;
}
}
/// <summary>
/// Check all required data needed to input for FW-Update safe and enables/disables the [FW Update] button.
/// This colors the labels and tabs to inform the user about the lack of data.
/// </summary>
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2021-Mar-26" author="Thomas Wiedebusch">
/// - [Build FW-Update Safe] check extended
/// </remarks>
/// <remarks date="2021-Mar-29" author="Thomas Wiedebusch">
/// - checks extended,
/// - avoid repeated setup of item if already done.
/// </remarks>
/// <remarks date="2021-Apr-01" author="Thomas Wiedebusch">
/// - Added builder license check.
/// </remarks>
/// <remarks date="2021-Apr-02" author="Thomas Wiedebusch">
/// - FW-Update package status added.
/// </remarks>
/// <remarks date="2021-Apr-06" author="Thomas Wiedebusch">
/// - Check order numbers.
/// </remarks>
/// <remarks date="2021-Apr-09" author="Thomas Wiedebusch">
/// - Check fw packages.
/// </remarks>
/// <remarks date="2021-Apr-10" author="Thomas Wiedebusch">
/// - Lock customer search button if customer is selected to avoid lose of information on new search.
/// </remarks>
/// <remarks date="2021-Apr-14" author="Thomas Wiedebusch">
/// - Today is a valid day.
/// </remarks>
/// <remarks date="2021-Apr-15" author="Thomas Wiedebusch">
/// - Metrology search items added.
/// </remarks>
/// <remarks date="2021-Apr-16" author="Thomas Wiedebusch">
/// - Pre-Build summary check.
/// </remarks>
/// <remarks date="2021-Apr-17" author="Thomas Wiedebusch">
/// - Cordonel selection check moved to production pre select.
/// </remarks>
/// <remarks date="2021-Apr-18" author="Thomas Wiedebusch">
/// - Cordonel selection check and Cordonel approval check differentiate.
/// </remarks>
/// <remarks date="2021-Apr-29" author="Thomas Wiedebusch">
/// - Use selected Cordonels to fill the FW package search infos.
/// </remarks>
private void CheckDataCollectionStatus()
{
// Customer Orders ----------------------------------------------------------------------------------------
// Check the order numbers (add one for the "*" )
if (_fwUpdateDbAccess?.DbCordonelCustomerOrders != null)
{
if (cbxCordonelProductionOrdersSearch.Items.Count != _fwUpdateDbAccess.DbCordonelCustomerOrders.Count + 1)
{
cbxCordonelProductionOrdersSearch.Items.Clear();
cbxCordonelProductionOrdersSearch.Text = @"*";
cbxCordonelProductionOrdersSearch.Items.Add("*");
foreach (var order in _fwUpdateDbAccess.DbCordonelCustomerOrders)
{
cbxCordonelProductionOrdersSearch.Items.Add($@"{order.CustomerOrderNumber}-{order.CustomerOrderPos}");
}
}
}
// Update Operator ----------------------------------------------------------------------------------------
// Set the background color for update operator and use it later for comparison to enable button
var backGroundColor = string.IsNullOrEmpty(lblUpdateOperator.Text) ? ColorBkMissing : ColorBkValid;
if (backGroundColor != lblUpdateOperator.BackColor)
{
lblUpdateOperator.BackColor = backGroundColor;
if (backGroundColor == ColorBkMissing)
{
tabPageUpdateOperator.ImageIndex = 0;
}
else tabPageUpdateOperator.ImageIndex = 1;
}
// Validation Time for FW update --------------------------------------------------------------------------
// Time for update validation has been properly set time including today (offset needed as the time
// will count up continuously)
backGroundColor = DateTime.Compare(DateTimeServer.GetDateTimeFromDateString(lblFwUpdateDutyDate.Text +
" 23:59:59", _cultureInfo), DateTime.Now) > 0 ? ColorBkValid : ColorBkMissing;
if (backGroundColor != lblFwUpdateDutyDate.BackColor)
{
lblFwUpdateDutyDate.BackColor = backGroundColor;
}
// Customer Name ------------------------------------------------------------------------------------------
backGroundColor = string.IsNullOrEmpty(tbxCustomerName.Text) ? ColorBkMissing : ColorBkValid;
if (backGroundColor != tbxCustomerName.BackColor)
{
tbxCustomerName.BackColor = backGroundColor;
lblCustomerNumber.BackColor = backGroundColor;
if (backGroundColor == ColorBkMissing)
{
tabPageCustomerSelection.ImageIndex = 0;
lblInfoSelectCustomer.Visible = true;
btnSearchCustomer.Enabled = true;
}
else
{
tabPageCustomerSelection.ImageIndex = 1;
lblInfoSelectCustomer.Visible = false;
btnSearchCustomer.Enabled = false;
}
}
// Customer Cordonels Search for this production number ---------------------------------------------------
if (tbxCordonelsCustomerCount.Text != _cordonelProductionSearchInfos.Count.ToString())
tbxCordonelsCustomerCount.Text = _cordonelProductionSearchInfos.Count.ToString();
backGroundColor = _cordonelProductionSearchInfos.Count == 0 ? ColorBkMissing : ColorBkValid;
if (backGroundColor != tbxCordonelsCustomerCount.BackColor)
{
tbxCordonelsCustomerCount.BackColor = backGroundColor;
}
// Selected Cordonels -------------------------------------------------------------------------------------
if (lblCordonelsSelectedCount.Text != _cordonelProductionPreSelectInfos.Count.ToString())
lblCordonelsSelectedCount.Text = _cordonelProductionPreSelectInfos.Count.ToString();
backGroundColor = _cordonelProductionPreSelectInfos.Count == 0 ? ColorBkMissing : ColorBkValid;
if (backGroundColor != lblCordonelsSelectedCount.BackColor)
{
lblCordonelsSelectedCount.BackColor = backGroundColor;
}
if (_cordonelProductionPreSelectInfos.Count == 0)
{
if (tabPageCordonelSelection.ImageIndex != 0) tabPageCordonelSelection.ImageIndex = 0;
}
else
{
if (tabPageCordonelSelection.ImageIndex != 1) tabPageCordonelSelection.ImageIndex = 1;
}
// Selected FW-Packages -----------------------------------------------------------------------------------
// Add fw packages to fw package selection combo box for Cordonel FW to install selection
if (_fwUpdateDbAccess?.DbCordonelFwPackages != null && _fwUpdatePackages != null &&
_cbxFwReleaseSelection != null)
{
if (_cbxFwReleaseSelection.Items.Count != _fwUpdatePackages.Count)
{
_cbxFwReleaseSelection.Items.Clear();
foreach (var fw in _fwUpdatePackages)
{
_cbxFwReleaseSelection.Items.Add(fw.ReleaseNameVersion);
}
}
}
// Check if FW packages are selected
if (_fwUpdatePackages != null && lblSelectedFwPackages.Text != _fwUpdatePackages.Count.ToString())
lblSelectedFwPackages.Text = _fwUpdatePackages.Count.ToString();
backGroundColor = _fwUpdatePackages != null && _fwUpdatePackages.Count == 0 ? ColorBkMissing : ColorBkValid;
if (backGroundColor != lblSelectedFwPackages.BackColor)
{
lblSelectedFwPackages.BackColor = backGroundColor;
if (backGroundColor == ColorBkMissing)
{
if (!btnFwPackageSearch.Enabled) btnFwPackageSearch.Enabled = true;
tabPageFwPackageSelection.ImageIndex = 0;
}
else
{
if (btnFwPackageSearch.Enabled) btnFwPackageSearch.Enabled = false;
tabPageFwPackageSelection.ImageIndex = 1;
}
}
// check if FW packages are loaded from DB and parsed to the search info to extract radio info
if (_radioSearchItems.Count + 1 != cbxFwPackageRadioMask.Items.Count)
{
cbxFwPackageRadioMask.Items.Clear();
cbxFwPackageRadioMask.Text = @"*";
cbxFwPackageRadioMask.Items.Add("*");
foreach (var item in _radioSearchItems)
{
if (!string.IsNullOrEmpty(item) && item != "?")
cbxFwPackageRadioMask.Items.Add(item);
}
}
// check if FW packages are loaded from DB and parsed to the search info to extract region info
if (_regionSearchItems.Count + 1 != cbxFwPackageRegionMask.Items.Count)
{
cbxFwPackageRegionMask.Items.Clear();
cbxFwPackageRegionMask.Text = @"*";
cbxFwPackageRegionMask.Items.Add("*");
foreach (var item in _regionSearchItems)
{
if (!string.IsNullOrEmpty(item) && item != "?")
cbxFwPackageRegionMask.Items.Add(item);
}
}
// check if FW packages are loaded from DB and parsed to the search info to extract size info
if (_sizeSearchItems.Count + 1 != cbxFwPackageSizeMask.Items.Count)
{
cbxFwPackageSizeMask.Items.Clear();
cbxFwPackageSizeMask.Text = @"*";
cbxFwPackageSizeMask.Items.Add("*");
foreach (var item in _sizeSearchItems)
{
if (!string.IsNullOrEmpty(item) && item != "?")
cbxFwPackageSizeMask.Items.Add(item);
}
}
// check if FW packages are loaded from DB and parsed to the search info to extract metrology info
if (_metrologySearchItems.Count + 1 != cbxFwPackageSearchMetrology.Items.Count)
{
cbxFwPackageSearchMetrology.Items.Clear();
cbxFwPackageSearchMetrology.Text = @"*";
cbxFwPackageSearchMetrology.Items.Add("*");
foreach (var item in _metrologySearchItems)
{
if (!string.IsNullOrEmpty(item) && item != "?")
cbxFwPackageSearchMetrology.Items.Add(item);
}
}
// check if FW packages are loaded from DB and parsed to the search info to extract core info
if (_coreSearchItems.Count + 1 != cbxFwPackageSearchCore.Items.Count)
{
cbxFwPackageSearchCore.Items.Clear();
cbxFwPackageSearchCore.Text = @"*";
cbxFwPackageSearchCore.Items.Add("*");
foreach (var item in _coreSearchItems)
{
if (!string.IsNullOrEmpty(item) && item != "?")
cbxFwPackageSearchCore.Items.Add(item);
}
}
// FW-Update Order Number ---------------------------------------------------------------------------------
backGroundColor = string.IsNullOrEmpty(tbxOrderNumber.Text) ? ColorBkMissing : ColorBkValid;
if (backGroundColor != tbxOrderNumber.BackColor)
{
tbxOrderNumber.BackColor = backGroundColor;
tbxOrderPosition.BackColor = backGroundColor;
}
// FW-Update Safe Upload Capability -----------------------------------------------------------------------
if (btnUploadSafeToDb.Enabled != _enableFwSafeUpload)
{
btnUploadSafeToDb.Enabled = _enableFwSafeUpload;
}
// Pre Build Summary Check --------------------------------------------------------------------------------
// search for missing approval in production list or missing FW update package
var updateLocked = (_cordonelProductionPreSelectInfos.Count == 0 ||
_cordonelProductionPreSelectInfos.Any(prodCord =>
!prodCord.IsApproved && prodCord.IsSelected)) ||
_cordonelUpdateList.Any(updCord => string.IsNullOrEmpty(updCord.RequiredRelease) ||
updCord.RequiredRelease == "?");
if (updateLocked)
{
if (tabPagePreBuildSummary.ImageIndex != 0)
tabPagePreBuildSummary.ImageIndex = 0;
}
else
{
if (tabPagePreBuildSummary.ImageIndex != 1)
tabPagePreBuildSummary.ImageIndex = 1;
}
// Approved Cordonels -------------------------------------------------------------------------------------
if (lblCordonelsApprovedCount.Text != _cordonelUpdateList.Count.ToString())
lblCordonelsApprovedCount.Text = _cordonelUpdateList.Count.ToString();
backGroundColor = _cordonelUpdateList.Count == 0 ? ColorBkMissing : ColorBkValid;
if (backGroundColor != lblCordonelsApprovedCount.BackColor)
{
lblCordonelsApprovedCount.BackColor = backGroundColor;
}
// Control Activation/ Deactivation -----------------------------------------------------------------------
if (_fwUpdateDbAccess != null && !_fwUpdateDbAccess.DbIsConnected)
{
if (btnBuildFwUpdateSafe.Enabled) btnBuildFwUpdateSafe.Enabled = false;
if (btnLicenseFwUpdateSw.Enabled) btnLicenseFwUpdateSw.Enabled = false;
if (btnLicenseFwUpdateBuilder.Enabled) btnLicenseFwUpdateBuilder.Enabled = false;
if (btnCordonelSearch.Enabled) btnCordonelSearch.Enabled = false;
if (btnSearchCustomer.Enabled) btnSearchCustomer.Enabled = false;
}
else
{
// license can be activated soon the DB is connected
if (!btnLicenseFwUpdateSw.Enabled) btnLicenseFwUpdateSw.Enabled = true;
if (!btnLicenseFwUpdateBuilder.Enabled) btnLicenseFwUpdateBuilder.Enabled = true;
if (!string.IsNullOrEmpty(lblCustomerNumber.Text) && !btnCordonelSearch.Enabled)
btnCordonelSearch.Enabled = true;
if (string.IsNullOrEmpty(lblCustomerNumber.Text) && btnCordonelSearch.Enabled)
btnCordonelSearch.Enabled = false;
// enable FW-Update Safe generation button
if (lblUpdateOperator.BackColor != ColorBkValid ||
lblFwUpdateDutyDate.BackColor != ColorBkValid ||
tbxCustomerName.BackColor != ColorBkValid ||
tbxOrderNumber.BackColor != ColorBkValid ||
_fwUpdatePackages.Count == 0 ||
_cordonelUpdateList.Count == 0 ||
updateLocked)
{
if (btnBuildFwUpdateSafe.Enabled) btnBuildFwUpdateSafe.Enabled = false;
return;
}
if (!btnBuildFwUpdateSafe.Enabled) btnBuildFwUpdateSafe.Enabled = true;
}
}
/// <summary>
/// Check for change in user account.
/// </summary>
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2021-Apr-04" author="Thomas Wiedebusch">
/// - Locked if operators are not loaded.
/// </remarks>
private void CheckUpdateOperatorAccountChange()
{
if (!_fwUpdateOperatorsPropertyChanged || _fwUpdateDbAccess?.DbFullQualifiedUpdateOperators == null ||
_fwUpdateDbAccess.DbFullQualifiedUpdateOperators.Count == 0) return;
_fwUpdateOperatorsPropertyChanged = false;
// update output information
FillDataGridWithUpdateOperatorInfos();
}
/// <summary>
/// Check for change of customer.
/// </summary>
/// <remarks date="2021-Mar-31" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2021-Apr-04" author="Thomas Wiedebusch">
/// - Locked if customers are not loaded.
/// </remarks>
private void CheckCustomerChange()
{
if (!_customersPropertyChanged || _fwUpdateDbAccess?.DbSearchedCordonelCustomers == null ||
_fwUpdateDbAccess.DbSearchedCordonelCustomers.Count == 0) return;
_customersPropertyChanged = false;
// update output information
FillDataGridWithCustomerInfos();
}
/// <summary>
/// Check for change of Cordonels.
/// </summary>
/// <remarks date="2021-Mar-31" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2021-Apr-04" author="Thomas Wiedebusch">
/// - Locked if Cordonels are not loaded.
/// </remarks>
/// <remarks date="2021-Apr-16" author="Thomas Wiedebusch">
/// - Added pre build summary.
/// </remarks>
private void CheckCordonelChange()
{
if (_cordonelsPropertyChanged)
{
_cordonelsPropertyChanged = false;
// update output information
FillDataGridWithCordonelInfos();
}
if (!_preBuildSummaryPropertyChanged) return;
_preBuildSummaryPropertyChanged = false;
// update output information
FillDataGridWithPreBuildSummaryInfos();
}
/// <summary>
/// Check for change of FW-Update packages.
/// </summary>
/// <remarks date="2021-Mar-31" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2021-Apr-04" author="Thomas Wiedebusch">
/// - Locked if FW-Packages are not loaded.
/// </remarks>
private void CheckFwPackageChange()
{
if (!_fwPackagePropertyChanged || _fwUpdateDbAccess?.DbCordonelFwPackages == null ||
_fwUpdateDbAccess.DbCordonelFwPackages.Count == 0) return;
_fwPackagePropertyChanged = false;
// update output information
FillDataGridWithFwPackageInfos();
}
/// <summary>
/// Check for change of report files.
/// </summary>
/// <remarks date="2021-Mar-31" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void CheckReportFilesChange()
{
if (!_fwReportFilesPropertyChanged) return;
_fwReportFilesPropertyChanged = false;
// update output information
FillDataGridWithReportFilesInfos();
}
/// <summary>
/// Check for change of Fw update safes.
/// </summary>
/// <remarks date="2021-Oct-28" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void CheckFwUpdateSafesChange()
{
if (!_fwUpdateSafesPropertyChanged) return;
_fwUpdateSafesPropertyChanged = false;
// update output information
FillDataGridWithFwUpdateSafesInfos();
}
#endregion --------------------------------------- Checks -----------------------------------------------------
#region ------------------------------------------ Tools ------------------------------------------------------
///// <summary>
///// Build the meter file update ruler to define releases which can be updated to another release.
///// </summary>
///// <remarks date="2021-Apr-07" author="Thomas Wiedebusch">
///// - Initial.
///// </remarks>
//public void BuildMeterFwUpdateRulerInfo()
//{
// var meterFwUpdateRuler = new List<MeterFwUpdateRuler>();
// var rule = new MeterFwUpdateRuler
// {
// Release = "R1066",
// Region = "EMEA",
// RadioFrequencyMhz = "433",
// CoreVersionMin = "162",
// CoreVersionMax = "164",
// MetrologyVersion = "287",
// MeterSizes = new List<String>
// {
// "DN50"
// },
// ApproverName = "Ami A Arsalan",
// ApprovalDate = new DateTime(2020, 12, 31)
// };
// meterFwUpdateRuler.Add(rule);
// rule = new MeterFwUpdateRuler
// {
// Release = "R1100",
// Region = "EMEA",
// RadioFrequencyMhz = "433",
// CoreVersionMin = "162",
// CoreVersionMax = "167",
// MetrologyVersion = "287",
// MeterSizes = null,
// ApproverName = "Willi Weber",
// ApprovalDate = new DateTime(2021, 04, 01)
// };
// meterFwUpdateRuler.Add(rule);
// rule = new MeterFwUpdateRuler
// {
// Release = "R106F",
// Region = "EMEA",
// RadioFrequencyMhz = "868",
// CoreVersionMin = "162",
// CoreVersionMax = "166",
// MetrologyVersion = "287",
// MeterSizes = new List<String>
// {
// "DN50",
// "DN60",
// "DN80",
// "DN150"
// },
// ApproverName = "Oliver Ohlsen",
// ApprovalDate = new DateTime(2021, 01, 08)
// };
// meterFwUpdateRuler.Add(rule);
// rule = new MeterFwUpdateRuler
// {
// Release = "B1070",
// Region = "NA",
// RadioFrequencyMhz = null,
// CoreVersionMin = "162",
// CoreVersionMax = "166",
// MetrologyVersion = "508",
// MeterSizes = new List<String>
// {
// "DN50"
// },
// ApproverName = "Mike M Miller",
// ApprovalDate = new DateTime(2021, 01, 13)
// };
// meterFwUpdateRuler.Add(rule);
// var text = JsonConvert.SerializeObject(meterFwUpdateRuler);
// var asciiStream = Encoding.UTF8.GetBytes(text);
// File.WriteAllBytes(FwUpdateConfig.MeterFwUpdateRulerConfigFileName, asciiStream);
//}
///// <summary>
///// Build the meter file erase restore information and export to MeterFilesConfigFilePathName.
///// </summary>
///// <remarks date="2021-Feb-17" author="Thomas Wiedebusch">
///// - Initial.
///// </remarks>
//public void BuildMeterFilesEraseRestoreInfo()
//{
// // loading the lists of meter files which shall be erased before the FW-Update and restored after.
// var meterFilesEraseRestore = new MeterFilesEraseRestore
// {
// Erase = new List<String>
// {
// "1\\tstfile",
// "1\\fdrdata",
// "1\\logdata",
// "1\\blklist",
// "1\\mettable",
// "1\\pulsedbg",
// "1\\upg*",
// "1\\img*"
// }
// };
// var meterFileRestore = new MeterFileRestore
// {
// Name = "1\\tstfile",
// ByteSize = 262144,
// Pattern = null
// };
// meterFilesEraseRestore.Restore = new List<MeterFileRestore>
// {
// meterFileRestore
// };
// var text = JsonConvert.SerializeObject(meterFilesEraseRestore);
// var asciiStream = Encoding.UTF8.GetBytes(text);
// File.WriteAllBytes(FwUpdateConfig.MeterFilesEraseRestoreConfigFileName, asciiStream);
//}
/// <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 = MessageBoxButtons.OK,
MessageBoxIcon icon = MessageBoxIcon.Asterisk)
{
MessageBox.Show(text, caption, buttons, icon, MessageBoxDefaultButton.Button1,
MessageBoxOptions.ServiceNotification);
}
/// <summary>
/// Output exclusively to user update remarks text window.
/// </summary>
/// <remarks date="2021-Apr-26" author="Thomas Wiedebusch">
/// - Color added.
/// </remarks>
private void LogText(String txtHistory)
{
InfoWindowColoredText(txtHistory, ColorDefault);
_logger.Info(txtHistory);
}
/// <summary>
/// Output exclusively to user update remarks text window.
/// </summary>
private void LogErrorText(String txtHistory)
{
InfoWindowColoredText(txtHistory, ColorProcessFailed);
_logger.Info(txtHistory);
}
/// <summary>
/// Output exclusively to user update remarks text window.
/// </summary>
private void LogSuccessText(String txtHistory)
{
InfoWindowColoredText(txtHistory, ColorSuccess);
_logger.Info(txtHistory);
}
/// <summary>
/// Output exclusively to user update remarks text window.
/// </summary>
private void InfoWindowColoredText(String txtHistory, Color color)
{
Invoke(new Action(() =>
{
rtbReport.SuspendLayout();
rtbReport.SelectionStart = rtbReport.Text.Length;
rtbReport.SelectionLength = 0;
rtbReport.SelectionColor = color;
rtbReport.AppendText($"{txtHistory}{Environment.NewLine}");
rtbReport.SelectionColor = rtbReport.ForeColor;
rtbReport.ScrollToCaret();
rtbReport.ResumeLayout();
}));
}
/// <summary>
/// Process bar - NOT invoked, just call from Form main thread.
/// </summary>
/// <remarks date="2021-Feb-25" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2021-Mar-24" 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 == false && visible == false) return;
ProgressBarStatus.Value = value;
ProgressBarStatus.Visible = visible;
}
/// <summary>
/// Common routine to hide the data picker and uninstall all events.
/// </summary>
/// <remarks date="2021-Feb-25" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
/// - Check user input.
/// </remarks>
private void HideDatePicker()
{
_datePicker.Visible = false;
_datePicker.CloseUp -= datePickerFwUpdateValidationDate_CloseUp;
_datePicker.CloseUp -= datePickerUserValidationDate_CloseUp;
// display the label
lblFwUpdateDutyDate.Visible = true;
CheckDataCollectionStatus();
}
/// <summary>
/// Common routine to disable all controls.
/// </summary>
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Apr-02" author="Thomas Wiedebusch">
/// - Added new buttons.
/// </remarks>
private void DisableAllControlsInvoked()
{
UiInvoker.ControlEnableInvoker(grpLanguageSelection, false);
UiInvoker.ControlEnableInvoker(btnBuildFwUpdateSafe, false);
UiInvoker.ControlEnableInvoker(btnUploadSafeToDb, false);
UiInvoker.ControlEnableInvoker(btnLicenseFwUpdateSw, false);
UiInvoker.ControlEnableInvoker(btnLicenseFwUpdateBuilder, false);
UiInvoker.ControlEnableInvoker(lblFwUpdateDutyDate, false);
UiInvoker.ControlEnableInvoker(tbxOrderNumber, false);
UiInvoker.ControlEnableInvoker(tbxOrderPosition, false);
UiInvoker.ControlEnableInvoker(tabControlSelection, false);
}
/// <summary>
/// Common routine to disable all controls except the language setting.
/// This should be used, if user is not licensed.
/// </summary>
/// <remarks date="2021-Apr-14" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void DisableControlsExceptLanguageInvoked()
{
UiInvoker.ControlEnableInvoker(grpLanguageSelection, true);
UiInvoker.ControlEnableInvoker(btnBuildFwUpdateSafe, false);
UiInvoker.ControlEnableInvoker(btnUploadSafeToDb, false);
UiInvoker.ControlEnableInvoker(btnLicenseFwUpdateSw, false);
UiInvoker.ControlEnableInvoker(btnLicenseFwUpdateBuilder, false);
UiInvoker.ControlEnableInvoker(lblFwUpdateDutyDate, false);
UiInvoker.ControlEnableInvoker(tbxOrderNumber, false);
UiInvoker.ControlEnableInvoker(tbxOrderPosition, false);
UiInvoker.ControlEnableInvoker(tabControlSelection, false);
}
/// <summary>
/// Common routine to enable inputs.
/// </summary>
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Apr-14" author="Thomas Wiedebusch">
/// - Avoid activation on unchecked license.
/// </remarks>
private void EnableInputsInvoked()
{
if (_licenseUnchecked || _regUser == null || !_regUser.AccountActive) return;
UiInvoker.ControlEnableInvoker(grpLanguageSelection, true);
UiInvoker.ControlEnableInvoker(lblFwUpdateDutyDate, true);
UiInvoker.ControlEnableInvoker(tbxOrderNumber, true);
UiInvoker.ControlEnableInvoker(tbxOrderPosition, true);
UiInvoker.ControlEnableInvoker(tabControlSelection, true);
}
#endregion --------------------------------------- Tools ------------------------------------------------------
#region ------------------------------------------ Threads and Tasks ------------------------------------------
/// <summary>
/// Upload FW-Update Safe to DB Task.
/// </summary>
/// <remarks date="2021-Apr-27" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void UploadFwUpdateSafeTask()
{
_invokerProcessState = _processState;
Task.Factory.StartNew(() =>
{
Thread.CurrentThread.CurrentUICulture = _cultureInfo;
Thread.CurrentThread.CurrentCulture = _cultureInfo;
_enableFwSafeUpload = !UploadFwUpdateSafeToDb();
}).ContinueWith(delegate
{
Thread.CurrentThread.CurrentUICulture = _cultureInfo;
Thread.CurrentThread.CurrentCulture = _cultureInfo;
if (!_enableFwSafeUpload)
{
var msg = $"{Resources.StrFwUpdateSafeUploadSuccessfull} \"{_fwUpdateSafeName}\"";
LogText(StrSeparator);
LogSuccessText(msg);
LogText(StrSeparator);
MessageBoxShow($"{Resources.StrFwUpdateSafeUploadSuccessfull}\n\n \"{_fwUpdateSafeName}\"",
Resources.StrSuccess);
_processState = ProcessState.Idle;
}
else
{
var msg = $"{Resources.StrFwUpdateSafeUploadFailed}";
LogText(StrSeparator);
LogErrorText(msg);
LogText(StrSeparator);
MessageBoxShow(msg, Resources.StrError, MessageBoxButtons.OK, MessageBoxIcon.Error);
_processState = ProcessState.Error;
}
EnableInputsInvoked();
});
}
/// <summary>
/// Start FW-Update Safe Builder Task.
/// </summary>
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2021-Apr-06" author="Thomas Wiedebusch">
/// - Error process state introduced.
/// </remarks>
private void BuildFwUpdateSafeTask()
{
_invokerProcessState = _processState;
Task.Factory.StartNew(() =>
{
Thread.CurrentThread.CurrentUICulture = _cultureInfo;
Thread.CurrentThread.CurrentCulture = _cultureInfo;
_enableFwSafeUpload = BuildFwUpdateSafe();
}).ContinueWith(delegate
{
Thread.CurrentThread.CurrentUICulture = _cultureInfo;
Thread.CurrentThread.CurrentCulture = _cultureInfo;
if (_enableFwSafeUpload)
{
var msg = $"{Resources.StrFwUpdateSafeBuildSuccessfully} \"{_fwUpdateSafeName}\"";
LogText(StrSeparator);
LogSuccessText(msg);
LogText(StrSeparator);
MessageBoxShow($"{Resources.StrFwUpdateSafeBuildSuccessfully}\n\n \"{_fwUpdateSafeName}\"",
Resources.StrSuccess);
_processState = ProcessState.Idle;
}
else
{
var msg = $"{Resources.StrFwUpdateSafeBuildFailed}";
LogText(StrSeparator);
LogErrorText(msg);
LogText(StrSeparator);
MessageBoxShow(msg, Resources.StrError, MessageBoxButtons.OK, MessageBoxIcon.Error);
_processState = ProcessState.Error;
}
EnableInputsInvoked();
});
}
/// <summary>
/// Establish the DB connection.
/// </summary>
/// <remarks date="2021-Mar-23" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2021-Apr-02" author="Thomas Wiedebusch">
/// - dbAccessLocked introduced.
/// </remarks>
/// <remarks date="2021-Apr-06" author="Thomas Wiedebusch">
/// - Error process state introduced.
/// </remarks>
private void EstablishDbConnectionTask()
{
_invokerProcessState = _processState;
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.Error;
}
}).ContinueWith(delegate
{
_processState = ProcessState.Idle;
});
}
/// <summary>
/// Acquire all FW-Update packages.
/// </summary>
/// <remarks date="2021-Mar-31" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2021-Apr-02" author="Thomas Wiedebusch">
/// - dbAccessLocked introduced.
/// </remarks>
/// <remarks date="2021-Apr-06" author="Thomas Wiedebusch">
/// - Error process state introduced.
/// </remarks>
private void LoadDbFwUpdateOperatorsTask()
{
_invokerProcessState = _processState;
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();
GetAllUpdateOperatorsFromDb();
}
catch (Exception)
{
_processState = ProcessState.Error;
}
}).ContinueWith(delegate
{
_fwUpdateOperatorsPropertyChanged = true;
_processState = ProcessState.Idle;
});
}
/// <summary>
/// Check the software license.
/// </summary>
/// <remarks date="2021-Apr-14" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void CheckLicenseTask()
{
_invokerProcessState = _processState;
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();
GetLicenseFromDb();
}
catch (Exception)
{
_processState = ProcessState.Error;
}
}).ContinueWith(delegate
{
if (_regUser.AccountActive)
{
_licenseValidDateTimeOffset = DateTimeServer.GetDateTimeTodayUntilMidnight();
_processState = ProcessState.Idle;
}
else _processState = ProcessState.DbAccessLocked;
});
}
/// <summary>
/// Acquire all FW packages from DB.
/// </summary>
/// <remarks date="2021-Apr-08" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2021-Oct-26" author="Thomas Wiedebusch">
/// - Load configuration files from DB as the latest MeterFwUpdateRuler.json is needed for the
/// FwUpdateBuilder FW package check and validation routine! This step has to be done in advance
/// to the FW package load, as the Builder uses the information of the MeterFwUpdateRuler to
/// create the package information!
/// </remarks>
private void LoadDbCordonelFwPackagesTask()
{
_invokerProcessState = _processState;
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();
// has to be done first to extract the MeterFwUpdateRuler
GetFwUpdateConfigFilesFromDb();
// load the packages and use the MeterFwUpdateRuler to assign the DN, EMEA, NA, 868, 433..
GetCordonelFwPackagesFromDb();
}
catch (Exception)
{
_processState = ProcessState.Error;
}
}).ContinueWith(delegate
{
_fwPackagePropertyChanged = true;
_processState = ProcessState.Idle;
});
}
/// <summary>
/// Acquire all report files from DB.
/// </summary>
/// <remarks date="2021-Oct-28" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void LoadDbReportFilesTask()
{
_invokerProcessState = _processState;
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();
GetReportFilesFromDb();
}
catch (Exception)
{
_processState = ProcessState.Error;
}
}).ContinueWith(delegate
{
_fwReportFilesPropertyChanged = true;
_processState = ProcessState.Idle;
});
}
/// <summary>
/// Acquire all FW-Update safes from DB.
/// </summary>
/// <remarks date="2021-Oct-28" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
private void LoadDbOutstandingFwUpdateSafesTask()
{
_invokerProcessState = _processState;
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();
GetOutstandingFwUpdateSafesFromDb();
}
catch (Exception)
{
_processState = ProcessState.Error;
}
}).ContinueWith(delegate
{
_fwUpdateSafesPropertyChanged = true;
_processState = ProcessState.Idle;
});
}
/// <summary>
/// Acquire all Customers specified by search mask from DB.
/// </summary>
/// <remarks date="2021-Mar-31" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2021-Apr-02" author="Thomas Wiedebusch">
/// - dbAccessLocked introduced.
/// </remarks>
/// <remarks date="2021-Apr-06" author="Thomas Wiedebusch">
/// - Error process state introduced.
/// </remarks>
private void LoadDbCordonelCustomersTask()
{
_invokerProcessState = _processState;
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();
GetAllCordonelCustomersFromDb();
}
catch (Exception)
{
_processState = ProcessState.Error;
}
}).ContinueWith(delegate
{
_customersPropertyChanged = true;
_processState = ProcessState.Idle;
});
}
/// <summary>
/// Acquire all Cordonel serial numbers of a specific production number.
/// </summary>
/// <remarks date="2021-Mar-31" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2021-Apr-02" author="Thomas Wiedebusch">
/// - dbAccessLocked introduced.
/// </remarks>
/// <remarks date="2021-Apr-06" author="Thomas Wiedebusch">
/// - Error process state introduced.
/// </remarks>
private void LoadDbCordonelSerialNumbersTask()
{
_invokerProcessState = _processState;
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();
GetAllCordonelSerialNumbersOfOrderFromDb();
}
catch (Exception)
{
_processState = ProcessState.Error;
}
}).ContinueWith(delegate
{
_cordonelsPropertyChanged = true;
_processState = ProcessState.Idle;
});
}
/// <summary>
/// Acquire all customer specific production orders from DB.
/// </summary>
/// <remarks date="2021-Apr-04" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2021-Apr-06" author="Thomas Wiedebusch">
/// - Error process state introduced.
/// </remarks>
private void LoadDbCordonelProductionOrdersTask()
{
_invokerProcessState = _processState;
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();
GetAllCordonelOrdersOfCustomerFromDb();
}
catch (Exception)
{
_processState = ProcessState.Error;
}
}).ContinueWith(delegate
{
_cordonelsPropertyChanged = true;
_processState = ProcessState.Idle;
});
}
#endregion --------------------------------------- Threads and Tasks ------------------------------------------
#region ------------------------------------------ Data Grid FW Packages --------------------------------------
/// <summary>
/// Overwrite cell click, because edit of cells is denied (read only == true). This is needed for FW-Update
/// packages selection. Multiple packages can be selected!
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2021-Apr-08" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Apr-10" author="Thomas Wiedebusch">
/// - Search column index starting with 0.
/// </remarks>
/// <remarks date="2021-Apr-13" author="Thomas Wiedebusch">
/// - User search from Cordonel FW-Packages as this contains lot more selected information than the clustered
/// file.
/// </remarks>
private void gridViewFwPackagesSelection_CellClick(Object sender, DataGridViewCellEventArgs e)
{
try
{
if (e.ColumnIndex < 0 || e.RowIndex < 0 || _fwUpdatePackages == null)
{
return;
}
// the e.RowIndex is referenced to the (sorted) data grid view
var fwPackage = new CordonelFirmware();
for (var columnIndex = 0; columnIndex < gridViewFwPackageSelection.ColumnCount; columnIndex++)
{
if (gridViewFwPackageSelection.Columns[columnIndex].Name == Resources.StrTableCordonelFwToInstall)
fwPackage.ReleaseNameVersion =
gridViewFwPackageSelection.Rows[e.RowIndex].Cells[columnIndex].Value.ToString();
}
// select FW package
if (gridViewFwPackageSelection.Columns[e.ColumnIndex].Name == Resources.StrTableSelect)
{
// Search the FW package name in data table, select if found
foreach (var fw in _cordonelFwPackageInfoSearch)
{
if (fw.ReleaseNameVersion == fwPackage.ReleaseNameVersion)
{
// toggle selection and set information on main screen
if (fw.IsSelected)
{
// remove FW package from list
fw.IsSelected = false;
foreach (var x in _fwUpdatePackages.Where(x => x.ReleaseNameVersion ==
fw.ReleaseNameVersion))
{
_fwUpdatePackages.Remove(x);
break;
}
}
else
{
// add selected package to list if not already in list
if (_fwUpdatePackages.All(x => x.ReleaseNameVersion != fw.ReleaseNameVersion))
_fwUpdatePackages.Add(fwPackage);
fw.IsSelected = true;
}
//search FW package in data table for update
for (var idx = 0; idx < _dataTableFwPackages.Rows.Count; idx++)
{
var dataRow = _dataTableFwPackages.Rows[idx];
if (fw.ReleaseNameVersion != (String)dataRow[Resources.StrTableCordonelFwToInstall])
continue;
dataRow[Resources.StrTableSelect] = fw.IsSelected;
break;
}
break;
} // FW package found
} // Cordonel search list files
}
_fwPackagePropertyChanged = false;
}
catch (Exception)
{
_processState = ProcessState.Error;
}
}
/// <summary>
/// Build data grid for FW-Update packages
/// </summary>
/// <remarks date="2021-Apr-08" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Apr-13" author="Thomas Wiedebusch">
/// - User search from Cordonel FW-Packages as this contains lot more selected information than the clustered
/// file.
/// </remarks>
/// <remarks date="2021-Apr-15" author="Thomas Wiedebusch">
/// - Search extended to metrology.
/// </remarks>
private void FillDataGridWithFwPackageInfos()
{
grpLanguageSelection.Enabled = false;
_dataTableFwPackages?.Dispose();
Thread.CurrentThread.CurrentUICulture = _cultureInfo;
Thread.CurrentThread.CurrentCulture = _cultureInfo;
_dataTableFwPackages = new DataTable();
_dataTableFwPackages.Columns.Add(Resources.StrTableSelect, typeof(Boolean));
_dataTableFwPackages.Columns.Add(Resources.StrTableCordonelFwToInstall, typeof(String));
_dataTableFwPackages.Columns.Add(Resources.StrTableCordonelFwIsLatest, typeof(Boolean));
_dataTableFwPackages.Columns.Add(Resources.StrTableCordonelFwIsReleased, typeof(Boolean));
_dataTableFwPackages.Columns.Add(Resources.StrTableCordonelFwVersion, typeof(String));
_dataTableFwPackages.Columns.Add(Resources.StrTableRegion, typeof(String));
_dataTableFwPackages.Columns.Add(Resources.StrTableRadioFrequency, typeof(String));
_dataTableFwPackages.Columns.Add(Resources.StrTableCordonelMetrology, typeof(String));
_dataTableFwPackages.Columns.Add(Resources.StrTableFwPackageCoreMin, typeof(String));
_dataTableFwPackages.Columns.Add(Resources.StrTableFwPackageCoreMax, typeof(String));
_dataTableFwPackages.Columns.Add(Resources.StrTableCordonelDiameter, typeof(String));
_dataTableFwPackages.Columns.Add(Resources.StrTableReleaseDate, typeof(DateTime));
try
{
foreach (var fw in _cordonelFwPackageInfoSearch)
{
// pre-selection of displayed FW packages
var requiredCoreVersion = 0;
if (cbxFwPackageSearchCore.Text != @"*")
{
var version = cbxFwPackageSearchCore.Text;
version = version.Replace(".", "");
Int32.TryParse(version, out requiredCoreVersion);
}
if (fw.Region != cbxFwPackageRegionMask.Text && cbxFwPackageRegionMask.Text != @"*" ||
fw.RadioFrequencyMhz != cbxFwPackageRadioMask.Text && cbxFwPackageRadioMask.Text != @"*" ||
fw.MeterSize != cbxFwPackageSizeMask.Text && cbxFwPackageSizeMask.Text != @"*" ||
(fw.CoreVersionMin > requiredCoreVersion || requiredCoreVersion > fw.CoreVersionMax) &&
cbxFwPackageSearchCore.Text != @"*" ||
fw.MetrologyVersion != cbxFwPackageSearchMetrology.Text &&
cbxFwPackageSearchMetrology.Text != @"*") continue;
var row = _dataTableFwPackages.NewRow();
row[Resources.StrTableSelect] = fw.IsSelected;
row[Resources.StrTableCordonelFwToInstall] = fw.ReleaseNameVersion;
row[Resources.StrTableCordonelFwIsLatest] = fw.FileIsLatest;
row[Resources.StrTableCordonelFwIsReleased] = fw.FwIsReleased;
row[Resources.StrTableCordonelFwVersion] = fw.ReleaseVersion;
row[Resources.StrTableRegion] = fw.Region;
row[Resources.StrTableRadioFrequency] = fw.RadioFrequencyMhz;
row[Resources.StrTableCordonelMetrology] = fw.MetrologyVersion;
row[Resources.StrTableFwPackageCoreMin] = $"{fw.CoreVersionMin / 100}.{fw.CoreVersionMin % 100}";
row[Resources.StrTableFwPackageCoreMax] = $"{fw.CoreVersionMax / 100}.{fw.CoreVersionMax % 100}";
row[Resources.StrTableCordonelDiameter] = fw.MeterSize;
row[Resources.StrTableReleaseDate] = fw.ReleaseDate.Date;
_dataTableFwPackages.Rows.Add(row);
}
//output data to data grid view
gridViewFwPackageSelection.DataSource = _dataTableFwPackages.DefaultView;
foreach (DataGridViewColumn column in gridViewFwPackageSelection.Columns)
{
column.SortMode = DataGridViewColumnSortMode.Automatic;
}
if (gridViewFwPackageSelection.Columns[Resources.StrTableCordonelFwVersion] != null)
gridViewFwPackageSelection.Sort(gridViewFwPackageSelection.Columns[Resources.StrTableCordonelFwVersion],
ListSortDirection.Descending);
}
catch (Exception)
{
_processState = ProcessState.Error;
}
finally
{
grpLanguageSelection.Enabled = true;
}
}
#endregion --------------------------------------- Data Grid FW Packages ---------------------------------------
#region ------------------------------------------ Data Grid Update Safes --------------------------------------
/// <summary>
/// Build data grid for FW-Update update safes
/// </summary>
/// <remarks date="2021-Oct-28" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void FillDataGridWithFwUpdateSafesInfos()
{
}
#endregion --------------------------------------- Data Grid Update Safes --------------------------------------
#region ------------------------------------------ Data Grid Report Files --------------------------------------
/// <summary>
/// Build data grid for FW-Update report files
/// </summary>
/// <remarks date="2021-Oct-28" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void FillDataGridWithReportFilesInfos()
{
}
#endregion --------------------------------------- Data Grid Report Files --------------------------------------
#region ------------------------------------------ Data Grid Pre Build Summary --------------------------------
/// <summary>
/// Overwrite cell click, because edit of cells is denied (read only == true). This is needed for
/// Pre build summary selection. Multiple Cordonels can be selected!
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2021-Apr-16" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Apr-17" author="Thomas Wiedebusch">
/// - Production pre select infos from production search infos.
/// </remarks>
private void gridViewPreBuildSummary_CellClick(Object sender, DataGridViewCellEventArgs e)
{
try
{
if (e.ColumnIndex < 0 || e.RowIndex < 0 || _dataTableSummary == null)
{
return;
}
// the e.RowIndex is referenced to the (sorted) data grid view
var cordonelDeviceInfo = new CordonelDeviceInfo();
for (var columnIndex = 0; columnIndex < gridViewPreBuildSummary.ColumnCount;
columnIndex++)
{
if (gridViewPreBuildSummary.Columns[columnIndex].Name == Resources.StrTableCordonelPcbId)
cordonelDeviceInfo.PcbId =
gridViewPreBuildSummary.Rows[e.RowIndex].Cells[columnIndex].Value.ToString();
// add here the required release
if (gridViewPreBuildSummary.Columns[columnIndex].Name == Resources.StrTableCordonelFwToInstall)
cordonelDeviceInfo.RequiredRelease =
gridViewPreBuildSummary.Rows[e.RowIndex].Cells[columnIndex].Value.ToString();
}
// select FW package with combo box
if (gridViewPreBuildSummary.Columns[e.ColumnIndex].Name == Resources.StrTableCordonelFwToInstall)
{
// take the actual cell value as default
_cbxFwReleaseSelection.Text = cordonelDeviceInfo.RequiredRelease;
// Adding combo box control into DataGridView
gridViewPreBuildSummary.Controls.Add(_cbxFwReleaseSelection);
// Rectangular area that represents the display area for a cell
var location = gridViewPreBuildSummary.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, true);
// Setting Location and size to fit within the cell
_cbxFwReleaseSelection.Height = location.Height;
_cbxFwReleaseSelection.Width = 200;
_cbxFwReleaseSelection.Location = new Point(location.X, location.Y);
// The final selection of the fw package
_fwPackageCordonelPcbId = cordonelDeviceInfo.PcbId;
_cbxFwReleaseSelection.DropDownClosed += CbxFwReleaseSelection_DropDownClosed;
_cbxFwReleaseSelection.Visible = true;
}
// select Cordonel
if (gridViewPreBuildSummary.Columns[e.ColumnIndex].Name == Resources.StrTableApprove)
{
// Search the cordonel in the production pre selected list
foreach (var cordonel in _cordonelProductionPreSelectInfos)
{
if (cordonel.PcbId == cordonelDeviceInfo.PcbId)
{
// toggle selection and set information on main screen
cordonel.IsApproved = !cordonel.IsApproved;
cordonel.IsRemoved = !cordonel.IsApproved;
// add cordonel to list
if (cordonel.IsApproved && cordonel.IsSelected &&
_cordonelUpdateList.All(x => x.PcbId != cordonelDeviceInfo.PcbId))
_cordonelUpdateList.Add(cordonelDeviceInfo);
//search cordonel in data table for update of "select" checkbox
for (var idx = 0; idx < _dataTableSummary.Rows.Count; idx++)
{
var dataRow = _dataTableSummary.Rows[idx];
if (cordonel.PcbId != (String)dataRow[Resources.StrTableCordonelPcbId]) continue;
dataRow[Resources.StrTableApprove] = cordonel.IsApproved;
dataRow[Resources.StrTableRemove] = cordonel.IsRemoved;
break;
}
break;
}// Cordonel found
}// Search the cordonel in the production list
}
// select Cordonel
if (gridViewPreBuildSummary.Columns[e.ColumnIndex].Name == Resources.StrTableRemove)
{
// Search the cordonel in the production list pre selected
foreach (var cordonel in _cordonelProductionPreSelectInfos)
{
if (cordonel.PcbId == cordonelDeviceInfo.PcbId)
{
// toggle selection and set information on main screen
cordonel.IsRemoved = !cordonel.IsRemoved;
cordonel.IsApproved = !cordonel.IsRemoved;
//search cordonel in data table for update of "select" checkbox
for (var idx = 0; idx < _dataTableSummary.Rows.Count; idx++)
{
var dataRow = _dataTableSummary.Rows[idx];
if (cordonel.PcbId != (String)dataRow[Resources.StrTableCordonelPcbId]) continue;
dataRow[Resources.StrTableApprove] = cordonel.IsApproved;
dataRow[Resources.StrTableRemove] = cordonel.IsRemoved;
break;
}
break;
}// Cordonel found
}// Search the cordonel in the production list
}
// select Cordonel
if (gridViewPreBuildSummary.Columns[e.ColumnIndex].Name == Resources.StrTableSelect)
{
// Search the cordonel in the production pre selected list
foreach (var cordPre in _cordonelProductionPreSelectInfos)
{
if (cordPre.PcbId == cordonelDeviceInfo.PcbId)
{
// toggle selection and set information on main screen
if (cordPre.IsSelected)
{
// remove cordonel from list
cordPre.IsSelected = false;
foreach (var x in _cordonelUpdateList.Where(x => x.PcbId == cordonelDeviceInfo.PcbId))
{
_cordonelUpdateList.Remove(x);
break;
}
}
else
{
// add cordonel to list
if (cordPre.IsApproved && _cordonelUpdateList.All(x => x.PcbId != cordonelDeviceInfo.PcbId))
_cordonelUpdateList.Add(cordonelDeviceInfo);
cordPre.IsSelected = true;
}
//search cordonel in data table for update of "select" checkbox
for (var idx = 0; idx < _dataTableSummary.Rows.Count; idx++)
{
var dataRow = _dataTableSummary.Rows[idx];
if (cordPre.PcbId != (String)dataRow[Resources.StrTableCordonelPcbId]) continue;
dataRow[Resources.StrTableSelect] = cordPre.IsSelected;
break;
}
_cordonelsPropertyChanged = true;
break;
}// Cordonel found
}// Search the cordonel in the production list
}
PreBuildSummaryInformationStyleSet();
}
catch (Exception)
{
_processState = ProcessState.Error;
}
}
/// <summary>
/// Build data grid for pre build summary
/// </summary>
/// <remarks date="2021-Apr-16" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Apr-17" author="Thomas Wiedebusch">
/// - Production pre select infos from production search infos.
/// </remarks>
/// <remarks date="2021-Apr-29" author="Thomas Wiedebusch">
/// - Fill search masks of GFW packages for core revision, diameter, radio, region and metrology based
/// on selected Cordonels
/// </remarks>
private void FillDataGridWithPreBuildSummaryInfos()
{
grpLanguageSelection.Enabled = false;
_dataTableSummary?.Dispose();
Thread.CurrentThread.CurrentUICulture = _cultureInfo;
Thread.CurrentThread.CurrentCulture = _cultureInfo;
_dataTableSummary = new DataTable();
_dataTableSummary.Columns.Add(Resources.StrTableSelect, typeof(Boolean));
_dataTableSummary.Columns.Add(Resources.StrTableApprove, typeof(Boolean));
_dataTableSummary.Columns.Add(Resources.StrTableRemove, typeof(Boolean));
_dataTableSummary.Columns.Add(Resources.StrTableCordonelCustomerSerialNumber, typeof(String));
_dataTableSummary.Columns.Add(Resources.StrTableCordonelPcbId, typeof(String));
_dataTableSummary.Columns.Add(Resources.StrTableCordonelFwToInstall, typeof(String));
_dataTableSummary.Columns.Add(Resources.StrTableCordonelMetrology, typeof(String));
_dataTableSummary.Columns.Add(Resources.StrTableCordonelMetrologyIsUpdateable, typeof(Boolean));
_dataTableSummary.Columns.Add(Resources.StrTableCordonelCore, typeof(String));
_dataTableSummary.Columns.Add(Resources.StrTableRegion, typeof(String));
_dataTableSummary.Columns.Add(Resources.StrTableRadioFrequency, typeof(String));
_dataTableSummary.Columns.Add(Resources.StrTableCordonelDiameter, typeof(String));
_dataTableSummary.Columns.Add(Resources.StrTableReason, typeof(String));
try
{
foreach (var cordonel in _cordonelProductionPreSelectInfos)
{
// fill search masks for FW package selection
if (!string.IsNullOrEmpty(cordonel.Diameter) && cordonel.Diameter != "?" &&
!_sizeSearchItems.Contains(cordonel.Diameter))
{
_sizeSearchItems.Add(cordonel.Diameter);
}
// fill search masks for FW package selection
if (!string.IsNullOrEmpty(cordonel.RadioFrequency) && cordonel.RadioFrequency != "?" &&
!_radioSearchItems.Contains(cordonel.RadioFrequency))
{
_radioSearchItems.Add(cordonel.RadioFrequency);
}
// fill search masks for FW package selection
if (!string.IsNullOrEmpty(cordonel.Region) && cordonel.Region != "?" &&
!_regionSearchItems.Contains(cordonel.Region))
{
_regionSearchItems.Add(cordonel.Region);
}
// fill search masks for FW package selection
if (!string.IsNullOrEmpty(cordonel.CoreRevision) && cordonel.CoreRevision != "?" &&
!_coreSearchItems.Contains(cordonel.CoreRevision))
{
_coreSearchItems.Add(cordonel.CoreRevision);
}
// fill search masks for FW package selection
if (!string.IsNullOrEmpty(cordonel.Metrology) && cordonel.Metrology != "?" &&
!_metrologySearchItems.Contains(cordonel.Metrology))
{
_metrologySearchItems.Add(cordonel.Metrology);
}
// search if this Cordonel is already in cordonelDeviceInfo list as this is the marker
// to update it and a new selection may overwrite the update (IsSelected == true) status
if (_cordonelUpdateList.Any(x => x.PcbId == cordonel.PcbId)) cordonel.IsSelected = true;
var row = _dataTableSummary.NewRow();
row[Resources.StrTableSelect] = cordonel.IsSelected;
row[Resources.StrTableApprove] = cordonel.IsApproved;
row[Resources.StrTableRemove] = cordonel.IsRemoved;
row[Resources.StrTableCordonelCustomerSerialNumber] = cordonel.CustomerSerialNumber ?? "?";
row[Resources.StrTableCordonelPcbId] = cordonel.PcbId ?? "?";
row[Resources.StrTableCordonelFwToInstall] = cordonel.RequiredReleaseNameVersion ?? "?";
row[Resources.StrTableCordonelMetrology] = cordonel.Metrology ?? "?";
row[Resources.StrTableCordonelMetrologyIsUpdateable] = cordonel.MetrologyIsUpdateable;
row[Resources.StrTableCordonelCore] = cordonel.CoreRevision ?? "?";
row[Resources.StrTableRegion] = cordonel.Region ?? "?";
row[Resources.StrTableRadioFrequency] = cordonel.RadioFrequency ?? "?";
row[Resources.StrTableCordonelDiameter] = cordonel.Diameter ?? "?";
row[Resources.StrTableReason] = cordonel.ReasonForUpdateDenied ?? "";
_dataTableSummary.Rows.Add(row);
}
gridViewPreBuildSummary.DataSource = _dataTableSummary;
foreach (DataGridViewColumn column in gridViewPreBuildSummary.Columns)
{
column.SortMode = DataGridViewColumnSortMode.Automatic;
}
// color the results of the compare
PreBuildSummaryInformationStyleSet();
}
catch (Exception)
{
_processState = ProcessState.Error;
}
finally
{
grpLanguageSelection.Enabled = true;
}
}
/// <summary>
/// Color the rows depending on the state
/// </summary>
/// <remarks date="2021-Apr-16" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void PreBuildSummaryInformationStyleSet()
{
Thread.CurrentThread.CurrentUICulture = _cultureInfo;
Thread.CurrentThread.CurrentCulture = _cultureInfo;
foreach (DataGridViewRow dataGridRow in gridViewPreBuildSummary.Rows)
{
// check if selected
if ((Boolean)dataGridRow.Cells[Resources.StrTableSelect].Value)
{
// approved by software or user
var requiredRelease = (String)dataGridRow.Cells[Resources.StrTableCordonelFwToInstall].Value;
if ((Boolean)dataGridRow.Cells[Resources.StrTableApprove].Value &&
!string.IsNullOrEmpty(requiredRelease) && requiredRelease != "?")
{
dataGridRow.DefaultCellStyle = _styleInstallationApproved;
}
// not approved and not rejected - user has to decide
else if (!(Boolean)dataGridRow.Cells[Resources.StrTableRemove].Value)
{
dataGridRow.DefaultCellStyle = _styleInstallationUserApproval;
}
// not approved but rejected
else
{
dataGridRow.DefaultCellStyle = _styleInstallationDenied;
}
}
else
{
dataGridRow.DefaultCellStyle = _styleInstallationRemoved;
}
}
}
/// <summary>
/// After sort event to update styles
/// </summary>
/// <remarks date="2021-Apr-16" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void gridViewPreBuildSummary_Sorted(Object sender, EventArgs e)
{
PreBuildSummaryInformationStyleSet();
}
#endregion --------------------------------------- Data Grid Pre Build Summary --------------------------------
#region ------------------------------------------ Data Grid Cordonels ----------------------------------------
/// <summary>
/// Overwrite cell click, because edit of cells is denied (read only == true). This is needed for
/// Cordonel selection. Multiple Cordonels can be selected!
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2021-Mar-31" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Apr-01" author="Thomas Wiedebusch">
/// - Idx search index started with 0 instead of 1.
/// </remarks>
/// <remarks date="2021-Apr-02" author="Thomas Wiedebusch">
/// - PCB Id may not always be unambiguously (Sensus GmbH Hannover PCB Id 19080071),
/// - Improved search speed.
/// </remarks>
/// <remarks date="2021-Apr-07" author="Thomas Wiedebusch">
/// - Check data table assignment.
/// </remarks>
/// <remarks date="2021-Apr-10" author="Thomas Wiedebusch">
/// - Added FW release picker,
/// - Search column index starting with 0.
/// </remarks>
/// <remarks date="2021-Apr-17" author="Thomas Wiedebusch">
/// - Production pre select infos from production search infos.
/// </remarks>
private void gridViewCordonelsSelection_CellClick(Object sender, DataGridViewCellEventArgs e)
{
try
{
if (e.ColumnIndex < 0 || e.RowIndex < 0 || _dataTableCordonels == null)
{
return;
}
// the e.RowIndex is referenced to the (sorted) data grid view
var cordSelect = new CordonelProductionInfosDb();
for (var columnIndex = 0; columnIndex < gridViewCordonelSelection.ColumnCount;
columnIndex++)
{
if (gridViewCordonelSelection.Columns[columnIndex].Name == Resources.StrTableCordonelPcbId)
cordSelect.PcbId =
gridViewCordonelSelection.Rows[e.RowIndex].Cells[columnIndex].Value.ToString();
// add here the required release
if (gridViewCordonelSelection.Columns[columnIndex].Name == Resources.StrTableCordonelFwToInstall)
cordSelect.RequiredReleaseNameVersion =
gridViewCordonelSelection.Rows[e.RowIndex].Cells[columnIndex].Value.ToString();
}
// select FW package with combo box
if (gridViewCordonelSelection.Columns[e.ColumnIndex].Name == Resources.StrTableCordonelFwToInstall)
{
// take the actual cell value as default
_cbxFwReleaseSelection.Text = cordSelect.RequiredReleaseNameVersion;
// Adding combo box control into DataGridView
gridViewCordonelSelection.Controls.Add(_cbxFwReleaseSelection);
// Rectangular area that represents the display area for a cell
var location = gridViewCordonelSelection.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, true);
// Setting Location and size to fit within the cell
_cbxFwReleaseSelection.Height = location.Height;
_cbxFwReleaseSelection.Width = 200;
_cbxFwReleaseSelection.Location = new Point(location.X, location.Y);
// The final selection of the fw package
_fwPackageCordonelPcbId = cordSelect.PcbId;
_cbxFwReleaseSelection.DropDownClosed += CbxFwReleaseSelection_DropDownClosed;
_cbxFwReleaseSelection.Visible = true;
}
// select Cordonel
if (gridViewCordonelSelection.Columns[e.ColumnIndex].Name == Resources.StrTableSelect)
{
// Search the cordonel in the production search list
foreach (var cordSearch in _cordonelProductionSearchInfos)
{
if (cordSearch.PcbId == cordSelect.PcbId)
{
// toggle selection and set information on main screen
if (cordSearch.IsSelected)
{
// remove cordonel from list
cordSearch.IsSelected = false;
foreach (var x in _cordonelProductionPreSelectInfos.Where(x =>
x.PcbId == cordSelect.PcbId))
{
_cordonelProductionPreSelectInfos.Remove(x);
break;
}
}
else
{
// add cordonel to list
cordSearch.IsSelected = true;
cordSearch.IsApproved = false;
cordSearch.IsRemoved = false;
if (_cordonelProductionPreSelectInfos.All(x => x.PcbId != cordSelect.PcbId))
_cordonelProductionPreSelectInfos.Add(cordSearch);
_preBuildSummaryPropertyChanged = true;
}
//search cordonel in data table for update of "select" checkbox
for (var idx = 0; idx < _dataTableCordonels.Rows.Count; idx++)
{
var dataRow = _dataTableCordonels.Rows[idx];
if (cordSearch.PcbId != (String)dataRow[Resources.StrTableCordonelPcbId]) continue;
dataRow[Resources.StrTableSelect] = cordSearch.IsSelected;
break;
}
break;
}// Cordonel found
}// Search the cordonel in the production search list
}
_cordonelsPropertyChanged = false;
// _preBuildSummaryPropertyChanged = false;
}
catch (Exception)
{
_processState = ProcessState.Error;
}
}
/// <summary>
/// Event on closing the fw package selection
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2021-Apr-10" author="Thomas Wiedebusch">
/// - Initial
/// </remarks>
/// <remarks date="2021-Apr-16" author="Thomas Wiedebusch">
/// - Pre build summary changed
/// </remarks>
/// <remarks date="2021-Apr-17" author="Thomas Wiedebusch">
/// - Production pre select infos from production search infos.
/// </remarks>
private void CbxFwReleaseSelection_DropDownClosed(Object sender, EventArgs e)
{
_cbxFwReleaseSelection.DropDownClosed -= CbxFwReleaseSelection_DropDownClosed;
if (!string.IsNullOrEmpty(_fwPackageCordonelPcbId) && _cbxFwReleaseSelection.SelectedItem != null)
{
// attach fw update package name to eventually unselected in production search list Cordonels
foreach (var cordonel in _cordonelProductionSearchInfos.Where(cordonel =>
cordonel.PcbId == _fwPackageCordonelPcbId))
{
cordonel.RequiredReleaseNameVersion = _cbxFwReleaseSelection.SelectedItem.ToString();
break;
}
// attach fw update package name in production pre selected list Cordonels
foreach (var cordonel in _cordonelProductionPreSelectInfos.Where(cordonel =>
cordonel.PcbId == _fwPackageCordonelPcbId))
{
cordonel.RequiredReleaseNameVersion = _cbxFwReleaseSelection.SelectedItem.ToString();
break;
}
// attach fw update package name in update list Cordonels
foreach (var cordonel in _cordonelUpdateList.Where(cordonel =>
cordonel.PcbId == _fwPackageCordonelPcbId))
{
cordonel.RequiredRelease = _cbxFwReleaseSelection.SelectedItem.ToString();
break;
}
}
_cbxFwReleaseSelection.Visible = false;
_cordonelsPropertyChanged = true;
_preBuildSummaryPropertyChanged = true;
}
/// <summary>
/// Build data grid for cordonels
/// </summary>
/// <remarks date="2021-Feb-24" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Apr-06" author="Thomas Wiedebusch">
/// - Order position added.
/// </remarks>
/// <remarks date="2021-Apr-07" author="Thomas Wiedebusch">
/// - New data tables, important for language change.
/// </remarks>
/// <remarks date="2021-Apr-12" author="Thomas Wiedebusch">
/// - Added region and radio frequency.
/// </remarks>
/// <remarks date="2021-Apr-15" author="Thomas Wiedebusch">
/// - Added customer serial number search.
/// </remarks>
private void FillDataGridWithCordonelInfos()
{
grpLanguageSelection.Enabled = false;
_dataTableCordonels?.Dispose();
Thread.CurrentThread.CurrentUICulture = _cultureInfo;
Thread.CurrentThread.CurrentCulture = _cultureInfo;
_dataTableCordonels = new DataTable();
_dataTableCordonels.Columns.Add(Resources.StrTableSelect, typeof(Boolean));
_dataTableCordonels.Columns.Add(Resources.StrTableCordonelCustomerSerialNumber, typeof(String));
_dataTableCordonels.Columns.Add(Resources.StrTableCordonelPcbId, typeof(String));
_dataTableCordonels.Columns.Add(Resources.StrTableCordonelFwToInstall, typeof(String));
_dataTableCordonels.Columns.Add(Resources.StrTableCordonelInstalledFw, typeof(String));
_dataTableCordonels.Columns.Add(Resources.StrTableCordonelMetrology, typeof(String));
_dataTableCordonels.Columns.Add(Resources.StrTableCordonelMetrologyIsUpdateable, typeof(Boolean));
_dataTableCordonels.Columns.Add(Resources.StrTableCordonelCore, typeof(String));
_dataTableCordonels.Columns.Add(Resources.StrTableRegion, typeof(String));
_dataTableCordonels.Columns.Add(Resources.StrTableRadioFrequency, typeof(String));
_dataTableCordonels.Columns.Add(Resources.StrTableCordonelDiameter, typeof(String));
_dataTableCordonels.Columns.Add(Resources.StrTableCordonelProductionOrder, typeof(Int64));
_dataTableCordonels.Columns.Add(Resources.StrTableCordonelProductionPos, typeof(Int64));
_dataTableCordonels.Columns.Add(Resources.StrTableCordonelSize, typeof(String));
_dataTableCordonels.Columns.Add(Resources.StrTableCordonelCatalogueNumber, typeof(String));
try
{
foreach (var cordSearch in _cordonelProductionSearchInfos)
{
// pre-selection of displayed production order
if (!cordSearch.CustomerSerialNumber.Contains(tbxCordonelProductionOrdersSearch.Text)
&& tbxCordonelProductionOrdersSearch.Text != @"*") continue;
// search if this Cordonel is already in production pre select list as this is the marker
foreach (var cordPre in _cordonelProductionPreSelectInfos.Where(x => x.PcbId == cordSearch.PcbId))
{
cordSearch.IsSelected = cordPre.IsSelected;
cordSearch.IsApproved = cordPre.IsApproved;
cordSearch.IsRemoved = cordPre.IsRemoved;
break;
}
var row = _dataTableCordonels.NewRow();
row[Resources.StrTableSelect] = cordSearch.IsSelected;
row[Resources.StrTableCordonelCustomerSerialNumber] = cordSearch.CustomerSerialNumber ?? "?";
row[Resources.StrTableCordonelPcbId] = cordSearch.PcbId ?? "?";
row[Resources.StrTableCordonelFwToInstall] = cordSearch.RequiredReleaseNameVersion ?? "?";
row[Resources.StrTableCordonelInstalledFw] = cordSearch.InstalledReleaseNameVersion ?? "?";
row[Resources.StrTableCordonelMetrology] = cordSearch.Metrology ?? "?";
row[Resources.StrTableCordonelMetrologyIsUpdateable] = cordSearch.MetrologyIsUpdateable;
row[Resources.StrTableCordonelCore] = cordSearch.CoreRevision ?? "?";
row[Resources.StrTableRegion] = cordSearch.Region ?? "?";
row[Resources.StrTableRadioFrequency] = cordSearch.RadioFrequency ?? "?";
row[Resources.StrTableCordonelDiameter] = cordSearch.Diameter ?? "?";
row[Resources.StrTableCordonelProductionOrder] = cordSearch.CustomerOrderNumber;
row[Resources.StrTableCordonelProductionPos] = cordSearch.CustomerOrderPos;
row[Resources.StrTableCordonelSize] = cordSearch.Length ?? "?";
row[Resources.StrTableCordonelCatalogueNumber] = cordSearch.CatalogNumber ?? "?";
_dataTableCordonels.Rows.Add(row);
}
gridViewCordonelSelection.DataSource = _dataTableCordonels;
foreach (DataGridViewColumn column in gridViewCordonelSelection.Columns)
{
column.SortMode = DataGridViewColumnSortMode.Automatic;
}
}
catch (Exception)
{
_processState = ProcessState.Error;
}
finally
{
grpLanguageSelection.Enabled = true;
}
}
#endregion --------------------------------------- Data Grid Cordonels ----------------------------------------
#region ------------------------------------------ Data Grid Controls Update Operators ------------------------
/// <summary>
/// Overwrite cell click, because edit of cells is denied (read only == true). This is needed for update user
/// selection. Exclusively one user can be selected.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2021-Feb-24" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Mar-10" author="Thomas Wiedebusch">
/// - Check for e.RowIndex below 0.
/// </remarks>
/// <remarks date="2021-Mar-22" author="Thomas Wiedebusch">
/// - Removed validation date for user as it should not be set by the FwUpdateBuilder operator,
/// - Avoid selection of outdated users.
/// </remarks>
/// <remarks date="2021-Mar-31" author="Thomas Wiedebusch">
/// - Embedded in try catch block,
/// - used data grid as cell reference to allow data grid sorting without refresh of data source!
/// </remarks>
/// <remarks date="2021-Apr-01" author="Thomas Wiedebusch">
/// - Idx search index started with 0 instead of 1.
/// </remarks>
/// <remarks date="2021-Apr-07" author="Thomas Wiedebusch">
/// - Check data table assignment.
/// </remarks>
/// <remarks date="2021-Apr-08" author="Thomas Wiedebusch">
/// - Removed _userInfo.
/// </remarks>
/// <remarks date="2021-Apr-10" author="Thomas Wiedebusch">
/// - Search column index starting with 0.
/// </remarks>
/// <remarks date="2021-Apr-27" author="Thomas Wiedebusch">
/// - Added _updateOperatorId needed to assign the fwUpdateSafeDb.
/// </remarks>
private void gridViewFwUpdateOperators_CellClick(Object sender, DataGridViewCellEventArgs e)
{
try
{
if (e.ColumnIndex < 0 || e.RowIndex < 0 || _dataTableUpdateOperators == null)
{
return;
}
// the e.RowIndex is referenced to the (sorted) data grid view
var updateOperatorName = "";
var validDate = "";
for (var columnIndex = 0; columnIndex < gridViewUpdateOperators.ColumnCount; columnIndex++)
{
if (gridViewUpdateOperators.Columns[columnIndex].Name == Resources.StrTableUserFullName)
updateOperatorName = gridViewUpdateOperators.Rows[e.RowIndex].Cells[columnIndex].Value.ToString();
if (gridViewUpdateOperators.Columns[columnIndex].Name == Resources.StrTableUserValidDate)
validDate = gridViewUpdateOperators.Rows[e.RowIndex].Cells[columnIndex].Value.ToString();
}
// select update operator
if (gridViewUpdateOperators.Columns[e.ColumnIndex].Name == Resources.StrTableSelect)
{
// Search the customer name in data table, select if found, set all others to false
foreach (var user in _fwUpdateDbAccess.DbFullQualifiedUpdateOperators)
{
if (user.FullName == updateOperatorName)
{
// avoid selection of outdated users
if (DateTimeOffset.Compare(DateTimeServer.GetDateTimeOffsetFromDateString(validDate),
DateTimeOffset.Now) < 1 || user.IsSelected || !user.AccountActive)
{
lblUpdateOperator.Text = "";
_updateOperatorId = 0;
user.IsSelected = false;
}
else
{
lblUpdateOperator.Text = user.FullName;
_updateOperatorId = user.Id;
user.IsSelected = true;
}
}
else user.IsSelected = false;
//search user in data table for update
for (var idx = 0; idx < _dataTableUpdateOperators.Rows.Count; idx++)
{
var dataRow = _dataTableUpdateOperators.Rows[idx];
if (user.FullName == (String)dataRow[Resources.StrTableUserFullName])
{
dataRow[Resources.StrTableSelect] = user.IsSelected;
}
}
}
}
_fwUpdateOperatorsPropertyChanged = false;
// select new validation date
//if (gridViewUsers.Columns[e.ColumnIndex].Name == Resources.StrTableUserValidDate)
//{
// // date time picker
// if (_userInfo != null)
// {
// if (_datePicker.Visible)
// {
// HideDatePicker();
// }
// // Adding DateTimePicker control into DataGridView
// gridViewUsers.Controls.Add(_datePicker);
// // Rectangular area that represents the display area for a cell
// var location = gridViewUsers.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, true);
// // Setting Location and size to fit within the cell
// _datePicker.Height = location.Height;
// _datePicker.Width = location.Width;
// _datePicker.Location = new Point(location.X, location.Y);
// // The final selection of the date
// _datePicker.CloseUp += datePickerUserValidationDate_CloseUp;
// // Now make it visible
// _datePicker.Visible = true;
// }
//}
//// select activation of account
//if (gridViewUsers.Columns[e.ColumnIndex].Name == Resources.StrTableUserActive)
//{
// // toggle selection
// dataRow[Resources.StrTableUserActive] = (Boolean)dataRow[Resources.StrTableUserActive] != true;
// if (_userInfo != null) _userInfo.AccountActive = (Boolean)dataRow[Resources.StrTableUserActive];
// _userAccountPropertyChanged = true;
//}
// color the results of the compare
UpdateUpdateOperatorsInformationStyleSet();
}
catch (Exception)
{
_processState = ProcessState.Error;
}
}
/// <summary>
/// Build data grid for all fully qualified users
/// </summary>
/// <remarks date="2021-Feb-24" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Mar-24" author="Thomas Wiedebusch">
/// - Disable language change during update.
/// </remarks>
/// <remarks date="2021-Apr-07" author="Thomas Wiedebusch">
/// - New data tables, important for language change.
/// </remarks>
/// <remarks date="2021-Apr-08" author="Thomas Wiedebusch">
/// - Added PC name.
/// </remarks>
/// <remarks date="2021-Apr-12" author="Thomas Wiedebusch">
/// - Registration and valid date to date time.
/// </remarks>
private void FillDataGridWithUpdateOperatorInfos()
{
grpLanguageSelection.Enabled = false;
_dataTableUpdateOperators?.Dispose();
Thread.CurrentThread.CurrentUICulture = _cultureInfo;
Thread.CurrentThread.CurrentCulture = _cultureInfo;
_dataTableUpdateOperators = new DataTable();
_dataTableUpdateOperators.Columns.Add(Resources.StrTableSelect, typeof(Boolean));
_dataTableUpdateOperators.Columns.Add(Resources.StrTableUserFullName, typeof(String));
_dataTableUpdateOperators.Columns.Add(Resources.StrTableUserDomain, typeof(String));
_dataTableUpdateOperators.Columns.Add(Resources.StrTableUserLogInName, typeof(String));
_dataTableUpdateOperators.Columns.Add(Resources.StrTableUserPcName, typeof(String));
_dataTableUpdateOperators.Columns.Add(Resources.StrTableUserRegDate, typeof(DateTime));
_dataTableUpdateOperators.Columns.Add(Resources.StrTableUserValidDate, typeof(DateTime));
_dataTableUpdateOperators.Columns.Add(Resources.StrTableUserActive, typeof(Boolean));
try
{
foreach (var user in _fwUpdateDbAccess.DbFullQualifiedUpdateOperators)
{
var row = _dataTableUpdateOperators.NewRow();
//application information read from configuration
row[Resources.StrTableSelect] = user.IsSelected;
row[Resources.StrTableUserFullName] = user.FullName;
row[Resources.StrTableUserDomain] = user.Domain;
row[Resources.StrTableUserLogInName] = user.LogInName;
row[Resources.StrTableUserPcName] = CryptInformation.GetPcNameFromHwId(user.HardwareId);
row[Resources.StrTableUserRegDate] = user.RegisterDate.Date;
row[Resources.StrTableUserValidDate] = user.ValidDate.Date;
row[Resources.StrTableUserActive] = user.AccountActive;
_dataTableUpdateOperators.Rows.Add(row);
}
//output data to data grid view
gridViewUpdateOperators.DataSource = _dataTableUpdateOperators.DefaultView;
foreach (DataGridViewColumn column in gridViewUpdateOperators.Columns)
{
column.SortMode = DataGridViewColumnSortMode.Automatic;
}
// color the results of the compare
UpdateUpdateOperatorsInformationStyleSet();
}
catch (Exception)
{
_processState = ProcessState.Error;
}
finally
{
grpLanguageSelection.Enabled = true;
}
}
/// <summary>
/// Color the rows depending on the state
/// </summary>
/// <remarks date="2021-Feb-26" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void UpdateUpdateOperatorsInformationStyleSet()
{
Thread.CurrentThread.CurrentUICulture = _cultureInfo;
Thread.CurrentThread.CurrentCulture = _cultureInfo;
foreach (DataGridViewRow dataGridRow in gridViewUpdateOperators.Rows)
{
if ((Boolean)dataGridRow.Cells[Resources.StrTableUserActive].Value &&
DateTimeServer.GetDateTimeOffsetFromDateString(
dataGridRow.Cells[Resources.StrTableUserValidDate].Value.ToString()) >= DateTimeOffset.Now)
{
dataGridRow.DefaultCellStyle = _styleValid;
}
else
{
dataGridRow.DefaultCellStyle = _styleInvalid;
}
}
}
/// <summary>
/// After sort event to update styles
/// </summary>
/// <remarks date="2021-Mar-31" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void gridViewUpdateOperators_Sorted(Object sender, EventArgs e)
{
UpdateUpdateOperatorsInformationStyleSet();
}
#endregion --------------------------------------- Data Grid Controls Update Operators ------------------------
#region ------------------------------------------ Data Grid Controls Customer Selection ----------------------
/// <summary>
/// Overwrite cell click, because edit of cells is denied (read only == true). This is needed for customer
/// selection. Exclusively one customer can be selected.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks date="2021-Mar-31" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Apr-01" author="Thomas Wiedebusch">
/// - Idx search index started with 0 instead of 1.
/// - Clear list of cordonels on new customer.
/// </remarks>
/// <remarks date="2021-Apr-06" author="Thomas Wiedebusch">
/// - clear production order numbers.
/// </remarks>
/// <remarks date="2021-Apr-07" author="Thomas Wiedebusch">
/// - Check data table assignment.
/// </remarks>
/// <remarks date="2021-Apr-10" author="Thomas Wiedebusch">
/// - Search column index starting with 0.
/// </remarks>
/// <remarks date="2021-Apr-17" author="Thomas Wiedebusch">
/// - Production pre select infos from production search infos.
/// </remarks>
private void gridViewCustomerSelection_CellClick(Object sender, DataGridViewCellEventArgs e)
{
try
{
if (e.ColumnIndex < 0 || e.RowIndex < 0 || _dataTableCustomers == null)
{
return;
}
// the e.RowIndex is referenced to the (sorted) data grid view
var customerNumber = 0L;
for (var columnIndex = 0; columnIndex < gridViewCustomerSelection.ColumnCount; columnIndex++)
{
if (gridViewCustomerSelection.Columns[columnIndex].Name != Resources.StrTableCustomerNumber) continue;
customerNumber = Convert.ToInt64(gridViewCustomerSelection.Rows[e.RowIndex].Cells[columnIndex].Value);
break;
}
// select customer
if (gridViewCustomerSelection.Columns[e.ColumnIndex].Name == Resources.StrTableSelect)
{
// clear all previously selected Cordonels as a new customer is selected or deselected
_dataTableCordonels?.Rows.Clear();
_dataTableCordonels?.Columns.Clear();
_fwUpdateCapability.Clear();
_cordonelUpdateList.Clear();
_cordonelProductionSearchInfos.Clear();
_cordonelProductionPreSelectInfos.Clear();
_customerNumberBeforeLastCordonelDbSearch = "";
// Search the customer name in data table, select if found, set all others to false
foreach (var customer in _fwUpdateDbAccess.DbSearchedCordonelCustomers)
{
if (customer.CustomerNumber == customerNumber)
{
// toggle selection and set information on main screen
if (customer.IsSelected)
{
tbxCustomerName.Text = "";
lblCustomerNumber.Text = "";
customer.IsSelected = false;
}
else
{
tbxCustomerName.Text = customer.CustomerName;
tbxCustomerName.Focus();
tbxCustomerName.SelectionStart = 0;
tbxCustomerName.SelectionLength = 0;
lblCustomerNumber.Text = customer.CustomerNumber.ToString();
customer.IsSelected = true;
}
}
else customer.IsSelected = false;
//search user in data table for update
for (var idx = 0; idx < _dataTableCustomers.Rows.Count; idx++)
{
var dataRow = _dataTableCustomers.Rows[idx];
if (customer.CustomerNumber == (Int64)dataRow[Resources.StrTableCustomerNumber])
{
dataRow[Resources.StrTableSelect] = customer.IsSelected;
}
}
}
}
_customersPropertyChanged = false;
}
catch (Exception)
{
_processState = ProcessState.Error;
}
}
/// <summary>
/// Build data grid for selected customers.
/// </summary>
/// <remarks date="2021-Feb-24" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Apr-07" author="Thomas Wiedebusch">
/// - New data tables, important for language change.
/// </remarks>
/// <remarks date="2021-Jun-08" author="Thomas Wiedebusch">
/// - Initially sorted by name.
/// </remarks>
private void FillDataGridWithCustomerInfos()
{
grpLanguageSelection.Enabled = false;
_dataTableCustomers?.Dispose();
Thread.CurrentThread.CurrentUICulture = _cultureInfo;
Thread.CurrentThread.CurrentCulture = _cultureInfo;
_dataTableCustomers = new DataTable();
_dataTableCustomers.Columns.Add(Resources.StrTableSelect, typeof(Boolean));
_dataTableCustomers.Columns.Add(Resources.StrTableCustomerName, typeof(String));
_dataTableCustomers.Columns.Add(Resources.StrTableCustomerNumber, typeof(Int64));
_dataTableCustomers.Columns.Add(Resources.StrTableCustomerLocation, typeof(String));
try
{
foreach (var customer in _fwUpdateDbAccess.DbSearchedCordonelCustomers)
{
var row = _dataTableCustomers.NewRow();
//application information read from configuration
row[Resources.StrTableSelect] = customer.IsSelected;
row[Resources.StrTableCustomerName] = customer.CustomerName;
row[Resources.StrTableCustomerNumber] = customer.CustomerNumber;
row[Resources.StrTableCustomerLocation] = customer.CustomerLocation;
_dataTableCustomers.Rows.Add(row);
}
//output data to data grid view
gridViewCustomerSelection.DataSource = _dataTableCustomers.DefaultView;
foreach (DataGridViewColumn column in gridViewCustomerSelection.Columns)
{
column.SortMode = DataGridViewColumnSortMode.Automatic;
}
var initialSortColumn = gridViewCustomerSelection.Columns[Resources.StrTableCustomerName];
if (initialSortColumn != null)
gridViewCustomerSelection.Sort(initialSortColumn, ListSortDirection.Ascending);
}
catch (Exception)
{
_processState = ProcessState.Error;
}
finally
{
grpLanguageSelection.Enabled = true;
}
}
#endregion --------------------------------------- Data Grid Controls Customer Selection ----------------------
#region ------------------------------------------ Load DB Contents -------------------------------------------
/// <summary>
/// Get the Cordonel customer orders from DB.
/// </summary>
/// <returns>true if successful</returns>
/// <remarks date="2021-Apr-04" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Apr-09" author="Thomas Wiedebusch">
/// - Getting orders directly from DB.
/// </remarks>
private void GetAllCordonelOrdersOfCustomerFromDb()
{
// get the customer ID
if (_fwUpdateDbAccess == null || string.IsNullOrEmpty(lblCustomerNumber.Text)) return;
if (Int64.TryParse(lblCustomerNumber.Text, out var customerId))
{
_fwUpdateDbAccess.GetAllCordonelCustomerOrdersFromDb(customerId);
}
_processState = ProcessState.Idle;
}
/// <summary>
/// Get the Cordonel serial numbers from DB.
/// </summary>
/// <remarks date="2021-Apr-04" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Apr-08" author="Thomas Wiedebusch">
/// - App versions added.
/// </remarks>
/// <remarks date="2021-Apr-09" author="Thomas Wiedebusch">
/// - Size and length applied to DN50, US2, 2" and 220 mm.
/// </remarks>
/// <remarks date="2021-Apr-15" author="Thomas Wiedebusch">
/// - Added radio frequency.
/// </remarks>
/// <remarks date="2021-Apr-17" author="Thomas Wiedebusch">
/// - Clear search info on new search.
/// </remarks>
private void GetAllCordonelSerialNumbersOfOrderFromDb()
{
// get the customer ID
if (_fwUpdateDbAccess == null || string.IsNullOrEmpty(lblCustomerNumber.Text)) return;
// remove last search infos
_cordonelProductionSearchInfos.Clear();
if (_fwUpdateDbAccess.DbCordonelCustomerOrders.Count > 0)
{
// Take the pre-processed CustomerOrderSEARCH-list deviated from CustomerOrder-list
foreach (var order in _cordonelCustomerOrdersSearch)
{
if (_fwUpdateDbAccess.GetAllCordonelSerialNumbersFromDb(order.CustomerOrderNumber,
order.CustomerOrderPos) && _fwUpdateDbAccess.DbCordonelSerialNumbers.Count > 0)
{
foreach (var cordonelSerialNumber in _fwUpdateDbAccess.DbCordonelSerialNumbers)
{
// copy all contents to the cordonel device information
var cordonel = new CordonelProductionInfosDb
{
CatalogNumber = order.CatalogNumber,
CustomerOrderNumber = order.CustomerOrderNumber,
CustomerOrderPos = order.CustomerOrderPos,
Diameter = MeterSizeConverter.ConvertOrderSizeNumberToSizeName(order.Diameter),
Length = order.Length < 150 ? $"{order.Length}\"" : $"{order.Length} mm",
PcbId = cordonelSerialNumber.PcbId.ToString(),
CustomerSerialNumber = cordonelSerialNumber.CustomerSerialNumber,
SensusSerialNumber = cordonelSerialNumber.SerialNumber.ToString()
};
// read for each Cordonel the AppListVersion
if (_fwUpdateDbAccess.DownloadCordonelAppVersionsFromDb(cordonel.PcbId, out var cordonelAppVersions))
{
foreach (var appVersion in cordonelAppVersions)
{
if (appVersion.Id == -1)
cordonel.CoreRevision = appVersion.Version;
if (appVersion.Id == -2)
cordonel.RadioFrequency = appVersion.Version;
if (appVersion.Id == 0x0F) //GENESISFLOW
{
cordonel.Metrology = appVersion.Version;
cordonel.MetrologyIsUpdateable = appVersion.IsUpdateable;
}
if (appVersion.Id == 0x18) //FLEXNETVERSION
{
// this is always a number like 1.23 or 10.2D or 60.2D, a msb higher 5 is
// indicating "B" version
var msb = appVersion.Version.Substring(0, 1);
var lsb = appVersion.Version.Substring(1, appVersion.Version.Length - 1);
if (Int16.TryParse(msb, out var msbNumber))
{
if (msbNumber >= 6)
{
msbNumber -= 5;
cordonel.InstalledReleaseNameVersion = $"B{msbNumber}{lsb}";
}
else cordonel.InstalledReleaseNameVersion = "R" + appVersion.Version;
}
}
}
}
cordonel.Region = string.IsNullOrEmpty(cordonel.RadioFrequency) ? "NA" : "EMEA";
_cordonelProductionSearchInfos.Add(cordonel);
}
}
}
}// orders from customer could be acquired
_processState = ProcessState.Idle;
}
/// <summary>
/// Get the Cordonel customers from DB.
/// </summary>
/// <remarks date="2021-Mar-31" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Ape-07" author="Thomas Wiedebusch">
/// - Search pattern added.
/// </remarks>
private void GetAllCordonelCustomersFromDb()
{
var searchPattern = tbxCustomerSearchMask.Text.Replace(" ", "");
_fwUpdateDbAccess?.GetAllCordonelCustomersFromDb(searchPattern);
_processState = ProcessState.Idle;
}
/// <summary>
/// Get Cordonel FW packages from DB end extract all needed information to select a package to the
/// CordonelFwPackageInfo search list.
/// </summary>
/// <remarks date="2021-Apr-13" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Apr-29" author="Thomas Wiedebusch">
/// - Meter FW update ruler.
/// </remarks>
/// <remarks date="2021-Oct-15" author="Thomas Wiedebusch">
/// - Configuration files loading from DB: - MeterFwUpdateRuler, configuration.json and MeterEraseRestore.
/// </remarks>
private void GetCordonelFwPackagesFromDb()
{
if (_fwUpdateDbAccess == null || !_fwUpdateDbAccess.GetAllCordonelFwInfoFilesFromDb() ||
_fwUpdateDbAccess.DbCordonelFwPackages.Count == 0 || _cordonelFwPackageInfoSearch == null)
return;
_cordonelFwPackageInfoSearch.Clear();
// The configuration files contain the latest MeterFwUpdateRuler.json (needed for the FwUpdateBuilder),
// the latest configuration.json and the latest MeterEraseRestore.json (needed for the FwUpdateSw).
// GetConfigurationFilesFromDb();
// Start with the last package, as this will be the latest
for (var idx = _fwUpdateDbAccess.DbCordonelFwPackages.Count - 1;
idx > _fwUpdateDbAccess.DbCordonelFwPackages.Count - 40; idx--)
{
// read the package without the content, skip all if fwPackageFilesInfo returns null
var dbCordonelFwFile = _fwUpdateDbAccess.DbCordonelFwPackages[idx];
var fileId = dbCordonelFwFile.FileId;
// Split to PROD_EMEA_433_DN50_R101D
var nameSplit = dbCordonelFwFile.FileName.Split('_');
if (_fwUpdateDbAccess.GetCordonelFwPackageFromDb(fileId, out var fwPackageFilesInfo, false) &&
fwPackageFilesInfo != null && fwPackageFilesInfo.Count > 0)
{
// parse file information
if (dbCordonelFwFile.CordonelFwFile_Dn != null)
{
var fwPackInfo = new CordonelFwPackageInfo
{
ReleaseNameVersion = dbCordonelFwFile.FileName,
Region = dbCordonelFwFile.FileName.Contains("EMEA") ? "EMEA" : "NA",
RadioFrequencyMhz = dbCordonelFwFile.FileName.Contains("433") ? "433" :
dbCordonelFwFile.FileName.Contains("868") ? "868" : "-",
FileIsLatest = dbCordonelFwFile.FileIsLatest,
MeterSize = MeterSizeConverter.ConvertOrderSizeNumberToSizeName(
MeterSizeConverter.ConvertToOrder((MeterSize)dbCordonelFwFile.CordonelFwFile_Dn)),
ReleaseDate = dbCordonelFwFile.FileDate,
ReleaseVersion = $"{nameSplit[nameSplit.Length - 1].Substring(0, 3)}." +
$"{nameSplit[nameSplit.Length - 1].Substring(3, 2)}"
};
// the release version is always the last element of the name split
foreach (var binfile in fwPackageFilesInfo)
{
// extract metrology version
if (binfile.FileName.Contains("binfile0F_"))
{
var msb = binfile.FileName.Substring(10, 2);
// remove leading 0
var msbMsb = msb.Substring(0, 1);
if (msbMsb == "0") msb = msb.Remove(0, 1);
var lsb = binfile.FileName.Substring(12, 2);
fwPackInfo.MetrologyVersion = $"{msb}.{lsb}";
break;
}
}
// take the meter fw update ruler to extract core min /max and released
foreach (var rule in _meterFwUpdateRuler)
{
var releaseVersion = $"{rule.Release.Substring(0, 3)}." +
$"{rule.Release.Substring(3, 2)}";
if (releaseVersion == fwPackInfo.ReleaseVersion)
{
int.TryParse(rule.CoreVersionMin, out var x);
fwPackInfo.CoreVersionMin = x;
int.TryParse(rule.CoreVersionMax, out x);
fwPackInfo.CoreVersionMax = x;
fwPackInfo.FwIsReleased = !string.IsNullOrEmpty(rule.ApproverName);
}
}
_cordonelFwPackageInfoSearch.Add(fwPackInfo);
}
}
}
}
/// <summary>
/// Get the license information from DB. In DEBUG mode the license of the software will be skipped,
/// but user license is of importance.
/// </summary>
/// <remarks date="2021-Apr-14" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void GetLicenseFromDb()
{
// FW-Update Builder validation with DB access
var access = false;
var msg = $"{Resources.StrStartMessageSwLicenseExpired}\n\n{_versionString}";
try
{
access = Xylem.Common.Logic.SoftwareAccessHelper.Access.HasAccess(_assemblyName);
}
catch (Exception)
{
LogErrorText(msg);
MessageBoxShow(msg, Resources.StrError, MessageBoxButtons.OK, MessageBoxIcon.Error);
Close();
}
if (!access)
{
LogErrorText(msg);
MessageBoxShow(msg, Resources.StrError, MessageBoxButtons.OK, MessageBoxIcon.Error);
Close();
}
_licenseUnchecked = false;
CheckUserRegistration();
}
/// <summary>
/// Upload the generated FW Update safe to DB.
/// </summary>
/// <returns>true if successful</returns>
/// <remarks date="2021-Apr-27" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private Boolean UploadFwUpdateSafeToDb()
{
var pcbIds = _cordonelUpdateList.Select(pcb => pcb.PcbId).ToList();
return _fwUpdateDbAccess != null && _fwUpdateDbAccess.UploadFwUpdateSafeToDb(_fwUpdateSafeDb, pcbIds);
}
/// <summary>
/// Get all FW update report files from DB.
/// </summary>
/// <remarks date="2021-Oct-28" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void GetReportFilesFromDb()
{
var fwUpdateReports = new List<FwUpdateReportDb>();
_fwUpdateDbAccess?.DownloadFwUpdateReportsFromDb(out fwUpdateReports);
}
/// <summary>
/// Get all active FW update safes from DB. Outdated safes cannot be accessed.
/// </summary>
/// <remarks date="2021-Oct-28" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void GetOutstandingFwUpdateSafesFromDb()
{
var fwUpdateSafes= new List<FwUpdateSafeDb>();
if (_fwUpdateDbAccess != null)
{
foreach (var user in _fwUpdateDbAccess.DbFullQualifiedUpdateOperators)
{
_fwUpdateDbAccess.ListAllFwUpdateSafesOfUserFromDb(user.Id, out var fwUpdateSafesOfUser);
fwUpdateSafes.AddRange(fwUpdateSafesOfUser);
}
}
}
/// <summary>
/// Get the full qualified user information from DB to generate the primary key for encryption.
/// </summary>
/// <remarks date="2021-Feb-04" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Feb-11" author="Thomas Wiedebusch">
/// - DB access.
/// </remarks>
/// <remarks date="2021-Feb-25" author="Thomas Wiedebusch">
/// - Call of get all users from DB.
/// </remarks>
/// <remarks date="2021-Mar-22" author="Thomas Wiedebusch">
/// - Removed DB status.
/// </remarks>
private void GetAllUpdateOperatorsFromDb()
{
_fwUpdateDbAccess?.GetAllUpdateOperatorsFromDb();
}
/// <summary>
/// Get the user information from DB to generate the primary key for encryption.
/// For this operation only fully qualified users can be used as the primary key needs as input the
/// HW Id, the domain, the LogInName and the users password hash.
/// The user registration has to be done in advance in the FW-Update Loader!
/// </summary>
/// <remarks date="2021-Feb-04" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Feb-11" author="Thomas Wiedebusch">
/// - Get fully qualified user information from DB searched by the users FullName.
/// </remarks>
/// <remarks date="2021-Apr-08" author="Thomas Wiedebusch">
/// - Replaced userInfo by name of update operator.
/// </remarks>
private void BuildPrimaryKey(String updateOperator)
{
if (_fwUpdateDbAccess == null ||
!_fwUpdateDbAccess.GetFullQualifiedUserByFullName(updateOperator, out var userInfo))
{
return;
}
_primaryKey = FwUpdateCrypt.BuildPrimaryKey(userInfo.HardwareId, userInfo.Domain,
userInfo.LogInName, userInfo.PasswordHash);
}
/// <summary>
/// Collect order number, radio address, skeleton key, password hashes and passwords from DB.
/// </summary>
/// <param name="cordonel"></param>
/// <returns>password container</returns>
/// <remarks date="2021-Feb-01" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Feb-02" author="Thomas Wiedebusch">
/// - Returns bool.
/// </remarks>
/// <remarks date="2021-Feb-03" author="Thomas Wiedebusch">
/// - Check content of password container.
/// </remarks>
/// <remarks date="2021-Feb-04" author="Thomas Wiedebusch">
/// - Using software access helper class.
/// </remarks>
/// <remarks date="2021-Feb-15" author="Thomas Wiedebusch">
/// - Exported base function to FwUpdateDb.
/// </remarks>
/// <remarks date="2021-Mar-25" author="Thomas Wiedebusch">
/// - Retries on missing DB connection or reading of file failed.
/// </remarks>
/// <remarks date="2021-Apr-01" author="Thomas Wiedebusch">
/// - Password container directly assigned.
/// </remarks>
private Boolean GetPwdFromDb(CordonelDeviceInfo cordonel)
{
var reties = 2;
do
{
if (_fwUpdateDbAccess == null ||
!_fwUpdateDbAccess.DownloadCordonelPwdFromDb(cordonel.PcbId, out cordonel.PwdContainer))
continue;
LogSuccessText(Resources.StrCordonelPwdAdded + " " + cordonel.PcbId + " " + cordonel.CustomerSerialNumber);
return true;
} while (reties-- > 0);
var msg = Resources.StrCordonelPwdMissing + " " + cordonel.PcbId + " " + cordonel.CustomerSerialNumber;
LogErrorText(msg);
MessageBoxShow(msg, Resources.StrError, MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
/// <summary>
/// Get Cordonel Fa update configuration files from DB.
/// The configuration files contain the latest MeterFwUpdateRuler.json (needed for the FwUpdateBuilder),
/// the latest configuration.json and the latest MeterEraseRestore.json (needed for the FwUpdateSw).
/// Copies the MeterFwUpdateRuler.json to the [exe-root] or [exe-root]/Library of the FwUpdateBuilder.
/// </summary>
/// <remarks date="2021-Oct-27" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private void GetFwUpdateConfigFilesFromDb()
{
if (_fwUpdateDbAccess == null ||
!_fwUpdateDbAccess.DownloadFwUpdateConfigurationFilesFromDb() ||
_fwUpdateDbAccess.DbFwUpdateConfigFiles.Count == 0)
return;
try
{
// extract the MeterFwUpdateRuler
foreach (var f in _fwUpdateDbAccess.DbFwUpdateConfigFiles)
{
if (f.FileName == FwUpdateConfig.MeterFwUpdateRulerConfigFileName)
{
// Copy MeterFwUpdateRuler either to exe-path or if existing to Library-subfolder
var fwUpdateBuilderExePath = AppDomain.CurrentDomain.BaseDirectory;
var fwUpdateBuilderLibraryPath = Path.Combine(fwUpdateBuilderExePath,
FwUpdateConfig.LibrarySubFolderName);
// check the Library path existence (will be used in Release build)
var meterFwUpdateRulerPath = Directory.Exists(fwUpdateBuilderLibraryPath) ?
fwUpdateBuilderLibraryPath : fwUpdateBuilderExePath;
var sourceFile = Path.Combine(meterFwUpdateRulerPath, f.FileName);
var fs = File.Open(sourceFile, FileMode.Create);
fs.Write(f.FileContent, 0, f.FileContent.Length);
fs.Close();
}
}
}
catch (Exception)
{
// nothing to do
}
}
/// <summary>
/// Get Cordonel SW and configuration files from DB.
/// The software is a container of dll files, language packages and logging setups.
/// The configuration files contain the latest MeterFwUpdateRuler.json (needed for the FwUpdateBuilder),
/// the latest configuration.json and the latest MeterEraseRestore.json (needed for the FwUpdateSw).
/// Creates License, FileCrc, FileLength and SubDiractories.
/// </summary>
/// <param name="fwUpdateSwLicense">license information of valid software</param>
/// <returns>true if successful</returns>
/// <remarks date="2021-Oct-27" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
private Boolean BuildFwUpdateSwContainerFromDb(SoftwareLicense fwUpdateSwLicense)
{
if (_fwUpdateDbAccess?.DbFwUpdateConfigFiles == null ||
!_fwUpdateDbAccess.DownloadFwUpdateSwContainerFromDb() ||
_fwUpdateDbAccess.DbFwUpdateSwPackage.Count == 0 ||
_fwUpdateDbAccess.DbFwUpdateConfigFiles.Count == 0)
return false;
_fwUpdateSwContainer = new SoftwareContainer
{
Major = fwUpdateSwLicense.Major,
Minor = fwUpdateSwLicense.Minor,
Build = fwUpdateSwLicense.Build,
Program = fwUpdateSwLicense.Program,
SoftwareDynLinkLibs = new List<FilePart>(),
RegisterDefinitionFile = new FilePart(),
SoftwareSetupFile = new FilePart(),
MeterFilesEraseRestore = new FilePart()
};
foreach (var f in _fwUpdateDbAccess.DbFwUpdateConfigFiles)
{
// load the register definition
if (f.FileName == ProgramConfig.RegisterDefinitionFileName)
{
f.FileContentLength = f.FileContent.Length;
f.FileContentCrc16CcittMsb = Crc16Ccitt.CalculateMsb1021(f.FileContent);
_fwUpdateSwContainer.RegisterDefinitionFile = f;
}
// load the meter files to erase and restore
if (f.FileName == FwUpdateConfig.MeterFilesEraseRestoreConfigFileName)
{
f.FileContentLength = f.FileContent.Length;
f.FileContentCrc16CcittMsb = Crc16Ccitt.CalculateMsb1021(f.FileContent);
_fwUpdateSwContainer.MeterFilesEraseRestore = f;
}
}
foreach (var f in _fwUpdateDbAccess.DbFwUpdateSwPackage)
{
// load the logging configuration
if (f.FileName == ProgramConfig.NlogConfig)
{
f.FileContentLength = f.FileContent.Length;
f.FileContentCrc16CcittMsb = Crc16Ccitt.CalculateMsb1021(f.FileContent);
_fwUpdateSwContainer.SoftwareSetupFile = f;
}
// load the DLLs
if (f.FileName.EndsWith(".dll"))
{
// extract sub-directory from file name in DB for sub-directory creation in FwUpdateLoader
// supports only depth of one level
if (f.FileName.Contains("\\"))
{
var fileName = f.FileName.Split('\\');
var subDirectory = fileName[0];
f.FileName = fileName[fileName.Length - 1];
f.SubDirectory = subDirectory;
}
f.FileContentLength = f.FileContent.Length;
f.FileContentCrc16CcittMsb = Crc16Ccitt.CalculateMsb1021(f.FileContent);
_fwUpdateSwContainer.SoftwareDynLinkLibs.Add(f);
}
}
return true;
}
/// <summary>
/// Build the FW-Update SW container
/// </summary>
/// <returns>true if successful</returns>
/// <remarks date="2021-Mar-22" author="Thomas Wiedebusch">
/// - Init.
/// </remarks>
/// <remarks date="2021-Apr-01" author="Thomas Wiedebusch">
/// - User license builder.
/// </remarks>
/// <remarks date="2021-Apr-02" author="Thomas Wiedebusch">
/// - Changed return signature.
/// </remarks>
/// <remarks date="2021-Apr-29" author="Thomas Wiedebusch">
/// - Take license from DB.
/// </remarks>
// ReSharper disable once UnusedMember.Local
private Boolean BuildFwUpdateSwContainer(SoftwareLicense fwUpdateSwLicense)
{
_fwUpdateSwContainer = new SoftwareContainer
{
Major = fwUpdateSwLicense.Major,
Minor = fwUpdateSwLicense.Minor,
Build = fwUpdateSwLicense.Build,
Program = fwUpdateSwLicense.Program,
SoftwareDynLinkLibs = new List<FilePart>(),
RegisterDefinitionFile = new FilePart(),
SoftwareSetupFile = new FilePart(),
MeterFilesEraseRestore = new FilePart()
};
try
{
// for debug purposes the locally stored files from download folder are taken
// copy all elements of software release in the main directory
var fileList = new List<String>();
if (SystemControl.GetFilesOfDirectoryAndSubDirectory(FwUpdateSwSourcePath, fileList)) return false;
foreach (var f in fileList)
{
// extract the file name
var fileName = Path.GetFileName(f);
var subDirectory =
Path.GetFullPath(f).Replace(FwUpdateSwSourcePath, "").Replace("\\", "").Replace(fileName, "");
// load the register definition
if (fileName == ProgramConfig.RegisterDefinitionFileName)
{
_fwUpdateSwContainer.RegisterDefinitionFile.FileName = fileName;
var file = new List<Byte>(File.ReadAllBytes(f));
_fwUpdateSwContainer.RegisterDefinitionFile.FileContent = new Byte[file.Count];
_fwUpdateSwContainer.RegisterDefinitionFile.FileContent = file.ToArray();
_fwUpdateSwContainer.RegisterDefinitionFile.FileContentLength = file.Count;
_fwUpdateSwContainer.RegisterDefinitionFile.SubDirectory = subDirectory;
_fwUpdateSwContainer.RegisterDefinitionFile.FileContentCrc16CcittMsb =
Crc16Ccitt.CalculateMsb1021(_fwUpdateSwContainer.RegisterDefinitionFile.FileContent);
}
// load the logging configuration
if (fileName == ProgramConfig.NlogConfig)
{
_fwUpdateSwContainer.SoftwareSetupFile.FileName = fileName;
var file = new List<Byte>(File.ReadAllBytes(f));
_fwUpdateSwContainer.SoftwareSetupFile.FileContent = new Byte[file.Count];
_fwUpdateSwContainer.SoftwareSetupFile.FileContent = file.ToArray();
_fwUpdateSwContainer.SoftwareSetupFile.FileContentLength = file.Count;
_fwUpdateSwContainer.SoftwareSetupFile.SubDirectory = subDirectory;
_fwUpdateSwContainer.SoftwareSetupFile.FileContentCrc16CcittMsb =
Crc16Ccitt.CalculateMsb1021(_fwUpdateSwContainer.SoftwareSetupFile.FileContent);
}
// load the meter files to erase and restore
if (fileName == FwUpdateConfig.MeterFilesEraseRestoreConfigFileName)
{
_fwUpdateSwContainer.MeterFilesEraseRestore.FileName = fileName;
var file = new List<Byte>(File.ReadAllBytes(f));
_fwUpdateSwContainer.MeterFilesEraseRestore.FileContent = new Byte[file.Count];
_fwUpdateSwContainer.MeterFilesEraseRestore.FileContent = file.ToArray();
_fwUpdateSwContainer.MeterFilesEraseRestore.FileContentLength = file.Count;
_fwUpdateSwContainer.MeterFilesEraseRestore.SubDirectory = subDirectory;
_fwUpdateSwContainer.MeterFilesEraseRestore.FileContentCrc16CcittMsb =
Crc16Ccitt.CalculateMsb1021(_fwUpdateSwContainer.MeterFilesEraseRestore.FileContent);
}
// load the DLLs
if (f.EndsWith(".dll"))
{
var filePart = new FilePart { FileName = fileName };
var file = new List<Byte>(File.ReadAllBytes(f));
filePart.FileContent = new Byte[file.Count];
filePart.FileContent = file.ToArray();
filePart.FileContentLength = file.Count;
filePart.SubDirectory = subDirectory;
filePart.FileContentCrc16CcittMsb = Crc16Ccitt.CalculateMsb1021(filePart.FileContent);
_fwUpdateSwContainer.SoftwareDynLinkLibs.Add(filePart);
}
}
}
catch (Exception)
{
_processState = ProcessState.Error;
return false;
}
return true;
}
/// <summary>
/// Build the license information for any FW.
/// </summary>
/// <param name="license"></param>
/// <param name="swName"></param>
/// <param name="version"></param>
/// <remarks date="2021-Feb-25" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Mar-22" author="Thomas Wiedebusch">
/// - Software license element naming adapted to DB content.
/// </remarks>
/// <remarks date="2021-Apr-01" author="Thomas Wiedebusch">
/// - Software license flexible for different software.
/// </remarks>
private void BuildSwLicense(String swName, out SoftwareLicense license, Version version = null)
{
// If version is not set, get the actual of this compilation
if (version == null) version = Assembly.GetExecutingAssembly().GetName().Version;
license = new SoftwareLicense
{
Major = version.Major,
Minor = version.Minor,
Build = version.Build,
ValidTo = DateTimeServer.GetDateTimeFromDateString(lblFwUpdateDutyDate.Text + " 23:59:59", _cultureInfo),
Program = swName,
Description = "valid",
ProgramNameIsUnique = true
};
}
/// <summary>
/// Set the FW-Update SW license information to DB
/// </summary>
/// <param name="license"></param>
/// <remarks date="2021-Mar-22" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Apr-01" author="Thomas Wiedebusch">
/// - Modified for flexible licenses.
/// </remarks>
private void SetFwUpdateSwLicenseToDb(SoftwareLicense license)
{
if (_fwUpdateDbAccess != null && _fwUpdateDbAccess.SetSwLicenseToDb(license))
{
LogSuccessText($"{Resources.StrSwLicenseSetSuccessfully} {license.Program} " +
$"{license.Major}.{license.Minor}.{license.Build}");
return;
}
if (_fwUpdateDbAccess != null && !_fwUpdateDbAccess.DbIsConnected)
{
LogErrorText(Resources.StrNotConnectedToDb);
MessageBoxShow(Resources.StrNotConnectedToDb, Resources.StrError, MessageBoxButtons.OK,
MessageBoxIcon.Error);
lblStatusDbConnect.Text = Resources.StrNotConnectedToDb;
lblStatusDbConnect.ForeColor = ColorProcessFailed;
}
else
{
LogErrorText(Resources.StrSwLicenseSetFailed);
MessageBoxShow(Resources.StrSwLicenseSetFailed, Resources.StrError, MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
/// <summary>
/// Get the FW-Update SW license information to DB
/// </summary>
/// <param name="programName"></param>
/// <param name="license"></param>
/// <remarks date="2021-Jan-28" author="Thomas Wiedebusch">
/// - Initial with simulated data.
/// </remarks>
/// <remarks date="2021-Apr-01" author="Thomas Wiedebusch">
/// - Modified for flexible licenses.
/// </remarks>
/// <remarks date="2021-Apr-07" author="Thomas Wiedebusch">
/// - License assigned in DB access.
/// </remarks>
/// <remarks date="2021-Apr-15" author="Thomas Wiedebusch">
/// - Messages removed.
/// </remarks>
private void GetFwUpdateSwLicenseFromDb(String programName, out SoftwareLicense license)
{
if (_fwUpdateDbAccess != null &&
_fwUpdateDbAccess.GetSwLicenseFromDb(programName, out license))
return;
license = null;
}
/// <summary>
/// Load a single firmware package from DB.
/// </summary>
/// <param name="releaseName">each Cordonel tells wich release to load</param>
/// <returns>true if succeeded</returns>
/// <remarks date="2021-Apr-09" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
/// <remarks date="2021-Apr-10" author="Thomas Wiedebusch">
/// - Removed configuration.json from FW package as this is part of the SW package.
/// </remarks>
private Boolean GetFwPackageFromDb(String releaseName)
{
// if this packages has already been loaded, exit immediately
if (_fwUpdatePackages.Any(package => package.ReleaseNameVersion == releaseName &&
package.BinaryApplicationFiles != null &&
package.BinaryApplicationFiles.Count > 0))
{
return true;
}
String msg;
// search file id in ClusteredFiles but as the name in unambiguous and files are stored several times
// with this file name, the last and therefor latest item has to be taken
if (_fwUpdateDbAccess?.DbCordonelFwPackages != null)
{
var fileId = (from cu in _fwUpdateDbAccess.DbCordonelFwPackages
where cu.FileName == releaseName
select cu.FileId).LastOrDefault();
if (_fwUpdateDbAccess.GetCordonelFwPackageFromDb(fileId, out var fwPackage))
{
try
{
// search the cordonel firmware
foreach (var fw in _fwUpdatePackages.Where(fw => fw.ReleaseNameVersion == releaseName))
{
fw.PackageDescriptionFile = new FilePart();
fw.BinaryApplicationFiles = new List<FilePart>();
foreach (var f in fwPackage)
{
// load the ADF
if (f.FileName.Contains("product") && f.FileName.EndsWith(".txt"))
{
fw.PackageDescriptionFile.FileName = f.FileName;
fw.PackageDescriptionFile.FileContent = new Byte[f.FileContent.Length];
fw.PackageDescriptionFile.FileContent = f.FileContent.ToArray();
}
// load the binaries
if (f.FileName.Contains("binfile") && f.FileName.EndsWith(".bin"))
{
var filePart = new FilePart
{
FileName = f.FileName,
FileContent = new Byte[f.FileContent.Length]
};
filePart.FileContent = f.FileContent.ToArray();
fw.BinaryApplicationFiles.Add(filePart);
}
}
LogSuccessText(Resources.StrFwPackageLoadSuccess + " " + releaseName);
return true;
}
}
catch (Exception e)
{
msg = Resources.StrFwPackageLoadFailed + @" " + releaseName;
LogErrorText(msg);
MessageBoxShow(msg, Resources.StrError, MessageBoxButtons.OK, MessageBoxIcon.Error);
MessageBoxShow(e.ToString(), Resources.StrError, MessageBoxButtons.OK,
MessageBoxIcon.Error);
_processState = ProcessState.Error;
return false;
}
}
}
msg = Resources.StrFwPackageLoadFailed + @" " + releaseName;
LogErrorText(msg);
MessageBoxShow(msg, Resources.StrError, MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
#endregion --------------------------------------- Load DB Contents -------------------------------------------
#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 required.
/// </remarks>
/// <remarks date="2021-Apr-06" author="Thomas Wiedebusch">
/// - Backup duty date for FW-Update during language change.
/// </remarks>
private void RadioBtnEnglishLanguage_Click(Object sender, EventArgs e)
{
if (Thread.CurrentThread.CurrentCulture.Name == "en-GB")
{
return;
}
_cultureInfo = new CultureInfo("en-GB");
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-06" author="Thomas Wiedebusch">
/// - Backup duty date for FW-Update during language change.
/// </remarks>
private void RadioBtnGermanLanguage_Click(Object sender, EventArgs e)
{
if (Thread.CurrentThread.CurrentCulture.Name == "de-DE")
{
return;
}
_cultureInfo = new CultureInfo("de-DE");
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-Mar-02" author="Thomas Wiedebusch">
/// - Update selected table headers of tab control.
/// </remarks>
/// <remarks date="2021-Apr-06" author="Thomas Wiedebusch">
/// - Restore duty date for FW-Update after language change.
/// </remarks>
private void ChangeLanguageControls()
{
Thread.CurrentThread.CurrentUICulture = _cultureInfo;
Thread.CurrentThread.CurrentCulture = _cultureInfo;
var resources = new ComponentResourceManager(typeof(FrmFwUpdateBuilder));
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 = ColorProcessFailed;
}
else
{
lblStatusDbConnect.Text = Resources.StrConnectedToDb;
lblStatusDbConnect.ForeColor = ColorSuccess;
}
lblFwUpdateInfo.Text = $@"Version: {_version.Major}.{_version.Minor}.{_version.Build}";
_fwUpdateOperatorsPropertyChanged = true;
_customersPropertyChanged = true;
_cordonelsPropertyChanged = true;
_fwPackagePropertyChanged = true;
_fwReportFilesPropertyChanged = true;
_fwUpdateSafesPropertyChanged = true;
_preBuildSummaryPropertyChanged = true;
lblFwUpdateDutyDate.Text = _datePicker.Value.ToShortDateString();
}
#endregion --------------------------------------- Language ---------------------------------------------------
}
}