Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/dev' into future
Browse files Browse the repository at this point in the history
  • Loading branch information
1nf0rmagician committed Dec 20, 2024
2 parents 0c68a7c + df9e1e9 commit 1fa62c3
Show file tree
Hide file tree
Showing 6 changed files with 527 additions and 93 deletions.
128 changes: 128 additions & 0 deletions src/Moryx.ControlSystem/Cells/SessionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// Copyright (c) 2024, Phoenix Contact GmbH & Co. KG
// Licensed under the Apache License, Version 2.0

using Moryx.AbstractionLayer.Recipes;
using Moryx.AbstractionLayer;
using Moryx.AbstractionLayer.Products;
using Moryx.ControlSystem.Recipes;
using System;
using Moryx.ControlSystem.Processes;

namespace Moryx.ControlSystem.Cells
{
/// <summary>
/// Extension methods on the <see cref="Session"/> to get product related information, activity details or just provide shortcuts based on the actual session type
/// </summary>
public static class SessionExtensions
{
/// <summary>
/// Extension method to get the <see cref="ProductInstance"/> from the <see cref="Process"/> of the <paramref name="session"/>
/// </summary>
/// <typeparam name="TProductInstance">Type of the <see cref="ProductInstance"/> that is expected.</typeparam>
/// <param name="session">The sesion to get the <see cref="ProductInstance"/> from</param>
/// <returns>
/// The <see cref="ProductInstance"/> in the session, if the <paramref name="session"/> belongs to a
/// <see cref="ProductionProcess"/> and the <see cref="ProductionProcess"/> holds a <typeparamref name="TProductInstance"/>;
/// Otherwise returns null
/// </returns>
public static TProductInstance GetProductInstance<TProductInstance>(this Session session) where TProductInstance : ProductInstance
{
if (session.Process is not ProductionProcess process) return null;

return process.ProductInstance as TProductInstance;
}

/// <summary>
/// Modifies the <see cref="IProductInstance"/> of type <typeparamref name="TInstance"/>
/// on the <see cref="IProcess"/> of the <paramref name="session"/> using the given
/// <paramref name="setter"/>.
/// </summary>
/// <typeparam name="TInstance">The expected type of the product instance</typeparam>
/// <param name="session">The sessopm holding the product instance</param>
/// <param name="setter">The action to be executed on the product instance</param>
/// <example>
/// <code>
/// <![CDATA[
/// session.ModifyProductInstance<MyProductInstance>((var instance) => instance.MyProperty = 1)
/// ]]>
/// </code>
/// </example>
/// <exception cref="InvalidCastException">Thrown if the <see cref="IProcess"/> of the
/// <paramref name="session"/> does not hold a product instance of type <typeparamref name="TInstance"/>
/// </exception>
/// <exception cref="InvalidOperationException">Thrown if the <see cref="IProcess"/> of the
/// <paramref name="session"/> is no <see cref="ProductionProcess"/></exception>
public static TInstance ModifyProductInstance<TInstance>(this Session session, Action<TInstance> setter)
where TInstance : IProductInstance => session.Process.ModifyProductInstance(setter);

/// <summary>
/// Tries to modifies the <see cref="IProductInstance"/> of type <typeparamref name="TInstance"/>
/// on the <see cref="IProcess"/> of the <paramref name="session"/> using the given
/// <paramref name="setter"/>. Returns false, if the
/// operation could not be executed.
/// </summary>
/// <typeparam name="TInstance">The expected type of the product instance</typeparam>
/// <param name="session">The sessopm holding the product instance</param>
/// <param name="setter">The action to be executed on the product instance</param>
/// <example>
/// <code>
/// <![CDATA[
/// session.TryModifyingProductInstance<MyProductInstance>((var instance) => instance.MyProperty = 1)
/// ]]>
/// </code>
/// </example>
public static bool TryModifyProductInstance<TInstance>(this Session session, Action<TInstance> setter)
where TInstance : IProductInstance => session.Process.TryModifyProductInstance(setter);

/// <summary>
/// Extension method to get the <see cref="Activity"/> from the <paramref name="session"/>
/// </summary>
/// <typeparam name="TActivityType">Type of the <see cref="Activity"/> that is expected.</typeparam>
/// <param name="session">The sesion to get the <see cref="Activity"/> from</param>
/// <returns>
/// The <see cref="Activity"/> in the session, if the <paramref name="session"/> currently handles an
/// Activity of type <typeparamref name="TActivityType"/>; Otherwise returns null
/// </returns>
public static TActivityType GetActivity<TActivityType>(this Session session) where TActivityType : Activity
{
if (session is ActivityCompleted completed)
return completed.CompletedActivity as TActivityType;
if (session is ActivityStart start)
return start.Activity as TActivityType;

return null;
}

/// <summary>
/// Extension method to get the last <see cref="Activity"/> from the <paramref name="session"/>
/// </summary>
/// <typeparam name="TActivityType">Type of the <see cref="Activity"/> that is expected.</typeparam>
/// <param name="session">The sesion to get the <see cref="Activity"/> from</param>
/// <returns>
/// The last <see cref="Activity"/> in the session, if the <paramref name="session"/> currently handles an
/// Activity of type <typeparamref name="TActivityType"/>; Otherwise returns null
/// </returns>
public static TActivityType GetLastActivity<TActivityType>(this Session session) where TActivityType : Activity
=> session.Process.LastActivity<TActivityType>() as TActivityType;

/// <summary>
/// Extension method to get the <see cref="ProductType"/> from the <paramref name="session"/>
/// </summary>
/// <typeparam name="TProductType">Type of the <see cref="ProductType"/> that is expected.</typeparam>
/// <param name="session">The session to get the <see cref="ProductType"/> from</param>
/// <returns>
/// The target <see cref="ProductType"/> in the session, if it belongs to a <see cref="ProductionProcess"/>
/// or holds an <see cref="ISetupRecipe"/> with a <typeparamref name="TProductType"/>; Otherwise returns null.
/// </returns>
public static TProductType GetProductType<TProductType>(this Session session) where TProductType : ProductType
{
if (session.Process.Recipe is ISetupRecipe setupRecipe)
return setupRecipe.TargetRecipe.Target as TProductType;

if (session.Process.Recipe is IProductRecipe prodcutRecipe)
return prodcutRecipe.Target as TProductType;

return default;
}
}
}
51 changes: 51 additions & 0 deletions src/Moryx.ControlSystem/Jobs/JobExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) 2024, Phoenix Contact GmbH & Co. KG
// Licensed under the Apache License, Version 2.0

