Skip to content

Commit

Permalink
Merge branch 'dev' into future
Browse files Browse the repository at this point in the history
  • Loading branch information
1nf0rmagician committed Dec 4, 2024
2 parents bf12e8d + e1dbcf2 commit 0c68a7c
Show file tree
Hide file tree
Showing 12 changed files with 152 additions and 29 deletions.
7 changes: 6 additions & 1 deletion src/Moryx.ControlSystem/Activities/ActivityClassification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ namespace Moryx.ControlSystem.Activities
[Flags]
public enum ActivityClassification
{
/// <summary>
/// Use in case the activity classification is unkown
/// </summary>
Unknown = 0x00,

/// <summary>
/// Default classification is production
/// </summary>
Expand All @@ -33,6 +38,6 @@ public enum ActivityClassification
/// <summary>
/// Activity performs a preparation, for example for a <see cref="Production"/> activity
/// </summary>
Preparation = 0x08
Preparation = 0x08,
}
}
3 changes: 0 additions & 3 deletions src/Moryx.ControlSystem/Cells/ActivityCompleted.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ namespace Moryx.ControlSystem.Cells
/// </summary>
public class ActivityCompleted : Session, ICompletableSession
{
/// <summary>
/// Initialize a new resource request for a certain resource
/// </summary>
internal ActivityCompleted(IActivity completed, Session currentSession)
: base(currentSession)
{
Expand Down
10 changes: 3 additions & 7 deletions src/Moryx.ControlSystem/Cells/ReadyToWork.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,20 +52,16 @@ internal ReadyToWork(Session currentSession)
/// </summary>
/// <param name="activity">The activity.</param>
public ActivityStart StartActivity(IActivity activity)
{
// Update process before next stage
Process = activity.Process;
return new ActivityStart(this, activity);
{
return new ActivityStart(this, activity) { Process = activity.Process };
}

/// <summary>
/// Creates the SequenceCompleted message
/// </summary>
public SequenceCompleted CompleteSequence(IProcess process, bool processActive, params long[] nextCells)
{
// Update process before next stage
Process = process;
return new SequenceCompleted(this, processActive, nextCells);
return new SequenceCompleted(this, processActive, nextCells) { Process = process };
}

/// <summary>
Expand Down
32 changes: 24 additions & 8 deletions src/Moryx.ControlSystem/Cells/Session.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public abstract class Session
/// <summary>
/// Empty array of constraints
/// </summary>
protected static readonly IConstraint[] EmptyConstraints = new IConstraint[0];
protected static readonly IConstraint[] EmptyConstraints = Array.Empty<IConstraint>();

/// <summary>
/// Initialize a new resource request for a certain resource
Expand All @@ -37,7 +37,7 @@ protected Session(Session currentSession)
/// <summary>
/// Context class holding all session information
/// </summary>
private readonly SessionContext _context;
private SessionContext _context;

/// <summary>
/// Unique id of the current production transaction
Expand Down Expand Up @@ -125,6 +125,19 @@ public static ReadyToWork StartSession(ActivityClassification classification, Re
return CreateSession(classification, type, ProcessReference.InstanceIdentity(identity), constraints);
}


/// <summary>
/// Creates a new <see cref="Session"/> for the <paramref name="unknown"/> activity
/// with a new session context and marks the activity as failed.
/// </summary>
/// <param name="unknown"></param>
public static UnknownActivityAborted WrapUnknownActivity(IActivity unknown)
{
var wrapper = StartSession(ActivityClassification.Unknown, ReadyToWorkType.Unset, unknown.Process.Id)
.CompleteSequence(null, false, new long[] { });
return new UnknownActivityAborted(unknown, wrapper);
}

private static ReadyToWork CreateSession(ActivityClassification classification, ReadyToWorkType type, ProcessReference reference, IConstraint[] constraints)
{
if (constraints == null)
Expand All @@ -134,24 +147,27 @@ private static ReadyToWork CreateSession(ActivityClassification classification,

#endregion

private class SessionContext
private struct SessionContext
{
internal SessionContext(ActivityClassification classification, Guid sessionId, ProcessReference reference)
{
Classification = classification;
SessionId = sessionId;
Reference = reference;

Tag = null;
Process = null;
}

public Guid SessionId { get; }
public Guid SessionId;

public IProcess Process { get; set; }
public IProcess Process;

public ProcessReference Reference { get; set; }
public ProcessReference Reference;

public ActivityClassification Classification { get; }
public ActivityClassification Classification;

public object Tag { get; set; }
public object Tag;
}
}
}
26 changes: 26 additions & 0 deletions src/Moryx.ControlSystem/Cells/UnknownActivityAborted.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) 2024, Phoenix Contact GmbH & Co. KG
// Licensed under the Apache License, Version 2.0

using Moryx.AbstractionLayer;

namespace Moryx.ControlSystem.Cells
{
/// <summary>
/// Message send by the resource managment when it aborted an activity for an
/// unkown session.
/// </summary>
public class UnknownActivityAborted : ActivityCompleted
{
internal UnknownActivityAborted(IActivity aborted, Session wrapper)
: base(aborted, wrapper)
{
aborted.Fail();
AbortedActivity = aborted;
}

/// <summary>
/// Activity that was aborted
/// </summary>
public IActivity AbortedActivity { get; }
}
}
12 changes: 9 additions & 3 deletions src/Moryx.ControlSystem/Jobs/Job.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,20 @@ public Job(IRecipe recipe, int amount)
/// Classification of the job
/// </summary>
public JobClassification Classification { get; set; }


/// <summary>
/// Detailed display name of the state
/// TODO: Remove this property in next major and replace with reworked JobClassification
/// </summary>
public virtual string StateDisplayName { get; protected set; }

private IReadOnlyList<IProcess> _runningProcesses;
/// <summary>
/// Currently running processes of the job
/// </summary>
public IReadOnlyList<IProcess> RunningProcesses
{
get => _runningProcesses ?? new IProcess[0];
get => _runningProcesses ?? Array.Empty<IProcess>();
protected set => _runningProcesses = value;
}

Expand All @@ -73,7 +79,7 @@ public IReadOnlyList<IProcess> RunningProcesses
/// </summary>
public IReadOnlyList<IProcess> AllProcesses
{
get => _allProcesses ?? new IProcess[0];
get => _allProcesses ?? Array.Empty<IProcess>();
protected set => _allProcesses = value;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Moryx.ControlSystem/Jobs/JobSchedulerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public abstract class JobSchedulerBase<T> : IJobScheduler
/// <summary>
/// Empty array for jobs without dependencies
/// </summary>
private readonly Job[] EmptyDependencies = new Job[0];
private readonly Job[] EmptyDependencies = Array.Empty<Job>();

/// <summary>
/// Dependency map that can be helpful for job scheduling
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ public static int ResultToEnumValue(Type resultEnum, InstructionResult result)
return int.Parse(result.Key);
}

/// <summary>
/// Extract result from response object depending on what values is present
/// </summary>
public static int ResultToEnumValue(Type resultEnum, ActiveInstructionResponse response)
{
if(response.SelectedResult != null)
return ResultToEnumValue(resultEnum, response.SelectedResult);

if (response.SelectedResult != null)
return ResultToEnumValue(resultEnum, response.SelectedResult);

throw new ArgumentException("No result found on response", nameof(response));
}

/// <summary>
/// Convert string result to typed enum
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System;
// Copyright (c) 2024, Phoenix Contact GmbH & Co. KG
// Licensed under the Apache License, Version 2.0

using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
Expand Down Expand Up @@ -155,6 +158,8 @@ private static long ExecuteWithEnum(this IVisualInstructor instructor, string ti
throw new ArgumentException("Result type is not an enum!");

var results = EnumInstructionResult.PossibleResults(attr.ResultEnum);
var resultObjects = EnumInstructionResult.PossibleInstructionResults(attr.ResultEnum);

Check warning on line 161 in src/Moryx.ControlSystem/VisualInstructions/VisualInstructorExtensions.cs

View workflow job for this annotation

GitHub Actions / Build / Build

'EnumInstructionResult.PossibleInstructionResults(Type, params string[])' is obsolete: 'Method took over the previous signature, use 'PossibleResults' instead'

Check warning on line 161 in src/Moryx.ControlSystem/VisualInstructions/VisualInstructorExtensions.cs

View workflow job for this annotation

GitHub Actions / UnitTests / UnitTests

'EnumInstructionResult.PossibleInstructionResults(Type, params string[])' is obsolete: 'Method took over the previous signature, use 'PossibleResults' instead'

Check warning on line 161 in src/Moryx.ControlSystem/VisualInstructions/VisualInstructorExtensions.cs

View workflow job for this annotation

GitHub Actions / IntegrationTests / IntegrationTests

'EnumInstructionResult.PossibleInstructionResults(Type, params string[])' is obsolete: 'Method took over the previous signature, use 'PossibleResults' instead'

return instructor.Execute(new ActiveInstruction
{
Title = title,
Expand All @@ -172,5 +177,19 @@ private static VisualInstruction[] GetInstructions(ActivityStart activity)

return parameters.Instructions;
}

/// <summary>
/// Returns a text instruction for the given string.
/// </summary>
/// <param name="text">Instruction text</param>
/// <returns><see cref="VisualInstruction"/> with type `Text` the given string as content</returns>
public static VisualInstruction AsInstruction(this string text)
{
return new VisualInstruction
{
Content = text,
Type = InstructionContentType.Text,
};
}
}
}
3 changes: 2 additions & 1 deletion src/Moryx.Orders/Assignment/Recipes/RecipeAssignmentBase.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) 2021, Phoenix Contact GmbH & Co. KG
// Licensed under the Apache License, Version 2.0

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
Expand Down Expand Up @@ -55,7 +56,7 @@ public virtual Task<IReadOnlyList<IProductRecipe>> PossibleRecipes(ProductIdenti
{
var product = ProductManagement.LoadType(identity);
if (product == null)
return Task.FromResult<IReadOnlyList<IProductRecipe>>(new IProductRecipe[0]);
return Task.FromResult<IReadOnlyList<IProductRecipe>>(Array.Empty<IProductRecipe>());

var recipes = ProductManagement.GetRecipes(product, RecipeClassification.Default | RecipeClassification.Alternative);
return Task.FromResult(recipes);
Expand Down
24 changes: 20 additions & 4 deletions src/Tests/Moryx.ControlSystem.Tests/ProductionSessionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,11 @@ public void TestCreateActivityStart()
{
var readyToWork = Session.StartSession(ActivityClassification.Production, ReadyToWorkType.Pull, 4242);

var activityStart = readyToWork.StartActivity(new DummyActivity { Process = new Process() });
var activityStart = readyToWork.StartActivity(new DummyActivity { Process = new Process { Id = 4242 } });

Assert.AreEqual(readyToWork.Reference, activityStart.Reference);
Assert.AreEqual(readyToWork.Id, activityStart.Id);
Assert.AreNotEqual(readyToWork.Process, activityStart.Process); // Make sure process is not populated back to RTW
}

[Test]
Expand Down Expand Up @@ -82,7 +83,7 @@ public void TestCreateActivityResult()
{
var readyToWork = Session.StartSession(ActivityClassification.Production, ReadyToWorkType.Pull, 4242);

var activityStart = readyToWork.StartActivity(new DummyActivity { Process = new Process() });
var activityStart = readyToWork.StartActivity(new DummyActivity { Process = new Process { Id = 4242 } });
activityStart.Activity.Complete(1);

var activityCompleted = activityStart.CreateResult();
Expand All @@ -96,7 +97,7 @@ public void TestCompleteSequence()
{
var readyToWork = Session.StartSession(ActivityClassification.Production, ReadyToWorkType.Pull, 4242);

var activityStart = readyToWork.StartActivity(new DummyActivity {Process = new Process()});
var activityStart = readyToWork.StartActivity(new DummyActivity { Process = new Process { Id = 4242 } });
activityStart.Activity.Complete(1);

var activityCompleted = activityStart.CreateResult();
Expand All @@ -123,7 +124,7 @@ public void TestContinueSession(ReadyToWorkType readyToWorkType)
{
var readyToWork = Session.StartSession(ActivityClassification.Production, readyToWorkType, 4242);

var activityStart = readyToWork.StartActivity(new DummyActivity { Process = new Process() });
var activityStart = readyToWork.StartActivity(new DummyActivity { Process = new Process { Id = 4242 } });
activityStart.Activity.Complete(1);

var activityCompleted = activityStart.CreateResult();
Expand All @@ -138,5 +139,20 @@ public void TestContinueSession(ReadyToWorkType readyToWorkType)
Assert.AreEqual(ReadyToWorkType.Pull, readyToWork2.ReadyToWorkType);
}

[Test]
public void TestUnknownActivityAborted()
{
// Arrange
var process = new Process { Id = 4242 };
var activity = new DummyActivity { Process = process };

// Act
var session = Session.WrapUnknownActivity(activity);

// Assert
Assert.That(session.AcceptedClassification, Is.EqualTo(ActivityClassification.Unknown));
Assert.That(session.AbortedActivity, Is.EqualTo(activity));
Assert.That(session.Reference.Matches(process));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) 2024, Phoenix Contact GmbH & Co. KG
// Licensed under the Apache License, Version 2.0

using Moq;
using Moryx.ControlSystem.VisualInstructions;
using NUnit.Framework;
using System;

namespace Moryx.ControlSystem.Tests.VisualInstructions
{
[TestFixture]

public class VisualInstructorExtensionsTests
{
[Test]
public void ExtensionCreatesStringAsInstruction()
{
var str = "text instruction";

var instruction = str.AsInstruction();

Assert.That(instruction.Type, Is.EqualTo(InstructionContentType.Text));
Assert.That(instruction.Content, Is.EqualTo(str));
}

}
}

0 comments on commit 0c68a7c

Please sign in to comment.