init
This commit is contained in:
@@ -0,0 +1,410 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using DTS.Common.Interface.DASFactory;
|
||||
using DTS.Common.Interface.DASFactory.Download;
|
||||
using DTS.Common.Interface.StatusAndProgressBar;
|
||||
using DTS.Common.Utilities.Logging;
|
||||
|
||||
namespace DTS.DASLib.Service.StateMachine
|
||||
{
|
||||
public class DownloadStatusInformation : IStatusInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// all possible status that can be relayed to consumers
|
||||
/// </summary>
|
||||
public enum StatusValues
|
||||
{
|
||||
Preparing,
|
||||
Downloading,
|
||||
CaptureAttributes,
|
||||
Failed,
|
||||
ROIFailed,
|
||||
Completed,
|
||||
Cancelling,
|
||||
Cancelled,
|
||||
CancelledPartial,
|
||||
DownloadDirectory,
|
||||
MissingHardware,
|
||||
NoDataToDownload,
|
||||
NotAllChannelsDownloaded,
|
||||
ExistingFiles,
|
||||
CleaningUp,
|
||||
QueryEventData
|
||||
}
|
||||
/// <summary>
|
||||
/// signals cancel was requested
|
||||
/// </summary>
|
||||
public ManualResetEvent CancelEvent = new ManualResetEvent(false);
|
||||
/// <summary>
|
||||
/// signals when ping and connect is finished
|
||||
/// </summary>
|
||||
public ManualResetEvent DoneEvent = new ManualResetEvent(false);
|
||||
/// <summary>
|
||||
/// action to take on completion of ping and connect
|
||||
/// </summary>
|
||||
public ActionCompleteDelegate CompleteAction { get; set; }
|
||||
/// <summary>
|
||||
/// action to take on progress notification
|
||||
/// </summary>
|
||||
public SetProgressValueDelegate ProgressAction { get; set; }
|
||||
/// <summary>
|
||||
/// action to take on a status notification
|
||||
/// </summary>
|
||||
public StatusIntDelegate StatusAction { get; set; }
|
||||
/// <summary>
|
||||
/// action to take on extended status notification
|
||||
/// </summary>
|
||||
public StatusExIntDelegate StatusExAction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// if we were told of DAS to download from,
|
||||
/// this will be true if all the das were downloaded
|
||||
/// </summary>
|
||||
public bool AllDASFinished { get; set; } = false;
|
||||
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
AllDASFinished = false;
|
||||
CompleteAction = null;
|
||||
StatusAction = null;
|
||||
StatusExAction = null;
|
||||
ProgressAction = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// starts Downloading, returns immediately
|
||||
/// </summary>
|
||||
public void Download()
|
||||
{
|
||||
_DownloadTask = Task.Run(() =>
|
||||
{
|
||||
AllDASFinished = false;
|
||||
var param = States.Instance.DownloadStart.Status.DownloadParams;
|
||||
var global = States.Instance.DownloadStart.Status.GlobalStatusParameters;
|
||||
var dasFactory = States.Instance.DownloadStart.DASFactory;
|
||||
var errorCallback = param.ErrorCallback;
|
||||
|
||||
//get a list of all the das to download from
|
||||
var dasList = param.DASList.ToList();
|
||||
|
||||
|
||||
StatusAction?.Invoke((int)StatusValues.Preparing);
|
||||
|
||||
//check if we are supposed to download from a unit, but it's not available
|
||||
var activeDASList = dasFactory.GetDASList();
|
||||
if (dasList.Exists(das => !activeDASList.Contains(das)))
|
||||
{
|
||||
var missingList = dasList.Where(das => !activeDASList.Contains(das)).ToList();
|
||||
var dr = errorCallback?.Invoke(StatusValues.MissingHardware.ToString(), string.Join(Environment.NewLine, missingList.Select(das => das.SerialNumber).ToList()));
|
||||
if (DialogResult.OK != dr)
|
||||
{
|
||||
StatusAction?.Invoke((int)StatusValues.Failed);
|
||||
}
|
||||
}
|
||||
|
||||
//check if we have any das left to download from
|
||||
if (!dasList.Any())
|
||||
{
|
||||
StatusAction?.Invoke((int)StatusValues.Failed);
|
||||
}
|
||||
|
||||
//check that all units have config data
|
||||
if (dasList.Exists(das => das.ConfigData == null))
|
||||
{
|
||||
//throw error. by state machine definition we should have gone through Config first
|
||||
StatusExAction?.Invoke((int)StatusValues.NoDataToDownload, dasList.Where(das => das.ConfigData == null).ToArray());
|
||||
}
|
||||
|
||||
//we have das, they have config data. get the event
|
||||
var oneEvent = GetOneEvent(dasList);
|
||||
if (null == oneEvent)
|
||||
{
|
||||
StatusAction?.Invoke((int)StatusValues.Failed);
|
||||
}
|
||||
|
||||
//create folder environment
|
||||
var eventId = oneEvent.EventId;
|
||||
|
||||
|
||||
var currentTestTestId = param.CurrentTestTestId;
|
||||
var currentTestTestIdNode = param.CurrentTestTestIdNode;
|
||||
var currentTestTestDirectory = param.CurrentTestTestDirectory;
|
||||
var currentTestOriginalTestDirectory = param.CurrentTestOriginalTestDirectory;
|
||||
var defaultDownloadFolder = param.DefaultDownloadFolder;
|
||||
var DownloadFolder = Path.Combine(Environment.CurrentDirectory, defaultDownloadFolder);
|
||||
var ROI = param.ROI;
|
||||
var recovery = param.Recovery;
|
||||
var foldersCopied = param.FoldersCopied;
|
||||
|
||||
var directory = Path.Combine(DownloadFolder, eventId, currentTestTestId, "Binary");
|
||||
if (!Directory.Exists(directory))
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
StatusAction?.Invoke((int)StatusValues.Failed);
|
||||
}
|
||||
}
|
||||
|
||||
StatusAction?.Invoke((int)StatusValues.DownloadDirectory);
|
||||
var DownloadDirectory = Path.Combine(directory, ROI ? "ROI" : "ALL");
|
||||
var TestItem = $"{defaultDownloadFolder}\\{eventId}\\{currentTestTestId}\\Binary\\{(ROI ? "ROI" : "ALL")}"; //optimize this
|
||||
|
||||
if (recovery && Directory.Exists(directory))
|
||||
{
|
||||
if (currentTestTestId != currentTestTestIdNode)
|
||||
{
|
||||
//We want to keep ROI and ALL "recovery" downloads in the same path, so use the same "Test Id" node in the path
|
||||
//Since the .../Binary folder exists, we know that this test has downloaded before, so create a recovery folder
|
||||
DownloadDirectory = Path.Combine(DownloadFolder, eventId, currentTestTestIdNode, "Binary", ROI ? "ROI" : "ALL");
|
||||
}
|
||||
|
||||
if ((currentTestTestId != currentTestTestIdNode || currentTestTestDirectory != currentTestOriginalTestDirectory) &&
|
||||
!foldersCopied)
|
||||
{
|
||||
//Either this is a "recovery" folder or the Test Id field was changed in Basic info.
|
||||
//Either way, the following files need to be copied from the original folder
|
||||
var copied = false;
|
||||
var originalTestIdNode = Path.GetFileName(currentTestOriginalTestDirectory);
|
||||
|
||||
var sourceDir = Path.Combine(DownloadFolder, eventId, originalTestIdNode, Common.Constants.DAS_CONFIGS);
|
||||
var destDir = Path.Combine(DownloadFolder, eventId, currentTestTestIdNode, Common.Constants.DAS_CONFIGS);
|
||||
DirectoryCopy(sourceDir, destDir, true, param, ref copied, false);
|
||||
|
||||
sourceDir = Path.Combine(DownloadFolder, eventId, originalTestIdNode, "Logs");
|
||||
destDir = Path.Combine(DownloadFolder, eventId, currentTestTestIdNode, "Logs");
|
||||
DirectoryCopy(sourceDir, destDir, true, param, ref copied, false);
|
||||
|
||||
sourceDir = Path.Combine(DownloadFolder, eventId, originalTestIdNode, Common.Constants.REPORT_DIR_NAME);
|
||||
destDir = Path.Combine(DownloadFolder, eventId, currentTestTestIdNode, Common.Constants.REPORT_DIR_NAME);
|
||||
DirectoryCopy(sourceDir, destDir, true, param, ref copied, false);
|
||||
|
||||
sourceDir = Path.Combine(DownloadFolder, eventId, originalTestIdNode, "SETUP");
|
||||
destDir = Path.Combine(DownloadFolder, eventId, currentTestTestIdNode, "SETUP");
|
||||
DirectoryCopy(sourceDir, destDir, true, param, ref copied, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var mre = new ManualResetEvent(false);
|
||||
mre.WaitOne();
|
||||
|
||||
if (!CancelEvent.WaitOne(1, false))
|
||||
{
|
||||
//check that all the units that should have been configured were
|
||||
var allDownloaded = Array.TrueForAll(param.DASList, d => dasList.Contains(d));
|
||||
AllDASFinished = allDownloaded;
|
||||
|
||||
CompleteAction?.Invoke();
|
||||
}
|
||||
|
||||
StatusAction?.Invoke((int)StatusValues.Completed);
|
||||
DoneEvent.Set();
|
||||
});
|
||||
}
|
||||
|
||||
private Task _DownloadTask = null;
|
||||
public async Task Cancel()
|
||||
{
|
||||
CancelEvent.Set();
|
||||
StatusAction?.Invoke((int)StatusValues.Cancelling);
|
||||
//simulate time spent waiting for cancel to be acknowledged
|
||||
Thread.Sleep(100);
|
||||
DoneEvent.WaitOne();
|
||||
StatusAction?.Invoke((int)StatusValues.Cancelled);
|
||||
}
|
||||
|
||||
#region helpers
|
||||
private static string GetHash(DownloadReport.EventInfo myEvent)
|
||||
{
|
||||
return $"{myEvent.TestID}_{myEvent.EventNumber:00}".ToUpper();
|
||||
}
|
||||
private IEventInfoAggregate GetOneEvent(List<IDASCommunication> dasList)
|
||||
{
|
||||
var eventInfo = new DownloadReport.EventInfo();
|
||||
var eventIds = new List<string>();
|
||||
var events = new Dictionary<string, IEventInfoAggregate>();
|
||||
foreach (var das in dasList)
|
||||
{
|
||||
if (null == das.EventInfo || !das.EventInfo.Events.Any()) { continue; }
|
||||
eventInfo = (DownloadReport.EventInfo)das.EventInfo.Events[0];
|
||||
var key = GetHash(eventInfo);
|
||||
if (!eventIds.Contains(key))
|
||||
{
|
||||
eventIds.Add(key);
|
||||
//TODO: Add Events, etc to
|
||||
//events.Add(key, new IEventInfoAggregate(eventInfo));
|
||||
}
|
||||
else
|
||||
{
|
||||
events[key].Add(eventInfo);
|
||||
}
|
||||
}
|
||||
IEventInfoAggregate oneEvent = null;
|
||||
if (events.Count > 0)
|
||||
{
|
||||
oneEvent = events[GetHash(eventInfo)];
|
||||
}
|
||||
return oneEvent;
|
||||
}
|
||||
/// <summary>
|
||||
/// we don't use move as we don't want to necessarily disturb directories already in the target location, and any files that are already there
|
||||
/// [but we will overwrite if a source file exists in the destination]
|
||||
/// </summary>
|
||||
/// <param name="sourceDirName"></param>
|
||||
/// <param name="destDirName"></param>
|
||||
/// <param name="copySubDirs"></param>
|
||||
/// <param name="param"></param>
|
||||
/// /// <param name="copied"></param>
|
||||
/// /// <param name="uploadingData"></param>
|
||||
public bool DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs, DownloadParameters param, ref bool copied, bool uploadingData)
|
||||
{
|
||||
try
|
||||
{
|
||||
var fileLocations = new List<string>();
|
||||
var destFileLocations = new List<string>();
|
||||
|
||||
var dirs = new List<string>();
|
||||
dirs.Add(sourceDirName);
|
||||
while (dirs.Count > 0)
|
||||
{
|
||||
var currentDir = dirs[0];
|
||||
dirs.RemoveAt(0);
|
||||
|
||||
var dir = new System.IO.DirectoryInfo(currentDir);
|
||||
if (!dir.Exists) { continue; }
|
||||
var files = dir.GetFiles();
|
||||
fileLocations.AddRange(files.Select(file => file.FullName));
|
||||
|
||||
var subDirs = dir.GetDirectories();
|
||||
dirs.AddRange(subDirs.Select(thisdir => thisdir.FullName));
|
||||
}
|
||||
|
||||
//uri requires folders end with \\
|
||||
if (!sourceDirName.EndsWith("\\")) { sourceDirName += "\\"; }
|
||||
var diSourceDir = new System.IO.DirectoryInfo(sourceDirName);
|
||||
if (!destDirName.EndsWith("\\")) { destDirName += "\\"; }
|
||||
|
||||
var curFileUndex = 1;
|
||||
var existingFiles = new List<string>();
|
||||
|
||||
for (var i = fileLocations.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var curFile = fileLocations[i];
|
||||
if (uploadingData)
|
||||
{
|
||||
var tokens = curFile.Split('\\');
|
||||
if (tokens.Contains("Binary"))
|
||||
{
|
||||
if (!param.DefaultUploadBinaries)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (tokens.Contains("DASConfigs"))
|
||||
{
|
||||
if (!param.DefaultUploadSetups)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (tokens.Contains("SETUP"))
|
||||
{
|
||||
if (!param.DefaultUploadSetups)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (tokens.Contains("Reports"))
|
||||
{
|
||||
if (!param.DefaultUploadReports)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (tokens.Contains("Logs"))
|
||||
{
|
||||
if (!param.DefaultUploadLogs)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (tokens.Contains("Exports"))
|
||||
{
|
||||
if (!param.DefaultUploadExports)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
var fiCurFile = new System.IO.FileInfo(curFile);
|
||||
|
||||
var path1 = new Uri("file:\\\\" + diSourceDir.FullName);
|
||||
var path2 = new Uri("file:\\\\" + fiCurFile.FullName);
|
||||
var diff = path1.MakeRelativeUri(path2);
|
||||
var relPath = diff.OriginalString;
|
||||
path2 = new Uri("file:\\\\" + destDirName);
|
||||
|
||||
path2 = new Uri(path2, relPath);
|
||||
|
||||
destFileLocations.Add(path2.LocalPath);
|
||||
if (System.IO.File.Exists(path2.LocalPath))
|
||||
{
|
||||
existingFiles.Add(path2.LocalPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (existingFiles.Count > 0)
|
||||
{
|
||||
var temp = new Uri("file:\\\\" + destDirName);
|
||||
var dr = param.ErrorCallback?.Invoke(StatusValues.ExistingFiles.ToString(), string.Format(Resources.UploadData_Files_Exist, temp.LocalPath, "\n\n"));
|
||||
|
||||
if (DialogResult.OK != dr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
for (var i = 0; i < fileLocations.Count && i < destFileLocations.Count; i++)
|
||||
{
|
||||
var fiSource = new System.IO.FileInfo(fileLocations[i]);
|
||||
var fiDest = new System.IO.FileInfo(destFileLocations[destFileLocations.Count - 1 - i]);
|
||||
|
||||
if (!System.IO.Directory.Exists(fiDest.Directory.FullName)) { System.IO.Directory.CreateDirectory(fiDest.Directory.FullName); }
|
||||
|
||||
System.IO.File.Copy(fiSource.FullName, fiDest.FullName, true);
|
||||
var percent = 100D * curFileUndex++ / fileLocations.Count;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
APILogger.Log("Upload Failure from ", sourceDirName, " to ", destDirName, ex);
|
||||
return false;
|
||||
}
|
||||
if (!uploadingData) return false;
|
||||
APILogger.Log("Upload Success from ", sourceDirName, " to ", destDirName);
|
||||
copied = true;
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
APILogger.Log("Upload Failure from ", sourceDirName, " to ", destDirName, ex);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
using DTS.Common.Enums.DASFactory;
|
||||
using DTS.Common.Interface.DASFactory.Diagnostics;
|
||||
using DTS.DASLib.Command.TDAS;
|
||||
|
||||
namespace DTS.DASLib.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// Each time <see cref="DTS.DASLib.Service.DiagnosticsService" />.Diagnose is called these values
|
||||
/// are populated. Each IDASCommunication will have one of these objects. It
|
||||
/// provides information about input voltage to the base unit, like power input,
|
||||
/// presence of a battery and battery output voltage.
|
||||
/// </summary>
|
||||
public class BaseInputValues : IBaseInputValues
|
||||
{
|
||||
/// <summary>
|
||||
/// The current input voltage to the base.
|
||||
/// </summary>
|
||||
public double InputMilliVolts { get; set; }
|
||||
|
||||
|
||||
//18740 DataPRO system settings Power setting values for TDAS rack do not change actual power values on device
|
||||
// added Min/Max valid and tied Valid bool to those values
|
||||
public virtual bool InputMilliVoltsValid => InputMilliVolts > 1000D * MinimumValidInputVoltage && InputMilliVolts < 1000D * MaximumValidInputVoltage;
|
||||
|
||||
/// <summary>
|
||||
/// The current input voltage to the base.
|
||||
/// </summary>
|
||||
public double InputVoltage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The minimum valid input voltage to the base.
|
||||
/// </summary>
|
||||
public double MinimumValidInputVoltage { get; set; } = 6D;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum valid input voltage to the base.
|
||||
/// </summary>
|
||||
public double MaximumValidInputVoltage { get; set; } = 16D;
|
||||
|
||||
public virtual bool BatteryMilliVoltsValid => BatteryMilliVolts > 1000D * MinimumValidBatteryVoltage && BatteryMilliVolts < 1000D * MaximumValidBatteryVoltage;
|
||||
|
||||
/// <summary>
|
||||
/// The current battery voltage.
|
||||
/// </summary>
|
||||
public double BatteryMilliVolts { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The current battery voltage.
|
||||
/// </summary>
|
||||
public double BatteryVoltage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// battery state of charge - null if not queried
|
||||
/// can be 0 if not available
|
||||
/// this is a percentage
|
||||
/// </summary>
|
||||
public double? BatterySoC { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum valid battery voltage to the base.
|
||||
/// </summary>
|
||||
public double MinimumValidBatteryVoltage { get; set; } = 6D;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum valid battery voltage to the base.
|
||||
/// </summary>
|
||||
public double MaximumValidBatteryVoltage { get; set; } = 16D;
|
||||
|
||||
/// <summary>
|
||||
/// TRUE if the battery is currently charging.
|
||||
/// </summary>
|
||||
public bool BatteryIsCharging { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Temperature sensed by logic in the hardware, in degrees Celsius.
|
||||
/// </summary>
|
||||
public double TemperatureC { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// returns status
|
||||
/// </summary>
|
||||
public virtual string BatteryVoltageStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// returns status
|
||||
/// </summary>
|
||||
public virtual string InputVoltageStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// returns status
|
||||
/// </summary>
|
||||
public virtual string StatusDisplayBattery { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// returns status
|
||||
/// </summary>
|
||||
public virtual string StatusDisplayInput { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// returns color
|
||||
/// </summary>
|
||||
public virtual DFConstantsAndEnums.VoltageStatusColor BatteryVoltageStatusColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// returns color
|
||||
/// </summary>
|
||||
public virtual DFConstantsAndEnums.VoltageStatusColor InputVoltageStatusColor { get; set; }
|
||||
|
||||
public double ChargeCapacity { get; set; } = double.NaN;
|
||||
|
||||
public bool ChargeCapacityValid => !double.IsNaN(ChargeCapacity) && ChargeCapacity > 0 && ChargeCapacity < 100;
|
||||
public BaseInputValues() { }
|
||||
public BaseInputValues(IBaseInputValues copy)
|
||||
{
|
||||
InputMilliVolts = copy.InputMilliVolts;
|
||||
InputVoltage = copy.InputVoltage;
|
||||
MinimumValidInputVoltage = copy.MinimumValidInputVoltage;
|
||||
MaximumValidInputVoltage = copy.MaximumValidInputVoltage;
|
||||
BatteryMilliVolts = copy.BatteryMilliVolts;
|
||||
BatteryVoltage = copy.BatteryVoltage;
|
||||
BatterySoC = copy.BatterySoC;
|
||||
MinimumValidBatteryVoltage = copy.MinimumValidBatteryVoltage;
|
||||
MaximumValidBatteryVoltage = copy.MaximumValidBatteryVoltage;
|
||||
BatteryIsCharging = copy.BatteryIsCharging;
|
||||
TemperatureC = copy.TemperatureC;
|
||||
BatteryVoltageStatus = copy.BatteryVoltageStatus;
|
||||
InputVoltageStatus = copy.InputVoltageStatus;
|
||||
StatusDisplayBattery = copy.StatusDisplayBattery;
|
||||
StatusDisplayInput = copy.StatusDisplayInput;
|
||||
BatteryVoltageStatusColor = copy.BatteryVoltageStatusColor;
|
||||
InputVoltageStatusColor = copy.InputVoltageStatusColor;
|
||||
ChargeCapacity = copy.ChargeCapacity;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user