using Moryx.AbstractionLayer.Recipes;
using Moryx.ControlSystem.Recipes;
using Moryx.ControlSystem.Setups;

namespace Moryx.ControlSystem.Jobs
{
/// <summary>
/// Extensions methods for <see cref="Job"/>s.
/// </summary>
public static class JobExtensions
{
/// <summary>
/// Checks whether the <paramref name="job"/> is an <see cref="IPredictiveJob"/>
/// and gets the predicted failure count; otherwise returns 0.
/// </summary>
public static int CountPredictedFailures(this Job job)
{
if (job is IPredictiveJob predictiveJob)
return predictiveJob.PredictedFailures.Count;

return 0;
}

/// <summary>
/// Checks if the <paramref name="job"/> references an <see cref="IProductionRecipe"/>
/// </summary>
public static bool IsProduction(this Job job) => job.Recipe is IProductionRecipe;

/// <summary>
/// Checks if the <paramref name="job"/> references an <see cref="ISetupRecipe"/>
/// </summary>
public static bool IsSetup(this Job job) => job.Recipe is ISetupRecipe;

/// <summary>
/// Checks if the <paramref name="job"/> holds an <see cref="ISetupRecipe"/>
/// that is set to be executed <see cref="SetupExecution.BeforeProduction"/>
/// </summary>
public static bool IsPreparingSetup(this Job job)
=> job.Recipe is ISetupRecipe setup && setup.Execution == SetupExecution.BeforeProduction;

/// <summary>
/// Checks if the <paramref name="job"/> holds an <see cref="ISetupRecipe"/>
/// that is set to be executed <see cref="SetupExecution.AfterProduction"/>
/// </summary>
public static bool IsCleaningUpSetup(this Job job)
=> job.Recipe is ISetupRecipe setup && setup.Execution == SetupExecution.AfterProduction;
}
}
70 changes: 70 additions & 0 deletions src/Moryx.ControlSystem/Processes/IProcessExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using Moryx.AbstractionLayer.Products;
using Moryx.AbstractionLayer;
using System;
using System.Collections.Generic;
using System.Text;

namespace Moryx.ControlSystem.Processes
{
/// <summary>
/// Extensions on an <see cref="IProcess"/>
/// </summary>
public static class IProcessExtensions
{
/// <summary>
/// Modifies the <see cref="IProductInstance"/> of type <typeparamref name="TInstance"/>
/// on the <see cref="IProcess"/> using the given <paramref name="setter"/>.
/// </summary>
/// <typeparam name="TInstance">The expected type of the product instance</typeparam>
/// <param name="process">The process holding the product instance</param>
/// <param name="setter">The action to be executed on the product instance</param>
/// <example>
/// <code>
/// <![CDATA[
/// process.ModifyProductInstance<MyProductInstance>((var instance) => instance.MyProperty = 1)
/// ]]>
/// </code>
/// </example>
/// <exception cref="InvalidCastException">Thrown if the given <paramref name="process"/> does
/// not hold a product instance of type <typeparamref name="TInstance"/></exception>
/// <exception cref="InvalidOperationException">Thrown if the given <paramref name="process"/>
/// is no <see cref="ProductionProcess"/></exception>
public static TInstance ModifyProductInstance<TInstance>(this IProcess process, Action<TInstance> setter)
where TInstance : IProductInstance
{
if (process is not ProductionProcess productionProcess)
throw new InvalidOperationException($"Cannot modify an {nameof(IProductInstance)} on a process of type {process.GetType()}");
if (productionProcess.ProductInstance is not TInstance instance)
throw new InvalidCastException($"Cannot cast {nameof(ProductionProcess.ProductInstance)} of type " +
$"{productionProcess?.ProductInstance?.GetType()} to {typeof(TInstance)}");
setter.Invoke(instance);
return instance;
}

/// <summary>
/// Tries to modifies the <see cref="IProductInstance"/> of type <typeparamref name="TInstance"/>
/// on the <see cref="IProcess"/> using the given <paramref name="setter"/>. Returns false, if the
/// operation could not be executed.
/// </summary>
/// <typeparam name="TInstance">The expected type of the product instance</typeparam>
/// <param name="process">The process holding the product instance</param>
/// <param name="setter">The action to be executed on the product instance</param>
/// <example>
/// <code>
/// <![CDATA[
/// process.TryModifyingProductInstance<MyProductInstance>((var instance) => instance.MyProperty = 1)
/// ]]>
/// </code>
/// </example>
public static bool TryModifyProductInstance<TInstance>(this IProcess process, Action<TInstance> setter)
where TInstance : IProductInstance
{
if (process is not ProductionProcess productionProcess)
return false;
if (productionProcess.ProductInstance is not TInstance instance)
return false;
setter.Invoke(instance);
return true;
}
}
}
Loading

0 comments on commit 1fa62c3

Please sign in to comment.