aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.Integration/Operation/MachineOperator.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Software/Visual_Studio/Tango.Integration/Operation/MachineOperator.cs')
-rw-r--r--Software/Visual_Studio/Tango.Integration/Operation/MachineOperator.cs2426
1 files changed, 1249 insertions, 1177 deletions
diff --git a/Software/Visual_Studio/Tango.Integration/Operation/MachineOperator.cs b/Software/Visual_Studio/Tango.Integration/Operation/MachineOperator.cs
index fed6825f3..c38348bce 100644
--- a/Software/Visual_Studio/Tango.Integration/Operation/MachineOperator.cs
+++ b/Software/Visual_Studio/Tango.Integration/Operation/MachineOperator.cs
@@ -46,6 +46,7 @@ using Tango.PMR.ThreadLoading;
using Tango.BL.DTO;
using Tango.PMR.IFS;
using System.Runtime.CompilerServices;
+using Tango.BL.Interfaces;
namespace Tango.Integration.Operation
{
@@ -75,18 +76,62 @@ namespace Tango.Integration.Operation
private bool _machineStatusSent;
private bool _inkFillingStatusSent;
private bool _threadLoadingSent;
- private static RunningJobStatus _last_job_status;
private bool _isPowerDownRequestInProgress;
private bool _isHeadCleaningInProgress;
- private List<BL.ValueObjects.JobRunLiquidQuantity> _lastJobLiquidQuantities;
private DateTime _diagnosticsTime;
- private MachineStatus _machineStatusBeforeJobStart;
private Configuration _machineConfiguration;
+ private MachineStatus _lastMachineStatus;
+
+ protected class CurrentJobContext
+ {
+ private List<BL.ValueObjects.JobRunLiquidQuantity> _liquidQuantities;
+ private Func<CurrentJobContext, List<BL.ValueObjects.JobRunLiquidQuantity>> _getLiquidQuantities;
+
+ public MachineStatus MachineStatusOnCreation { get; private set; }
+
+ public DateTime StartDate { get; set; }
+ public DateTime? UploadingStartDate { get; set; }
+ public DateTime? HeatingStartDate { get; set; }
+ public DateTime? ActualStartDate { get; set; }
+
+ public Job Job { get; set; }
+ public Job OriginalJob { get; set; }
+ public Job ClonedJob { get; set; }
+ public Job JobForJobRun { get; set; }
+
+ public JobTicket JobTicket { get; set; }
+
+ public JobHandler JobHandler { get; set; }
+
+ public bool RequestSent { get; set; }
+ public JobRequest JobRequest { get; set; }
+
+ public bool JobCompleted { get; set; }
+ public bool ResponseLogged { get; set; }
+
+ public bool InitialUseKeepAlive { get; set; }
+
+ public bool IsResumingJob { get; set; }
+
+ public List<BL.ValueObjects.JobRunLiquidQuantity> GetLiquidQuantities()
+ {
+ if (_liquidQuantities == null)
+ {
+ _liquidQuantities = _getLiquidQuantities(this).ToList();
+ }
+
+ return _liquidQuantities;
+ }
+
+ public CurrentJobContext(MachineStatus currentMachineStatus, Func<CurrentJobContext, List<BL.ValueObjects.JobRunLiquidQuantity>> getLiquidQuantities)
+ {
+ MachineStatusOnCreation = currentMachineStatus.Clone();
+ _getLiquidQuantities = getLiquidQuantities;
+ JobRequest = new JobRequest();
+ StartDate = DateTime.UtcNow;
+ }
+ }
- private DateTime _jobStartDate;
- private DateTime? _jobUploadingStartDate;
- private DateTime? _jobHeatingStartDate;
- private DateTime? _jobActualStartDate;
private List<Event> _emulatedEvents;
private List<BitResultComposition> _bitResults;
private JobSpoolType _currentSpoolType;
@@ -850,6 +895,7 @@ namespace Tango.Integration.Operation
SendContinuousRequest<StartMachineStatusUpdateRequest, StartMachineStatusUpdateResponse>(request, new TransportContinuousRequestConfig() { ShouldLog = true }).ObserveOn(new NewThreadScheduler()).Subscribe(
(response) =>
{
+ _lastMachineStatus = response.Message.Status?.Clone();
OnMachineStatusChanged(response);
if (!responseLogged)
@@ -1308,14 +1354,14 @@ namespace Tango.Integration.Operation
/// </summary>
/// <param name="handler">The handler.</param>
/// <param name="job">The job.</param>
- protected virtual void OnPrintingStarted(JobHandler handler, Job job, bool isResumed = false)
+ protected virtual void OnPrintingStarted(CurrentJobContext context)
{
LogManager.Log("Raising printing started event...");
- PrintingStarted?.Invoke(this, new PrintingEventArgs(handler, job)
+ PrintingStarted?.Invoke(this, new PrintingEventArgs(context.JobHandler, context.JobForJobRun)
{
- StartDate = _jobStartDate,
- IsResumed = isResumed
+ StartDate = context.StartDate,
+ IsResumingJob = context.IsResumingJob
});
}
@@ -1324,20 +1370,21 @@ namespace Tango.Integration.Operation
/// </summary>
/// <param name="handler">The handler.</param>
/// <param name="job">The job.</param>
- protected virtual void OnPrintingCompleted(JobHandler handler, Job job)
+ protected virtual void OnPrintingCompleted(CurrentJobContext context)
{
LogManager.Log("Raising printing completed event...");
- PrintingCompleted?.Invoke(this, new PrintingEventArgs(handler, job)
+ PrintingCompleted?.Invoke(this, new PrintingEventArgs(context.JobHandler, context.JobForJobRun)
{
- LiquidQuantities = _lastJobLiquidQuantities.ToList(),
- StartDate = _jobStartDate,
- UploadingStartTime = _jobUploadingStartDate,
- HeatingStartTime = _jobHeatingStartDate,
- ActualStartTime = _jobActualStartDate,
+ LiquidQuantities = context.GetLiquidQuantities(),
+ StartDate = context.StartDate,
+ UploadingStartTime = context.UploadingStartDate,
+ HeatingStartTime = context.HeatingStartDate,
+ ActualStartTime = context.ActualStartDate,
+ IsResumingJob = context.IsResumingJob
});
- OnPrintingEnded(handler, job);
+ OnPrintingEnded(context);
}
/// <summary>
@@ -1346,19 +1393,20 @@ namespace Tango.Integration.Operation
/// <param name="handler">The handler.</param>
/// <param name="job">The job.</param>
/// <param name="exception">The exception.</param>
- protected virtual void OnPrintingFailed(JobHandler handler, Job job, Exception exception)
+ protected virtual void OnPrintingFailed(CurrentJobContext context, Exception exception)
{
LogManager.Log("Raising printing failed event...");
- PrintingFailed?.Invoke(this, new PrintingFailedEventArgs(handler, job, exception)
+ PrintingFailed?.Invoke(this, new PrintingFailedEventArgs(context.JobHandler, context.JobForJobRun, exception)
{
- LiquidQuantities = _lastJobLiquidQuantities.ToList(),
- StartDate = _jobStartDate,
- UploadingStartTime = _jobUploadingStartDate,
- HeatingStartTime = _jobHeatingStartDate,
- ActualStartTime = _jobActualStartDate,
+ LiquidQuantities = context.GetLiquidQuantities(),
+ StartDate = context.StartDate,
+ UploadingStartTime = context.UploadingStartDate,
+ HeatingStartTime = context.HeatingStartDate,
+ ActualStartTime = context.ActualStartDate,
+ IsResumingJob = context.IsResumingJob
});
- OnPrintingEnded(handler, job);
+ OnPrintingEnded(context);
}
/// <summary>
@@ -1366,19 +1414,20 @@ namespace Tango.Integration.Operation
/// </summary>
/// <param name="handler">The handler.</param>
/// <param name="job">The job.</param>
- protected virtual void OnPrintingAborted(JobHandler handler, Job job)
+ protected virtual void OnPrintingAborted(CurrentJobContext context)
{
LogManager.Log("Raising printing aborted event...");
- PrintingAborted?.Invoke(this, new PrintingEventArgs(handler, job)
+ PrintingAborted?.Invoke(this, new PrintingEventArgs(context.JobHandler, context.JobForJobRun)
{
- LiquidQuantities = _lastJobLiquidQuantities.ToList(),
- StartDate = _jobStartDate,
- UploadingStartTime = _jobUploadingStartDate,
- HeatingStartTime = _jobHeatingStartDate,
- ActualStartTime = _jobActualStartDate,
+ LiquidQuantities = context.GetLiquidQuantities(),
+ StartDate = context.StartDate,
+ UploadingStartTime = context.UploadingStartDate,
+ HeatingStartTime = context.HeatingStartDate,
+ ActualStartTime = context.ActualStartDate,
+ IsResumingJob = context.IsResumingJob
});
- OnPrintingEnded(handler, job);
+ OnPrintingEnded(context);
}
/// <summary>
@@ -1386,33 +1435,32 @@ namespace Tango.Integration.Operation
/// </summary>
/// <param name="handler">The handler.</param>
/// <param name="job">The job.</param>
- protected virtual void OnPrintingEnded(JobHandler handler, Job job)
+ protected virtual void OnPrintingEnded(CurrentJobContext context)
{
IsSpoolReplaced = false;
LogManager.Log("Raising printing ended event...");
- PrintingEnded?.Invoke(this, new PrintingEventArgs(handler, job)
+ PrintingEnded?.Invoke(this, new PrintingEventArgs(context.JobHandler, context.JobForJobRun)
{
- LiquidQuantities = _lastJobLiquidQuantities.ToList(),
- StartDate = _jobStartDate,
- UploadingStartTime = _jobUploadingStartDate,
- HeatingStartTime = _jobHeatingStartDate,
- ActualStartTime = _jobActualStartDate,
+ LiquidQuantities = context.GetLiquidQuantities(),
+ StartDate = context.StartDate,
+ UploadingStartTime = context.UploadingStartDate,
+ HeatingStartTime = context.HeatingStartDate,
+ ActualStartTime = context.ActualStartDate,
+ IsResumingJob = context.IsResumingJob
});
}
- protected virtual void OnHeadCleaningEnded(HeadCleaningHandler handler, JobRunStatus status)
+ protected virtual void OnHeadCleaningEnded(CurrentJobContext context, HeadCleaningHandler handler, JobRunStatus status)
{
- SaveLastJobLiquidQuantities(null, null, null, null);
-
HeadCleaningEnded?.Invoke(this, new HeadCleaningEndedEventArgs()
{
- StartDate = _jobStartDate,
+ StartDate = context.StartDate,
Length = handler.Status.Total,
EndPosition = handler.Status.Progress,
Status = status,
- LiquidQuantities = _lastJobLiquidQuantities.ToList(),
+ LiquidQuantities = context.GetLiquidQuantities(),
});
}
@@ -1444,7 +1492,7 @@ namespace Tango.Integration.Operation
_eventsSent = false;
_machineStatusSent = false;
- MachineStatus = null;
+ //MachineStatus = null;
if (Status != MachineStatuses.Disconnected)
{
@@ -1562,7 +1610,7 @@ namespace Tango.Integration.Operation
if (EnableJobResume)
{
- //ResumeJob();
+ ResumeJob();
}
if (response.Message.IsAfterReset)
@@ -1642,7 +1690,7 @@ namespace Tango.Integration.Operation
InkFillingStatusChanged?.Invoke(this, new InkFillingStatusChangedEventArgs() { Status = InkFillingStatus });
}
- private void SaveCachedJobOperation(Job job)
+ private void SaveCachedJobOperation(Job job, AdditionalJobConfiguration config)
{
try
{
@@ -1652,6 +1700,7 @@ namespace Tango.Integration.Operation
cache.MachineStatus = MachineStatus;
cache.ProcessParametersDTO = ProcessParametersTableDTO.FromObservable(CurrentProcessParameters);
cache.MachineConfigurationDTO = ConfigurationDTO.FromObservable(job.Machine.Configuration);
+ cache.Config = config;
var json = JsonConvert.SerializeObject(cache);
Directory.CreateDirectory(Path.GetDirectoryName(CachedJobOperationFile));
File.WriteAllText(CachedJobOperationFile, json);
@@ -1748,197 +1797,197 @@ namespace Tango.Integration.Operation
});
}
- private async void ResumeJob()
- {
- LogManager.Log("Checking if a job is in progress...");
+ //private async void ResumeJob()
+ //{
+ // LogManager.Log("Checking if a job is in progress...");
- try
- {
- var res = await SendRequest<CurrentJobRequest, CurrentJobResponse>(new CurrentJobRequest(), new TransportRequestConfig() { ShouldLog = true });
+ // try
+ // {
+ // var res = await SendRequest<CurrentJobRequest, CurrentJobResponse>(new CurrentJobRequest(), new TransportRequestConfig() { ShouldLog = true });
- if (res.Message.IsJobInProgress)
- {
- LogManager.Log("Job is in progress. Trying to resume job...");
- CachedJobOperation cache = LoadCachedJobOperation();
+ // if (res.Message.IsJobInProgress)
+ // {
+ // LogManager.Log("Job is in progress. Trying to resume job...");
+ // CachedJobOperation cache = LoadCachedJobOperation();
- if (cache == null)
- {
- LogManager.Log("Cannot resume current job with no cached operation.", LogCategory.Error);
- return;
- }
+ // if (cache == null)
+ // {
+ // LogManager.Log("Cannot resume current job with no cached operation.", LogCategory.Error);
+ // return;
+ // }
- Job job = null;
- Configuration configuration = null;
- ProcessParametersTable processParameters = null;
+ // Job job = null;
+ // Configuration configuration = null;
+ // ProcessParametersTable processParameters = null;
- try
- {
- processParameters = cache.ProcessParametersDTO.ToObservable();
- job = cache.JobDTO.ToObservable();
- configuration = cache.MachineConfigurationDTO.ToObservable();
- CurrentProcessParameters = processParameters;
- }
- catch (Exception ex)
- {
- LogManager.Log(ex, "Error deserializing cache job operation. Aborting resume.");
- return;
- }
+ // try
+ // {
+ // processParameters = cache.ProcessParametersDTO.ToObservable();
+ // job = cache.JobDTO.ToObservable();
+ // configuration = cache.MachineConfigurationDTO.ToObservable();
+ // CurrentProcessParameters = processParameters;
+ // }
+ // catch (Exception ex)
+ // {
+ // LogManager.Log(ex, "Error deserializing cache job operation. Aborting resume.");
+ // return;
+ // }
- JobTicket jobTicket = res.Message.JobTicket;
+ // JobTicket jobTicket = res.Message.JobTicket;
- ResumingJobEventArgs args = new ResumingJobEventArgs(() =>
- {
- RunningJob = null;
- RunningJobStatus = null;
+ // ResumingJobEventArgs args = new ResumingJobEventArgs(() =>
+ // {
+ // RunningJob = null;
+ // RunningJobStatus = null;
- var request = new ResumeCurrentJobRequest();
+ // var request = new ResumeCurrentJobRequest();
- JobHandler handler = null;
+ // JobHandler handler = null;
- handler = new JobHandler(async () =>
- {
- try
- {
- if (handler.CanCancel)
- {
- handler.CanCancel = false;
- handler.IsCanceled = true;
- LogManager.Log("Aborting current job...");
- var result = await SendRequest<AbortJobRequest, AbortJobResponse>(new AbortJobRequest(), new TransportRequestConfig() { ShouldLog = true });
- SaveLastJobLiquidQuantities(job, configuration, processParameters, handler);
- OnPrintingAborted(handler, job);
- handler.RaiseCanceled();
- if (Status != MachineStatuses.Disconnected)
- {
- UpdateStatus(MachineStatuses.ReadyToDye);
- }
- }
- }
- catch (Exception ex)
- {
- handler.CanCancel = true;
- LogManager.Log(ex, "Failed to cancel job.");
- }
- }, job, jobTicket, processParameters, JobHandlingMode);
+ // handler = new JobHandler(async () =>
+ // {
+ // try
+ // {
+ // if (handler.CanCancel)
+ // {
+ // handler.CanCancel = false;
+ // handler.IsCanceled = true;
+ // LogManager.Log("Aborting current job...");
+ // var result = await SendRequest<AbortJobRequest, AbortJobResponse>(new AbortJobRequest(), new TransportRequestConfig() { ShouldLog = true });
+ // SaveLastJobLiquidQuantities(job, configuration, processParameters, handler);
+ // OnPrintingAborted(handler, job);
+ // handler.RaiseCanceled();
+ // if (Status != MachineStatuses.Disconnected)
+ // {
+ // UpdateStatus(MachineStatuses.ReadyToDye);
+ // }
+ // }
+ // }
+ // catch (Exception ex)
+ // {
+ // handler.CanCancel = true;
+ // LogManager.Log(ex, "Failed to cancel job.");
+ // }
+ // }, job, jobTicket, processParameters, JobHandlingMode);
- handler.StatusChanged += (x, s) =>
- {
- RunningJobStatus = s;
- };
+ // handler.StatusChanged += (x, s) =>
+ // {
+ // RunningJobStatus = s;
+ // };
- if (MachineStatus != null)
- {
- _machineStatusBeforeJobStart = MachineStatus.Clone();
- }
- else
- {
- _machineStatusBeforeJobStart = cache.MachineStatus.Clone();
- }
+ // if (MachineStatus != null)
+ // {
+ // _machineStatusBeforeJobStart = MachineStatus.Clone();
+ // }
+ // else
+ // {
+ // _machineStatusBeforeJobStart = cache.MachineStatus.Clone();
+ // }
- _jobStartDate = DateTime.UtcNow;
- _jobUploadingStartDate = _jobStartDate;
- _jobHeatingStartDate = _jobStartDate;
- _jobActualStartDate = null;
+ // _jobStartDate = DateTime.UtcNow;
+ // _jobUploadingStartDate = _jobStartDate;
+ // _jobHeatingStartDate = _jobStartDate;
+ // _jobActualStartDate = null;
- bool responseLogged = false;
- bool completed = false;
+ // bool responseLogged = false;
+ // bool completed = false;
- Thread.Sleep(500); //Just wait maybe Shlomo is getting this message to fast after restart ?
+ // Thread.Sleep(500); //Just wait maybe Shlomo is getting this message to fast after restart ?
- SendContinuousRequest<ResumeCurrentJobRequest, ResumeCurrentJobResponse>(request, new TransportContinuousRequestConfig() { ContinuousTimeout = TimeSpan.FromSeconds(10), ShouldLog = true }).Subscribe((response) =>
- {
- if (!completed)
- {
- handler.RaiseStatusReceived(response.Message.Status);
- _last_job_status = handler.Status;
+ // SendContinuousRequest<ResumeCurrentJobRequest, ResumeCurrentJobResponse>(request, new TransportContinuousRequestConfig() { ContinuousTimeout = TimeSpan.FromSeconds(10), ShouldLog = true }).Subscribe((response) =>
+ // {
+ // if (!completed)
+ // {
+ // handler.RaiseStatusReceived(response.Message.Status);
+ // _last_job_status = handler.Status;
- if (response.Message.Status.Progress > 0)
- {
- if (_jobActualStartDate == null)
- {
- _jobActualStartDate = DateTime.UtcNow;
- }
- }
+ // if (response.Message.Status.Progress > 0)
+ // {
+ // if (_jobActualStartDate == null)
+ // {
+ // _jobActualStartDate = DateTime.UtcNow;
+ // }
+ // }
- if (!responseLogged)
- {
- UpdateStatus(MachineStatuses.GettingReady);
- responseLogged = true;
- RunningJob = job;
- OnPrintingStarted(handler, job, true);
- }
+ // if (!responseLogged)
+ // {
+ // UpdateStatus(MachineStatuses.GettingReady);
+ // responseLogged = true;
+ // RunningJob = job;
+ // OnPrintingStarted(handler, job, true);
+ // }
- if (JobHandlingMode == JobHandlerModes.SettingUp)
- {
- if (response.Message.Status.Progress > CurrentProcessParameters.DryerBufferLengthMeters)
- {
- if (!completed)
- {
- UpdateStatus(MachineStatuses.Printing);
- }
- }
- }
- else
- {
- if (response.Message.Status.Progress > 0)
- {
- if (!completed)
- {
- UpdateStatus(MachineStatuses.Printing);
- }
- }
- }
- }
- }, (ex) =>
- {
- if (!completed)
- {
- completed = true;
+ // if (JobHandlingMode == JobHandlerModes.SettingUp)
+ // {
+ // if (response.Message.Status.Progress > CurrentProcessParameters.DryerBufferLengthMeters)
+ // {
+ // if (!completed)
+ // {
+ // UpdateStatus(MachineStatuses.Printing);
+ // }
+ // }
+ // }
+ // else
+ // {
+ // if (response.Message.Status.Progress > 0)
+ // {
+ // if (!completed)
+ // {
+ // UpdateStatus(MachineStatuses.Printing);
+ // }
+ // }
+ // }
+ // }
+ // }, (ex) =>
+ // {
+ // if (!completed)
+ // {
+ // completed = true;
- if (Status != MachineStatuses.Disconnected)
- {
- UpdateStatus(MachineStatuses.ReadyToDye);
- }
+ // if (Status != MachineStatuses.Disconnected)
+ // {
+ // UpdateStatus(MachineStatuses.ReadyToDye);
+ // }
- if (!handler.IsCanceled)
- {
- SaveLastJobLiquidQuantities(job, configuration, processParameters, handler);
+ // if (!handler.IsCanceled)
+ // {
+ // SaveLastJobLiquidQuantities(job, configuration, processParameters, handler);
- Exception finalException = ex;
+ // Exception finalException = ex;
- if (ex is ContinuousResponseAbortedException continuousException)
- {
- finalException = new ContinuousResponseAbortedException($"Job aborted by the embedded device ({continuousException.Container.ErrorMessage}).");
- }
+ // if (ex is ContinuousResponseAbortedException continuousException)
+ // {
+ // finalException = new ContinuousResponseAbortedException($"Job aborted by the embedded device ({continuousException.Container.ErrorMessage}).");
+ // }
- OnPrintingFailed(handler, job, finalException);
- handler.RaiseFailed(finalException);
- }
- }
- }, () =>
- {
- if (!completed)
- {
- completed = true;
- UpdateStatus(MachineStatuses.ReadyToDye);
- SaveLastJobLiquidQuantities(job, configuration, processParameters, handler);
- OnPrintingCompleted(handler, job);
- handler.RaiseCompleted();
- }
- });
+ // OnPrintingFailed(handler, job, finalException);
+ // handler.RaiseFailed(finalException);
+ // }
+ // }
+ // }, () =>
+ // {
+ // if (!completed)
+ // {
+ // completed = true;
+ // UpdateStatus(MachineStatuses.ReadyToDye);
+ // SaveLastJobLiquidQuantities(job, configuration, processParameters, handler);
+ // OnPrintingCompleted(handler, job);
+ // handler.RaiseCompleted();
+ // }
+ // });
- return handler;
- });
+ // return handler;
+ // });
- args.JobGuid = jobTicket.Guid;
- ResumingJob?.Invoke(this, args);
- }
- }
- catch (Exception ex)
- {
- LogManager.Log(ex);
- }
- }
+ // args.JobGuid = jobTicket.Guid;
+ // ResumingJob?.Invoke(this, args);
+ // }
+ // }
+ // catch (Exception ex)
+ // {
+ // LogManager.Log(ex);
+ // }
+ //}
/// <summary>
/// Creates a PMR job segment.
@@ -2022,85 +2071,85 @@ namespace Tango.Integration.Operation
return jobSegment;
}
- private void ContinueSingleSpoolJob(Segment segment, Job job, ProcessParametersTable processParameters, JobHandler handler)
- {
- JobRequest request = new JobRequest();
+ //private void ContinueSingleSpoolJob(Segment segment, Job job, ProcessParametersTable processParameters, JobHandler handler)
+ //{
+ // JobRequest request = new JobRequest();
- JobTicket ticket = new JobTicket();
- ticket.Guid = handler.Job.Guid;
- ticket.EnableInterSegment = job.EnableInterSegment;
- ticket.InterSegmentLength = job.InterSegmentLength;
- ticket.Length = segment.Length;
- ticket.WindingMethod = (JobWindingMethod)job.WindingMethod.Code;
- ticket.Spool = new JobSpool();
+ // JobTicket ticket = new JobTicket();
+ // ticket.Guid = handler.Job.Guid;
+ // ticket.EnableInterSegment = job.EnableInterSegment;
+ // ticket.InterSegmentLength = job.InterSegmentLength;
+ // ticket.Length = segment.Length;
+ // ticket.WindingMethod = (JobWindingMethod)job.WindingMethod.Code;
+ // ticket.Spool = new JobSpool();
- job.SpoolType.MapPrimitivesTo(ticket.Spool);
- ticket.Spool.JobSpoolType = (JobSpoolType)job.SpoolType.Code;
+ // job.SpoolType.MapPrimitivesTo(ticket.Spool);
+ // ticket.Spool.JobSpoolType = (JobSpoolType)job.SpoolType.Code;
- ProcessParameters process = new ProcessParameters();
- processParameters.MapPrimitivesTo(process);
- ticket.ProcessParameters = process;
+ // ProcessParameters process = new ProcessParameters();
+ // processParameters.MapPrimitivesTo(process);
+ // ticket.ProcessParameters = process;
- ticket.Segments.Add(CreatePMRJobSegment(segment, job, processParameters));
+ // ticket.Segments.Add(CreatePMRJobSegment(segment, job, processParameters));
- request.JobTicket = ticket;
+ // request.JobTicket = ticket;
- bool responseLogged = false;
+ // bool responseLogged = false;
- var previous_segments_length = job.Segments.Where(x => x.SegmentIndex < segment.SegmentIndex).Sum(x => x.Length);
+ // var previous_segments_length = job.Segments.Where(x => x.SegmentIndex < segment.SegmentIndex).Sum(x => x.Length);
- SendContinuousRequest<JobRequest, JobResponse>(request, new TransportContinuousRequestConfig() { ContinuousTimeout = ContinuousRequestTimeout, ShouldLog = true }).Subscribe((response) =>
- {
- response.Message.Status.Progress += previous_segments_length;
+ // SendContinuousRequest<JobRequest, JobResponse>(request, new TransportContinuousRequestConfig() { ContinuousTimeout = ContinuousRequestTimeout, ShouldLog = true }).Subscribe((response) =>
+ // {
+ // response.Message.Status.Progress += previous_segments_length;
- handler.RaiseStatusReceived(response.Message.Status);
+ // handler.RaiseStatusReceived(response.Message.Status);
- if (!responseLogged && segment == job.OrderedSegments.First())
- {
- responseLogged = true;
- UpdateStatus(MachineStatuses.Printing);
- RunningJob = handler.Job;
- OnPrintingStarted(handler, handler.Job);
- }
+ // if (!responseLogged && segment == job.OrderedSegments.First())
+ // {
+ // responseLogged = true;
+ // UpdateStatus(MachineStatuses.Printing);
+ // RunningJob = handler.Job;
+ // OnPrintingStarted(handler, handler.Job);
+ // }
- }, (ex) =>
- {
- if (!(ex is ContinuousResponseAbortedException))
- {
- UpdateStatus(MachineStatuses.ReadyToDye);
+ // }, (ex) =>
+ // {
+ // if (!(ex is ContinuousResponseAbortedException))
+ // {
+ // UpdateStatus(MachineStatuses.ReadyToDye);
- if (!handler.IsCanceled)
- {
- OnPrintingFailed(handler, handler.Job, ex);
- handler.RaiseFailed(ex);
- }
- }
- else
- {
- UpdateStatus(MachineStatuses.ReadyToDye);
- }
- }, () =>
- {
- if (segment == job.OrderedSegments.Last())
- {
- UpdateStatus(MachineStatuses.ReadyToDye);
- OnPrintingCompleted(handler, handler.Job);
- handler.RaiseCompleted();
- }
- else
- {
- handler.RaiseSpoolChangeRequired(() =>
- {
- ContinueSingleSpoolJob(segment.GetNextSegment(), job, processParameters, handler);
- }, () =>
- {
- OnPrintingAborted(handler, handler.Job);
- UpdateStatus(MachineStatuses.ReadyToDye);
- handler.RaiseCanceled();
- });
- }
- });
- }
+ // if (!handler.IsCanceled)
+ // {
+ // OnPrintingFailed(handler, handler.Job, ex);
+ // handler.RaiseFailed(ex);
+ // }
+ // }
+ // else
+ // {
+ // UpdateStatus(MachineStatuses.ReadyToDye);
+ // }
+ // }, () =>
+ // {
+ // if (segment == job.OrderedSegments.Last())
+ // {
+ // UpdateStatus(MachineStatuses.ReadyToDye);
+ // OnPrintingCompleted(handler, handler.Job);
+ // handler.RaiseCompleted();
+ // }
+ // else
+ // {
+ // handler.RaiseSpoolChangeRequired(() =>
+ // {
+ // ContinueSingleSpoolJob(segment.GetNextSegment(), job, processParameters, handler);
+ // }, () =>
+ // {
+ // OnPrintingAborted(handler, handler.Job);
+ // UpdateStatus(MachineStatuses.ReadyToDye);
+ // handler.RaiseCanceled();
+ // });
+ // }
+ // });
+ //}
private List<RequiredLiquid> ValidateJobLiquidQuantity(Job job, ProcessParametersTable processParameters, Configuration configuration)
{
@@ -2356,25 +2405,22 @@ namespace Tango.Integration.Operation
/// <param name="job">The job.</param>
/// <param name="configuration">The configuration.</param>
/// <param name="handler">The handler.</param>
- private void SaveLastJobLiquidQuantities(Job job, Configuration configuration, ProcessParametersTable processParameters, JobHandler handler)
+ private List<BL.ValueObjects.JobRunLiquidQuantity> GetJobRunLiquidQuantities(CurrentJobContext context)
{
LogManager.Log($"Calculating job run liquid quantities using '{JobLiquidQuantityCalculationMode}' method...");
- if (configuration == null)
- {
- configuration = _machineConfiguration;
- }
+ var liquidQuantities = new List<BL.ValueObjects.JobRunLiquidQuantity>();
try
{
- _lastJobLiquidQuantities = new List<BL.ValueObjects.JobRunLiquidQuantity>();
-
- if (JobLiquidQuantityCalculationMode == JobLiquidQuantityCalculationMode.MachineStatus)
+ //if (JobLiquidQuantityCalculationMode == JobLiquidQuantityCalculationMode.MachineStatus)
+ //{
+ foreach (var pack in _machineConfiguration.NoneEmptyIdsPacks.ToList())
{
- foreach (var pack in configuration.NoneEmptyIdsPacks.ToList())
+ try
{
var packLevelAfter = MachineStatus.IDSPacksLevels.SingleOrDefault(x => x.Index == pack.PackIndex);
- var packLevelBefore = _machineStatusBeforeJobStart.IDSPacksLevels.SingleOrDefault(x => x.Index == pack.PackIndex);
+ var packLevelBefore = context.MachineStatusOnCreation.IDSPacksLevels.SingleOrDefault(x => x.Index == pack.PackIndex);
if (packLevelAfter != null && packLevelBefore != null)
{
@@ -2384,25 +2430,32 @@ namespace Tango.Integration.Operation
continue;
}
- _lastJobLiquidQuantities.Add(new BL.ValueObjects.JobRunLiquidQuantity()
+ liquidQuantities.Add(new BL.ValueObjects.JobRunLiquidQuantity()
{
LiquidType = pack.LiquidType.Type,
Quantity = packLevelBefore.DispenserLevel64 - packLevelAfter.DispenserLevel64,
});
}
}
+ catch (Exception ex)
+ {
+ LogManager.Log(ex, $"Error calculating liquid quantity for {pack.LiquidType.Name}");
+ }
}
- else
- {
- _lastJobLiquidQuantities = CreateJobRunLiquidQuantities(job, configuration, processParameters, handler.Status.Progress, handler.Status.TotalProgress);
- }
+ //}
+ //else
+ //{
+ // liquidQuantities = CreateJobRunLiquidQuantitiesUsingIntegral(job, configuration, processParameters, jobProgress, jobTotalProgress);
+ //}
- LogManager.Log($"Job run liquid quantities calculation completed:\n{_lastJobLiquidQuantities.ToJsonString()}");
+ LogManager.Log($"Job run liquid quantities calculation completed:\n{liquidQuantities.ToJsonString()}");
}
catch (Exception ex)
{
LogManager.Log(ex, LogCategory.Critical, "Error calculating and saving last job run liquid quantities.");
}
+
+ return liquidQuantities;
}
#endregion
@@ -2419,7 +2472,7 @@ namespace Tango.Integration.Operation
/// <param name="length">The length.</param>
/// <param name="gradientResolution">The gradient resolution.</param>
/// <returns></returns>
- public static List<BL.ValueObjects.JobRunLiquidQuantity> CreateJobRunLiquidQuantities(Job job, Configuration configuration, ProcessParametersTable processParameters, double position, double length)
+ public static List<BL.ValueObjects.JobRunLiquidQuantity> CreateJobRunLiquidQuantitiesUsingIntegral(Job job, Configuration configuration, ProcessParametersTable processParameters, double position, double length)
{
var units = Math.Max(job.NumberOfUnits, 1);
@@ -2543,876 +2596,6 @@ namespace Tango.Integration.Operation
#region Public Methods
/// <summary>
- /// Prints the specified job.
- /// The process parameters table will be calculated using color conversion gamut region.
- /// This method cannot accept brush stops with 'Volume' as color space.
- /// </summary>
- /// <param name="job">The job.</param>
- /// <param name="config">Optional job configuration.</param>
- /// <returns></returns>
- public async Task<JobHandler> Print(Job job, AdditionalJobConfiguration config = null)
- {
- ProcessParametersTable processParameters = null;
-
- if (config == null) config = new AdditionalJobConfiguration();
-
- await Task.Factory.StartNew(() =>
- {
- IColorConverter converter = new DefaultColorConverter();
-
- if (job.Rml == null)
- {
- throw new NullReferenceException("Job RML is null");
- }
-
- var processGroup = job.Rml.ProcessParametersTablesGroups.FirstOrDefault(x => x.Active);
-
- if (processGroup == null)
- {
- throw new NullReferenceException("Could not locate an active process parameters tables group for RML " + job.Rml.Name);
- }
-
- try
- {
- bool useLightInks = config.UseLightInks;
- if (job.OrderedSegmentsWithGroups.Count > 1 && !job.EnableInterSegment) useLightInks = false;
-
- processParameters = converter.GetRecommendedProcessParameters(job, useLightInks);
- }
- catch (Exception ex)
- {
- throw LogManager.Log(new InvalidOperationException($"An error occurred while trying to resolve the recommended process parameters.\n{ex.Message}"));
- }
-
- if (processParameters == null)
- {
- throw new NullReferenceException("Could not locate any process parameters table in group " + processGroup.Name + " for RML " + job.Rml.Name);
- }
-
- try
- {
- foreach (var stop in job.OrderedSegmentsWithGroups.SelectMany(x => x.BrushStops).ToList())
- {
- stop.SetLiquidVolumes(job.Machine.Configuration, job.Rml, processParameters);
- }
- }
- catch (Exception ex)
- {
- throw LogManager.Log(new InvalidOperationException($"An error occurred while trying to apply final liquid volumes.\n{ex.Message}"));
- }
- });
-
- return await Print(job, processParameters, config);
- }
-
- /// <summary>
- /// Prints the specified job using the specified job parameters.
- /// </summary>
- /// <param name="job">The job.</param>
- /// <param name="processParameters">Process parameters table</param>
- /// <returns></returns>
- public Task<JobHandler> Print(Job job, ProcessParametersTable processParameters, AdditionalJobConfiguration config = null)
- {
- //processParameters.DryerBufferLength = 10; //TODO: REMOVE !!!
-
- return Task.Factory.StartNew(() =>
- {
- if (config == null) config = new AdditionalJobConfiguration();
-
- if (!CanPrint)
- {
- throw new InvalidOperationException("Could not print while status = " + Status);
- }
-
- _jobStartDate = DateTime.UtcNow;
-
- LogManager.Log($"Executing job '{job.Name}'...");
-
- if (MachineStatus == null)
- {
- LogManager.Log("Aborting job execution. No machine status received yet.");
- throw new InvalidOperationException("Cannot execute a job before at least one machine status has been received.");
- }
-
- _lastJobLiquidQuantities = new List<BL.ValueObjects.JobRunLiquidQuantity>();
- _jobUploadingStartDate = null;
- _jobHeatingStartDate = null;
- _jobActualStartDate = null;
-
- RunningJob = null;
- RunningJobStatus = null;
-
- if (job.NumberOfUnits < 1)
- {
- job.NumberOfUnits = 1;
- }
-
- var originalJob = job;
- var clonedJob = job.Clone();
- clonedJob.Guid = job.Guid;
- clonedJob.Name = job.Name;
-
- job = job.Clone();
- job.Guid = originalJob.Guid;
- job.Name = originalJob.Name;
-
- var jobSegments = job.OrderedSegmentsWithGroups;
-
- //Color Conversion
- if (config.UseColorConversion)
- {
- IColorConverter converter = new DefaultColorConverter();
-
- bool useLightInks = config.UseLightInks;
-
- //Use light inks only if one segment or inter segment is enabled.
- if (MachineType == MachineTypes.TS1800 && job.OrderedSegmentsWithGroups.Count > 1 && !job.EnableInterSegment) useLightInks = false;
-
- foreach (var segment in jobSegments)
- {
- foreach (var stop in segment.BrushStops)
- {
- try
- {
- var output = converter.Convert(stop, false, useLightInks && segment.BrushStops.Count == 1); //Use light inks only if this is a solid segment.
- output.ApplyOnBrushStopLiquidVolumes(stop, processParameters);
- }
- catch (Exception ex)
- {
- throw new InvalidOperationException($"Error processing the coordinates of stop '{stop.StopIndex}' of segment '{stop.Segment.SegmentIndex}'.", ex);
- }
-
- if (stop.IsLiquidVolumesOutOfRange)
- {
- throw new InvalidOperationException($"The specified ink volumes at segment {segment.SegmentIndex} exceeds the maximum allowed total volume for the current thread.");
- }
- }
- }
- }
-
- //Lubrication
- if (job.EnableLubrication)
- {
- if (config.UseLubricantVolume)
- {
- LogManager.Log($"Job custom lubrication is enabled. Settings all brush stops to {config.LubricationVolume}% lubricant.");
-
- foreach (var stop in jobSegments.SelectMany(x => x.BrushStops).ToList())
- {
- var lubricantVolume = stop.LiquidVolumes.SingleOrDefault(x => x.IdsPack != null && x.IdsPack.LiquidType != null && x.LiquidType == LiquidTypes.Lubricant);
-
- if (lubricantVolume != null)
- {
- lubricantVolume.Volume = config.LubricationVolume;
- }
- }
- }
- else
- {
- LogManager.Log($"Job auto lubrication is enabled. Settings all none Volume brush stops to 100% lubricant.");
-
- foreach (var stop in jobSegments.SelectMany(x => x.BrushStops).Where(x => x.BrushColorSpace != ColorSpaces.Volume).ToList())
- {
- var lubricantVolume = stop.LiquidVolumes.SingleOrDefault(x => x.IdsPack != null && x.IdsPack.LiquidType != null && x.LiquidType == LiquidTypes.Lubricant);
-
- if (lubricantVolume != null)
- {
- lubricantVolume.Volume = 100;
- }
- }
- }
- }
- else
- {
- LogManager.Log("Job lubrication is disabled.");
- }
-
- //Modify transparent/white brush stops. (Transparent/white stops should be all zeros and 100% TI)
- LogManager.Log("Modifying all 'white' brush stops...");
- foreach (var stop in job.OrderedSegmentsWithGroups.SelectMany(x => x.BrushStops).Where(x => x.IsTransparent || x.IsWhite).ToList())
- {
- foreach (var liquidVolume in stop.LiquidVolumes.Where(x => x.LiquidType != LiquidTypes.TransparentInk && x.LiquidType != LiquidTypes.Lubricant).ToList())
- {
- liquidVolume.Volume = 0;
- }
-
- var tiLiquid = stop.LiquidVolumes.SingleOrDefault(x => x.IdsPack != null && x.IdsPack.LiquidType != null && x.LiquidType == LiquidTypes.TransparentInk);
-
- if (tiLiquid != null)
- {
- tiLiquid.Volume = 100;
- }
- }
-
- var segments = job.OrderedSegmentsWithGroups.ToList();
-
- List<RequiredLiquid> requiredLiquids = null;
-
- //Validate liquid quantities
- if (EnableJobLiquidQuantityValidation && MachineType == MachineTypes.TS1800)
- {
- if (!originalJob.Rml.UseColorLibGradients) //Validate liquid quantities when ColorLib generate gradient is disabled
- {
- requiredLiquids = ValidateJobLiquidQuantity(job, processParameters, job.Machine.Configuration);
- }
- else //Validate liquid quantities when ColorLib generate gradient is enabled
- {
- JobTicket t = new JobTicket();
- t.NumberOfUnits = (uint)originalJob.NumberOfUnits;
-
- foreach (var segment in segments)
- {
- if (segment is Segment simpleSegment)
- {
- t.Segments.Add(CreatePMRJobSegment(simpleSegment, originalJob, processParameters));
- }
- else if (segment is SegmentsGroup group)
- {
- List<JobSegment> groupSegments = new List<JobSegment>();
-
- foreach (var innerSegment in group.OrderedSegments)
- {
- groupSegments.Add(CreatePMRJobSegment(innerSegment, originalJob, processParameters));
- }
-
- for (int i = 0; i < group.Repeats; i++)
- {
- t.Segments.AddRange(groupSegments.ToList());
- }
- }
- }
-
- requiredLiquids = ValidateJobLiquidQuantity(t, processParameters, job.Machine.Configuration);
- }
- }
- else
- {
- LogManager.Log("Liquid quantity validation is disabled. Skipping...");
- }
-
- CurrentProcessParameters = processParameters;
-
- JobRequest request = new JobRequest();
-
- var jobForJobRun = job.Clone();
- jobForJobRun.Guid = job.Guid;
- jobForJobRun.Name = job.Name;
- jobForJobRun.ID = job.ID;
-
- if (config.ResumeConfig != null)
- {
- jobForJobRun.ResumeStartPosition = config.ResumeConfig.ResumeProgress;
- }
-
- int max = job.OrderedSegmentsWithGroups.Last().SegmentIndex + 1;
-
- for (int i = 0; i < job.NumberOfUnits - 1; i++)
- {
- foreach (var s in segments)
- {
- var cloned = s.Clone(job);
- cloned.SegmentIndex = max++;
-
- if (cloned is Segment simpleSegment)
- {
- job.Segments.Add(simpleSegment);
- }
- else if (cloned is SegmentsGroup g)
- {
- job.SegmentsGroups.Add(g);
- }
- }
- }
-
- JobTicket ticket = new JobTicket();
- ticket.Guid = originalJob.Guid;
- ticket.EnableInterSegment = job.EnableInterSegment;
- ticket.InterSegmentLength = Math.Max(job.InterSegmentLength, 1);
- ticket.EnableLubrication = job.EnableLubrication;
- ticket.Length = job.Length;
- ticket.WindingMethod = (JobWindingMethod)job.WindingMethod.Code;
- ticket.UploadStrategy = JobUploadStrategy;
-
- if (JobUnitsMethod == JobUnitsMethods.Device)
- {
- ticket.NumberOfUnits = (uint)Math.Max(job.NumberOfUnits, 1);
- }
-
- //Spool parameters
- ticket.Spool = new JobSpool();
- job.SpoolType.MapPropertiesTo(ticket.Spool);
- ticket.Spool.JobSpoolType = (JobSpoolType)job.SpoolType.Code;
-
- //Override spool parameters from RML Spool calibration
- var rmlSpool = job.Rml.RmlsSpools.FirstOrDefault(x => x.SpoolType.Guid == job.SpoolType.Guid);
- if (rmlSpool != null)
- {
- ticket.Spool.RotationsPerPassage = rmlSpool.RotationsPerPassage != null ? rmlSpool.RotationsPerPassage.Value : ticket.Spool.RotationsPerPassage;
- ticket.Spool.Length = rmlSpool.Length != null ? rmlSpool.Length.Value : ticket.Spool.Length;
- ticket.Spool.BackingRate = rmlSpool.BackingRate != null ? rmlSpool.BackingRate.Value : ticket.Spool.BackingRate;
- ticket.Spool.BottomBackingRate = rmlSpool.BottomBackingRate != null ? rmlSpool.BottomBackingRate.Value : ticket.Spool.BottomBackingRate;
- ticket.Spool.BtsrSpoolTension = rmlSpool.BtsrSpoolTension != null ? rmlSpool.BtsrSpoolTension.Value : ticket.Spool.BtsrSpoolTension;
- ticket.Spool.StartOffsetPulses = rmlSpool.StartOffsetPulses != null ? rmlSpool.StartOffsetPulses.Value : ticket.Spool.StartOffsetPulses;
- ticket.Spool.SegmentOffsetPulses = rmlSpool.SegmentOffsetPulses != null ? rmlSpool.SegmentOffsetPulses.Value : ticket.Spool.SegmentOffsetPulses;
- }
-
- //Override spool parameters from Machine Spool calibration
- var machineSpool = job.Machine.Spools.FirstOrDefault(x => x.SpoolType.Guid == job.SpoolType.Guid);
- if (machineSpool != null)
- {
- ticket.Spool.LimitSwitchStartPointOffset = machineSpool.LimitSwitchStartPointOffset != null ? machineSpool.LimitSwitchStartPointOffset.Value : ticket.Spool.LimitSwitchStartPointOffset;
- //ticket.Spool.StartOffsetPulses = machineSpool.StartOffsetPulses != null ? machineSpool.StartOffsetPulses.Value : ticket.Spool.StartOffsetPulses;
- //ticket.Spool.BackingRate = machineSpool.BackingRate != null ? machineSpool.BackingRate.Value : ticket.Spool.BackingRate;
- //ticket.Spool.SegmentOffsetPulses = machineSpool.SegmentOffsetPulses != null ? machineSpool.SegmentOffsetPulses.Value : ticket.Spool.SegmentOffsetPulses;
- //ticket.Spool.BottomBackingRate = machineSpool.BottomBackingRate != null ? machineSpool.BottomBackingRate.Value : ticket.Spool.BottomBackingRate;
- }
-
- //Thread Parameters
- ticket.ThreadParameters = new ThreadParameters();
- job.Rml.MapPrimitivesTo(ticket.ThreadParameters);
-
- ProcessParameters process = new ProcessParameters();
- processParameters.MapPrimitivesTo(process);
- ticket.ProcessParameters = process;
-
- //Head Cleaning Parameters
- ticket.HeadCleaningParameters = new HeadCleaningParameters();
- ticket.HeadCleaningParameters.CleanerFlow = job.Rml.CleanerFlow;
- ticket.HeadCleaningParameters.ArcHeadCleaningMotorSpeed = job.Rml.ArcHeadCleaningMotorSpeed;
-
- //BTSR Parameters
- ticket.BtsrParameters = new PMR.BTSR.BtsrParameters();
- ticket.BtsrParameters.BtsrApplicationType = job.Rml.BtsrApplicationType != null ? (PMR.BTSR.BtsrApplicationType)job.Rml.BtsrApplicationType.Code : PMR.BTSR.BtsrApplicationType.Seamless;
- ticket.BtsrParameters.BtsrYarnType = job.Rml.BtsrYarnType != null ? (PMR.BTSR.BtsrYarnType)job.Rml.BtsrYarnType.Code : PMR.BTSR.BtsrYarnType.AllYarn3;
- ticket.BtsrParameters.TensionError = (float)job.Rml.BtsrTensionError;
-
- JobHandler handler = null;
- StorageFileHandler fileUploadHandler = null;
-
- bool requestSent = false;
-
- handler = new JobHandler(async () =>
- {
- try
- {
- if (handler.CanCancel)
- {
- handler.CanCancel = false;
- handler.IsCanceled = true;
- LogManager.Log("Aborting current job...");
- LogManager.Log($"Aborting current gradient generation...");
- GradientGenerationConfiguration.AbortCurrentGeneration();
-
- if (fileUploadHandler != null)
- {
- LogManager.Log("Job is currently uploading. Aborting file upload...");
- await fileUploadHandler.Cancel();
- fileUploadHandler = null;
- LogManager.Log("Job upload canceled.");
- if (Status != MachineStatuses.Disconnected)
- {
- UpdateStatus(MachineStatuses.ReadyToDye);
- }
- OnPrintingAborted(handler, jobForJobRun);
- handler.RaiseCanceled();
- }
- else
- {
- if (requestSent)
- {
- var result = await SendRequest<AbortJobRequest, AbortJobResponse>(new AbortJobRequest(), new TransportRequestConfig() { ShouldLog = true });
- }
-
- SaveLastJobLiquidQuantities(clonedJob, originalJob.Machine.Configuration, processParameters, handler);
-
- if (Status != MachineStatuses.Disconnected)
- {
- UpdateStatus(MachineStatuses.ReadyToDye);
- }
-
- OnPrintingAborted(handler, jobForJobRun);
- handler.RaiseCanceled();
- }
- }
- }
- catch (Exception ex)
- {
- handler.CanCancel = true;
- LogManager.Log(ex, "Failed to cancel job.");
- }
- }, clonedJob, ticket, processParameters, JobHandlingMode, config.ResumeConfig);
-
- handler.StatusChanged += (x, s) =>
- {
- RunningJobStatus = s;
- };
-
- if (!job.IsAllSegmentsPerSpool)
- {
- ContinueSingleSpoolJob(job.OrderedSegments.First(), job, processParameters, handler);
- return handler;
- }
-
- ThreadFactory.StartNew(async () =>
- {
- if (handler.IsCanceled)
- {
- UpdateStatus(MachineStatuses.ReadyToDye);
- return;
- }
-
- UpdateStatus(MachineStatuses.GettingReady);
- RunningJob = clonedJob;
- OnPrintingStarted(handler, clonedJob);
-
- Thread.Sleep(100);
-
- handler.RaiseStatusReceived(new JobStatus()
- {
- CurrentSegmentIndex = 0,
- Progress = 0,
- Message = "Preparing Job...",
- });
-
- foreach (var segment in segments)
- {
- try
- {
- if (segment is Segment simpleSegment)
- {
- ticket.Segments.Add(CreatePMRJobSegment(simpleSegment, originalJob, processParameters));
- }
- else if (segment is SegmentsGroup group)
- {
- List<JobSegment> groupSegments = new List<JobSegment>();
-
- foreach (var innerSegment in group.OrderedSegments)
- {
- groupSegments.Add(CreatePMRJobSegment(innerSegment, originalJob, processParameters));
- }
-
- for (int i = 0; i < group.Repeats; i++)
- {
- ticket.Segments.AddRange(groupSegments.ToList());
- }
- }
- }
- catch (Exception ex)
- {
- handler.RaiseFailed(ex);
- UpdateStatus(MachineStatuses.ReadyToDye);
- return;
- }
-
- if (handler.IsCanceled)
- {
- UpdateStatus(MachineStatuses.ReadyToDye);
- return;
- }
- }
-
- //Log Job Outline (Only first and last brush stops if gradient).
- var ticketToLog = ticket.Clone();
- ticketToLog.Segments.Clear();
-
- foreach (var seg in ticket.Segments)
- {
- JobSegment segmentToLog = new JobSegment();
-
- segmentToLog.Length = seg.Length;
- segmentToLog.BrushStops.Add(seg.BrushStops.First());
-
- if (seg.BrushStops.Count > 1)
- {
- segmentToLog.BrushStops.Add(seg.BrushStops.Last());
- }
-
- ticketToLog.Segments.Add(segmentToLog);
- }
-
- if (!job.EnableInterSegment)
- {
- NormalizeJobTicket(ticketToLog, processParameters);
- }
-
- LogManager.Log($"Job outline for '{job.Name}':\n{ticketToLog.ToJsonString()}");
-
- if (handler.IsCanceled)
- {
- UpdateStatus(MachineStatuses.ReadyToDye);
- return;
- }
-
- var segs = new List<JobSegment>();
-
- if (JobUnitsMethod == JobUnitsMethods.Operator)
- {
- for (int i = 0; i < job.NumberOfUnits; i++)
- {
- foreach (var s in ticket.Segments)
- {
- var cloned = s.Clone();
- segs.Add(cloned);
- }
- }
- }
- else
- {
- foreach (var s in ticket.Segments)
- {
- var cloned = s.Clone();
- segs.Add(cloned);
- }
- }
-
- if (segs.Count > 0)
- {
- ticket.Segments.Clear();
- ticket.Segments.AddRange(segs);
- }
-
- if (!job.EnableInterSegment)
- {
- NormalizeJobTicket(ticket, processParameters);
- }
-
- request.JobTicket = ticket.Clone();
-
- LogManager.Log($"Job upload method is set to {JobUploadStrategy}...");
-
- if (handler.IsCanceled)
- {
- UpdateStatus(MachineStatuses.ReadyToDye);
- return;
- }
-
- var oldKeepAlive = UseKeepAlive;
-
- if (requiredLiquids != null)
- {
- JobPrepareRequest prepareRequest = new JobPrepareRequest();
- prepareRequest.ProcessParameters = ticket.ProcessParameters;
-
- foreach (var requiredLiquid in requiredLiquids)
- {
- JobPrepareDispenser prepareDispenser = new JobPrepareDispenser();
- prepareDispenser.DispenserLiquidType = (DispenserLiquidType)requiredLiquid.IdsPack.LiquidType.Type;
- prepareDispenser.Index = requiredLiquid.IdsPack.PackIndex;
- prepareDispenser.TotalNanoliter = Convert.ToInt32(requiredLiquid.Quantity);
- prepareDispenser.Active = requiredLiquid.Quantity > 0;
-
- prepareRequest.Dispensers.Add(prepareDispenser);
- }
-
- try
- {
- var response = await SendRequest<JobPrepareRequest, JobPrepareResponse>(prepareRequest, new TransportRequestConfig()
- {
- ShouldLog = true,
- Timeout = TimeSpan.FromSeconds(10)
- });
- }
- catch (ResponseErrorException ex)
- {
- LogManager.Log(ex, "Error sending job preparation request. Aborting job...");
- UseKeepAlive = oldKeepAlive;
- UpdateStatus(MachineStatuses.ReadyToDye);
- OnPrintingFailed(handler, jobForJobRun, ex);
- handler.RaiseFailed(ex);
- return;
- }
- catch (Exception ex)
- {
- LogManager.Log(ex, "Error sending job preparation request.");
- }
- }
-
- if (JobUploadStrategy == JobUploadStrategy.JobDescriptionFile)
- {
- LogManager.Log("Generating job description file...");
-
- try
- {
- request.JobTicket.Segments.Clear();
-
- JobDescriptionFile jobDescriptionFile = new JobDescriptionFile(ticket.Segments);
- MemoryStream ms = jobDescriptionFile.ToStream();
-
- handler.RaiseStatusReceived(new JobStatus()
- {
- CurrentSegmentIndex = 0,
- Progress = 0,
- Message = "Uploading job description file...",
- });
-
- if (handler.IsCanceled)
- {
- UpdateStatus(MachineStatuses.ReadyToDye);
- return;
- }
-
- LogManager.Log("Creating storage API manager...");
- var storage = CreateStorageManager();
-
- if (handler.IsCanceled)
- {
- UpdateStatus(MachineStatuses.ReadyToDye);
- return;
- }
-
- //Suppress keep alive while job uploads.
- //storage.SuppressKeepAliveWhileFileUploads = true;
- UseKeepAlive = false; //This is a work around for Shlomo not managing to keep alive while parsing the file.
-
- LogManager.Log("Getting storage drive information...");
- var storageInfo = await storage.GetStorageDrive();
- LogManager.Log("Getting root folder information...");
- var root_folder = await storage.GetRootFolder();
-
- var existing_item = root_folder.Items.SingleOrDefault(x => x.Name == JOB_DESCRIPTION_FILE_NAME);
- if (existing_item != null)
- {
- LogManager.Log("Removing previous job description file...");
- await storage.DeleteItem(existing_item);
- }
-
- String job_file_path = Path.Combine(storageInfo.Root, JOB_DESCRIPTION_FILE_NAME);
-
- LogManager.Log($"Uploading job description file '{job_file_path}' of size: {ms.Length} bytes...");
-
- TaskCompletionSource<object> uploadCompletion = new TaskCompletionSource<object>();
- _jobUploadingStartDate = DateTime.UtcNow;
- fileUploadHandler = await storage.UploadFile(job_file_path, ms);
- bool uploadCanceled = false;
- Exception uploadException = null;
- fileUploadHandler.Canceled += (_, __) =>
- {
- uploadCanceled = true;
- uploadCompletion.SetResult(true);
- };
- fileUploadHandler.Completed += (_, __) =>
- {
- uploadCompletion.SetResult(true);
- };
- fileUploadHandler.Failed += (_, e) =>
- {
- uploadCompletion.SetException(e);
- };
-
- try
- {
- await uploadCompletion.Task;
- }
- catch (Exception ue)
- {
- if (uploadException != null)
- {
- throw uploadException;
- }
- else
- {
- throw ue;
- }
- }
- finally
- {
- try
- {
- fileUploadHandler = null;
- ms.Dispose();
- }
- catch { }
- }
-
- if (uploadCanceled)
- {
- return;
- }
- else
- {
- LogManager.Log("Job upload completed successfully.");
- }
-
- request.JobTicket.JobDescriptionFile = job_file_path;
- }
- catch (Exception ex)
- {
- UseKeepAlive = oldKeepAlive;
- UpdateStatus(MachineStatuses.ReadyToDye);
- OnPrintingFailed(handler, jobForJobRun, ex);
- handler.RaiseFailed(ex);
- return;
- }
- }
- else
- {
- _jobUploadingStartDate = DateTime.UtcNow;
- }
-
- if (handler.IsCanceled)
- {
- UseKeepAlive = oldKeepAlive;
- UpdateStatus(MachineStatuses.ReadyToDye);
- return;
- }
-
- _machineStatusBeforeJobStart = MachineStatus.Clone();
-
- SaveCachedJobOperation(clonedJob); //Cache job and machine status for job resume!
-
- bool responseLogged = false;
- bool completed = false; //Use this in case Shlomo is sending progress after completion.
-
- _jobHeatingStartDate = DateTime.UtcNow;
-
- if (handler.IsCanceled)
- {
- UseKeepAlive = oldKeepAlive;
- UpdateStatus(MachineStatuses.ReadyToDye);
- return;
- }
-
- double resumePreProgress = 0;
-
- if (config.ResumeConfig != null)
- {
- LogManager.Log("Job Resume Detected...");
-
- resumePreProgress = config.ResumeConfig.GlobalStartPosition;// - config.ResumeConfig.FirstUnitStartPosition;//- processParameters.DryerBufferLengthMeters;
-
- request.FirstUnitStartPosition = config.ResumeConfig.GlobalStartPosition;
-
- //LogManager.Log($" resumePreProgress = {resumePreProgress}, GlobalStartPosition {config.ResumeConfig.GlobalStartPosition} FirstUnitStartPosition {request.FirstUnitStartPosition}");
- request.JobTicket.Length = (request.JobTicket.Length / Math.Max(request.JobTicket.NumberOfUnits, 1)) * (int)Math.Max(config.ResumeConfig.RemainingUnits, 1);
- request.JobTicket.NumberOfUnits = (uint)Math.Max(config.ResumeConfig.RemainingUnits, 1);
-
- LogManager.Log($"Resume Config:\n{config.ResumeConfig.ToJsonString()}\n");
- }
-
- SendContinuousRequest<JobRequest, JobResponse>(request, new TransportContinuousRequestConfig() { Timeout = TimeSpan.FromSeconds(10), ContinuousTimeout = TimeSpan.FromSeconds(10), ShouldLog = true }).Subscribe((response) =>
- {
- if (!completed)
- {
- //if (resumePreProgress > 0 && response.Message.Status.Progress > 0)
- //{
- // //LogManager.Log($"Appending Resume Progress {resumePreProgress} + {response.Message.Status.Progress}", LogCategory.Debug);
- // //response.Message.Status.Progress += resumePreProgress;
- //}
-
- handler.RaiseStatusReceived(response.Message.Status);
- _last_job_status = handler.Status;
-
- if (response.Message.Status.Progress > 0)
- if (oldKeepAlive != UseKeepAlive)
- {
- {
- UseKeepAlive = oldKeepAlive;
- }
-
- if (_jobActualStartDate == null)
- {
- _jobActualStartDate = DateTime.UtcNow;
- }
- }
-
- if (!responseLogged)
- {
- requestSent = true;
- responseLogged = true;
- }
-
- if (JobHandlingMode == JobHandlerModes.SettingUp)
- {
- var printingStartPosition = processParameters.DryerBufferLengthMeters;
-
- if (config != null && config.ResumeConfig != null && config.ResumeConfig.GlobalStartPosition > 0)
- {
- printingStartPosition = config.ResumeConfig.GlobalStartPosition;
- }
-
- if (response.Message.Status.Progress > printingStartPosition)
- {
- if (!completed)
- {
- UpdateStatus(MachineStatuses.Printing);
- }
- }
- }
- else
- {
- if (response.Message.Status.Progress > 0)
- {
- if (!completed)
- {
- UpdateStatus(MachineStatuses.Printing);
- }
- }
- }
- }
-
- }, (ex) =>
- {
- if (!completed)
- {
- completed = true;
-
- UseKeepAlive = oldKeepAlive;
-
- if (Status != MachineStatuses.Disconnected)
- {
- UpdateStatus(MachineStatuses.ReadyToDye);
- }
-
- if (!handler.IsCanceled)
- {
- SaveLastJobLiquidQuantities(originalJob, originalJob.Machine.Configuration, processParameters, handler);
-
- Exception finalException = ex;
-
- if (ex is ContinuousResponseAbortedException continuousException)
- {
- finalException = new ContinuousResponseAbortedException($"Job aborted by the embedded device ({continuousException.Container.ErrorMessage}).");
- }
-
- handler.RaiseFailed(finalException);
- OnPrintingFailed(handler, jobForJobRun, finalException);
- }
- }
- }, () =>
- {
- if (!completed)
- {
- completed = true;
-
- UseKeepAlive = oldKeepAlive;
-
- UpdateStatus(MachineStatuses.ReadyToDye);
- SaveLastJobLiquidQuantities(clonedJob, originalJob.Machine.Configuration, processParameters, handler);
- handler.RaiseCompleted();
- OnPrintingCompleted(handler, jobForJobRun);
- }
- });
- });
-
- return handler;
-
- });
- }
-
- private void NormalizeJobTicket(JobTicket ticket, ProcessParametersTable processParameters)
- {
- var maxNanoStop = ticket.Segments.SelectMany(x => x.BrushStops).OrderBy(x => x.GetTotalNanoliterPerCentimeter()).Last();
- double maxNanoliter = maxNanoStop.GetTotalNanoliterPerCentimeter();
-
- LogManager.Log($"Normalizing brush stops TI quantities by {maxNanoliter} nanoliters...");
-
- foreach (var stop in ticket.Segments.SelectMany(x => x.BrushStops).Where(x => x != maxNanoStop))
- {
- stop.NormalizeStop(maxNanoliter, processParameters.MinInkUptake, processParameters.DyeingSpeed);
- }
- }
-
- /// <summary>
/// Uploads the specified process parameters to the embedded device.
/// </summary>
/// <param name="processParameters">The process parameters.</param>
@@ -4498,6 +3681,8 @@ namespace Tango.Integration.Operation
_isHeadCleaningInProgress = true;
bool _completed = false;
+ var context = CreateJobContext(null, null);
+
HeadCleaningHandler handler = null;
handler = new HeadCleaningHandler(() =>
{
@@ -4507,7 +3692,7 @@ namespace Tango.Integration.Operation
if (!_completed)
{
_completed = true;
- OnHeadCleaningEnded(handler, JobRunStatus.Aborted);
+ OnHeadCleaningEnded(context, handler, JobRunStatus.Aborted);
}
var r = SendRequest<AbortHeadCleaningRequest, AbortHeadCleaningResponse>(new AbortHeadCleaningRequest(), new TransportRequestConfig() { ShouldLog = true }).Result;
@@ -4517,11 +3702,7 @@ namespace Tango.Integration.Operation
{
Thread.Sleep(100);
- _lastJobLiquidQuantities = new List<BL.ValueObjects.JobRunLiquidQuantity>();
- _machineStatusBeforeJobStart = MachineStatus.Clone();
-
bool firstResponse = true;
- _jobStartDate = DateTime.UtcNow;
SendContinuousRequest<StartHeadCleaningRequest, StartHeadCleaningResponse>(new StartHeadCleaningRequest() { IsLongJob = longCleaning }, new TransportContinuousRequestConfig() { ContinuousTimeout = TimeSpan.FromSeconds(5), ShouldLog = true }).ObserveOn(new NewThreadScheduler()).Subscribe((response) =>
{
@@ -4543,7 +3724,7 @@ namespace Tango.Integration.Operation
if (!_completed)
{
_completed = true;
- OnHeadCleaningEnded(handler, JobRunStatus.Failed);
+ OnHeadCleaningEnded(context, handler, JobRunStatus.Failed);
}
}, () =>
{
@@ -4553,7 +3734,7 @@ namespace Tango.Integration.Operation
if (!_completed)
{
_completed = true;
- OnHeadCleaningEnded(handler, JobRunStatus.Completed);
+ OnHeadCleaningEnded(context, handler, JobRunStatus.Completed);
}
});
});
@@ -4787,7 +3968,7 @@ namespace Tango.Integration.Operation
{
try
{
- await SendRequest<SetWhiteThreadSkipRequest, SetWhiteThreadSkipResponse>(new SetWhiteThreadSkipRequest() { Enabled = enable});
+ await SendRequest<SetWhiteThreadSkipRequest, SetWhiteThreadSkipResponse>(new SetWhiteThreadSkipRequest() { Enabled = enable });
LogManager.Log($"Machine white thread skip is now {(enable ? "Enabled" : "Disabled")}.");
}
catch (Exception ex)
@@ -4797,5 +3978,896 @@ namespace Tango.Integration.Operation
}
#endregion
+
+ #region Print
+
+ /// <summary>
+ /// Prints the specified job.
+ /// The process parameters table will be calculated using color conversion gamut region.
+ /// This method cannot accept brush stops with 'Volume' as color space.
+ /// </summary>
+ /// <param name="job">The job.</param>
+ /// <param name="config">Optional job configuration.</param>
+ /// <returns></returns>
+ public async Task<JobHandler> Print(Job job, AdditionalJobConfiguration config = null)
+ {
+ ProcessParametersTable processParameters = null;
+
+ if (config == null) config = new AdditionalJobConfiguration();
+
+ await Task.Factory.StartNew(() =>
+ {
+ IColorConverter converter = new DefaultColorConverter();
+
+ if (job.Rml == null)
+ {
+ throw new NullReferenceException("Job RML is null");
+ }
+
+ var processGroup = job.Rml.ProcessParametersTablesGroups.FirstOrDefault(x => x.Active);
+
+ if (processGroup == null)
+ {
+ throw new NullReferenceException("Could not locate an active process parameters tables group for RML " + job.Rml.Name);
+ }
+
+ try
+ {
+ bool useLightInks = config.UseLightInks;
+ if (job.OrderedSegmentsWithGroups.Count > 1 && !job.EnableInterSegment) useLightInks = false;
+
+ processParameters = converter.GetRecommendedProcessParameters(job, useLightInks);
+ }
+ catch (Exception ex)
+ {
+ throw LogManager.Log(new InvalidOperationException($"An error occurred while trying to resolve the recommended process parameters.\n{ex.Message}"));
+ }
+
+ if (processParameters == null)
+ {
+ throw new NullReferenceException("Could not locate any process parameters table in group " + processGroup.Name + " for RML " + job.Rml.Name);
+ }
+
+ try
+ {
+ foreach (var stop in job.OrderedSegmentsWithGroups.SelectMany(x => x.BrushStops).ToList())
+ {
+ stop.SetLiquidVolumes(job.Machine.Configuration, job.Rml, processParameters);
+ }
+ }
+ catch (Exception ex)
+ {
+ throw LogManager.Log(new InvalidOperationException($"An error occurred while trying to apply final liquid volumes.\n{ex.Message}"));
+ }
+ });
+
+ return await Print(job, processParameters, config);
+ }
+
+ /// <summary>
+ /// Prints the specified job using the specified job parameters.
+ /// </summary>
+ /// <param name="job">The job.</param>
+ /// <param name="processParameters">Process parameters table</param>
+ /// <returns></returns>
+ public Task<JobHandler> Print(Job job, ProcessParametersTable processParameters, AdditionalJobConfiguration config = null)
+ {
+ return Task.Run(async () =>
+ {
+ if (config == null) config = new AdditionalJobConfiguration();
+
+ if (!CanPrint)
+ {
+ throw new InvalidOperationException("Could not print while status = " + Status);
+ }
+
+ LogManager.Log($"Executing job '{job.Name}'...");
+
+ if (MachineStatus == null)
+ {
+ LogManager.Log("Aborting job execution. No machine status received yet.");
+ throw new InvalidOperationException("Cannot execute a job before at least one machine status has been received.");
+ }
+
+ var context = CreateJobContext(job, config);
+
+ CurrentProcessParameters = processParameters;
+
+ UseKeepAlive = false;
+
+ try
+ {
+ //Color Conversion
+ await ApplyColorConversion(context.Job, processParameters, config);
+
+ //Lubrication
+ await ApplyLubrication(context.Job, config);
+
+ //Modify transparent/white brush stops. (Transparent/white stops should be all zeros and 100% TI)
+ await ApplyTransparentBrushStops(context.Job);
+
+ //Validate liquid quantities
+ List<RequiredLiquid> requiredLiquids = await PerformLiquidQuantityValidation(context.Job, processParameters);
+
+ //Normalize Segments Group (Deprecated)
+ await ApplySegmentsGroupsToJob(context.Job);
+
+ //Create Job Ticket
+ context.JobTicket = await CreateJobTicket(context, processParameters);
+
+ //Create Job Handler
+ context.JobHandler = CreateJobHandler(processParameters, config, context);
+
+ //Apply PMR Segments to Job Ticket
+ await ApplyPMRSegmentsToJobTicket(context, processParameters);
+
+ //Log Job Outline (Only first and last brush stops if gradient).
+ //await LogJobOutline(job, processParameters, ticket);
+
+ //Add job ticket segments per number of units for the actual request.
+ context.JobRequest.JobTicket = await NormalizeJobTicketUnits(job, processParameters, context.JobTicket);
+
+ //Send Job Preperation Request.
+ await SendJobPrepareRequest(context, requiredLiquids);
+
+ //Upload Job Description File.
+ await UploadJobDescriptionFile(context);
+
+ ApplyResumeConfig(context, config);
+
+ //Cache job and machine status for job resume.
+ SaveCachedJobOperation(context.ClonedJob, config);
+ }
+ catch (Exception)
+ {
+ UseKeepAlive = context.InitialUseKeepAlive;
+ throw;
+ }
+
+ ThreadFactory.StartNew(() =>
+ {
+ Thread.Sleep(100); //Give some time for callers to register for the job handler events..
+ UpdateStatus(MachineStatuses.GettingReady);
+ OnPrintingStarted(context);
+
+ SendContinuousRequest<JobRequest, JobResponse>(context.JobRequest, new TransportContinuousRequestConfig() { Timeout = TimeSpan.FromSeconds(10), ContinuousTimeout = TimeSpan.FromSeconds(10), ShouldLog = true }).Subscribe((response) =>
+ {
+ ProcessJobStatus(context, response.Message.Status, processParameters, config?.ResumeConfig);
+ }, (ex) =>
+ {
+ ProcessJobError(context, processParameters, ex);
+ }, () =>
+ {
+ ProcessJobCompletion(context, processParameters);
+ });
+ });
+
+ return context.JobHandler;
+ });
+ }
+
+ private async void ResumeJob()
+ {
+ LogManager.Log("Checking if a job is in progress...");
+
+ try
+ {
+ var res = await SendRequest<CurrentJobRequest, CurrentJobResponse>(new CurrentJobRequest(), new TransportRequestConfig() { ShouldLog = true });
+
+ if (res.Message.IsJobInProgress)
+ {
+ LogManager.Log("Job is in progress. Trying to resume job...");
+ CachedJobOperation cache = LoadCachedJobOperation();
+
+ if (cache == null)
+ {
+ LogManager.Log("Cannot resume current job with no cached operation.", LogCategory.Error);
+ return;
+ }
+
+ if (res.Message.JobTicket == null)
+ {
+ LogManager.Log("Cannot resume current. No job ticket received by the embedded device.", LogCategory.Error);
+ return;
+ }
+
+ Guid g;
+ if (res.Message.JobTicket.Guid == null || !Guid.TryParse(res.Message.JobTicket.Guid, out g))
+ {
+ LogManager.Log("Cannot resume current. Invalid job guid received by the embedded device.", LogCategory.Error);
+ return;
+ }
+
+ var processParameters = cache.ProcessParametersDTO.ToObservable();
+ var job = cache.JobDTO.ToObservable();
+ var machineConfiguration = cache.MachineConfigurationDTO.ToObservable();
+ var config = cache.Config;
+
+ CurrentProcessParameters = processParameters;
+ _machineConfiguration = machineConfiguration;
+
+ ResumingJobEventArgs args = new ResumingJobEventArgs((actualJob) =>
+ {
+ var context = CreateJobContext(actualJob, config, _lastMachineStatus);
+ context.IsResumingJob = true;
+ context.JobTicket = res.Message.JobTicket;
+ context.JobHandler = CreateJobHandler(processParameters, config, context);
+
+ RunningJob = null;
+ RunningJobStatus = null;
+
+ var request = new ResumeCurrentJobRequest();
+
+ ThreadFactory.StartNew(() =>
+ {
+ Thread.Sleep(1000); //Give some time for callers to register for the job handler events..
+ UpdateStatus(MachineStatuses.GettingReady);
+ OnPrintingStarted(context);
+
+ SendContinuousRequest<ResumeCurrentJobRequest, ResumeCurrentJobResponse>(request, new TransportContinuousRequestConfig() { Timeout = TimeSpan.FromSeconds(10), ContinuousTimeout = TimeSpan.FromSeconds(10), ShouldLog = true }).Subscribe((response) =>
+ {
+ ProcessJobStatus(context, response.Message.Status, processParameters, config?.ResumeConfig);
+ }, (ex) =>
+ {
+ ProcessJobError(context, processParameters, ex);
+ }, () =>
+ {
+ ProcessJobCompletion(context, processParameters);
+ });
+ });
+
+ return context.JobHandler;
+ });
+
+ args.JobGuid = res.Message.JobTicket.Guid;
+ ResumingJob?.Invoke(this, args);
+ }
+ }
+ catch (Exception ex)
+ {
+ LogManager.Log(ex);
+ }
+ }
+
+ private void ApplyResumeConfig(CurrentJobContext context, AdditionalJobConfiguration config)
+ {
+ if (config.ResumeConfig != null)
+ {
+ LogManager.Log("Job Resume Detected...");
+
+ context.JobRequest.FirstUnitStartPosition = config.ResumeConfig.GlobalStartPosition;
+
+ context.JobRequest.JobTicket.Length = (context.JobRequest.JobTicket.Length / Math.Max(context.JobRequest.JobTicket.NumberOfUnits, 1)) * (int)Math.Max(config.ResumeConfig.RemainingUnits, 1);
+ context.JobRequest.JobTicket.NumberOfUnits = (uint)Math.Max(config.ResumeConfig.RemainingUnits, 1);
+
+ LogManager.Log($"Resume Config:\n{config.ResumeConfig.ToJsonString()}\n");
+ }
+ }
+
+ private void ProcessJobStatus(CurrentJobContext context, JobStatus status, ProcessParametersTable processParameters, AdditionalJobConfiguration.ResumeConfiguration resumeConfig)
+ {
+ if (!context.JobCompleted)
+ {
+ context.JobHandler.RaiseStatusReceived(status);
+
+ if (!context.ResponseLogged)
+ {
+ context.HeatingStartDate = DateTime.UtcNow;
+ context.RequestSent = true;
+ context.ResponseLogged = true;
+ }
+
+ if (status.Progress > 0)
+ {
+ if (context.InitialUseKeepAlive != UseKeepAlive)
+ {
+ UseKeepAlive = context.InitialUseKeepAlive;
+ }
+
+ if (context.ActualStartDate == null)
+ {
+ context.ActualStartDate = DateTime.UtcNow;
+ }
+ }
+
+ if (JobHandlingMode == JobHandlerModes.SettingUp)
+ {
+ var printingStartPosition = processParameters.DryerBufferLengthMeters;
+
+ if (resumeConfig != null && resumeConfig.GlobalStartPosition > 0)
+ {
+ printingStartPosition = resumeConfig.GlobalStartPosition;
+ }
+
+ if (status.Progress > printingStartPosition)
+ {
+ if (!context.JobCompleted)
+ {
+ UpdateStatus(MachineStatuses.Printing);
+ }
+ }
+ }
+ else
+ {
+ if (status.Progress > 0)
+ {
+ if (!context.JobCompleted)
+ {
+ UpdateStatus(MachineStatuses.Printing);
+ }
+ }
+ }
+ }
+ }
+
+ private void ProcessJobError(CurrentJobContext context, ProcessParametersTable processParameters, Exception ex)
+ {
+ if (!context.JobCompleted)
+ {
+ context.JobCompleted = true;
+
+ UseKeepAlive = context.InitialUseKeepAlive;
+
+ if (Status != MachineStatuses.Disconnected)
+ {
+ UpdateStatus(MachineStatuses.ReadyToDye);
+ }
+
+ if (!context.JobHandler.IsCanceled)
+ {
+ Exception finalException = ex;
+
+ if (ex is ContinuousResponseAbortedException continuousException)
+ {
+ finalException = new ContinuousResponseAbortedException($"Job aborted by the embedded device ({continuousException.Container.ErrorMessage}).");
+ }
+
+ context.JobHandler.RaiseFailed(finalException);
+ OnPrintingFailed(context, finalException);
+ }
+ }
+ }
+
+ private void ProcessJobCompletion(CurrentJobContext context, ProcessParametersTable processParameters)
+ {
+ if (!context.JobCompleted)
+ {
+ context.JobCompleted = true;
+
+ UseKeepAlive = context.InitialUseKeepAlive;
+
+ UpdateStatus(MachineStatuses.ReadyToDye);
+ context.JobHandler.RaiseCompleted();
+ OnPrintingCompleted(context);
+ }
+ }
+
+ private void OnJobHandlerStatusChanged(object sender, RunningJobStatus e)
+ {
+ RunningJobStatus = e;
+ }
+
+ private async void OnJobHandlerCanceled(CurrentJobContext context)
+ {
+ try
+ {
+ if (context.JobHandler.CanCancel)
+ {
+ context.JobHandler.CanCancel = false;
+ context.JobHandler.IsCanceled = true;
+ LogManager.Log("Aborting current job...");
+
+ if (context.RequestSent)
+ {
+ var result = await SendRequest<AbortJobRequest, AbortJobResponse>(new AbortJobRequest(), new TransportRequestConfig() { ShouldLog = true });
+ }
+
+ if (Status != MachineStatuses.Disconnected)
+ {
+ UpdateStatus(MachineStatuses.ReadyToDye);
+ }
+
+ OnPrintingAborted(context);
+ context.JobHandler.RaiseCanceled();
+ }
+ }
+ catch (Exception ex)
+ {
+ context.JobHandler.CanCancel = true;
+ LogManager.Log(ex, "Failed to cancel job.");
+ }
+ }
+
+ private async Task UploadJobDescriptionFile(CurrentJobContext context)
+ {
+ context.UploadingStartDate = DateTime.UtcNow;
+
+ if (JobUploadStrategy == JobUploadStrategy.JobDescriptionFile)
+ {
+ LogManager.Log("Generating job description file...");
+
+ context.JobRequest.JobTicket.Segments.Clear();
+
+ JobDescriptionFile jobDescriptionFile = new JobDescriptionFile(context.JobTicket.Segments);
+ MemoryStream ms = jobDescriptionFile.ToStream();
+
+ context.JobHandler.RaiseStatusReceived(new JobStatus()
+ {
+ CurrentSegmentIndex = 0,
+ Progress = 0,
+ Message = "Uploading job description file...",
+ });
+
+ LogManager.Log("Creating storage API manager...");
+ var storage = CreateStorageManager();
+
+ LogManager.Log("Getting storage drive information...");
+ var storageInfo = await storage.GetStorageDrive();
+ LogManager.Log("Getting root folder information...");
+ var root_folder = await storage.GetRootFolder();
+
+ var existing_item = root_folder.Items.SingleOrDefault(x => x.Name == JOB_DESCRIPTION_FILE_NAME);
+ if (existing_item != null)
+ {
+ LogManager.Log("Removing previous job description file...");
+ await storage.DeleteItem(existing_item);
+ }
+
+ String job_file_path = Path.Combine(storageInfo.Root, JOB_DESCRIPTION_FILE_NAME);
+
+ LogManager.Log($"Uploading job description file '{job_file_path}' of size: {ms.Length} bytes...");
+
+ TaskCompletionSource<object> uploadCompletion = new TaskCompletionSource<object>();
+
+ var uploader = await storage.UploadFile(job_file_path, ms);
+ uploader.Canceled += (_, __) =>
+ {
+ uploadCompletion.SetResult(true);
+ };
+ uploader.Completed += (_, __) =>
+ {
+ uploadCompletion.SetResult(true);
+ };
+ uploader.Failed += (_, e) =>
+ {
+ uploadCompletion.SetException(e);
+ };
+
+ await uploadCompletion.Task;
+
+ context.JobRequest.JobTicket.JobDescriptionFile = job_file_path;
+ }
+ }
+
+ private async Task SendJobPrepareRequest(CurrentJobContext context, List<RequiredLiquid> requiredLiquids)
+ {
+ if (requiredLiquids.Count > 0)
+ {
+ JobPrepareRequest prepareRequest = new JobPrepareRequest();
+ prepareRequest.ProcessParameters = context.JobTicket.ProcessParameters;
+
+ foreach (var requiredLiquid in requiredLiquids)
+ {
+ JobPrepareDispenser prepareDispenser = new JobPrepareDispenser();
+ prepareDispenser.DispenserLiquidType = (DispenserLiquidType)requiredLiquid.IdsPack.LiquidType.Type;
+ prepareDispenser.Index = requiredLiquid.IdsPack.PackIndex;
+ prepareDispenser.TotalNanoliter = Convert.ToInt32(requiredLiquid.Quantity);
+ prepareDispenser.Active = requiredLiquid.Quantity > 0;
+
+ prepareRequest.Dispensers.Add(prepareDispenser);
+ }
+
+ var response = await SendRequest<JobPrepareRequest, JobPrepareResponse>(prepareRequest, new TransportRequestConfig()
+ {
+ ShouldLog = true,
+ Timeout = TimeSpan.FromSeconds(10)
+ });
+ }
+ }
+
+ private Task<JobTicket> NormalizeJobTicketUnits(Job job, ProcessParametersTable processParameters, JobTicket ticket)
+ {
+ return Task.Run(() =>
+ {
+ ticket = ticket.Clone();
+
+ var segs = new List<JobSegment>();
+
+ if (JobUnitsMethod == JobUnitsMethods.Operator)
+ {
+ for (int i = 0; i < job.NumberOfUnits; i++)
+ {
+ foreach (var s in ticket.Segments)
+ {
+ var cloned = s.Clone();
+ segs.Add(cloned);
+ }
+ }
+ }
+ else
+ {
+ foreach (var s in ticket.Segments)
+ {
+ var cloned = s.Clone();
+ segs.Add(cloned);
+ }
+ }
+
+ if (segs.Count > 0)
+ {
+ ticket.Segments.Clear();
+ ticket.Segments.AddRange(segs);
+ }
+
+ if (!job.EnableInterSegment)
+ {
+ NormalizeJobTicket(ticket, processParameters);
+ }
+
+ return ticket;
+ });
+ }
+
+ private Task LogJobOutline(Job job, ProcessParametersTable processParameters, JobTicket ticket)
+ {
+ return Task.Run(() =>
+ {
+ var ticketToLog = ticket.Clone();
+ ticketToLog.Segments.Clear();
+
+ foreach (var seg in ticket.Segments)
+ {
+ JobSegment segmentToLog = new JobSegment();
+
+ segmentToLog.Length = seg.Length;
+ segmentToLog.BrushStops.Add(seg.BrushStops.First());
+
+ if (seg.BrushStops.Count > 1)
+ {
+ segmentToLog.BrushStops.Add(seg.BrushStops.Last());
+ }
+
+ ticketToLog.Segments.Add(segmentToLog);
+ }
+
+ if (!job.EnableInterSegment)
+ {
+ NormalizeJobTicket(ticketToLog, processParameters);
+ }
+
+ LogManager.Log($"Job outline for '{job.Name}':\n{ticketToLog.ToJsonString()}");
+ });
+ }
+
+ private static void RaiseHandlerInitialStatus(JobHandler handler)
+ {
+ handler.RaiseStatusReceived(new JobStatus()
+ {
+ CurrentSegmentIndex = 0,
+ Progress = 0,
+ Message = "Preparing Job...",
+ });
+ }
+
+ private Task ApplyPMRSegmentsToJobTicket(CurrentJobContext context, ProcessParametersTable processParameters)
+ {
+ return Task.Run(() =>
+ {
+ foreach (var segment in context.Job.OrderedSegmentsWithGroups.ToList())
+ {
+ if (segment is Segment simpleSegment)
+ {
+ context.JobTicket.Segments.Add(CreatePMRJobSegment(simpleSegment, context.OriginalJob, processParameters));
+ }
+ else if (segment is SegmentsGroup group)
+ {
+ List<JobSegment> groupSegments = new List<JobSegment>();
+
+ foreach (var innerSegment in group.OrderedSegments)
+ {
+ groupSegments.Add(CreatePMRJobSegment(innerSegment, context.OriginalJob, processParameters));
+ }
+
+ for (int i = 0; i < group.Repeats; i++)
+ {
+ context.JobTicket.Segments.AddRange(groupSegments.ToList());
+ }
+ }
+ }
+ });
+ }
+
+ private JobHandler CreateJobHandler(ProcessParametersTable processParameters, AdditionalJobConfiguration config, CurrentJobContext context)
+ {
+ JobHandler handler = new JobHandler(() => OnJobHandlerCanceled(context), context.ClonedJob, context.JobTicket, processParameters, JobHandlingMode, config.ResumeConfig);
+ handler.StatusChanged += OnJobHandlerStatusChanged;
+ return handler;
+ }
+
+ private Task<JobTicket> CreateJobTicket(CurrentJobContext context, ProcessParametersTable processParameters)
+ {
+ Job job = context.Job;
+
+ return Task.Run(() =>
+ {
+ JobTicket ticket = new JobTicket();
+ ticket.Guid = context.OriginalJob.Guid;
+ ticket.EnableInterSegment = job.EnableInterSegment;
+ ticket.InterSegmentLength = Math.Max(job.InterSegmentLength, 1);
+ ticket.EnableLubrication = job.EnableLubrication;
+ ticket.Length = job.Length;
+ ticket.WindingMethod = (JobWindingMethod)job.WindingMethod.Code;
+ ticket.UploadStrategy = JobUploadStrategy;
+
+ if (JobUnitsMethod == JobUnitsMethods.Device)
+ {
+ ticket.NumberOfUnits = (uint)Math.Max(job.NumberOfUnits, 1);
+ }
+
+ //Spool parameters
+ ticket.Spool = new JobSpool();
+ job.SpoolType.MapPropertiesTo(ticket.Spool);
+ ticket.Spool.JobSpoolType = (JobSpoolType)job.SpoolType.Code;
+
+ //Override spool parameters from RML Spool calibration
+ var rmlSpool = job.Rml.RmlsSpools.FirstOrDefault(x => x.SpoolType.Guid == job.SpoolType.Guid);
+ if (rmlSpool != null)
+ {
+ ticket.Spool.RotationsPerPassage = rmlSpool.RotationsPerPassage != null ? rmlSpool.RotationsPerPassage.Value : ticket.Spool.RotationsPerPassage;
+ ticket.Spool.Length = rmlSpool.Length != null ? rmlSpool.Length.Value : ticket.Spool.Length;
+ ticket.Spool.BackingRate = rmlSpool.BackingRate != null ? rmlSpool.BackingRate.Value : ticket.Spool.BackingRate;
+ ticket.Spool.BottomBackingRate = rmlSpool.BottomBackingRate != null ? rmlSpool.BottomBackingRate.Value : ticket.Spool.BottomBackingRate;
+ ticket.Spool.BtsrSpoolTension = rmlSpool.BtsrSpoolTension != null ? rmlSpool.BtsrSpoolTension.Value : ticket.Spool.BtsrSpoolTension;
+ ticket.Spool.StartOffsetPulses = rmlSpool.StartOffsetPulses != null ? rmlSpool.StartOffsetPulses.Value : ticket.Spool.StartOffsetPulses;
+ ticket.Spool.SegmentOffsetPulses = rmlSpool.SegmentOffsetPulses != null ? rmlSpool.SegmentOffsetPulses.Value : ticket.Spool.SegmentOffsetPulses;
+ }
+
+ //Override spool parameters from Machine Spool calibration
+ var machineSpool = job.Machine.Spools.FirstOrDefault(x => x.SpoolType.Guid == job.SpoolType.Guid);
+ if (machineSpool != null)
+ {
+ ticket.Spool.LimitSwitchStartPointOffset = machineSpool.LimitSwitchStartPointOffset != null ? machineSpool.LimitSwitchStartPointOffset.Value : ticket.Spool.LimitSwitchStartPointOffset;
+ //ticket.Spool.StartOffsetPulses = machineSpool.StartOffsetPulses != null ? machineSpool.StartOffsetPulses.Value : ticket.Spool.StartOffsetPulses;
+ //ticket.Spool.BackingRate = machineSpool.BackingRate != null ? machineSpool.BackingRate.Value : ticket.Spool.BackingRate;
+ //ticket.Spool.SegmentOffsetPulses = machineSpool.SegmentOffsetPulses != null ? machineSpool.SegmentOffsetPulses.Value : ticket.Spool.SegmentOffsetPulses;
+ //ticket.Spool.BottomBackingRate = machineSpool.BottomBackingRate != null ? machineSpool.BottomBackingRate.Value : ticket.Spool.BottomBackingRate;
+ }
+
+ //Thread Parameters
+ ticket.ThreadParameters = new ThreadParameters();
+ job.Rml.MapPrimitivesTo(ticket.ThreadParameters);
+
+ ProcessParameters process = new ProcessParameters();
+ processParameters.MapPrimitivesTo(process);
+ ticket.ProcessParameters = process;
+
+ //Head Cleaning Parameters
+ ticket.HeadCleaningParameters = new HeadCleaningParameters();
+ ticket.HeadCleaningParameters.CleanerFlow = job.Rml.CleanerFlow;
+ ticket.HeadCleaningParameters.ArcHeadCleaningMotorSpeed = job.Rml.ArcHeadCleaningMotorSpeed;
+
+ //BTSR Parameters
+ ticket.BtsrParameters = new PMR.BTSR.BtsrParameters();
+ ticket.BtsrParameters.BtsrApplicationType = job.Rml.BtsrApplicationType != null ? (PMR.BTSR.BtsrApplicationType)job.Rml.BtsrApplicationType.Code : PMR.BTSR.BtsrApplicationType.Seamless;
+ ticket.BtsrParameters.BtsrYarnType = job.Rml.BtsrYarnType != null ? (PMR.BTSR.BtsrYarnType)job.Rml.BtsrYarnType.Code : PMR.BTSR.BtsrYarnType.AllYarn3;
+ ticket.BtsrParameters.TensionError = (float)job.Rml.BtsrTensionError;
+ return ticket;
+ });
+ }
+
+ private Task ApplySegmentsGroupsToJob(Job job)
+ {
+ return Task.Run(() =>
+ {
+ int max = job.OrderedSegmentsWithGroups.Last().SegmentIndex + 1;
+
+ for (int i = 0; i < job.NumberOfUnits - 1; i++)
+ {
+ foreach (var s in job.OrderedSegmentsWithGroups.ToList())
+ {
+ var cloned = s.Clone(job);
+ cloned.SegmentIndex = max++;
+
+ if (cloned is Segment simpleSegment)
+ {
+ job.Segments.Add(simpleSegment);
+ }
+ else if (cloned is SegmentsGroup g)
+ {
+ job.SegmentsGroups.Add(g);
+ }
+ }
+ }
+ });
+ }
+
+ private Task<List<RequiredLiquid>> PerformLiquidQuantityValidation(Job job, ProcessParametersTable processParameters)
+ {
+ return Task.Run(() =>
+ {
+ List<RequiredLiquid> requiredLiquids = new List<RequiredLiquid>();
+
+ //Validate liquid quantities
+ if (EnableJobLiquidQuantityValidation && MachineType == MachineTypes.TS1800)
+ {
+ requiredLiquids = ValidateJobLiquidQuantity(job, processParameters, job.Machine.Configuration);
+ }
+ else
+ {
+ LogManager.Log("Liquid quantity validation is disabled. Skipping...");
+ }
+
+ return requiredLiquids;
+ });
+ }
+
+ private Task ApplyTransparentBrushStops(Job job)
+ {
+ return Task.Run(() =>
+ {
+ LogManager.Log("Modifying all 'white' brush stops...");
+ foreach (var stop in job.OrderedSegmentsWithGroups.SelectMany(x => x.BrushStops).Where(x => x.IsTransparent || x.IsWhite).ToList())
+ {
+ foreach (var liquidVolume in stop.LiquidVolumes.Where(x => x.LiquidType != LiquidTypes.TransparentInk && x.LiquidType != LiquidTypes.Lubricant).ToList())
+ {
+ liquidVolume.Volume = 0;
+ }
+
+ var tiLiquid = stop.LiquidVolumes.SingleOrDefault(x => x.IdsPack != null && x.IdsPack.LiquidType != null && x.LiquidType == LiquidTypes.TransparentInk);
+
+ if (tiLiquid != null)
+ {
+ tiLiquid.Volume = 100;
+ }
+ }
+ });
+ }
+
+ private Task ApplyLubrication(Job job, AdditionalJobConfiguration config)
+ {
+ return Task.Run(() =>
+ {
+ if (job.EnableLubrication)
+ {
+ if (config.UseLubricantVolume)
+ {
+ LogManager.Log($"Job custom lubrication is enabled. Settings all brush stops to {config.LubricationVolume}% lubricant.");
+
+ foreach (var stop in job.OrderedSegmentsWithGroups.ToList().SelectMany(x => x.BrushStops).ToList())
+ {
+ var lubricantVolume = stop.LiquidVolumes.SingleOrDefault(x => x.IdsPack != null && x.IdsPack.LiquidType != null && x.LiquidType == LiquidTypes.Lubricant);
+
+ if (lubricantVolume != null)
+ {
+ lubricantVolume.Volume = config.LubricationVolume;
+ }
+ }
+ }
+ else
+ {
+ LogManager.Log($"Job auto lubrication is enabled. Settings all none Volume brush stops to 100% lubricant.");
+
+ foreach (var stop in job.OrderedSegmentsWithGroups.ToList().SelectMany(x => x.BrushStops).Where(x => x.BrushColorSpace != ColorSpaces.Volume).ToList())
+ {
+ var lubricantVolume = stop.LiquidVolumes.SingleOrDefault(x => x.IdsPack != null && x.IdsPack.LiquidType != null && x.LiquidType == LiquidTypes.Lubricant);
+
+ if (lubricantVolume != null)
+ {
+ lubricantVolume.Volume = 100;
+ }
+ }
+ }
+ }
+ else
+ {
+ LogManager.Log("Job lubrication is disabled.");
+ }
+ });
+ }
+
+ private Task ApplyColorConversion(Job job, ProcessParametersTable processParameters, AdditionalJobConfiguration config)
+ {
+ return Task.Run(() =>
+ {
+ if (config.UseColorConversion)
+ {
+ IColorConverter converter = new DefaultColorConverter();
+
+ bool useLightInks = config.UseLightInks;
+
+ //Use light inks only if one segment or inter segment is enabled.
+ if (MachineType == MachineTypes.TS1800 && job.OrderedSegmentsWithGroups.Count > 1 && !job.EnableInterSegment) useLightInks = false;
+
+ foreach (var segment in job.OrderedSegmentsWithGroups.ToList())
+ {
+ foreach (var stop in segment.BrushStops)
+ {
+ try
+ {
+ var output = converter.Convert(stop, false, useLightInks && segment.BrushStops.Count == 1); //Use light inks only if this is a solid segment.
+ output.ApplyOnBrushStopLiquidVolumes(stop, processParameters);
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"Error processing the coordinates of stop '{stop.StopIndex}' of segment '{stop.Segment.SegmentIndex}'.", ex);
+ }
+
+ if (stop.IsLiquidVolumesOutOfRange)
+ {
+ throw new InvalidOperationException($"The specified ink volumes at segment {segment.SegmentIndex} exceeds the maximum allowed total volume for the current thread.");
+ }
+ }
+ }
+ }
+ });
+ }
+
+ protected CurrentJobContext CreateJobContext(Job job, AdditionalJobConfiguration config, MachineStatus machineStatus = null)
+ {
+ var jobContext = new CurrentJobContext(machineStatus ?? MachineStatus, GetJobRunLiquidQuantities);
+
+ jobContext.InitialUseKeepAlive = UseKeepAlive;
+
+ jobContext.StartDate = DateTime.UtcNow;
+
+ RunningJob = null;
+ RunningJobStatus = null;
+
+ if (job != null)
+ {
+ if (job.NumberOfUnits < 1)
+ {
+ job.NumberOfUnits = 1;
+ }
+
+ jobContext.Job = job;
+ jobContext.OriginalJob = job;
+
+ var clonedJob = job.Clone();
+ clonedJob.Guid = job.Guid;
+ clonedJob.Name = job.Name;
+
+ jobContext.ClonedJob = clonedJob;
+
+ job = job.Clone();
+ job.Guid = jobContext.OriginalJob.Guid;
+ job.Name = jobContext.OriginalJob.Name;
+ jobContext.Job = job;
+
+ var jobForJobRun = job.Clone();
+ jobForJobRun.Guid = job.Guid;
+ jobForJobRun.Name = job.Name;
+ jobForJobRun.ID = job.ID;
+
+ if (config.ResumeConfig != null)
+ {
+ jobForJobRun.ResumeStartPosition = config.ResumeConfig.ResumeProgress;
+ }
+
+ jobContext.JobForJobRun = jobForJobRun;
+
+ RunningJob = clonedJob;
+ }
+
+ return jobContext;
+ }
+
+ private Task NormalizeJobTicket(JobTicket ticket, ProcessParametersTable processParameters)
+ {
+ return Task.Run(() =>
+ {
+ var maxNanoStop = ticket.Segments.SelectMany(x => x.BrushStops).OrderBy(x => x.GetTotalNanoliterPerCentimeter()).Last();
+ double maxNanoliter = maxNanoStop.GetTotalNanoliterPerCentimeter();
+
+ LogManager.Log($"Normalizing brush stops TI quantities by {maxNanoliter} nanoliters...");
+
+ foreach (var stop in ticket.Segments.SelectMany(x => x.BrushStops).Where(x => x != maxNanoStop))
+ {
+ stop.NormalizeStop(maxNanoliter, processParameters.MinInkUptake, processParameters.DyeingSpeed);
+ }
+ });
+ }
+
+ #endregion
}
}